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