machdep_boot.c revision 331524
1/*-
2 * Copyright (c) 2004 Olivier Houchard
3 * Copyright (c) 1994-1998 Mark Brinicombe.
4 * Copyright (c) 1994 Brini.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "opt_platform.h"
30#include "opt_ddb.h"
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: stable/11/sys/arm/arm/machdep_boot.c 331524 2018-03-25 02:04:44Z ian $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/ctype.h>
38#include <sys/linker.h>
39#include <sys/reboot.h>
40#include <sys/sysctl.h>
41#if defined(LINUX_BOOT_ABI)
42#include <sys/boot.h>
43#endif
44
45#include <machine/atags.h>
46#include <machine/cpu.h>
47#include <machine/machdep.h>
48#include <machine/metadata.h>
49#include <machine/physmem.h>
50#include <machine/vmparam.h>	/* For KERNVIRTADDR */
51
52#ifdef FDT
53#include <contrib/libfdt/libfdt.h>
54#include <dev/fdt/fdt_common.h>
55#endif
56
57#ifdef EFI
58#include <sys/efi.h>
59#endif
60
61#ifdef DDB
62#include <ddb/ddb.h>
63#endif
64
65#ifdef DEBUG
66#define	debugf(fmt, args...) printf(fmt, ##args)
67#else
68#define	debugf(fmt, args...)
69#endif
70
71extern int *end;
72
73static uint32_t board_revision;
74/* hex representation of uint64_t */
75static char board_serial[32];
76static char *loader_envp;
77
78#if defined(LINUX_BOOT_ABI)
79#define LBABI_MAX_BANKS	10
80#define CMDLINE_GUARD "FreeBSD:"
81static uint32_t board_id;
82static struct arm_lbabi_tag *atag_list;
83static char linux_command_line[LBABI_MAX_COMMAND_LINE + 1];
84static char atags[LBABI_MAX_COMMAND_LINE * 2];
85#endif /* defined(LINUX_BOOT_ABI) */
86
87SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes");
88SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD,
89    &board_revision, 0, "Board revision");
90SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD,
91    board_serial, 0, "Board serial");
92
93int vfp_exists;
94SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
95    &vfp_exists, 0, "Floating point support enabled");
96
97void
98board_set_serial(uint64_t serial)
99{
100
101	snprintf(board_serial, sizeof(board_serial)-1,
102		    "%016jx", serial);
103}
104
105void
106board_set_revision(uint32_t revision)
107{
108
109	board_revision = revision;
110}
111
112static char *
113kenv_next(char *cp)
114{
115
116	if (cp != NULL) {
117		while (*cp != 0)
118			cp++;
119		cp++;
120		if (*cp == 0)
121			cp = NULL;
122	}
123	return (cp);
124}
125
126void
127arm_print_kenv(void)
128{
129	char *cp;
130
131	debugf("loader passed (static) kenv:\n");
132	if (loader_envp == NULL) {
133		debugf(" no env, null ptr\n");
134		return;
135	}
136	debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp);
137
138	for (cp = loader_envp; cp != NULL; cp = kenv_next(cp))
139		debugf(" %x %s\n", (uint32_t)cp, cp);
140}
141
142
143#if defined(LINUX_BOOT_ABI)
144
145/* Convert the U-Boot command line into FreeBSD kenv and boot options. */
146static void
147cmdline_set_env(char *cmdline, const char *guard)
148{
149	char *cmdline_next, *env;
150	size_t size, guard_len;
151	int i;
152
153	size = strlen(cmdline);
154	/* Skip leading spaces. */
155	for (; isspace(*cmdline) && (size > 0); cmdline++)
156		size--;
157
158	/* Test and remove guard. */
159	if (guard != NULL && guard[0] != '\0') {
160		guard_len  =  strlen(guard);
161		if (strncasecmp(cmdline, guard, guard_len) != 0)
162			return;
163		cmdline += guard_len;
164		size -= guard_len;
165	}
166
167	/* Skip leading spaces. */
168	for (; isspace(*cmdline) && (size > 0); cmdline++)
169		size--;
170
171	/* Replace ',' with '\0'. */
172	/* TODO: implement escaping for ',' character. */
173	cmdline_next = cmdline;
174	while(strsep(&cmdline_next, ",") != NULL)
175		;
176	init_static_kenv(cmdline, 0);
177	/* Parse boothowto. */
178	for (i = 0; howto_names[i].ev != NULL; i++) {
179		env = kern_getenv(howto_names[i].ev);
180		if (env != NULL) {
181			if (strtoul(env, NULL, 10) != 0)
182				boothowto |= howto_names[i].mask;
183			freeenv(env);
184		}
185	}
186}
187
188void arm_parse_fdt_bootargs(void)
189{
190
191#ifdef FDT
192	if (loader_envp == NULL && fdt_get_chosen_bootargs(linux_command_line,
193	    LBABI_MAX_COMMAND_LINE) == 0)
194		cmdline_set_env(linux_command_line, CMDLINE_GUARD);
195#endif
196}
197
198static vm_offset_t
199linux_parse_boot_param(struct arm_boot_params *abp)
200{
201	struct arm_lbabi_tag *walker;
202	uint32_t revision;
203	uint64_t serial;
204	int size;
205	vm_offset_t lastaddr;
206#ifdef FDT
207	struct fdt_header *dtb_ptr;
208	uint32_t dtb_size;
209#endif
210
211	/*
212	 * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2
213	 * is atags or dtb pointer.  If all of these aren't satisfied,
214	 * then punt. Unfortunately, it looks like DT enabled kernels
215	 * doesn't uses board type and U-Boot delivers 0 in r1 for them.
216	 */
217	if (abp->abp_r0 != 0 || abp->abp_r2 == 0)
218		return (0);
219#ifdef FDT
220	/* Test if r2 point to valid DTB. */
221	dtb_ptr = (struct fdt_header *)abp->abp_r2;
222	if (fdt_check_header(dtb_ptr) == 0) {
223		dtb_size = fdt_totalsize(dtb_ptr);
224		return (fake_preload_metadata(abp, dtb_ptr, dtb_size));
225	}
226#endif
227
228	board_id = abp->abp_r1;
229	walker = (struct arm_lbabi_tag *)abp->abp_r2;
230
231	if (ATAG_TAG(walker) != ATAG_CORE)
232		return 0;
233
234	atag_list = walker;
235	while (ATAG_TAG(walker) != ATAG_NONE) {
236		switch (ATAG_TAG(walker)) {
237		case ATAG_CORE:
238			break;
239		case ATAG_MEM:
240			arm_physmem_hardware_region(walker->u.tag_mem.start,
241			    walker->u.tag_mem.size);
242			break;
243		case ATAG_INITRD2:
244			break;
245		case ATAG_SERIAL:
246			serial = walker->u.tag_sn.high;
247			serial <<= 32;
248			serial |= walker->u.tag_sn.low;
249			board_set_serial(serial);
250			break;
251		case ATAG_REVISION:
252			revision = walker->u.tag_rev.rev;
253			board_set_revision(revision);
254			break;
255		case ATAG_CMDLINE:
256			size = ATAG_SIZE(walker) -
257			    sizeof(struct arm_lbabi_header);
258			size = min(size, LBABI_MAX_COMMAND_LINE);
259			strncpy(linux_command_line, walker->u.tag_cmd.command,
260			    size);
261			linux_command_line[size] = '\0';
262			break;
263		default:
264			break;
265		}
266		walker = ATAG_NEXT(walker);
267	}
268
269	/* Save a copy for later */
270	bcopy(atag_list, atags,
271	    (char *)walker - (char *)atag_list + ATAG_SIZE(walker));
272
273	lastaddr = fake_preload_metadata(abp, NULL, 0);
274	cmdline_set_env(linux_command_line, CMDLINE_GUARD);
275	return lastaddr;
276}
277#endif
278
279#if defined(FREEBSD_BOOT_LOADER)
280static vm_offset_t
281freebsd_parse_boot_param(struct arm_boot_params *abp)
282{
283	vm_offset_t lastaddr = 0;
284	void *mdp;
285	void *kmdp;
286#ifdef DDB
287	vm_offset_t ksym_start;
288	vm_offset_t ksym_end;
289#endif
290
291	/*
292	 * Mask metadata pointer: it is supposed to be on page boundary. If
293	 * the first argument (mdp) doesn't point to a valid address the
294	 * bootloader must have passed us something else than the metadata
295	 * ptr, so we give up.  Also give up if we cannot find metadta section
296	 * the loader creates that we get all this data out of.
297	 */
298
299	if ((mdp = (void *)(abp->abp_r0 & ~PAGE_MASK)) == NULL)
300		return 0;
301	preload_metadata = mdp;
302	kmdp = preload_search_by_type("elf kernel");
303	if (kmdp == NULL)
304		return 0;
305
306	boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
307	loader_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
308	init_static_kenv(loader_envp, 0);
309	lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
310#ifdef DDB
311	ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
312	ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
313	db_fetch_ksymtab(ksym_start, ksym_end);
314#endif
315	return lastaddr;
316}
317#endif
318
319vm_offset_t
320default_parse_boot_param(struct arm_boot_params *abp)
321{
322	vm_offset_t lastaddr;
323
324#if defined(LINUX_BOOT_ABI)
325	if ((lastaddr = linux_parse_boot_param(abp)) != 0)
326		return lastaddr;
327#endif
328#if defined(FREEBSD_BOOT_LOADER)
329	if ((lastaddr = freebsd_parse_boot_param(abp)) != 0)
330		return lastaddr;
331#endif
332	/* Fall back to hardcoded metadata. */
333	lastaddr = fake_preload_metadata(abp, NULL, 0);
334
335	return lastaddr;
336}
337
338/*
339 * Stub version of the boot parameter parsing routine.  We are
340 * called early in initarm, before even VM has been initialized.
341 * This routine needs to preserve any data that the boot loader
342 * has passed in before the kernel starts to grow past the end
343 * of the BSS, traditionally the place boot-loaders put this data.
344 *
345 * Since this is called so early, things that depend on the vm system
346 * being setup (including access to some SoC's serial ports), about
347 * all that can be done in this routine is to copy the arguments.
348 *
349 * This is the default boot parameter parsing routine.  Individual
350 * kernels/boards can override this weak function with one of their
351 * own.  We just fake metadata...
352 */
353__weak_reference(default_parse_boot_param, parse_boot_param);
354
355
356/*
357 * Fake up a boot descriptor table
358 */
359vm_offset_t
360fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr,
361    size_t dtb_size)
362{
363#ifdef DDB
364	vm_offset_t zstart = 0, zend = 0;
365#endif
366	vm_offset_t lastaddr;
367	int i = 0;
368	static uint32_t fake_preload[35];
369
370	fake_preload[i++] = MODINFO_NAME;
371	fake_preload[i++] = strlen("kernel") + 1;
372	strcpy((char*)&fake_preload[i++], "kernel");
373	i += 1;
374	fake_preload[i++] = MODINFO_TYPE;
375	fake_preload[i++] = strlen("elf kernel") + 1;
376	strcpy((char*)&fake_preload[i++], "elf kernel");
377	i += 2;
378	fake_preload[i++] = MODINFO_ADDR;
379	fake_preload[i++] = sizeof(vm_offset_t);
380	fake_preload[i++] = KERNVIRTADDR;
381	fake_preload[i++] = MODINFO_SIZE;
382	fake_preload[i++] = sizeof(uint32_t);
383	fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR;
384#ifdef DDB
385	if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) {
386		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM;
387		fake_preload[i++] = sizeof(vm_offset_t);
388		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4);
389		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM;
390		fake_preload[i++] = sizeof(vm_offset_t);
391		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8);
392		lastaddr = *(uint32_t *)(KERNVIRTADDR + 8);
393		zend = lastaddr;
394		zstart = *(uint32_t *)(KERNVIRTADDR + 4);
395		db_fetch_ksymtab(zstart, zend);
396	} else
397#endif
398		lastaddr = (vm_offset_t)&end;
399	if (dtb_ptr != NULL) {
400		/* Copy DTB to KVA space and insert it into module chain. */
401		lastaddr = roundup(lastaddr, sizeof(int));
402		fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP;
403		fake_preload[i++] = sizeof(uint32_t);
404		fake_preload[i++] = (uint32_t)lastaddr;
405		memmove((void *)lastaddr, dtb_ptr, dtb_size);
406		lastaddr += dtb_size;
407		lastaddr = roundup(lastaddr, sizeof(int));
408	}
409	fake_preload[i++] = 0;
410	fake_preload[i] = 0;
411	preload_metadata = (void *)fake_preload;
412
413	init_static_kenv(NULL, 0);
414
415	return (lastaddr);
416}
417
418#ifdef EFI
419void
420arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr,
421    int *mrcnt)
422{
423	struct efi_md *map, *p;
424	const char *type;
425	size_t efisz, memory_size;
426	int ndesc, i, j;
427
428	static const char *types[] = {
429		"Reserved",
430		"LoaderCode",
431		"LoaderData",
432		"BootServicesCode",
433		"BootServicesData",
434		"RuntimeServicesCode",
435		"RuntimeServicesData",
436		"ConventionalMemory",
437		"UnusableMemory",
438		"ACPIReclaimMemory",
439		"ACPIMemoryNVS",
440		"MemoryMappedIO",
441		"MemoryMappedIOPortSpace",
442		"PalCode",
443		"PersistentMemory"
444	};
445
446	*mrcnt = 0;
447
448	/*
449	 * Memory map data provided by UEFI via the GetMemoryMap
450	 * Boot Services API.
451	 */
452	efisz = roundup2(sizeof(struct efi_map_header), 0x10);
453	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
454
455	if (efihdr->descriptor_size == 0)
456		return;
457	ndesc = efihdr->memory_size / efihdr->descriptor_size;
458
459	if (boothowto & RB_VERBOSE)
460		printf("%23s %12s %12s %8s %4s\n",
461		    "Type", "Physical", "Virtual", "#Pages", "Attr");
462
463	memory_size = 0;
464	for (i = 0, j = 0, p = map; i < ndesc; i++,
465	    p = efi_next_descriptor(p, efihdr->descriptor_size)) {
466		if (boothowto & RB_VERBOSE) {
467			if (p->md_type < nitems(types))
468				type = types[p->md_type];
469			else
470				type = "<INVALID>";
471			printf("%23s %012llx %12p %08llx ", type, p->md_phys,
472			    p->md_virt, p->md_pages);
473			if (p->md_attr & EFI_MD_ATTR_UC)
474				printf("UC ");
475			if (p->md_attr & EFI_MD_ATTR_WC)
476				printf("WC ");
477			if (p->md_attr & EFI_MD_ATTR_WT)
478				printf("WT ");
479			if (p->md_attr & EFI_MD_ATTR_WB)
480				printf("WB ");
481			if (p->md_attr & EFI_MD_ATTR_UCE)
482				printf("UCE ");
483			if (p->md_attr & EFI_MD_ATTR_WP)
484				printf("WP ");
485			if (p->md_attr & EFI_MD_ATTR_RP)
486				printf("RP ");
487			if (p->md_attr & EFI_MD_ATTR_XP)
488				printf("XP ");
489			if (p->md_attr & EFI_MD_ATTR_NV)
490				printf("NV ");
491			if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
492				printf("MORE_RELIABLE ");
493			if (p->md_attr & EFI_MD_ATTR_RO)
494				printf("RO ");
495			if (p->md_attr & EFI_MD_ATTR_RT)
496				printf("RUNTIME");
497			printf("\n");
498		}
499
500		switch (p->md_type) {
501		case EFI_MD_TYPE_CODE:
502		case EFI_MD_TYPE_DATA:
503		case EFI_MD_TYPE_BS_CODE:
504		case EFI_MD_TYPE_BS_DATA:
505		case EFI_MD_TYPE_FREE:
506			/*
507			 * We're allowed to use any entry with these types.
508			 */
509			break;
510		default:
511			continue;
512		}
513
514		j++;
515		if (j >= FDT_MEM_REGIONS)
516			break;
517
518		mr[j].mr_start = p->md_phys;
519		mr[j].mr_size = p->md_pages * PAGE_SIZE;
520		memory_size += mr[j].mr_size;
521	}
522
523	*mrcnt = j;
524}
525#endif /* EFI */
526