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