From a90e3279219af078d02d3176c554e81444391d85 Mon Sep 17 00:00:00 2001 From: oliviermartin Date: Tue, 12 Mar 2013 01:02:44 +0000 Subject: [PATCH] ArmPkg/BdsLib: Free the memory when Linux fails to start Not freeing the memory prevents Linux to be started again. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14193 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c | 69 ++++++++++++++++------ ArmPkg/Library/BdsLib/BdsLinuxFdt.c | 10 +++- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c b/ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c index e3249e1307..0c4d9f6b08 100644 --- a/ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c +++ b/ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c @@ -146,11 +146,13 @@ BdsBootLinuxAtag ( { EFI_STATUS Status; UINT32 LinuxImageSize; + UINT32 InitrdImageBaseSize = 0; UINT32 InitrdImageSize = 0; UINT32 AtagSize; EFI_PHYSICAL_ADDRESS AtagBase; EFI_PHYSICAL_ADDRESS LinuxImage; - EFI_PHYSICAL_ADDRESS InitrdImage; + EFI_PHYSICAL_ADDRESS InitrdImageBase = 0; + EFI_PHYSICAL_ADDRESS InitrdImage = 0; PERF_START (NULL, "BDS", NULL, 0); @@ -164,21 +166,24 @@ BdsBootLinuxAtag ( if (InitrdDevicePath) { // Load the initrd near to the Linux kernel - InitrdImage = LINUX_KERNEL_MAX_OFFSET; - Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); + InitrdImageBase = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize); if (Status == EFI_OUT_OF_RESOURCES) { - Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); + Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize); } if (EFI_ERROR(Status)) { Print (L"ERROR: Did not find initrd image.\n"); - return Status; + goto EXIT_FREE_LINUX; } // Check if the initrd is a uInitrd - if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { + if (*(UINT32*)((UINTN)InitrdImageBase) == LINUX_UIMAGE_SIGNATURE) { // Skip the 64-byte image header - InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); - InitrdImageSize -= 64; + InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64); + InitrdImageSize = InitrdImageBaseSize - 64; + } else { + InitrdImage = InitrdImageBase; + InitrdImageSize = InitrdImageBaseSize; } } @@ -190,10 +195,20 @@ BdsBootLinuxAtag ( Status = PrepareAtagList (CommandLineArguments, InitrdImage, InitrdImageSize, &AtagBase, &AtagSize); if (EFI_ERROR(Status)) { Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); - return Status; + goto EXIT_FREE_INITRD; } return StartLinux (LinuxImage, LinuxImageSize, AtagBase, AtagSize, PcdGet32(PcdArmMachineType)); + +EXIT_FREE_INITRD: + if (InitrdDevicePath) { + gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize)); + } + +EXIT_FREE_LINUX: + gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize)); + + return Status; } /** @@ -218,11 +233,13 @@ BdsBootLinuxFdt ( { EFI_STATUS Status; UINT32 LinuxImageSize; + UINT32 InitrdImageBaseSize = 0; UINT32 InitrdImageSize = 0; UINT32 FdtBlobSize; EFI_PHYSICAL_ADDRESS FdtBlobBase; EFI_PHYSICAL_ADDRESS LinuxImage; - EFI_PHYSICAL_ADDRESS InitrdImage; + EFI_PHYSICAL_ADDRESS InitrdImageBase = 0; + EFI_PHYSICAL_ADDRESS InitrdImage = 0; PERF_START (NULL, "BDS", NULL, 0); @@ -235,21 +252,24 @@ BdsBootLinuxFdt ( } if (InitrdDevicePath) { - InitrdImage = LINUX_KERNEL_MAX_OFFSET; - Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); + InitrdImageBase = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImageBase, &InitrdImageBaseSize); if (Status == EFI_OUT_OF_RESOURCES) { - Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); + Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImageBase, &InitrdImageBaseSize); } if (EFI_ERROR(Status)) { Print (L"ERROR: Did not find initrd image.\n"); - return Status; + goto EXIT_FREE_LINUX; } // Check if the initrd is a uInitrd if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { // Skip the 64-byte image header - InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); - InitrdImageSize -= 64; + InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImageBase + 64); + InitrdImageSize = InitrdImageBaseSize - 64; + } else { + InitrdImage = InitrdImageBase; + InitrdImageSize = InitrdImageBaseSize; } } @@ -258,7 +278,7 @@ BdsBootLinuxFdt ( Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize); if (EFI_ERROR(Status)) { Print (L"ERROR: Did not find Device Tree blob.\n"); - return Status; + goto EXIT_FREE_INITRD; } // Update the Fdt with the Initrd information. The FDT will increase in size. @@ -266,9 +286,22 @@ BdsBootLinuxFdt ( Status = PrepareFdt (CommandLineArguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize); if (EFI_ERROR(Status)) { Print(L"ERROR: Can not load kernel with FDT. Status=%r\n", Status); - return Status; + goto EXIT_FREE_FDT; } return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize, ARM_FDT_MACHINE_TYPE); + +EXIT_FREE_FDT: + gBS->FreePages (FdtBlobBase, EFI_SIZE_TO_PAGES (FdtBlobSize)); + +EXIT_FREE_INITRD: + if (InitrdDevicePath) { + gBS->FreePages (InitrdImageBase, EFI_SIZE_TO_PAGES (InitrdImageBaseSize)); + } + +EXIT_FREE_LINUX: + gBS->FreePages (LinuxImage, EFI_SIZE_TO_PAGES (LinuxImageSize)); + + return Status; } diff --git a/ArmPkg/Library/BdsLib/BdsLinuxFdt.c b/ArmPkg/Library/BdsLib/BdsLinuxFdt.c index 1baa237162..b5dd237136 100644 --- a/ArmPkg/Library/BdsLib/BdsLinuxFdt.c +++ b/ArmPkg/Library/BdsLib/BdsLinuxFdt.c @@ -310,7 +310,7 @@ PrepareFdt ( Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase); if (EFI_ERROR(Status)) { ASSERT_EFI_ERROR(Status); - goto FAIL_NEW_FDT; + goto FAIL_ALLOCATE_NEW_FDT; } else { DEBUG ((EFI_D_WARN, "WARNING: Loaded FDT at random address 0x%lX.\nWARNING: There is a risk of accidental overwriting by other code/data.\n", NewFdtBlobBase)); } @@ -515,12 +515,18 @@ PrepareFdt ( //DebugDumpFdt (fdt); DEBUG_CODE_END(); + // If we succeeded to generate the new Device Tree then free the old Device Tree + gBS->FreePages (*FdtBlobBase, EFI_SIZE_TO_PAGES (*FdtBlobSize)); + *FdtBlobBase = NewFdtBlobBase; *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase)); return EFI_SUCCESS; FAIL_NEW_FDT: - *FdtBlobSize = OriginalFdtSize; + gBS->FreePages (NewFdtBlobBase, EFI_SIZE_TO_PAGES (NewFdtBlobSize)); + +FAIL_ALLOCATE_NEW_FDT: + *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase)); // Return success even if we failed to update the FDT blob. The original one is still valid. return EFI_SUCCESS; }