From 91dd4cbea0393c56efe4baecb3ef2a07389d0000 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sat, 18 Oct 2014 21:12:12 +0000 Subject: [PATCH] [FREELDR] - Improve memory layout by moving the 32/64 bit stack to 0x7000-0xF000 and moving the BIOSCALLBUFFER up a bit. This gives us 56 KB additional space for freeldr itself. This allows to compile freeldr with /RTC1 (x86 only, the x64 version would get too big). And yes, it works. - Implement FrLdrBugCheckWithMessage to get some useful messages on the screen and use it in MmCheckFreeldrImageFile - Merge the .rtc section into the .text section, when we use RTC1 - Check the location of the Extended BIOS Data Area, add it to the memory descriptors and make sure we have enough space to put freeldr in. If the location of the EBDA is too low, print out a nice message on a blue screen :) svn path=/trunk/; revision=64815 --- reactos/boot/freeldr/freeldr/CMakeLists.txt | 2 + .../boot/freeldr/freeldr/arch/amd64/entry.S | 2 +- .../boot/freeldr/freeldr/arch/i386/entry.S | 2 +- .../boot/freeldr/freeldr/arch/i386/i386bug.c | 42 +++++++++++- .../boot/freeldr/freeldr/arch/i386/pcmem.c | 67 +++++++++++++++++-- reactos/boot/freeldr/freeldr/debug.c | 1 + .../freeldr/include/arch/pc/x86common.h | 10 +-- reactos/boot/freeldr/freeldr/include/debug.h | 10 +++ reactos/boot/freeldr/freeldr/mm/meminit.c | 59 ++++++++++------ 9 files changed, 159 insertions(+), 36 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/CMakeLists.txt b/reactos/boot/freeldr/freeldr/CMakeLists.txt index 1eac9b09303..f5b3d1b7de8 100644 --- a/reactos/boot/freeldr/freeldr/CMakeLists.txt +++ b/reactos/boot/freeldr/freeldr/CMakeLists.txt @@ -216,6 +216,7 @@ if(STACK_PROTECTOR) elseif(RUNTIME_CHECKS) target_link_libraries(freeldr_pe runtmchk) target_link_libraries(freeldr_pe_dbg runtmchk) + add_target_link_flags(freeldr_pe "/MERGE:.rtc=.text") endif() add_dependencies(freeldr_pe asm) @@ -279,6 +280,7 @@ if(STACK_PROTECTOR) elseif(RUNTIME_CHECKS) target_link_libraries(setupldr_pe runtmchk) target_link_libraries(setupldr_pe_dbg runtmchk) + add_target_link_flags(setupldr_pe "/MERGE:.rtc=.text") endif() add_dependencies(setupldr_pe asm) diff --git a/reactos/boot/freeldr/freeldr/arch/amd64/entry.S b/reactos/boot/freeldr/freeldr/arch/amd64/entry.S index 9379008f9de..47080b39cf4 100644 --- a/reactos/boot/freeldr/freeldr/arch/amd64/entry.S +++ b/reactos/boot/freeldr/freeldr/arch/amd64/entry.S @@ -121,7 +121,7 @@ CallRealMode_return: /* 64-bit stack pointer */ stack64: - .double STACK64ADDR + .double STACKADDR PUBLIC FrldrBootDrive FrldrBootDrive: diff --git a/reactos/boot/freeldr/freeldr/arch/i386/entry.S b/reactos/boot/freeldr/freeldr/arch/i386/entry.S index 795cd40afe0..09003cff5f4 100644 --- a/reactos/boot/freeldr/freeldr/arch/i386/entry.S +++ b/reactos/boot/freeldr/freeldr/arch/i386/entry.S @@ -257,7 +257,7 @@ stack16: /* 32-bit stack pointer */ stack32: - .long STACK32ADDR + .long STACKADDR .align 4 /* force 4-byte alignment */ gdt: diff --git a/reactos/boot/freeldr/freeldr/arch/i386/i386bug.c b/reactos/boot/freeldr/freeldr/arch/i386/i386bug.c index 1722b6c4294..d31796d16de 100644 --- a/reactos/boot/freeldr/freeldr/arch/i386/i386bug.c +++ b/reactos/boot/freeldr/freeldr/arch/i386/i386bug.c @@ -86,11 +86,11 @@ i386PrintFrames(PKTRAP_FRAME TrapFrame) PrintText("Frames:\n"); #ifdef _M_IX86 for (Frame = (FRAME*)TrapFrame->Ebp; - Frame != 0 && (ULONG_PTR)Frame < STACK32ADDR; + Frame != 0 && (ULONG_PTR)Frame < STACKADDR; Frame = Frame->Next) #else for (Frame = (FRAME*)TrapFrame->TrapFrame; - Frame != 0 && (ULONG_PTR)Frame < STACK32ADDR; + Frame != 0 && (ULONG_PTR)Frame < STACKADDR; Frame = Frame->Next) #endif { @@ -171,6 +171,44 @@ i386PrintExceptionText(ULONG TrapIndex, PKTRAP_FRAME TrapFrame, PKSPECIAL_REGIST InstructionPointer[6], InstructionPointer[7]); } +VOID +NTAPI +FrLdrBugCheckWithMessage( + ULONG BugCode, + PCHAR File, + ULONG Line, + PSTR Format, + ...) +{ + CHAR Buffer[1024]; + va_list argptr; + + /* Blue screen for the win */ + MachVideoClearScreen(SCREEN_ATTR); + i386_ScreenPosX = 0; + i386_ScreenPosY = 0; + + PrintText("A problem has been detected and FreeLoader boot has been aborted.\n\n"); + + PrintText("%ld: %s\n\n", BugCode, BugCodeStrings[BugCode]); + + if (File) + { + PrintText("Location: %s:%ld\n\n", File, Line); + } + + va_start(argptr, Format); + _vsnprintf(Buffer, sizeof(Buffer), Format, argptr); + va_end(argptr); + Buffer[sizeof(Buffer) - 1] = 0; + + i386PrintText(Buffer); + + _disable(); + __halt(); + for (;;); +} + void NTAPI FrLdrBugCheckEx( diff --git a/reactos/boot/freeldr/freeldr/arch/i386/pcmem.c b/reactos/boot/freeldr/freeldr/arch/i386/pcmem.c index 2b21b698741..76601e4118a 100644 --- a/reactos/boot/freeldr/freeldr/arch/i386/pcmem.c +++ b/reactos/boot/freeldr/freeldr/arch/i386/pcmem.c @@ -28,15 +28,15 @@ DBG_DEFAULT_CHANNEL(MEMORY); #define MAX_BIOS_DESCRIPTORS 32 + +#define STACK_BASE_PAGE (STACKLOW / PAGE_SIZE) #define FREELDR_BASE_PAGE (FREELDR_BASE / PAGE_SIZE) #define DISKBUF_BASE_PAGE (DISKREADBUFFER / PAGE_SIZE) -#define STACK_BASE_PAGE (STACKLOWLIMIT / PAGE_SIZE) -#define STACK_END_PAGE (STACK32ADDR / PAGE_SIZE) #define BIOSBUF_BASE_PAGE (BIOSCALLBUFFER / PAGE_SIZE) +#define STACK_PAGE_COUNT (FREELDR_BASE_PAGE - STACK_BASE_PAGE) #define FREELDR_PAGE_COUNT (DISKBUF_BASE_PAGE - FREELDR_BASE_PAGE) -#define DISKBUF_PAGE_COUNT (STACK_BASE_PAGE - DISKBUF_BASE_PAGE) -#define STACK_PAGE_COUNT (STACK_END_PAGE - STACK_BASE_PAGE) +#define DISKBUF_PAGE_COUNT (0x10) #define BIOSBUF_PAGE_COUNT (1) BIOS_MEMORY_MAP PcBiosMemoryMap[MAX_BIOS_DESCRIPTORS]; @@ -45,11 +45,12 @@ ULONG PcBiosMapCount; FREELDR_MEMORY_DESCRIPTOR PcMemoryMap[MAX_BIOS_DESCRIPTORS + 1] = { { LoaderFirmwarePermanent, 0x00, 1 }, // realmode int vectors - { LoaderFirmwareTemporary, 0x01, FREELDR_BASE_PAGE - 1 }, // freeldr stack + cmdline + { LoaderFirmwareTemporary, 0x01, STACK_BASE_PAGE - 1 }, // freeldr stack + cmdline + { LoaderOsloaderStack, STACK_BASE_PAGE, FREELDR_BASE_PAGE - STACK_BASE_PAGE }, // prot mode stack. { LoaderLoadedProgram, FREELDR_BASE_PAGE, FREELDR_PAGE_COUNT }, // freeldr image { LoaderFirmwareTemporary, DISKBUF_BASE_PAGE, DISKBUF_PAGE_COUNT }, // Disk read buffer for int 13h. DISKREADBUFFER - { LoaderOsloaderStack, STACK_BASE_PAGE, STACK_PAGE_COUNT }, // prot mode stack. { LoaderFirmwareTemporary, BIOSBUF_BASE_PAGE, BIOSBUF_PAGE_COUNT }, // BIOSCALLBUFFER + { LoaderFirmwarePermanent, 0x9F, 0x1 }, // EBDA { LoaderFirmwarePermanent, 0xA0, 0x50 }, // ROM / Video { LoaderSpecialMemory, 0xF0, 0x10 }, // ROM / Video { LoaderSpecialMemory, 0xFFF, 1 }, // unusable memory @@ -193,10 +194,64 @@ PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSi ULONG MapCount = 0; ULONGLONG RealBaseAddress, RealSize; TYPE_OF_MEMORY MemoryType; + ULONG Size; ASSERT(PcBiosMapCount == 0); TRACE("GetBiosMemoryMap()\n"); + /* Make sure the usable memory is large enough. To do this we check the 16 + bit value at address 0x413 inside the BDA, which gives us the usable size + in KB */ + Size = (*(PUSHORT)(ULONG_PTR)0x413) * 1024; + if (Size < 0x9F000) + { + FrLdrBugCheckWithMessage( + MEMORY_INIT_FAILURE, + __FILE__, + __LINE__, + "The BIOS reported a usable memory range up to 0x%x, which is too small!\n", + Size); + } + + /* Get the address of the Extended BIOS Data Area (EBDA). + * Int 15h, AH=C1h + * SYSTEM - RETURN EXTENDED-BIOS DATA-AREA SEGMENT ADDRESS (PS) + * + * Return: + * CF set on error + * CF clear if successful + * ES = segment of data area + */ + Regs.x.eax = 0x0000C100; + Int386(0x15, &Regs, &Regs); + + /* If the function fails, there is no EBDA */ + if (INT386_SUCCESS(Regs)) + { + /* Check if this is high enough */ + ULONG EbdaBase = (ULONG)Regs.w.es << 4; + if (EbdaBase < 0x9F000) + { + FrLdrBugCheckWithMessage( + MEMORY_INIT_FAILURE, + __FILE__, + __LINE__, + "The location of your EBDA is 0x%lx, which is too low!\n" + "If you see this, please report to the ReactOS team!", + EbdaBase); + } + + /* Calculate the (max) size of the EBDA */ + Size = 0xA0000 - EbdaBase; + + /* Add the descriptor */ + MapCount = AddMemoryDescriptor(PcMemoryMap, + MAX_BIOS_DESCRIPTORS, + (EbdaBase / MM_PAGE_SIZE), + (Size / MM_PAGE_SIZE), + LoaderFirmwarePermanent); + } + /* Int 15h AX=E820h * Newer BIOSes - GET SYSTEM MEMORY MAP * diff --git a/reactos/boot/freeldr/freeldr/debug.c b/reactos/boot/freeldr/freeldr/debug.c index dfde53f27d7..22b8cb83e3b 100644 --- a/reactos/boot/freeldr/freeldr/debug.c +++ b/reactos/boot/freeldr/freeldr/debug.c @@ -444,6 +444,7 @@ char *BugCodeStrings[] = "TEST_BUGCHECK", "MISSING_HARDWARE_REQUIREMENTS", "FREELDR_IMAGE_CORRUPTION", + "MEMORY_INIT_FAILURE", }; ULONG_PTR BugCheckInfo[5]; diff --git a/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h b/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h index 3d5c7ffb4cb..b238a8fd97a 100644 --- a/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h +++ b/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h @@ -11,13 +11,13 @@ //#endif #define STACK16ADDR HEX(6F00) /* The 16-bit stack top will be at 0000:6F00 */ #define BSS_START HEX(6F00) +#define STACKLOW HEX(7000) +#define STACKADDR HEX(F000) /* The 32/64-bit stack top will be at 0000:F000, or 0xF000 */ #define FREELDR_BASE HEX(F800) #define FREELDR_PE_BASE HEX(10000) -#define DISKREADBUFFER HEX(80000) /* Buffer to store data read in from the disk via the BIOS */ -#define STACKLOWLIMIT HEX(90000) -#define STACK32ADDR HEX(98000) /* The 32-bit stack top will be at 9000:8000, or 0xA8000 */ -#define STACK64ADDR HEX(98000) /* The 64-bit stack top will be at 98000 */ -#define BIOSCALLBUFFER HEX(98000) /* Buffer to store temporary data for any Int386() call */ +#define DISKREADBUFFER HEX(8E000) /* Buffer to store data read in from the disk via the BIOS */ +#define BIOSCALLBUFFER HEX(9E000) /* Buffer to store temporary data for any Int386() call */ +/* 9F000- 9FFFF is reserved for the EBDA */ #define DISKREADBUFFER_SIZE HEX(10000) #define BIOSCALLBUFSEGMENT (BIOSCALLBUFFER/16) /* Buffer to store temporary data for any Int386() call */ diff --git a/reactos/boot/freeldr/freeldr/include/debug.h b/reactos/boot/freeldr/freeldr/include/debug.h index b88c1bd0b49..77a7eed98ac 100644 --- a/reactos/boot/freeldr/freeldr/include/debug.h +++ b/reactos/boot/freeldr/freeldr/include/debug.h @@ -124,12 +124,22 @@ void NTAPI FrLdrBugCheck(ULONG BugCode); +VOID +NTAPI +FrLdrBugCheckWithMessage( + ULONG BugCode, + PCHAR File, + ULONG Line, + PSTR Format, + ...); + /* Bugcheck codes */ enum _FRLDR_BUGCHECK_CODES { TEST_BUGCHECK, MISSING_HARDWARE_REQUIREMENTS, FREELDR_IMAGE_CORRUPTION, + MEMORY_INIT_FAILURE, }; extern char *BugCodeStrings[]; diff --git a/reactos/boot/freeldr/freeldr/mm/meminit.c b/reactos/boot/freeldr/freeldr/mm/meminit.c index 80871c79c08..b0db4bdd487 100644 --- a/reactos/boot/freeldr/freeldr/mm/meminit.c +++ b/reactos/boot/freeldr/freeldr/mm/meminit.c @@ -159,8 +159,8 @@ ArcGetMemoryDescriptor(const FREELDR_MEMORY_DESCRIPTOR* Current) } } - -BOOLEAN +static +VOID MmCheckFreeldrImageFile() { PIMAGE_NT_HEADERS NtHeaders; @@ -172,7 +172,11 @@ MmCheckFreeldrImageFile() if (!NtHeaders) { ERR("Could not get NtHeaders!\n"); - return FALSE; + FrLdrBugCheckWithMessage( + FREELDR_IMAGE_CORRUPTION, + __FILE__, + __LINE__, + "Could not get NtHeaders!\n"); } /* Check the file header */ @@ -184,12 +188,21 @@ MmCheckFreeldrImageFile() (FileHeader->SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))) { ERR("FreeLdr FileHeader is invalid.\n"); - BugCheckInfo[0] = FileHeader->Machine; - BugCheckInfo[1] = FileHeader->NumberOfSections; - BugCheckInfo[2] = FileHeader->PointerToSymbolTable; - BugCheckInfo[3] = FileHeader->NumberOfSymbols; - BugCheckInfo[4] = FileHeader->SizeOfOptionalHeader; - return FALSE; + FrLdrBugCheckWithMessage( + FREELDR_IMAGE_CORRUPTION, + __FILE__, + __LINE__, + "FreeLdr FileHeader is invalid.\n" + "Machine == 0x%lx, expected 0x%lx\n" + "NumberOfSections == 0x%lx, expected 0x%lx\n" + "PointerToSymbolTable == 0x%lx, expected 0\n" + "NumberOfSymbols == 0x%lx, expected 0\n" + "SizeOfOptionalHeader == 0x%lx, expected 0x%lx\n", + FileHeader->Machine, IMAGE_FILE_MACHINE_NATIVE, + FileHeader->NumberOfSections, FREELDR_SECTION_COUNT, + FileHeader->PointerToSymbolTable, + FileHeader->NumberOfSymbols, + FileHeader->SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)); } /* Check the optional header */ @@ -201,15 +214,22 @@ MmCheckFreeldrImageFile() (OptionalHeader->SectionAlignment != OptionalHeader->FileAlignment)) { ERR("FreeLdr OptionalHeader is invalid.\n"); - BugCheckInfo[0] = 0x80000000 | (OptionalHeader->Subsystem << 16) | OptionalHeader->Magic; - BugCheckInfo[1] = OptionalHeader->ImageBase; - BugCheckInfo[2] = OptionalHeader->SizeOfImage; - BugCheckInfo[3] = OptionalHeader->SectionAlignment; - BugCheckInfo[4] = OptionalHeader->FileAlignment; - return FALSE; + FrLdrBugCheckWithMessage( + FREELDR_IMAGE_CORRUPTION, + __FILE__, + __LINE__, + "FreeLdr OptionalHeader is invalid.\n" + "Magic == 0x%lx, expected 0x%lx\n" + "Subsystem == 0x%lx, expected 1 (native)\n" + "ImageBase == 0x%lx, expected 0x%lx\n" + "SizeOfImage == 0x%lx, maximum 0x%lx\n" + "SectionAlignment 0x%lx doesn't match FileAlignment 0x%lx\n", + OptionalHeader->Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC, + OptionalHeader->Subsystem, + OptionalHeader->ImageBase, FREELDR_PE_BASE, + OptionalHeader->SizeOfImage, MAX_FREELDR_PE_SIZE, + OptionalHeader->SectionAlignment, OptionalHeader->FileAlignment); } - - return TRUE; } BOOLEAN MmInitializeMemoryManager(VOID) @@ -221,10 +241,7 @@ BOOLEAN MmInitializeMemoryManager(VOID) TRACE("Initializing Memory Manager.\n"); /* Check the freeldr binary */ - if (!MmCheckFreeldrImageFile()) - { - FrLdrBugCheck(FREELDR_IMAGE_CORRUPTION); - } + MmCheckFreeldrImageFile(); BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount);