In Linux running on an x86 platform where is the real mode address space mapped to in protected kernel mode? In kernel mode, a thread can access the kernel address space directly. The kernel is in the lower 8MB, The page table is at a certain position, etc (as describe here). But where does the real mode address space go? Can it be accessed directly? For example the BIOS and BIOS addons (See here)?
相关问题
- Is shmid returned by shmget() unique across proces
- how to get running process information in java?
- Kernel oops Oops: 80000005 on arm embedded system
- Error building gcc 4.8.3 from source: libstdc++.so
- Why should we check WIFEXITED after wait in order
For Linux x86 32 bits, the first
896MB
of physical RAM is mapped to a contiguous block of virtual memory starting at virtual address0xC0000000
to0xF7FFFFFF
. Virtual addresses from0xF8000000
to0xFFFFFFFF
are assigned dynamically to various parts of the physical memory, so the kernel can have a window of128MB
mapped into any part of physical memory beyond the896MB
limit.The kernel itself loads at physical address 1MB and up, leaving the first MB free. This first MB is used, for instance, to have DMA buffers that ISA devices needs to be there, because they use the 8237 DMA controller, which can only be mapped to such addresses.
So, reading from virtual memory address
0xC0000000
is actually reading from physical address0x00000000
(provided the kernel has flagged that page as present)(My x86-fu is a bit weak. I'll add some tags so that other people can (hopefully) correct me if I'm lying anywhere.)
Physical addresses are the same in real and protected mode. The only difference is in how you get from an address (offset) specified in an instruction to a physical address:
In real mode, the physical address is basically
(segment_reg << 4) + offset
.In protected mode, the physical address is
translate_via_page_table([segment_reg] + offset)
.By
[segment_reg]
I mean the base address of the segment, looked up in the Global or Local Descriptor Table at the offset insegment_reg
.translate_via_page_table()
means the address translation done via paging (if enabled).Looking here, it seems the BIOS ROM appears at physical addresses 0x000F0000-0x000FFFFF. To get at that memory in protected mode with paging, you would have to map it into the virtual address space somewhere by setting up correct page table entries. Assuming 4 KB pages (the usual case), mapping the entire range should require 16 ((0xFFFFF-0xF0000+1)/4096) entries.
To see how the Linux kernel does things, you could look into how e.g.
/dev/mem
, which allows reading of arbitrary physical addresses, is implemented. The implementation is in drivers/char/mem.c.The following command (from e.g. this answer) will dump the memory range 0xC0000-0xFFFFF (meaning it includes the video BIOS too, per the memory map linked above):
1024*768 = 0xC0000, and 1024*(768+256) - 1 = 0xFFFFF, which gives the expected physical memory range.
Tracing things a bit,
read_mem()
in drivers/char/mem.c callsxlate_dev_mem_ptr()
, which has an x86-specific implementation in arch/x86/mm/ioremap.c. Theioremap_cache()
call in that function seems to be responsible for mapping in the page if needed.Note that BIOS routines won't work in protected mode by the way. They assume the CPU is running in real mode.