xref: /freebsd/sys/arm/arm/machdep_boot.c (revision 4d846d26)
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/physmem.h>
40 #include <sys/reboot.h>
41 #include <sys/sysctl.h>
42 #if defined(LINUX_BOOT_ABI)
43 #include <sys/boot.h>
44 #endif
45 
46 #include <machine/atags.h>
47 #include <machine/cpu.h>
48 #include <machine/machdep.h>
49 #include <machine/metadata.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 | CTLFLAG_MPSAFE, 0,
92     "Board attributes");
93 SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD,
94     &board_revision, 0, "Board revision");
95 SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD,
96     board_serial, 0, "Board serial");
97 
98 int vfp_exists;
99 SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
100     &vfp_exists, 0, "Floating point support enabled");
101 
102 void
103 board_set_serial(uint64_t serial)
104 {
105 
106 	snprintf(board_serial, sizeof(board_serial)-1,
107 		    "%016jx", serial);
108 }
109 
110 void
111 board_set_revision(uint32_t revision)
112 {
113 
114 	board_revision = revision;
115 }
116 
117 static char *
118 kenv_next(char *cp)
119 {
120 
121 	if (cp != NULL) {
122 		while (*cp != 0)
123 			cp++;
124 		cp++;
125 		if (*cp == 0)
126 			cp = NULL;
127 	}
128 	return (cp);
129 }
130 
131 void
132 arm_print_kenv(void)
133 {
134 	char *cp;
135 
136 	debugf("loader passed (static) kenv:\n");
137 	if (loader_envp == NULL) {
138 		debugf(" no env, null ptr\n");
139 		return;
140 	}
141 	debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp);
142 
143 	for (cp = loader_envp; cp != NULL; cp = kenv_next(cp))
144 		debugf(" %x %s\n", (uint32_t)cp, cp);
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 			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, 0);
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  * Fake up a boot descriptor table
348  */
349 vm_offset_t
350 fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr,
351     size_t dtb_size)
352 {
353 	vm_offset_t lastaddr;
354 	int i = 0;
355 	static uint32_t fake_preload[35];
356 
357 	lastaddr = (vm_offset_t)&end;
358 
359 	fake_preload[i++] = MODINFO_NAME;
360 	fake_preload[i++] = strlen("kernel") + 1;
361 	strcpy((char*)&fake_preload[i++], "kernel");
362 	i += 1;
363 	fake_preload[i++] = MODINFO_TYPE;
364 	fake_preload[i++] = strlen("elf kernel") + 1;
365 	strcpy((char*)&fake_preload[i++], "elf kernel");
366 	i += 2;
367 	fake_preload[i++] = MODINFO_ADDR;
368 	fake_preload[i++] = sizeof(vm_offset_t);
369 	fake_preload[i++] = KERNVIRTADDR;
370 	fake_preload[i++] = MODINFO_SIZE;
371 	fake_preload[i++] = sizeof(uint32_t);
372 	fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR;
373 	if (dtb_ptr != NULL) {
374 		/* Copy DTB to KVA space and insert it into module chain. */
375 		lastaddr = roundup(lastaddr, sizeof(int));
376 		fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP;
377 		fake_preload[i++] = sizeof(uint32_t);
378 		fake_preload[i++] = (uint32_t)lastaddr;
379 		memmove((void *)lastaddr, dtb_ptr, dtb_size);
380 		lastaddr += dtb_size;
381 		lastaddr = roundup(lastaddr, sizeof(int));
382 	}
383 	fake_preload[i++] = 0;
384 	fake_preload[i] = 0;
385 	preload_metadata = (void *)fake_preload;
386 
387 	init_static_kenv(NULL, 0);
388 
389 	return (lastaddr);
390 }
391 
392 #ifdef EFI
393 void
394 arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr,
395     int *mrcnt)
396 {
397 	struct efi_md *map, *p;
398 	const char *type;
399 	size_t efisz;
400 	int ndesc, i, j;
401 
402 	static const char *types[] = {
403 		"Reserved",
404 		"LoaderCode",
405 		"LoaderData",
406 		"BootServicesCode",
407 		"BootServicesData",
408 		"RuntimeServicesCode",
409 		"RuntimeServicesData",
410 		"ConventionalMemory",
411 		"UnusableMemory",
412 		"ACPIReclaimMemory",
413 		"ACPIMemoryNVS",
414 		"MemoryMappedIO",
415 		"MemoryMappedIOPortSpace",
416 		"PalCode",
417 		"PersistentMemory"
418 	};
419 
420 	*mrcnt = 0;
421 
422 	/*
423 	 * Memory map data provided by UEFI via the GetMemoryMap
424 	 * Boot Services API.
425 	 */
426 	efisz = roundup2(sizeof(struct efi_map_header), 0x10);
427 	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
428 
429 	if (efihdr->descriptor_size == 0)
430 		return;
431 	ndesc = efihdr->memory_size / efihdr->descriptor_size;
432 
433 	if (boothowto & RB_VERBOSE)
434 		printf("%23s %12s %12s %8s %4s\n",
435 		    "Type", "Physical", "Virtual", "#Pages", "Attr");
436 
437 	for (i = 0, j = 0, p = map; i < ndesc; i++,
438 	    p = efi_next_descriptor(p, efihdr->descriptor_size)) {
439 		if (boothowto & RB_VERBOSE) {
440 			if (p->md_type < nitems(types))
441 				type = types[p->md_type];
442 			else
443 				type = "<INVALID>";
444 			printf("%23s %012llx %012llx %08llx ", type, p->md_phys,
445 			    p->md_virt, p->md_pages);
446 			if (p->md_attr & EFI_MD_ATTR_UC)
447 				printf("UC ");
448 			if (p->md_attr & EFI_MD_ATTR_WC)
449 				printf("WC ");
450 			if (p->md_attr & EFI_MD_ATTR_WT)
451 				printf("WT ");
452 			if (p->md_attr & EFI_MD_ATTR_WB)
453 				printf("WB ");
454 			if (p->md_attr & EFI_MD_ATTR_UCE)
455 				printf("UCE ");
456 			if (p->md_attr & EFI_MD_ATTR_WP)
457 				printf("WP ");
458 			if (p->md_attr & EFI_MD_ATTR_RP)
459 				printf("RP ");
460 			if (p->md_attr & EFI_MD_ATTR_XP)
461 				printf("XP ");
462 			if (p->md_attr & EFI_MD_ATTR_NV)
463 				printf("NV ");
464 			if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
465 				printf("MORE_RELIABLE ");
466 			if (p->md_attr & EFI_MD_ATTR_RO)
467 				printf("RO ");
468 			if (p->md_attr & EFI_MD_ATTR_RT)
469 				printf("RUNTIME");
470 			printf("\n");
471 		}
472 
473 		switch (p->md_type) {
474 		case EFI_MD_TYPE_CODE:
475 		case EFI_MD_TYPE_DATA:
476 		case EFI_MD_TYPE_BS_CODE:
477 		case EFI_MD_TYPE_BS_DATA:
478 		case EFI_MD_TYPE_FREE:
479 			/*
480 			 * We're allowed to use any entry with these types.
481 			 */
482 			break;
483 		default:
484 			continue;
485 		}
486 
487 		j++;
488 		if (j >= FDT_MEM_REGIONS)
489 			break;
490 
491 		mr[j].mr_start = p->md_phys;
492 		mr[j].mr_size = p->md_pages * EFI_PAGE_SIZE;
493 	}
494 
495 	*mrcnt = j;
496 }
497 #endif /* EFI */
498