blob: fd7ee9c8624dabd09c3b2be53b0bb6d9e2662930 [file] [log] [blame]
/** @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;
}