Understanding x86 PC memory maps with qemu

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
sunnysideup
Member
Member
Posts: 106
Joined: Sat Feb 08, 2020 11:11 am
Libera.chat IRC: sunnysideup

Understanding x86 PC memory maps with qemu

Post by sunnysideup »

I wanted to understand the system memory layout in x86 PCs by breaking them.
Here is what I did:
* Create the simplest legacy BIOS payload ( jmp $ + 0x55AA at end of sector) called test.bin
* Run it on qemu. `qemu-system-x86_64 -m 4G test.bin`
* View the system memory tree by running `info mtree` in the qemu monitor

Here is the memory tree that I get:

Code: Select all

memory-region: system
  0000000000000000-ffffffffffffffff (prio 0, i/o): system
    0000000000000000-00000000bfffffff (prio 0, ram): alias ram-below-4g @pc.ram 0000000000000000-00000000bfffffff
    0000000000000000-ffffffffffffffff (prio -1, i/o): pci
      00000000000a0000-00000000000bffff (prio 1, i/o): vga-lowmem
      00000000000c0000-00000000000dffff (prio 1, rom): pc.rom
      00000000000e0000-00000000000fffff (prio 1, rom): alias isa-bios @pc.bios 0000000000020000-000000000003ffff
      00000000fd000000-00000000fdffffff (prio 1, ram): vga.vram
      00000000febc0000-00000000febdffff (prio 1, i/o): e1000-mmio
      00000000febf0000-00000000febf0fff (prio 1, i/o): vga.mmio
        00000000febf0000-00000000febf017f (prio 0, i/o): edid
        00000000febf0400-00000000febf041f (prio 0, i/o): vga ioports remapped
        00000000febf0500-00000000febf0515 (prio 0, i/o): bochs dispi interface
        00000000febf0600-00000000febf0607 (prio 0, i/o): qemu extended regs
      00000000fffc0000-00000000ffffffff (prio 0, rom): pc.bios
    00000000000a0000-00000000000bffff (prio 1, i/o): alias smram-region @pci 00000000000a0000-00000000000bffff
    00000000000c0000-00000000000c3fff (prio 1, ram): alias pam-rom @pc.ram 00000000000c0000-00000000000c3fff
    00000000000c4000-00000000000c7fff (prio 1, ram): alias pam-rom @pc.ram 00000000000c4000-00000000000c7fff
    00000000000c8000-00000000000cbfff (prio 1, ram): alias pam-rom @pc.ram 00000000000c8000-00000000000cbfff
    00000000000cb000-00000000000cdfff (prio 1000, ram): alias kvmvapic-rom @pc.ram 00000000000cb000-00000000000cdfff
    00000000000cc000-00000000000cffff (prio 1, ram): alias pam-rom @pc.ram 00000000000cc000-00000000000cffff
    00000000000d0000-00000000000d3fff (prio 1, ram): alias pam-rom @pc.ram 00000000000d0000-00000000000d3fff
    00000000000d4000-00000000000d7fff (prio 1, ram): alias pam-rom @pc.ram 00000000000d4000-00000000000d7fff
    00000000000d8000-00000000000dbfff (prio 1, ram): alias pam-rom @pc.ram 00000000000d8000-00000000000dbfff
    00000000000dc000-00000000000dffff (prio 1, ram): alias pam-rom @pc.ram 00000000000dc000-00000000000dffff
    00000000000e0000-00000000000e3fff (prio 1, ram): alias pam-rom @pc.ram 00000000000e0000-00000000000e3fff
    00000000000e4000-00000000000e7fff (prio 1, ram): alias pam-rom @pc.ram 00000000000e4000-00000000000e7fff
    00000000000e8000-00000000000ebfff (prio 1, ram): alias pam-ram @pc.ram 00000000000e8000-00000000000ebfff
    00000000000ec000-00000000000effff (prio 1, ram): alias pam-ram @pc.ram 00000000000ec000-00000000000effff
    00000000000f0000-00000000000fffff (prio 1, ram): alias pam-rom @pc.ram 00000000000f0000-00000000000fffff
    00000000fec00000-00000000fec00fff (prio 0, i/o): ioapic
    00000000fed00000-00000000fed003ff (prio 0, i/o): hpet
    00000000fee00000-00000000feefffff (prio 4096, i/o): apic-msi
    0000000100000000-000000023fffffff (prio 0, ram): alias ram-above-4g @pc.ram 00000000c0000000-00000001ffffffff
I have a couple of questions:

* Writes to memory address 0xb8000 will print to the screen. However, in qemu, this region is aliased as 'smram-region' (after resolving qemu's priorities). Why is this?
* It looks like 3GB of DRAM is mapped below 4GB in the system memory region, with the 4th GB of DRAM occupies addresses 4GB - 5GB in the system memory. Even in the 3GB mapped DRAM region (within 4GB system memory), it looks like there are 'holes' (E.g. 0xA0000 - 0xBFFFF). That is, you are never 100% utilizing the DRAM you buy. Is this true?
* info mtree also gives me things called address-spaces. For instance, the contents of address-space:memory is the same as memory-region:system. What is the distinction between address-spaces and memory-regions?
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: Understanding x86 PC memory maps with qemu

Post by thewrongchristian »

sunnysideup wrote:I wanted to understand the system memory layout in x86 PCs by breaking them.

I have a couple of questions:

* Writes to memory address 0xb8000 will print to the screen. However, in qemu, this region is aliased as 'smram-region' (after resolving qemu's priorities). Why is this?
* It looks like 3GB of DRAM is mapped below 4GB in the system memory region, with the 4th GB of DRAM occupies addresses 4GB - 5GB in the system memory. Even in the 3GB mapped DRAM region (within 4GB system memory), it looks like there are 'holes' (E.g. 0xA0000 - 0xBFFFF). That is, you are never 100% utilizing the DRAM you buy. Is this true?
* info mtree also gives me things called address-spaces. For instance, the contents of address-space:memory is the same as memory-region:system. What is the distinction between address-spaces and memory-regions?
- "smram-region" is memory reserved for System Management Mode. In RAM, its memory reserved to save state when entering SMM mode, so the firmware can do its thing behind the back of the OS. Not sure what this means in the context of 0xb8000 though, perhaps QEMU's SMM mode uses it to emulate the text mode, rendering characters to the framebuffer as they're written to the text mode memory. It's also marked as i/o memory in my QEMU v6.

Code: Select all

    00000000000a0000-00000000000bffff (prio 1, i/o): alias smram-region @pci 00000000000a0000-00000000000bffff
- Yes, it's true that you will lose memory access in some holes. It may not be entirely wasted, the BIOS might configure the chipset to shadow ROM in the address space between 640K-1024K, as RAM is generally quicker to access than ROM, but on the grand scheme of things these days, the amount of RAM "wasted" by the holes is trivial.

- The address spaces are just different views of address space, I suppose like the difference between virtual address space and physical address space. It just so happens on the x86, the address spaces match up, so address 0 as seen by the chipset (which I think is the system space in this context) will be the same address 0 as seen the CPU, and the same address 0 as seen by the PCI bus. But not all platforms are like this. The Raspberry Pi SoC, for example, the CPU address 0 corresponds to the VideoCore address 0x40000000, so the CPU and VC have a different view on the address space.
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Understanding x86 PC memory maps with qemu

Post by nexos »

That is, you are never 100% utilizing the DRAM you buy. Is this true?
Yep, look here:
Image
Installed physical memory is 8GB, but 0.12GB of that is covered by the hardware.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Understanding x86 PC memory maps with qemu

Post by Octocontrabass »

sunnysideup wrote:* Writes to memory address 0xb8000 will print to the screen. However, in qemu, this region is aliased as 'smram-region' (after resolving qemu's priorities). Why is this?
The chipset maps both of those things to the same physical addresses, but not at the same time. When the CPU is running SMM code, RAM is accessible. When the CPU is running any other code, the VGA MMIO region is accessible.
sunnysideup wrote:* It looks like 3GB of DRAM is mapped below 4GB in the system memory region, with the 4th GB of DRAM occupies addresses 4GB - 5GB in the system memory. Even in the 3GB mapped DRAM region (within 4GB system memory), it looks like there are 'holes' (E.g. 0xA0000 - 0xBFFFF). That is, you are never 100% utilizing the DRAM you buy. Is this true?
Those "holes" are not necessarily unused: RAM that would map to 0xA0000-0xBFFFF is usually reserved for SMM, and RAM that would map to 0xC0000-0xFFFFF is usually reserved for ROM shadowing. (I've seen a 386 chipset that makes the reserved RAM available to the OS when it would otherwise be unused, but 384kiB is a significant portion of the total RAM on a 386.) Chipsets may also reserve other portions of RAM for things like integrated graphics or SGX enclaves.
Post Reply