xref: /freebsd/sys/arm/arm/machdep_boot.c (revision 0957b409)
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$");
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 
71 #ifdef LINUX_BOOT_ABI
72 static char static_kenv[4096];
73 #endif
74 
75 extern int *end;
76 
77 static uint32_t board_revision;
78 /* hex representation of uint64_t */
79 static char board_serial[32];
80 static char *loader_envp;
81 
82 #if defined(LINUX_BOOT_ABI)
83 #define LBABI_MAX_BANKS	10
84 #define CMDLINE_GUARD "FreeBSD:"
85 static uint32_t board_id;
86 static struct arm_lbabi_tag *atag_list;
87 static char linux_command_line[LBABI_MAX_COMMAND_LINE + 1];
88 static char atags[LBABI_MAX_COMMAND_LINE * 2];
89 #endif /* defined(LINUX_BOOT_ABI) */
90 
91 SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes");
92 SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD,
93     &board_revision, 0, "Board revision");
94 SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD,
95     board_serial, 0, "Board serial");
96 
97 int vfp_exists;
98 SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
99     &vfp_exists, 0, "Floating point support enabled");
100 
101 void
102 board_set_serial(uint64_t serial)
103 {
104 
105 	snprintf(board_serial, sizeof(board_serial)-1,
106 		    "%016jx", serial);
107 }
108 
109 void
110 board_set_revision(uint32_t revision)
111 {
112 
113 	board_revision = revision;
114 }
115 
116 static char *
117 kenv_next(char *cp)
118 {
119 
120 	if (cp != NULL) {
121 		while (*cp != 0)
122 			cp++;
123 		cp++;
124 		if (*cp == 0)
125 			cp = NULL;
126 	}
127 	return (cp);
128 }
129 
130 void
131 arm_print_kenv(void)
132 {
133 	char *cp;
134 
135 	debugf("loader passed (static) kenv:\n");
136 	if (loader_envp == NULL) {
137 		debugf(" no env, null ptr\n");
138 		return;
139 	}
140 	debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp);
141 
142 	for (cp = loader_envp; cp != NULL; cp = kenv_next(cp))
143 		debugf(" %x %s\n", (uint32_t)cp, cp);
144 }
145 
146 
147 #if defined(LINUX_BOOT_ABI)
148 
149 /* Convert the U-Boot command line into FreeBSD kenv and boot options. */
150 static void
151 cmdline_set_env(char *cmdline, const char *guard)
152 {
153 	size_t guard_len;
154 
155 	/* Skip leading spaces. */
156 	while (isspace(*cmdline))
157 		cmdline++;
158 
159 	/* Test and remove guard. */
160 	if (guard != NULL && guard[0] != '\0') {
161 		guard_len  =  strlen(guard);
162 		if (strncasecmp(cmdline, guard, guard_len) != 0)
163 			return;
164 		cmdline += guard_len;
165 	}
166 
167 	boothowto |= boot_parse_cmdline(cmdline);
168 }
169 
170 /*
171  * Called for armv6 and newer.
172  */
173 void arm_parse_fdt_bootargs(void)
174 {
175 
176 #ifdef FDT
177 	if (loader_envp == NULL && fdt_get_chosen_bootargs(linux_command_line,
178 	    LBABI_MAX_COMMAND_LINE) == 0) {
179 		init_static_kenv(static_kenv, sizeof(static_kenv));
180 		cmdline_set_env(linux_command_line, CMDLINE_GUARD);
181 	}
182 #endif
183 }
184 
185 /*
186  * Called for armv[45].
187  */
188 static vm_offset_t
189 linux_parse_boot_param(struct arm_boot_params *abp)
190 {
191 	struct arm_lbabi_tag *walker;
192 	uint32_t revision;
193 	uint64_t serial;
194 	int size;
195 	vm_offset_t lastaddr;
196 #ifdef FDT
197 	struct fdt_header *dtb_ptr;
198 	uint32_t dtb_size;
199 #endif
200 
201 	/*
202 	 * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2
203 	 * is atags or dtb pointer.  If all of these aren't satisfied,
204 	 * then punt. Unfortunately, it looks like DT enabled kernels
205 	 * doesn't uses board type and U-Boot delivers 0 in r1 for them.
206 	 */
207 	if (abp->abp_r0 != 0 || abp->abp_r2 == 0)
208 		return (0);
209 #ifdef FDT
210 	/* Test if r2 point to valid DTB. */
211 	dtb_ptr = (struct fdt_header *)abp->abp_r2;
212 	if (fdt_check_header(dtb_ptr) == 0) {
213 		dtb_size = fdt_totalsize(dtb_ptr);
214 		return (fake_preload_metadata(abp, dtb_ptr, dtb_size));
215 	}
216 #endif
217 
218 	board_id = abp->abp_r1;
219 	walker = (struct arm_lbabi_tag *)abp->abp_r2;
220 
221 	if (ATAG_TAG(walker) != ATAG_CORE)
222 		return 0;
223 
224 	atag_list = walker;
225 	while (ATAG_TAG(walker) != ATAG_NONE) {
226 		switch (ATAG_TAG(walker)) {
227 		case ATAG_CORE:
228 			break;
229 		case ATAG_MEM:
230 			arm_physmem_hardware_region(walker->u.tag_mem.start,
231 			    walker->u.tag_mem.size);
232 			break;
233 		case ATAG_INITRD2:
234 			break;
235 		case ATAG_SERIAL:
236 			serial = walker->u.tag_sn.high;
237 			serial <<= 32;
238 			serial |= walker->u.tag_sn.low;
239 			board_set_serial(serial);
240 			break;
241 		case ATAG_REVISION:
242 			revision = walker->u.tag_rev.rev;
243 			board_set_revision(revision);
244 			break;
245 		case ATAG_CMDLINE:
246 			size = ATAG_SIZE(walker) -
247 			    sizeof(struct arm_lbabi_header);
248 			size = min(size, LBABI_MAX_COMMAND_LINE);
249 			strncpy(linux_command_line, walker->u.tag_cmd.command,
250 			    size);
251 			linux_command_line[size] = '\0';
252 			break;
253 		default:
254 			break;
255 		}
256 		walker = ATAG_NEXT(walker);
257 	}
258 
259 	/* Save a copy for later */
260 	bcopy(atag_list, atags,
261 	    (char *)walker - (char *)atag_list + ATAG_SIZE(walker));
262 
263 	lastaddr = fake_preload_metadata(abp, NULL, 0);
264 	init_static_kenv(static_kenv, sizeof(static_kenv));
265 	cmdline_set_env(linux_command_line, CMDLINE_GUARD);
266 	return lastaddr;
267 }
268 #endif
269 
270 #if defined(FREEBSD_BOOT_LOADER)
271 static vm_offset_t
272 freebsd_parse_boot_param(struct arm_boot_params *abp)
273 {
274 	vm_offset_t lastaddr = 0;
275 	void *mdp;
276 	void *kmdp;
277 #ifdef DDB
278 	vm_offset_t ksym_start;
279 	vm_offset_t ksym_end;
280 #endif
281 
282 	/*
283 	 * Mask metadata pointer: it is supposed to be on page boundary. If
284 	 * the first argument (mdp) doesn't point to a valid address the
285 	 * bootloader must have passed us something else than the metadata
286 	 * ptr, so we give up.  Also give up if we cannot find metadta section
287 	 * the loader creates that we get all this data out of.
288 	 */
289 
290 	if ((mdp = (void *)(abp->abp_r0 & ~PAGE_MASK)) == NULL)
291 		return 0;
292 	preload_metadata = mdp;
293 	kmdp = preload_search_by_type("elf kernel");
294 	if (kmdp == NULL)
295 		return 0;
296 
297 	boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
298 	loader_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
299 	init_static_kenv(loader_envp, 0);
300 	lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
301 #ifdef DDB
302 	ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
303 	ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
304 	db_fetch_ksymtab(ksym_start, ksym_end);
305 #endif
306 	return lastaddr;
307 }
308 #endif
309 
310 vm_offset_t
311 default_parse_boot_param(struct arm_boot_params *abp)
312 {
313 	vm_offset_t lastaddr;
314 
315 #if defined(LINUX_BOOT_ABI)
316 	if ((lastaddr = linux_parse_boot_param(abp)) != 0)
317 		return lastaddr;
318 #endif
319 #if defined(FREEBSD_BOOT_LOADER)
320 	if ((lastaddr = freebsd_parse_boot_param(abp)) != 0)
321 		return lastaddr;
322 #endif
323 	/* Fall back to hardcoded metadata. */
324 	lastaddr = fake_preload_metadata(abp, NULL, 0);
325 
326 	return lastaddr;
327 }
328 
329 /*
330  * Stub version of the boot parameter parsing routine.  We are
331  * called early in initarm, before even VM has been initialized.
332  * This routine needs to preserve any data that the boot loader
333  * has passed in before the kernel starts to grow past the end
334  * of the BSS, traditionally the place boot-loaders put this data.
335  *
336  * Since this is called so early, things that depend on the vm system
337  * being setup (including access to some SoC's serial ports), about
338  * all that can be done in this routine is to copy the arguments.
339  *
340  * This is the default boot parameter parsing routine.  Individual
341  * kernels/boards can override this weak function with one of their
342  * own.  We just fake metadata...
343  */
344 __weak_reference(default_parse_boot_param, parse_boot_param);
345 
346 
347 /*
348  * Fake up a boot descriptor table
349  */
350 vm_offset_t
351 fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr,
352     size_t dtb_size)
353 {
354 #ifdef DDB
355 	vm_offset_t zstart = 0, zend = 0;
356 #endif
357 	vm_offset_t lastaddr;
358 	int i = 0;
359 	static uint32_t fake_preload[35];
360 
361 	fake_preload[i++] = MODINFO_NAME;
362 	fake_preload[i++] = strlen("kernel") + 1;
363 	strcpy((char*)&fake_preload[i++], "kernel");
364 	i += 1;
365 	fake_preload[i++] = MODINFO_TYPE;
366 	fake_preload[i++] = strlen("elf kernel") + 1;
367 	strcpy((char*)&fake_preload[i++], "elf kernel");
368 	i += 2;
369 	fake_preload[i++] = MODINFO_ADDR;
370 	fake_preload[i++] = sizeof(vm_offset_t);
371 	fake_preload[i++] = KERNVIRTADDR;
372 	fake_preload[i++] = MODINFO_SIZE;
373 	fake_preload[i++] = sizeof(uint32_t);
374 	fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR;
375 #ifdef DDB
376 	if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) {
377 		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM;
378 		fake_preload[i++] = sizeof(vm_offset_t);
379 		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4);
380 		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM;
381 		fake_preload[i++] = sizeof(vm_offset_t);
382 		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8);
383 		lastaddr = *(uint32_t *)(KERNVIRTADDR + 8);
384 		zend = lastaddr;
385 		zstart = *(uint32_t *)(KERNVIRTADDR + 4);
386 		db_fetch_ksymtab(zstart, zend);
387 	} else
388 #endif
389 		lastaddr = (vm_offset_t)&end;
390 	if (dtb_ptr != NULL) {
391 		/* Copy DTB to KVA space and insert it into module chain. */
392 		lastaddr = roundup(lastaddr, sizeof(int));
393 		fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP;
394 		fake_preload[i++] = sizeof(uint32_t);
395 		fake_preload[i++] = (uint32_t)lastaddr;
396 		memmove((void *)lastaddr, dtb_ptr, dtb_size);
397 		lastaddr += dtb_size;
398 		lastaddr = roundup(lastaddr, sizeof(int));
399 	}
400 	fake_preload[i++] = 0;
401 	fake_preload[i] = 0;
402 	preload_metadata = (void *)fake_preload;
403 
404 	init_static_kenv(NULL, 0);
405 
406 	return (lastaddr);
407 }
408 
409 #ifdef EFI
410 void
411 arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr,
412     int *mrcnt)
413 {
414 	struct efi_md *map, *p;
415 	const char *type;
416 	size_t efisz, memory_size;
417 	int ndesc, i, j;
418 
419 	static const char *types[] = {
420 		"Reserved",
421 		"LoaderCode",
422 		"LoaderData",
423 		"BootServicesCode",
424 		"BootServicesData",
425 		"RuntimeServicesCode",
426 		"RuntimeServicesData",
427 		"ConventionalMemory",
428 		"UnusableMemory",
429 		"ACPIReclaimMemory",
430 		"ACPIMemoryNVS",
431 		"MemoryMappedIO",
432 		"MemoryMappedIOPortSpace",
433 		"PalCode",
434 		"PersistentMemory"
435 	};
436 
437 	*mrcnt = 0;
438 
439 	/*
440 	 * Memory map data provided by UEFI via the GetMemoryMap
441 	 * Boot Services API.
442 	 */
443 	efisz = roundup2(sizeof(struct efi_map_header), 0x10);
444 	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
445 
446 	if (efihdr->descriptor_size == 0)
447 		return;
448 	ndesc = efihdr->memory_size / efihdr->descriptor_size;
449 
450 	if (boothowto & RB_VERBOSE)
451 		printf("%23s %12s %12s %8s %4s\n",
452 		    "Type", "Physical", "Virtual", "#Pages", "Attr");
453 
454 	memory_size = 0;
455 	for (i = 0, j = 0, p = map; i < ndesc; i++,
456 	    p = efi_next_descriptor(p, efihdr->descriptor_size)) {
457 		if (boothowto & RB_VERBOSE) {
458 			if (p->md_type < nitems(types))
459 				type = types[p->md_type];
460 			else
461 				type = "<INVALID>";
462 			printf("%23s %012llx %12p %08llx ", type, p->md_phys,
463 			    p->md_virt, p->md_pages);
464 			if (p->md_attr & EFI_MD_ATTR_UC)
465 				printf("UC ");
466 			if (p->md_attr & EFI_MD_ATTR_WC)
467 				printf("WC ");
468 			if (p->md_attr & EFI_MD_ATTR_WT)
469 				printf("WT ");
470 			if (p->md_attr & EFI_MD_ATTR_WB)
471 				printf("WB ");
472 			if (p->md_attr & EFI_MD_ATTR_UCE)
473 				printf("UCE ");
474 			if (p->md_attr & EFI_MD_ATTR_WP)
475 				printf("WP ");
476 			if (p->md_attr & EFI_MD_ATTR_RP)
477 				printf("RP ");
478 			if (p->md_attr & EFI_MD_ATTR_XP)
479 				printf("XP ");
480 			if (p->md_attr & EFI_MD_ATTR_NV)
481 				printf("NV ");
482 			if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
483 				printf("MORE_RELIABLE ");
484 			if (p->md_attr & EFI_MD_ATTR_RO)
485 				printf("RO ");
486 			if (p->md_attr & EFI_MD_ATTR_RT)
487 				printf("RUNTIME");
488 			printf("\n");
489 		}
490 
491 		switch (p->md_type) {
492 		case EFI_MD_TYPE_CODE:
493 		case EFI_MD_TYPE_DATA:
494 		case EFI_MD_TYPE_BS_CODE:
495 		case EFI_MD_TYPE_BS_DATA:
496 		case EFI_MD_TYPE_FREE:
497 			/*
498 			 * We're allowed to use any entry with these types.
499 			 */
500 			break;
501 		default:
502 			continue;
503 		}
504 
505 		j++;
506 		if (j >= FDT_MEM_REGIONS)
507 			break;
508 
509 		mr[j].mr_start = p->md_phys;
510 		mr[j].mr_size = p->md_pages * PAGE_SIZE;
511 		memory_size += mr[j].mr_size;
512 	}
513 
514 	*mrcnt = j;
515 }
516 #endif /* EFI */
517