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