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/12/sys/arm/arm/machdep_boot.c 360703 2020-05-06 19:50:27Z mhorne $");
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, 0, "Board attributes");
92 SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD,
93 &board_revision, 0, "Board revision");
94 SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD,
95 board_serial, 0, "Board serial");
96
97 int vfp_exists;
98 SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
99 &vfp_exists, 0, "Floating point support enabled");
100
101 void
board_set_serial(uint64_t serial)102 board_set_serial(uint64_t serial)
103 {
104
105 snprintf(board_serial, sizeof(board_serial)-1,
106 "%016jx", serial);
107 }
108
109 void
board_set_revision(uint32_t revision)110 board_set_revision(uint32_t revision)
111 {
112
113 board_revision = revision;
114 }
115
116 static char *
kenv_next(char * cp)117 kenv_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
130 void
arm_print_kenv(void)131 arm_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. */
150 static void
cmdline_set_env(char * cmdline,const char * guard)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 */
arm_parse_fdt_bootargs(void)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
linux_parse_boot_param(struct arm_boot_params * abp)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
freebsd_parse_boot_param(struct arm_boot_params * abp)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);
305 #endif
306 return lastaddr;
307 }
308 #endif
309
310 vm_offset_t
default_parse_boot_param(struct arm_boot_params * abp)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 /*
348 * Fake up a boot descriptor table
349 */
350 vm_offset_t
fake_preload_metadata(struct arm_boot_params * abp __unused,void * dtb_ptr,size_t dtb_size)351 fake_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
410 void
arm_add_efi_map_entries(struct efi_map_header * efihdr,struct mem_region * mr,int * mrcnt)411 arm_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