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