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