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