]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/machdep_boot.c
MFV: r362513
[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/physmem.h>
40 #include <sys/reboot.h>
41 #include <sys/sysctl.h>
42 #if defined(LINUX_BOOT_ABI)
43 #include <sys/boot.h>
44 #endif
45
46 #include <machine/atags.h>
47 #include <machine/cpu.h>
48 #include <machine/machdep.h>
49 #include <machine/metadata.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 | CTLFLAG_MPSAFE, 0,
92     "Board attributes");
93 SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD,
94     &board_revision, 0, "Board revision");
95 SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD,
96     board_serial, 0, "Board serial");
97
98 int vfp_exists;
99 SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
100     &vfp_exists, 0, "Floating point support enabled");
101
102 void
103 board_set_serial(uint64_t serial)
104 {
105
106         snprintf(board_serial, sizeof(board_serial)-1,
107                     "%016jx", serial);
108 }
109
110 void
111 board_set_revision(uint32_t revision)
112 {
113
114         board_revision = revision;
115 }
116
117 static char *
118 kenv_next(char *cp)
119 {
120
121         if (cp != NULL) {
122                 while (*cp != 0)
123                         cp++;
124                 cp++;
125                 if (*cp == 0)
126                         cp = NULL;
127         }
128         return (cp);
129 }
130
131 void
132 arm_print_kenv(void)
133 {
134         char *cp;
135
136         debugf("loader passed (static) kenv:\n");
137         if (loader_envp == NULL) {
138                 debugf(" no env, null ptr\n");
139                 return;
140         }
141         debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp);
142
143         for (cp = loader_envp; cp != NULL; cp = kenv_next(cp))
144                 debugf(" %x %s\n", (uint32_t)cp, cp);
145 }
146
147
148 #if defined(LINUX_BOOT_ABI)
149
150 /* Convert the U-Boot command line into FreeBSD kenv and boot options. */
151 static void
152 cmdline_set_env(char *cmdline, const char *guard)
153 {
154         size_t guard_len;
155
156         /* Skip leading spaces. */
157         while (isspace(*cmdline))
158                 cmdline++;
159
160         /* Test and remove guard. */
161         if (guard != NULL && guard[0] != '\0') {
162                 guard_len  =  strlen(guard);
163                 if (strncasecmp(cmdline, guard, guard_len) != 0)
164                         return;
165                 cmdline += guard_len;
166         }
167
168         boothowto |= boot_parse_cmdline(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                         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, 0);
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         vm_offset_t lastaddr;
356         int i = 0;
357         static uint32_t fake_preload[35];
358
359         lastaddr = (vm_offset_t)&end;
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         if (dtb_ptr != NULL) {
376                 /* Copy DTB to KVA space and insert it into module chain. */
377                 lastaddr = roundup(lastaddr, sizeof(int));
378                 fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP;
379                 fake_preload[i++] = sizeof(uint32_t);
380                 fake_preload[i++] = (uint32_t)lastaddr;
381                 memmove((void *)lastaddr, dtb_ptr, dtb_size);
382                 lastaddr += dtb_size;
383                 lastaddr = roundup(lastaddr, sizeof(int));
384         }
385         fake_preload[i++] = 0;
386         fake_preload[i] = 0;
387         preload_metadata = (void *)fake_preload;
388
389         init_static_kenv(NULL, 0);
390
391         return (lastaddr);
392 }
393
394 #ifdef EFI
395 void
396 arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr,
397     int *mrcnt)
398 {
399         struct efi_md *map, *p;
400         const char *type;
401         size_t efisz, memory_size;
402         int ndesc, i, j;
403
404         static const char *types[] = {
405                 "Reserved",
406                 "LoaderCode",
407                 "LoaderData",
408                 "BootServicesCode",
409                 "BootServicesData",
410                 "RuntimeServicesCode",
411                 "RuntimeServicesData",
412                 "ConventionalMemory",
413                 "UnusableMemory",
414                 "ACPIReclaimMemory",
415                 "ACPIMemoryNVS",
416                 "MemoryMappedIO",
417                 "MemoryMappedIOPortSpace",
418                 "PalCode",
419                 "PersistentMemory"
420         };
421
422         *mrcnt = 0;
423
424         /*
425          * Memory map data provided by UEFI via the GetMemoryMap
426          * Boot Services API.
427          */
428         efisz = roundup2(sizeof(struct efi_map_header), 0x10);
429         map = (struct efi_md *)((uint8_t *)efihdr + efisz);
430
431         if (efihdr->descriptor_size == 0)
432                 return;
433         ndesc = efihdr->memory_size / efihdr->descriptor_size;
434
435         if (boothowto & RB_VERBOSE)
436                 printf("%23s %12s %12s %8s %4s\n",
437                     "Type", "Physical", "Virtual", "#Pages", "Attr");
438
439         memory_size = 0;
440         for (i = 0, j = 0, p = map; i < ndesc; i++,
441             p = efi_next_descriptor(p, efihdr->descriptor_size)) {
442                 if (boothowto & RB_VERBOSE) {
443                         if (p->md_type < nitems(types))
444                                 type = types[p->md_type];
445                         else
446                                 type = "<INVALID>";
447                         printf("%23s %012llx %12p %08llx ", type, p->md_phys,
448                             p->md_virt, p->md_pages);
449                         if (p->md_attr & EFI_MD_ATTR_UC)
450                                 printf("UC ");
451                         if (p->md_attr & EFI_MD_ATTR_WC)
452                                 printf("WC ");
453                         if (p->md_attr & EFI_MD_ATTR_WT)
454                                 printf("WT ");
455                         if (p->md_attr & EFI_MD_ATTR_WB)
456                                 printf("WB ");
457                         if (p->md_attr & EFI_MD_ATTR_UCE)
458                                 printf("UCE ");
459                         if (p->md_attr & EFI_MD_ATTR_WP)
460                                 printf("WP ");
461                         if (p->md_attr & EFI_MD_ATTR_RP)
462                                 printf("RP ");
463                         if (p->md_attr & EFI_MD_ATTR_XP)
464                                 printf("XP ");
465                         if (p->md_attr & EFI_MD_ATTR_NV)
466                                 printf("NV ");
467                         if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
468                                 printf("MORE_RELIABLE ");
469                         if (p->md_attr & EFI_MD_ATTR_RO)
470                                 printf("RO ");
471                         if (p->md_attr & EFI_MD_ATTR_RT)
472                                 printf("RUNTIME");
473                         printf("\n");
474                 }
475
476                 switch (p->md_type) {
477                 case EFI_MD_TYPE_CODE:
478                 case EFI_MD_TYPE_DATA:
479                 case EFI_MD_TYPE_BS_CODE:
480                 case EFI_MD_TYPE_BS_DATA:
481                 case EFI_MD_TYPE_FREE:
482                         /*
483                          * We're allowed to use any entry with these types.
484                          */
485                         break;
486                 default:
487                         continue;
488                 }
489
490                 j++;
491                 if (j >= FDT_MEM_REGIONS)
492                         break;
493
494                 mr[j].mr_start = p->md_phys;
495                 mr[j].mr_size = p->md_pages * PAGE_SIZE;
496                 memory_size += mr[j].mr_size;
497         }
498
499         *mrcnt = j;
500 }
501 #endif /* EFI */