https://git.reactos.org/?p=reactos.git;a=commitdiff;h=96692636e461b5cc4d0f5…
commit 96692636e461b5cc4d0f5e9fe4e937eb3fcb8d84
Author: Stanislav Motylkov <x86corez(a)gmail.com>
AuthorDate: Tue Dec 31 18:10:34 2019 +0300
Commit: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue Dec 31 16:10:34 2019 +0100
[FREELDR] Obtain Xbox memory map via multiboot spec (#1971)
- Also obtain framebuffer memory size the same way.
References:
https://wiki.osdev.org/Detecting_Memory_(x86)#Memory_Map_Via_GRUB
https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-info…
CORE-16216 CORE-16300
---
boot/freeldr/freeldr/arch/i386/multiboot.S | 43 ++++++++++++
boot/freeldr/freeldr/arch/i386/xboxmem.c | 106 +++++++++++++++++++++++++----
boot/freeldr/freeldr/arch/i386/xboxvideo.c | 50 +++++++++++++-
boot/freeldr/freeldr/include/multiboot.h | 21 ++++++
4 files changed, 204 insertions(+), 16 deletions(-)
diff --git a/boot/freeldr/freeldr/arch/i386/multiboot.S
b/boot/freeldr/freeldr/arch/i386/multiboot.S
index 6094000a0e0..296ce0de73f 100644
--- a/boot/freeldr/freeldr/arch/i386/multiboot.S
+++ b/boot/freeldr/freeldr/arch/i386/multiboot.S
@@ -29,9 +29,13 @@
* the header signature and uses the header to load it.
*/
+#define MB_INFO_SIZE 60 /* sizeof(multiboot_info_t) */
#define MB_INFO_FLAGS_OFFSET 0
#define MB_INFO_BOOT_DEVICE_OFFSET 12
#define MB_INFO_COMMAND_LINE_OFFSET 16
+#define MB_INFO_MMAP_LEN_OFFSET 44
+#define MB_INFO_MMAP_ADDR_OFFSET 48
+#define MB_MMAP_SIZE 480 /* 20 * sizeof(memory_map_t) - up to 20 entries
*/
#define CMDLINE_SIZE 256
/*
@@ -91,6 +95,35 @@ MultibootEntry:
cmp eax, MULTIBOOT_BOOTLOADER_MAGIC
jne mbfail
+ /* Save multiboot info structure */
+ mov esi, ebx
+ mov edi, offset MultibootInfo + INITIAL_BASE - FREELDR_BASE
+ mov ecx, (MB_INFO_SIZE / 4)
+ rep movsd
+ mov dword ptr ds:[MultibootInfo + INITIAL_BASE - FREELDR_BASE +
MB_INFO_MMAP_ADDR_OFFSET], 0
+ mov dword ptr ds:[_MultibootInfoPtr + INITIAL_BASE - FREELDR_BASE], offset
MultibootInfo
+
+ /* See if the memory map was passed in */
+ test dword ptr ds:[ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_MEMORY_MAP
+ jz mbchk_command_line
+ /* Check memory map length */
+ mov ecx, dword ptr ds:[ebx + MB_INFO_MMAP_LEN_OFFSET]
+ test ecx, ecx
+ jz mbchk_command_line
+ cmp ecx, MB_MMAP_SIZE
+ jg mbchk_command_line
+ /* Check memory map address */
+ mov esi, dword ptr ds:[ebx + MB_INFO_MMAP_ADDR_OFFSET]
+ test esi, esi
+ jz mbchk_command_line
+ /* Save memory map structure */
+ mov edi, offset MultibootMemoryMap + INITIAL_BASE - FREELDR_BASE
+ shr ecx, 2
+ rep movsd
+ /* Relocate memory map address */
+ mov dword ptr ds:[MultibootInfo + INITIAL_BASE - FREELDR_BASE +
MB_INFO_MMAP_ADDR_OFFSET], offset MultibootMemoryMap
+
+mbchk_command_line:
/* Save command line */
test dword ptr ds:[ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
jz mb2
@@ -171,6 +204,16 @@ gdtptr:
.word HEX(17) /* Limit */
.long gdt /* Base Address */
+PUBLIC _MultibootInfoPtr
+_MultibootInfoPtr:
+ .long 0
+
+MultibootInfo:
+ .space MB_INFO_SIZE
+
+MultibootMemoryMap:
+ .space MB_MMAP_SIZE
+
PUBLIC cmdline
cmdline:
.space CMDLINE_SIZE
diff --git a/boot/freeldr/freeldr/arch/i386/xboxmem.c
b/boot/freeldr/freeldr/arch/i386/xboxmem.c
index bf7721dc32c..e8ea7b016ea 100644
--- a/boot/freeldr/freeldr/arch/i386/xboxmem.c
+++ b/boot/freeldr/freeldr/arch/i386/xboxmem.c
@@ -26,6 +26,7 @@ DBG_DEFAULT_CHANNEL(MEMORY);
static ULONG InstalledMemoryMb = 0;
static ULONG AvailableMemoryMb = 0;
+extern multiboot_info_t * MultibootInfoPtr;
extern PVOID FrameBuffer;
extern ULONG FrameBufferSize;
@@ -98,30 +99,107 @@ XboxMemInit(VOID)
AvailableMemoryMb = InstalledMemoryMb;
}
+memory_map_t *
+XboxGetMultibootMemoryMap(INT * Count)
+{
+ memory_map_t * MemoryMap;
+
+ if (!MultibootInfoPtr)
+ {
+ ERR("Multiboot info structure not found!\n");
+ return NULL;
+ }
+
+ if (!(MultibootInfoPtr->flags & MB_INFO_FLAG_MEMORY_MAP))
+ {
+ ERR("Multiboot memory map is not passed!\n");
+ return NULL;
+ }
+
+ MemoryMap = (memory_map_t *)MultibootInfoPtr->mmap_addr;
+
+ if (!MemoryMap ||
+ MultibootInfoPtr->mmap_length == 0 ||
+ MultibootInfoPtr->mmap_length % sizeof(memory_map_t) != 0)
+ {
+ ERR("Multiboot memory map structure is malformed!\n");
+ return NULL;
+ }
+
+ *Count = MultibootInfoPtr->mmap_length / sizeof(memory_map_t);
+ return MemoryMap;
+}
+
+TYPE_OF_MEMORY
+XboxMultibootMemoryType(ULONG Type)
+{
+ switch (Type)
+ {
+ case 0: // Video RAM
+ return LoaderFirmwarePermanent;
+ case 1: // Available RAM
+ return LoaderFree;
+ case 3: // ACPI area
+ return LoaderFirmwareTemporary;
+ case 4: // Hibernation area
+ return LoaderSpecialMemory;
+ case 5: // Reserved or invalid memory
+ return LoaderSpecialMemory;
+ default:
+ return LoaderFirmwarePermanent;
+ }
+}
+
FREELDR_MEMORY_DESCRIPTOR XboxMemoryMap[MAX_BIOS_DESCRIPTORS + 1];
PFREELDR_MEMORY_DESCRIPTOR
XboxMemGetMemoryMap(ULONG *MemoryMapSize)
{
+ memory_map_t * MbMap;
+ INT Count, i;
+
TRACE("XboxMemGetMemoryMap()\n");
- /* FIXME: Obtain memory map via multiboot spec */
- /* Synthesize memory map */
+ MbMap = XboxGetMultibootMemoryMap(&Count);
+ if (MbMap)
+ {
+ /* Obtain memory map via multiboot spec */
- /* Available RAM block */
- SetMemory(XboxMemoryMap,
- 0,
- AvailableMemoryMb * 1024 * 1024,
- LoaderFree);
+ for (i = 0; i < Count; i++, MbMap++)
+ {
+ TRACE("i = %d, base_addr_low = 0x%p, length_low = 0x%p\n", i,
MbMap->base_addr_low, MbMap->length_low);
- if (FrameBufferSize != 0)
+ if (MbMap->base_addr_high > 0 || MbMap->length_high > 0)
+ {
+ ERR("Memory descriptor base or size is greater than 4 GB, should not
happen on Xbox!\n");
+ ASSERT(FALSE);
+ }
+
+ SetMemory(XboxMemoryMap,
+ MbMap->base_addr_low,
+ MbMap->length_low,
+ XboxMultibootMemoryType(MbMap->type));
+ }
+ }
+ else
{
- /* Video memory */
- ReserveMemory(XboxMemoryMap,
- (ULONG_PTR)FrameBuffer,
- FrameBufferSize,
- LoaderFirmwarePermanent,
- "Video memory");
+ /* Synthesize memory map */
+
+ /* Available RAM block */
+ SetMemory(XboxMemoryMap,
+ 0,
+ AvailableMemoryMb * 1024 * 1024,
+ LoaderFree);
+
+ if (FrameBufferSize != 0)
+ {
+ /* Video memory */
+ ReserveMemory(XboxMemoryMap,
+ (ULONG_PTR)FrameBuffer,
+ FrameBufferSize,
+ LoaderFirmwarePermanent,
+ "Video memory");
+ }
}
*MemoryMapSize = PcMemFinalizeMemoryMap(XboxMemoryMap);
diff --git a/boot/freeldr/freeldr/arch/i386/xboxvideo.c
b/boot/freeldr/freeldr/arch/i386/xboxvideo.c
index d5839024d43..ffc2144d408 100644
--- a/boot/freeldr/freeldr/arch/i386/xboxvideo.c
+++ b/boot/freeldr/freeldr/arch/i386/xboxvideo.c
@@ -30,6 +30,7 @@ static ULONG ScreenWidth;
static ULONG ScreenHeight;
static ULONG BytesPerPixel;
static ULONG Delta;
+extern multiboot_info_t * MultibootInfoPtr;
#define CHAR_WIDTH 8
#define CHAR_HEIGHT 16
@@ -127,6 +128,46 @@ NvGetCrtc(UCHAR Index)
return *((PUCHAR) NV2A_CRTC_REGISTER_VALUE);
}
+ULONG
+XboxGetFramebufferSize(PVOID Offset)
+{
+ memory_map_t * MemoryMap;
+ INT Count, i;
+
+ if (!MultibootInfoPtr)
+ {
+ return 0;
+ }
+
+ if (!(MultibootInfoPtr->flags & MB_INFO_FLAG_MEMORY_MAP))
+ {
+ return 0;
+ }
+
+ MemoryMap = (memory_map_t *)MultibootInfoPtr->mmap_addr;
+
+ if (!MemoryMap ||
+ MultibootInfoPtr->mmap_length == 0 ||
+ MultibootInfoPtr->mmap_length % sizeof(memory_map_t) != 0)
+ {
+ return 0;
+ }
+
+ Count = MultibootInfoPtr->mmap_length / sizeof(memory_map_t);
+ for (i = 0; i < Count; i++, MemoryMap++)
+ {
+ TRACE("i = %d, base_addr_low = 0x%p, MemoryMap->length_low =
0x%p\n", i, MemoryMap->base_addr_low, MemoryMap->length_low);
+
+ if (MemoryMap->base_addr_low == (ULONG)Offset &&
MemoryMap->base_addr_high == 0)
+ {
+ TRACE("Video memory found\n");
+ return MemoryMap->length_low;
+ }
+ }
+ ERR("Video memory not found!\n");
+ return 0;
+}
+
VOID
XboxVideoInit(VOID)
{
@@ -135,8 +176,13 @@ XboxVideoInit(VOID)
/* Verify that framebuffer address is page-aligned */
ASSERT((ULONG_PTR)FrameBuffer % PAGE_SIZE == 0);
- /* FIXME: obtain fb size from firmware somehow (Cromwell reserves high 4 MB of RAM) */
- FrameBufferSize = 4 * 1024 * 1024;
+ /* Obtain framebuffer memory size from multiboot memory map */
+ if ((FrameBufferSize = XboxGetFramebufferSize(FrameBuffer)) == 0)
+ {
+ /* Fallback to Cromwell standard which reserves high 4 MB of RAM */
+ FrameBufferSize = 4 * 1024 * 1024;
+ WARN("Could not detect framebuffer memory size, fallback to 4 MB\n");
+ }
ScreenWidth = *((PULONG) NV2A_RAMDAC_FP_HVALID_END) + 1;
ScreenHeight = *((PULONG) NV2A_RAMDAC_FP_VVALID_END) + 1;
diff --git a/boot/freeldr/freeldr/include/multiboot.h
b/boot/freeldr/freeldr/include/multiboot.h
index 732e5c89b53..b5627d6db89 100644
--- a/boot/freeldr/freeldr/include/multiboot.h
+++ b/boot/freeldr/freeldr/include/multiboot.h
@@ -90,6 +90,27 @@ typedef struct elf_section_header_table
unsigned long shndx;
} elf_section_header_table_t;
+/* The Multiboot information. */
+typedef struct multiboot_info
+{
+ unsigned long flags;
+ unsigned long mem_lower;
+ unsigned long mem_upper;
+ unsigned long boot_device;
+ unsigned long cmdline;
+ unsigned long mods_count;
+ unsigned long mods_addr;
+ union
+ {
+ aout_symbol_table_t aout_sym;
+ elf_section_header_table_t elf_sec;
+ } u;
+ unsigned long mmap_length;
+ unsigned long mmap_addr;
+ unsigned long drives_length;
+ unsigned long drives_addr;
+} multiboot_info_t;
+
/* The memory map. Be careful that the offset 0 is base_addr_low
but no size. */
typedef struct memory_map