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: stable/11/sys/arm/arm/machdep_boot.c 344619 2019-02-27 13:01:17Z kevans $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/ctype.h>
38#include <sys/linker.h>
39#include <sys/reboot.h>
40#include <sys/sysctl.h>
41#if defined(LINUX_BOOT_ABI)
42#include <sys/boot.h>
43#endif
44
45#include <machine/atags.h>
46#include <machine/cpu.h>
47#include <machine/machdep.h>
48#include <machine/metadata.h>
49#include <machine/physmem.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
72static char static_kenv[4096];
73#endif
74
75extern int *end;
76
77static uint32_t board_revision;
78/* hex representation of uint64_t */
79static char board_serial[32];
80static char *loader_envp;
81
82#if defined(LINUX_BOOT_ABI)
83#define LBABI_MAX_BANKS	10
84#define CMDLINE_GUARD "FreeBSD:"
85static uint32_t board_id;
86static struct arm_lbabi_tag *atag_list;
87static char linux_command_line[LBABI_MAX_COMMAND_LINE + 1];
88static char atags[LBABI_MAX_COMMAND_LINE * 2];
89#endif /* defined(LINUX_BOOT_ABI) */
90
91SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes");
92SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD,
93    &board_revision, 0, "Board revision");
94SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD,
95    board_serial, 0, "Board serial");
96
97int vfp_exists;
98SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
99    &vfp_exists, 0, "Floating point support enabled");
100
101void
102board_set_serial(uint64_t serial)
103{
104
105	snprintf(board_serial, sizeof(board_serial)-1,
106		    "%016jx", serial);
107}
108
109void
110board_set_revision(uint32_t revision)
111{
112
113	board_revision = revision;
114}
115
116static char *
117kenv_next(char *cp)
118{
119
120	if (cp != NULL) {
121		while (*cp != 0)
122			cp++;
123		cp++;
124		if (*cp == 0)
125			cp = NULL;
126	}
127	return (cp);
128}
129
130void
131arm_print_kenv(void)
132{
133	char *cp;
134
135	debugf("loader passed (static) kenv:\n");
136	if (loader_envp == NULL) {
137		debugf(" no env, null ptr\n");
138		return;
139	}
140	debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp);
141
142	for (cp = loader_envp; cp != NULL; cp = kenv_next(cp))
143		debugf(" %x %s\n", (uint32_t)cp, cp);
144}
145
146
147#if defined(LINUX_BOOT_ABI)
148
149/* Convert the U-Boot command line into FreeBSD kenv and boot options. */
150static void
151cmdline_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 */
173void 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 */
188static vm_offset_t
189linux_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			arm_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)
271static vm_offset_t
272freebsd_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);
305#endif
306	return lastaddr;
307}
308#endif
309
310vm_offset_t
311default_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/*
348 * Fake up a boot descriptor table
349 */
350vm_offset_t
351fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr,
352    size_t dtb_size)
353{
354#ifdef DDB
355	vm_offset_t zstart = 0, zend = 0;
356#endif
357	vm_offset_t lastaddr;
358	int i = 0;
359	static uint32_t fake_preload[35];
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#ifdef DDB
376	if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) {
377		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM;
378		fake_preload[i++] = sizeof(vm_offset_t);
379		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4);
380		fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM;
381		fake_preload[i++] = sizeof(vm_offset_t);
382		fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8);
383		lastaddr = *(uint32_t *)(KERNVIRTADDR + 8);
384		zend = lastaddr;
385		zstart = *(uint32_t *)(KERNVIRTADDR + 4);
386		db_fetch_ksymtab(zstart, zend);
387	} else
388#endif
389		lastaddr = (vm_offset_t)&end;
390	if (dtb_ptr != NULL) {
391		/* Copy DTB to KVA space and insert it into module chain. */
392		lastaddr = roundup(lastaddr, sizeof(int));
393		fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP;
394		fake_preload[i++] = sizeof(uint32_t);
395		fake_preload[i++] = (uint32_t)lastaddr;
396		memmove((void *)lastaddr, dtb_ptr, dtb_size);
397		lastaddr += dtb_size;
398		lastaddr = roundup(lastaddr, sizeof(int));
399	}
400	fake_preload[i++] = 0;
401	fake_preload[i] = 0;
402	preload_metadata = (void *)fake_preload;
403
404	init_static_kenv(NULL, 0);
405
406	return (lastaddr);
407}
408
409#ifdef EFI
410void
411arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr,
412    int *mrcnt)
413{
414	struct efi_md *map, *p;
415	const char *type;
416	size_t efisz, memory_size;
417	int ndesc, i, j;
418
419	static const char *types[] = {
420		"Reserved",
421		"LoaderCode",
422		"LoaderData",
423		"BootServicesCode",
424		"BootServicesData",
425		"RuntimeServicesCode",
426		"RuntimeServicesData",
427		"ConventionalMemory",
428		"UnusableMemory",
429		"ACPIReclaimMemory",
430		"ACPIMemoryNVS",
431		"MemoryMappedIO",
432		"MemoryMappedIOPortSpace",
433		"PalCode",
434		"PersistentMemory"
435	};
436
437	*mrcnt = 0;
438
439	/*
440	 * Memory map data provided by UEFI via the GetMemoryMap
441	 * Boot Services API.
442	 */
443	efisz = roundup2(sizeof(struct efi_map_header), 0x10);
444	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
445
446	if (efihdr->descriptor_size == 0)
447		return;
448	ndesc = efihdr->memory_size / efihdr->descriptor_size;
449
450	if (boothowto & RB_VERBOSE)
451		printf("%23s %12s %12s %8s %4s\n",
452		    "Type", "Physical", "Virtual", "#Pages", "Attr");
453
454	memory_size = 0;
455	for (i = 0, j = 0, p = map; i < ndesc; i++,
456	    p = efi_next_descriptor(p, efihdr->descriptor_size)) {
457		if (boothowto & RB_VERBOSE) {
458			if (p->md_type < nitems(types))
459				type = types[p->md_type];
460			else
461				type = "<INVALID>";
462			printf("%23s %012llx %12p %08llx ", type, p->md_phys,
463			    p->md_virt, p->md_pages);
464			if (p->md_attr & EFI_MD_ATTR_UC)
465				printf("UC ");
466			if (p->md_attr & EFI_MD_ATTR_WC)
467				printf("WC ");
468			if (p->md_attr & EFI_MD_ATTR_WT)
469				printf("WT ");
470			if (p->md_attr & EFI_MD_ATTR_WB)
471				printf("WB ");
472			if (p->md_attr & EFI_MD_ATTR_UCE)
473				printf("UCE ");
474			if (p->md_attr & EFI_MD_ATTR_WP)
475				printf("WP ");
476			if (p->md_attr & EFI_MD_ATTR_RP)
477				printf("RP ");
478			if (p->md_attr & EFI_MD_ATTR_XP)
479				printf("XP ");
480			if (p->md_attr & EFI_MD_ATTR_NV)
481				printf("NV ");
482			if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
483				printf("MORE_RELIABLE ");
484			if (p->md_attr & EFI_MD_ATTR_RO)
485				printf("RO ");
486			if (p->md_attr & EFI_MD_ATTR_RT)
487				printf("RUNTIME");
488			printf("\n");
489		}
490
491		switch (p->md_type) {
492		case EFI_MD_TYPE_CODE:
493		case EFI_MD_TYPE_DATA:
494		case EFI_MD_TYPE_BS_CODE:
495		case EFI_MD_TYPE_BS_DATA:
496		case EFI_MD_TYPE_FREE:
497			/*
498			 * We're allowed to use any entry with these types.
499			 */
500			break;
501		default:
502			continue;
503		}
504
505		j++;
506		if (j >= FDT_MEM_REGIONS)
507			break;
508
509		mr[j].mr_start = p->md_phys;
510		mr[j].mr_size = p->md_pages * PAGE_SIZE;
511		memory_size += mr[j].mr_size;
512	}
513
514	*mrcnt = j;
515}
516#endif /* EFI */
517