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