Home | History | Annotate | Download | only in Arm
      1 /** @file
      2 *
      3 *  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
      4 *
      5 *  This program and the accompanying materials
      6 *  are licensed and made available under the terms and conditions of the BSD License
      7 *  which accompanies this distribution.  The full text of the license may be found at
      8 *  http://opensource.org/licenses/bsd-license.php
      9 *
     10 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 *
     13 **/
     14 
     15 #include "LinuxAtag.h"
     16 #include "LinuxLoader.h"
     17 
     18 // Point to the current ATAG
     19 STATIC LINUX_ATAG *mLinuxKernelCurrentAtag;
     20 
     21 STATIC
     22 VOID
     23 SetupCoreTag (
     24   IN UINT32 PageSize
     25   )
     26 {
     27   mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_CORE);
     28   mLinuxKernelCurrentAtag->header.type = ATAG_CORE;
     29 
     30   mLinuxKernelCurrentAtag->body.core_tag.flags    = 1;            /* ensure read-only */
     31   mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize;     /* systems PageSize (4k) */
     32   mLinuxKernelCurrentAtag->body.core_tag.rootdev  = 0;            /* zero root device (typically overridden from kernel command line )*/
     33 
     34   // move pointer to next tag
     35   mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);
     36 }
     37 
     38 STATIC
     39 VOID
     40 SetupMemTag (
     41   IN UINTN StartAddress,
     42   IN UINT32 Size
     43   )
     44 {
     45   mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_MEM);
     46   mLinuxKernelCurrentAtag->header.type = ATAG_MEM;
     47 
     48   mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress;    /* Start of memory chunk for AtagMem */
     49   mLinuxKernelCurrentAtag->body.mem_tag.size  = Size;             /* Size of memory chunk for AtagMem */
     50 
     51   // move pointer to next tag
     52   mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);
     53 }
     54 
     55 STATIC
     56 VOID
     57 SetupCmdlineTag (
     58   IN CONST CHAR8 *CmdLine
     59   )
     60 {
     61   UINT32 LineLength;
     62 
     63   // Increment the line length by 1 to account for the null string terminator character
     64   LineLength = AsciiStrLen (CmdLine) + 1;
     65 
     66   /* Check for NULL strings.
     67    * Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer.
     68    * Remember, you have at least one null string terminator character.
     69    */
     70   if (LineLength > 1) {
     71     mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof (LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2;
     72     mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE;
     73 
     74     /* place CommandLine into tag */
     75     AsciiStrCpy (mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine);
     76 
     77     // move pointer to next tag
     78     mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);
     79   }
     80 }
     81 
     82 STATIC
     83 VOID
     84 SetupInitrdTag (
     85   IN UINT32 InitrdImage,
     86   IN UINT32 InitrdImageSize
     87   )
     88 {
     89   mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_INITRD2);
     90   mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2;
     91 
     92   mLinuxKernelCurrentAtag->body.initrd2_tag.start = InitrdImage;
     93   mLinuxKernelCurrentAtag->body.initrd2_tag.size = InitrdImageSize;
     94 
     95   // Move pointer to next tag
     96   mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag);
     97 }
     98 STATIC
     99 VOID
    100 SetupEndTag (
    101   VOID
    102   )
    103 {
    104   // Empty tag ends list; this has zero length and no body
    105   mLinuxKernelCurrentAtag->header.type = ATAG_NONE;
    106   mLinuxKernelCurrentAtag->header.size = 0;
    107 
    108   /* We can not calculate the next address by using the standard macro:
    109    * Params = next_tag_address (Params);
    110    * because it relies on the header.size, which here it is 0 (zero).
    111    * The easiest way is to add the sizeof (mLinuxKernelCurrentAtag->header).
    112    */
    113   mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof (mLinuxKernelCurrentAtag->header));
    114 }
    115 
    116 EFI_STATUS
    117 PrepareAtagList (
    118   IN  EFI_PHYSICAL_ADDRESS  SystemMemoryBase,
    119   IN  CONST CHAR8*          CommandLineString,
    120   IN  EFI_PHYSICAL_ADDRESS  InitrdImage,
    121   IN  UINTN                 InitrdImageSize,
    122   OUT EFI_PHYSICAL_ADDRESS  *AtagBase,
    123   OUT UINT32                *AtagSize
    124   )
    125 {
    126   EFI_STATUS                  Status;
    127   LIST_ENTRY                  *ResourceLink;
    128   LIST_ENTRY                  ResourceList;
    129   EFI_PHYSICAL_ADDRESS        AtagStartAddress;
    130   SYSTEM_MEMORY_RESOURCE      *Resource;
    131 
    132   AtagStartAddress = LINUX_ATAG_MAX_OFFSET;
    133   Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES (ATAG_MAX_SIZE), &AtagStartAddress);
    134   if (EFI_ERROR (Status)) {
    135     DEBUG ((EFI_D_WARN, "Warning: Failed to allocate Atag at 0x%lX (%r). The Atag will be allocated somewhere else in System Memory.\n", AtagStartAddress, Status));
    136     Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES (ATAG_MAX_SIZE), &AtagStartAddress);
    137     if (EFI_ERROR (Status)) {
    138       return Status;
    139     }
    140   }
    141 
    142   // Ready to setup the atag list
    143   mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress;
    144 
    145   // Standard core tag 4k PageSize
    146   SetupCoreTag ( (UINT32)SIZE_4KB );
    147 
    148   // Physical memory setup
    149   GetSystemMemoryResources (&ResourceList);
    150   ResourceLink = ResourceList.ForwardLink;
    151   while (ResourceLink != NULL && ResourceLink != &ResourceList) {
    152     Resource = (SYSTEM_MEMORY_RESOURCE*)ResourceLink;
    153     DEBUG ((EFI_D_INFO, "- [0x%08X,0x%08X]\n",
    154         (UINT32)Resource->PhysicalStart,
    155         (UINT32)Resource->PhysicalStart + (UINT32)Resource->ResourceLength));
    156     SetupMemTag ((UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength );
    157     ResourceLink = ResourceLink->ForwardLink;
    158   }
    159 
    160   // CommandLine setting root device
    161   if (CommandLineString) {
    162     SetupCmdlineTag (CommandLineString);
    163   }
    164 
    165   if (InitrdImageSize > 0 && InitrdImage != 0) {
    166     SetupInitrdTag ((UINT32)InitrdImage, (UINT32)InitrdImageSize);
    167   }
    168 
    169   // End of tags
    170   SetupEndTag ();
    171 
    172   // Calculate atag list size
    173   *AtagBase = AtagStartAddress;
    174   *AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1;
    175 
    176   return EFI_SUCCESS;
    177 }
    178