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