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