/** @file | |
* | |
* Copyright (c) 2011-2015, ARM Limited. All rights reserved. | |
* | |
* This program and the accompanying materials | |
* are licensed and made available under the terms and conditions of the BSD License | |
* which accompanies this distribution. The full text of the license may be found at | |
* http://opensource.org/licenses/bsd-license.php | |
* | |
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
* | |
**/ | |
#include "LinuxAtag.h" | |
#include "LinuxLoader.h" | |
// Point to the current ATAG | |
STATIC LINUX_ATAG *mLinuxKernelCurrentAtag; | |
STATIC | |
VOID | |
SetupCoreTag ( | |
IN UINT32 PageSize | |
) | |
{ | |
mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_CORE); | |
mLinuxKernelCurrentAtag->header.type = ATAG_CORE; | |
mLinuxKernelCurrentAtag->body.core_tag.flags = 1; /* ensure read-only */ | |
mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */ | |
mLinuxKernelCurrentAtag->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/ | |
// move pointer to next tag | |
mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag); | |
} | |
STATIC | |
VOID | |
SetupMemTag ( | |
IN UINTN StartAddress, | |
IN UINT32 Size | |
) | |
{ | |
mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_MEM); | |
mLinuxKernelCurrentAtag->header.type = ATAG_MEM; | |
mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */ | |
mLinuxKernelCurrentAtag->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */ | |
// move pointer to next tag | |
mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag); | |
} | |
STATIC | |
VOID | |
SetupCmdlineTag ( | |
IN CONST CHAR8 *CmdLine | |
) | |
{ | |
UINT32 LineLength; | |
// Increment the line length by 1 to account for the null string terminator character | |
LineLength = AsciiStrLen (CmdLine) + 1; | |
/* Check for NULL strings. | |
* Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer. | |
* Remember, you have at least one null string terminator character. | |
*/ | |
if (LineLength > 1) { | |
mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof (LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2; | |
mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE; | |
/* place CommandLine into tag */ | |
AsciiStrCpy (mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine); | |
// move pointer to next tag | |
mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag); | |
} | |
} | |
STATIC | |
VOID | |
SetupInitrdTag ( | |
IN UINT32 InitrdImage, | |
IN UINT32 InitrdImageSize | |
) | |
{ | |
mLinuxKernelCurrentAtag->header.size = tag_size (LINUX_ATAG_INITRD2); | |
mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2; | |
mLinuxKernelCurrentAtag->body.initrd2_tag.start = InitrdImage; | |
mLinuxKernelCurrentAtag->body.initrd2_tag.size = InitrdImageSize; | |
// Move pointer to next tag | |
mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag); | |
} | |
STATIC | |
VOID | |
SetupEndTag ( | |
VOID | |
) | |
{ | |
// Empty tag ends list; this has zero length and no body | |
mLinuxKernelCurrentAtag->header.type = ATAG_NONE; | |
mLinuxKernelCurrentAtag->header.size = 0; | |
/* We can not calculate the next address by using the standard macro: | |
* Params = next_tag_address (Params); | |
* because it relies on the header.size, which here it is 0 (zero). | |
* The easiest way is to add the sizeof (mLinuxKernelCurrentAtag->header). | |
*/ | |
mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof (mLinuxKernelCurrentAtag->header)); | |
} | |
EFI_STATUS | |
PrepareAtagList ( | |
IN EFI_PHYSICAL_ADDRESS SystemMemoryBase, | |
IN CONST CHAR8* CommandLineString, | |
IN EFI_PHYSICAL_ADDRESS InitrdImage, | |
IN UINTN InitrdImageSize, | |
OUT EFI_PHYSICAL_ADDRESS *AtagBase, | |
OUT UINT32 *AtagSize | |
) | |
{ | |
EFI_STATUS Status; | |
LIST_ENTRY *ResourceLink; | |
LIST_ENTRY ResourceList; | |
EFI_PHYSICAL_ADDRESS AtagStartAddress; | |
SYSTEM_MEMORY_RESOURCE *Resource; | |
AtagStartAddress = LINUX_ATAG_MAX_OFFSET; | |
Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES (ATAG_MAX_SIZE), &AtagStartAddress); | |
if (EFI_ERROR (Status)) { | |
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)); | |
Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES (ATAG_MAX_SIZE), &AtagStartAddress); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} | |
// Ready to setup the atag list | |
mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress; | |
// Standard core tag 4k PageSize | |
SetupCoreTag ( (UINT32)SIZE_4KB ); | |
// Physical memory setup | |
GetSystemMemoryResources (&ResourceList); | |
ResourceLink = ResourceList.ForwardLink; | |
while (ResourceLink != NULL && ResourceLink != &ResourceList) { | |
Resource = (SYSTEM_MEMORY_RESOURCE*)ResourceLink; | |
DEBUG ((EFI_D_INFO, "- [0x%08X,0x%08X]\n", | |
(UINT32)Resource->PhysicalStart, | |
(UINT32)Resource->PhysicalStart + (UINT32)Resource->ResourceLength)); | |
SetupMemTag ((UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength ); | |
ResourceLink = ResourceLink->ForwardLink; | |
} | |
// CommandLine setting root device | |
if (CommandLineString) { | |
SetupCmdlineTag (CommandLineString); | |
} | |
if (InitrdImageSize > 0 && InitrdImage != 0) { | |
SetupInitrdTag ((UINT32)InitrdImage, (UINT32)InitrdImageSize); | |
} | |
// End of tags | |
SetupEndTag (); | |
// Calculate atag list size | |
*AtagBase = AtagStartAddress; | |
*AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1; | |
return EFI_SUCCESS; | |
} |