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