diff --git a/src/csmwrap.c b/src/csmwrap.c index d322387..944b126 100644 --- a/src/csmwrap.c +++ b/src/csmwrap.c @@ -45,27 +45,6 @@ static void *find_table(uint32_t signature, uint8_t *csm_bin_base, size_t size) return Table; } -int test_bios_region_rw() -{ - uint32_t backup; - uint32_t *bios_region = (uint32_t *)BIOSROM_START; - uint32_t *bios_region_end = (uint32_t *)BIOSROM_END; - uint32_t *ptr = bios_region; - - while (ptr < bios_region_end) { - backup = *ptr; - *ptr = 0xdeadbeef; - if (*ptr != 0xdeadbeef) { - printf("Unable to write to BIOS region\n"); - return -1; - } - *ptr = backup; - ptr++; - } - - return 0; -} - int set_smbios_table() { UINTN i; @@ -134,11 +113,6 @@ EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } printf("Unlock!\n"); - if (test_bios_region_rw()) { - printf("BIOS region bad\n"); - return -1; - } - apply_intel_platform_workarounds(); csm_bin_base = (uintptr_t)BIOSROM_END - sizeof(Csm16_bin); diff --git a/src/io.h b/src/io.h index df7ad7c..8e491da 100644 --- a/src/io.h +++ b/src/io.h @@ -6,6 +6,10 @@ #define barrier() __asm__ __volatile__("": : :"memory") +static inline void clflush(void *addr) { + asm volatile ("clflush (%0)" :: "r"(addr) : "memory"); +} + static inline void writel(void *addr, uint32_t val) { barrier(); *(volatile uint32_t *)addr = val; diff --git a/src/unlock_region.c b/src/unlock_region.c index 5810fe7..c83f759 100644 --- a/src/unlock_region.c +++ b/src/unlock_region.c @@ -5,6 +5,7 @@ * with fallback to direct PCI configuration space access for specific chipsets. */ +#include #include #include "csmwrap.h" #include "edk2/LegacyRegion2.h" @@ -298,6 +299,30 @@ EFI_STATUS print_legacy_region_info(EFI_LEGACY_REGION2_PROTOCOL *legacy_region) return EFI_SUCCESS; } +static bool test_bios_region_rw(void) { + uint32_t *bios_region = (uint32_t *)BIOSROM_START; + uint32_t *bios_region_end = (uint32_t *)BIOSROM_END; + uint32_t *ptr = bios_region; + + while (ptr < bios_region_end) { + clflush(ptr); + uint32_t val = readl(ptr); + + writel(ptr, ~val); + clflush(ptr); + + if (readl(ptr) != ~val) { + printf("Unable to write to BIOS region\n"); + return false; + } + + writel(ptr, val); + ptr++; + } + + return true; +} + /** * Main function to unlock the BIOS region * Tries to use the UEFI protocol first, then falls back to chipset-specific methods @@ -309,6 +334,11 @@ int unlock_bios_region(void) EFI_LEGACY_REGION2_PROTOCOL *legacy_region = NULL; EFI_STATUS status; + // No need to do anything if the region is already unlocked and working. + if (test_bios_region_rw()) { + return 0; + } + /* First, try to use the Legacy Region 2 Protocol */ status = gBS->LocateProtocol( &gEfiLegacyRegion2ProtocolGuid, @@ -322,7 +352,7 @@ int unlock_bios_region(void) /* Try to unlock using the protocol */ status = unlock_legacy_region_protocol(); - if (!EFI_ERROR(status)) { + if (!EFI_ERROR(status) && test_bios_region_rw()) { return 0; /* Success */ } @@ -367,5 +397,5 @@ int unlock_bios_region(void) break; } - return status == 0 ? 0 : -1; + return (status == 0 && test_bios_region_rw()) ? 0 : -1; }