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