The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/arm/machdep_boot.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 #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                         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, 0);
  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  * Fake up a boot descriptor table
  348  */
  349 vm_offset_t
  350 fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr,
  351     size_t dtb_size)
  352 {
  353         vm_offset_t lastaddr;
  354         int i = 0;
  355         static uint32_t fake_preload[35];
  356 
  357         lastaddr = (vm_offset_t)&end;
  358 
  359         fake_preload[i++] = MODINFO_NAME;
  360         fake_preload[i++] = strlen("kernel") + 1;
  361         strcpy((char*)&fake_preload[i++], "kernel");
  362         i += 1;
  363         fake_preload[i++] = MODINFO_TYPE;
  364         fake_preload[i++] = strlen("elf kernel") + 1;
  365         strcpy((char*)&fake_preload[i++], "elf kernel");
  366         i += 2;
  367         fake_preload[i++] = MODINFO_ADDR;
  368         fake_preload[i++] = sizeof(vm_offset_t);
  369         fake_preload[i++] = KERNVIRTADDR;
  370         fake_preload[i++] = MODINFO_SIZE;
  371         fake_preload[i++] = sizeof(uint32_t);
  372         fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR;
  373         if (dtb_ptr != NULL) {
  374                 /* Copy DTB to KVA space and insert it into module chain. */
  375                 lastaddr = roundup(lastaddr, sizeof(int));
  376                 fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP;
  377                 fake_preload[i++] = sizeof(uint32_t);
  378                 fake_preload[i++] = (uint32_t)lastaddr;
  379                 memmove((void *)lastaddr, dtb_ptr, dtb_size);
  380                 lastaddr += dtb_size;
  381                 lastaddr = roundup(lastaddr, sizeof(int));
  382         }
  383         fake_preload[i++] = 0;
  384         fake_preload[i] = 0;
  385         preload_metadata = (void *)fake_preload;
  386 
  387         init_static_kenv(NULL, 0);
  388 
  389         return (lastaddr);
  390 }
  391 
  392 #ifdef EFI
  393 void
  394 arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr,
  395     int *mrcnt)
  396 {
  397         struct efi_md *map, *p;
  398         const char *type;
  399         size_t efisz;
  400         int ndesc, i, j;
  401 
  402         static const char *types[] = {
  403                 "Reserved",
  404                 "LoaderCode",
  405                 "LoaderData",
  406                 "BootServicesCode",
  407                 "BootServicesData",
  408                 "RuntimeServicesCode",
  409                 "RuntimeServicesData",
  410                 "ConventionalMemory",
  411                 "UnusableMemory",
  412                 "ACPIReclaimMemory",
  413                 "ACPIMemoryNVS",
  414                 "MemoryMappedIO",
  415                 "MemoryMappedIOPortSpace",
  416                 "PalCode",
  417                 "PersistentMemory"
  418         };
  419 
  420         *mrcnt = 0;
  421 
  422         /*
  423          * Memory map data provided by UEFI via the GetMemoryMap
  424          * Boot Services API.
  425          */
  426         efisz = roundup2(sizeof(struct efi_map_header), 0x10);
  427         map = (struct efi_md *)((uint8_t *)efihdr + efisz);
  428 
  429         if (efihdr->descriptor_size == 0)
  430                 return;
  431         ndesc = efihdr->memory_size / efihdr->descriptor_size;
  432 
  433         if (boothowto & RB_VERBOSE)
  434                 printf("%23s %12s %12s %8s %4s\n",
  435                     "Type", "Physical", "Virtual", "#Pages", "Attr");
  436 
  437         for (i = 0, j = 0, p = map; i < ndesc; i++,
  438             p = efi_next_descriptor(p, efihdr->descriptor_size)) {
  439                 if (boothowto & RB_VERBOSE) {
  440                         if (p->md_type < nitems(types))
  441                                 type = types[p->md_type];
  442                         else
  443                                 type = "<INVALID>";
  444                         printf("%23s %012llx %012llx %08llx ", type, p->md_phys,
  445                             p->md_virt, p->md_pages);
  446                         if (p->md_attr & EFI_MD_ATTR_UC)
  447                                 printf("UC ");
  448                         if (p->md_attr & EFI_MD_ATTR_WC)
  449                                 printf("WC ");
  450                         if (p->md_attr & EFI_MD_ATTR_WT)
  451                                 printf("WT ");
  452                         if (p->md_attr & EFI_MD_ATTR_WB)
  453                                 printf("WB ");
  454                         if (p->md_attr & EFI_MD_ATTR_UCE)
  455                                 printf("UCE ");
  456                         if (p->md_attr & EFI_MD_ATTR_WP)
  457                                 printf("WP ");
  458                         if (p->md_attr & EFI_MD_ATTR_RP)
  459                                 printf("RP ");
  460                         if (p->md_attr & EFI_MD_ATTR_XP)
  461                                 printf("XP ");
  462                         if (p->md_attr & EFI_MD_ATTR_NV)
  463                                 printf("NV ");
  464                         if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
  465                                 printf("MORE_RELIABLE ");
  466                         if (p->md_attr & EFI_MD_ATTR_RO)
  467                                 printf("RO ");
  468                         if (p->md_attr & EFI_MD_ATTR_RT)
  469                                 printf("RUNTIME");
  470                         printf("\n");
  471                 }
  472 
  473                 switch (p->md_type) {
  474                 case EFI_MD_TYPE_CODE:
  475                 case EFI_MD_TYPE_DATA:
  476                 case EFI_MD_TYPE_BS_CODE:
  477                 case EFI_MD_TYPE_BS_DATA:
  478                 case EFI_MD_TYPE_FREE:
  479                         /*
  480                          * We're allowed to use any entry with these types.
  481                          */
  482                         break;
  483                 default:
  484                         continue;
  485                 }
  486 
  487                 j++;
  488                 if (j >= FDT_MEM_REGIONS)
  489                         break;
  490 
  491                 mr[j].mr_start = p->md_phys;
  492                 mr[j].mr_size = p->md_pages * EFI_PAGE_SIZE;
  493         }
  494 
  495         *mrcnt = j;
  496 }
  497 #endif /* EFI */

Cache object: 83e5efad84dd6d33619597eca6180df0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.