mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[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-information-format CORE-16216 CORE-16300
This commit is contained in:
parent
7523a7b138
commit
96692636e4
4 changed files with 206 additions and 18 deletions
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/* Available RAM block */
|
||||
SetMemory(XboxMemoryMap,
|
||||
0,
|
||||
AvailableMemoryMb * 1024 * 1024,
|
||||
LoaderFree);
|
||||
|
||||
if (FrameBufferSize != 0)
|
||||
MbMap = XboxGetMultibootMemoryMap(&Count);
|
||||
if (MbMap)
|
||||
{
|
||||
/* Video memory */
|
||||
ReserveMemory(XboxMemoryMap,
|
||||
(ULONG_PTR)FrameBuffer,
|
||||
FrameBufferSize,
|
||||
LoaderFirmwarePermanent,
|
||||
"Video memory");
|
||||
/* Obtain memory map via multiboot spec */
|
||||
|
||||
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 (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
|
||||
{
|
||||
/* 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue