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