/** @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; }