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