Skip to content

Commit

Permalink
[FREELDR] Obtain Xbox memory map via multiboot spec
Browse files Browse the repository at this point in the history
  • Loading branch information
binarymaster committed Oct 17, 2019
1 parent fb4591c commit 945c8f5
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 16 deletions.
46 changes: 46 additions & 0 deletions boot/freeldr/freeldr/arch/i386/multiboot.S
Original file line number Diff line number Diff line change
Expand Up @@ -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

/*
Expand Down Expand Up @@ -91,6 +95,36 @@ 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
shr ecx, 2
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
Expand Down Expand Up @@ -171,6 +205,18 @@ gdtptr:
.word HEX(17) /* Limit */
.long gdt /* Base Address */

PUBLIC _MultibootInfoPtr
_MultibootInfoPtr:
.long 0

PUBLIC _MultibootInfo
_MultibootInfo:
.space MB_INFO_SIZE, 0

PUBLIC _MultibootMemoryMap
_MultibootMemoryMap:
.space MB_MMAP_SIZE, 0

PUBLIC cmdline
cmdline:
.space CMDLINE_SIZE
Expand Down
106 changes: 92 additions & 14 deletions boot/freeldr/freeldr/arch/i386/xboxmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
50 changes: 48 additions & 2 deletions boot/freeldr/freeldr/arch/i386/xboxvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down
21 changes: 21 additions & 0 deletions boot/freeldr/freeldr/include/multiboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 945c8f5

Please sign in to comment.