diff options
author | Michael Brown | 2016-02-19 04:18:11 +0100 |
---|---|---|
committer | Michael Brown | 2016-02-19 04:21:38 +0100 |
commit | 163f8acba0fbb6e3c44aec5286d3d076e1f44f22 (patch) | |
tree | 324861e35a5c0748b4cb5e597b92a04a37d08558 /src/arch | |
parent | [librm] Prepare for long-mode memory map (diff) | |
download | ipxe-163f8acba0fbb6e3c44aec5286d3d076e1f44f22.tar.gz ipxe-163f8acba0fbb6e3c44aec5286d3d076e1f44f22.tar.xz ipxe-163f8acba0fbb6e3c44aec5286d3d076e1f44f22.zip |
[librm] Generate page tables for 64-bit builds
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/x86/scripts/pcbios.lds | 12 | ||||
-rw-r--r-- | src/arch/x86/transitions/librm.S | 183 | ||||
-rw-r--r-- | src/arch/x86_64/Makefile.pcbios | 4 |
3 files changed, 197 insertions, 2 deletions
diff --git a/src/arch/x86/scripts/pcbios.lds b/src/arch/x86/scripts/pcbios.lds index 865591ae..dccdfbed 100644 --- a/src/arch/x86/scripts/pcbios.lds +++ b/src/arch/x86/scripts/pcbios.lds @@ -27,6 +27,12 @@ SECTIONS { PROVIDE ( _max_align = 16 ); /* + * Default to not generating space for page tables + * + */ + PROVIDE ( _use_page_tables = 0 ); + + /* * Allow decompressor to require a minimum amount of temporary stack * space. * @@ -127,6 +133,12 @@ SECTIONS { *(COMMON) *(.stack) *(.stack.*) + *(.pages) + *(.pages.*) + _textdata_paged_len = ABSOLUTE ( . - _textdata ); + _textdata_ptes = ABSOLUTE ( ( _textdata_paged_len + 4095 ) / 4096 ); + _textdata_pdes = ABSOLUTE ( ( _textdata_ptes + 511 ) / 512 ); + . += ( _use_page_tables ? ( _textdata_pdes * 4096 ) : 0 ); _etextdata = .; } _textdata_filesz = ABSOLUTE ( _mtextdata ) - ABSOLUTE ( _textdata ); diff --git a/src/arch/x86/transitions/librm.S b/src/arch/x86/transitions/librm.S index 495f272d..f3854dfe 100644 --- a/src/arch/x86/transitions/librm.S +++ b/src/arch/x86/transitions/librm.S @@ -10,8 +10,38 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) /* Drag in local definitions */ #include "librm.h" -/* For switches to/from protected mode */ -#define CR0_PE 1 +/* CR0: protection enabled */ +#define CR0_PE ( 1 << 0 ) + +/* CR0: paging */ +#define CR0_PG ( 1 << 31 ) + +/* CR4: physical address extensions */ +#define CR4_PAE ( 1 << 5 ) + +/* Page: present */ +#define PG_P 0x01 + +/* Page: read/write */ +#define PG_RW 0x02 + +/* Page: user/supervisor */ +#define PG_US 0x04 + +/* Page: page size */ +#define PG_PS 0x80 + +/* Size of various paging-related data structures */ +#define SIZEOF_PTE_LOG2 3 +#define SIZEOF_PTE ( 1 << SIZEOF_PTE_LOG2 ) +#define SIZEOF_PT_LOG2 12 +#define SIZEOF_PT ( 1 << SIZEOF_PT_LOG2 ) +#define SIZEOF_4KB_PAGE_LOG2 12 +#define SIZEOF_4KB_PAGE ( 1 << SIZEOF_4KB_PAGE_LOG2 ) +#define SIZEOF_2MB_PAGE_LOG2 21 +#define SIZEOF_2MB_PAGE ( 1 << SIZEOF_2MB_PAGE_LOG2 ) +#define SIZEOF_LOW_4GB_LOG2 32 +#define SIZEOF_LOW_4GB ( 1 << SIZEOF_LOW_4GB_LOG2 ) /* Size of various C data structures */ #define SIZEOF_I386_SEG_REGS 12 @@ -226,6 +256,10 @@ init_librm: .if32 ; subl %edi, %eax ; .endif movl %eax, rm_data16 +.if64 ; /* Reset page tables, if applicable */ + xorl %eax, %eax + movl %eax, pml4 +.endif /* Switch to protected mode */ virtcall init_librm_pmode .section ".text.init_librm", "ax", @progbits @@ -242,6 +276,10 @@ init_librm_pmode: rep movsl popw %ds +.if64 ; /* Initialise page tables, if applicable */ + movl VIRTUAL(virt_offset), %edi + call init_pages +.endif /* Return to real mode */ ret .section ".text16.init_librm", "ax", @progbits @@ -714,3 +752,144 @@ interrupt_wrapper: /* Restore registers and return */ popal iret + +/**************************************************************************** + * Page tables + * + **************************************************************************** + */ + .section ".pages", "aw", @nobits + .align SIZEOF_PT + + /* Page map level 4 entries (PML4Es) + * + * This comprises + * + * - PML4E[0x000] covering [0x0000000000000000-0x0000007fffffffff] + * - PML4E[0x1ff] covering [0xffffff8000000000-0xffffffffffffffff] + * + * These point to the PDPT. This creates some aliased + * addresses within unused portions of the 64-bit address + * space, but allows us to use just a single PDPT. + */ +pml4e: + .space SIZEOF_PT + .size pml4e, . - pml4e + + /* Page directory pointer table entries (PDPTEs) + * + * This comprises: + * + * - PDPTE[0x000] covering [0x0000000000000000-0x000000003fffffff] + * - PDPTE[0x001] covering [0x0000000040000000-0x000000007fffffff] + * - PDPTE[0x002] covering [0x0000000080000000-0x00000000bfffffff] + * - PDPTE[0x003] covering [0x00000000c0000000-0x00000000ffffffff] + * + * These point to the appropriate page directories (in pde_low) + * used to identity-map the whole of the 32-bit address space. + * + * - PDPTE[0x1ff] covering [0xffffffffc0000000-0xffffffffffffffff] + * + * This points back to the PDPT itself, allowing the PDPT to be + * (ab)used to hold PDEs covering .textdata. + * + * - PDE[N-M] covering [_textdata,_end) + * + * These are used to point to the page tables (in pte_textdata) + * used to map our .textdata section. Note that each PDE + * covers 2MB, so we are likely to use only a single PDE in + * practice. + */ +pdpte: + .space SIZEOF_PT + .size pdpte, . - pdpte + .equ pde_textdata, pdpte /* (ab)use */ + + /* Page directory entries (PDEs) for the low 4GB + * + * This comprises 2048 2MB pages to identity-map the whole of + * the 32-bit address space. + */ +pde_low: + .equ PDE_LOW_PTES, ( SIZEOF_LOW_4GB / SIZEOF_2MB_PAGE ) + .equ PDE_LOW_PTS, ( ( PDE_LOW_PTES * SIZEOF_PTE ) / SIZEOF_PT ) + .space ( PDE_LOW_PTS * SIZEOF_PT ) + .size pde_low, . - pde_low + + /* Page table entries (PTEs) for .textdata + * + * This comprises enough 4kB pages to map the whole of + * .textdata. The required number of PTEs is calculated by + * the linker script. + * + * Note that these mappings do not cover the PTEs themselves. + * This does not matter, since code running with paging + * enabled never needs to access these PTEs. + */ +pte_textdata: + /* Allocated by linker script; must be at the end of .textdata */ + + .section ".bss16.pml4", "aw", @nobits +pml4: .long 0 + +/**************************************************************************** + * init_pages (protected-mode near call) + * + * Initialise the page tables ready for long mode. + * + * Parameters: + * %edi : virt_offset + **************************************************************************** + */ + .section ".text.init_pages", "ax", @progbits + .code32 +init_pages: + /* Initialise PML4Es for low 4GB and negative 2GB */ + leal ( VIRTUAL(pdpte) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax + movl %eax, VIRTUAL(pml4e) + movl %eax, ( VIRTUAL(pml4e) + SIZEOF_PT - SIZEOF_PTE ) + + /* Initialise PDPTE for negative 1GB */ + movl %eax, ( VIRTUAL(pdpte) + SIZEOF_PT - SIZEOF_PTE ) + + /* Initialise PDPTEs for low 4GB */ + movl $PDE_LOW_PTS, %ecx + leal ( VIRTUAL(pde_low) + ( PDE_LOW_PTS * SIZEOF_PT ) + \ + ( PG_P | PG_RW | PG_US ) )(%edi), %eax +1: subl $SIZEOF_PT, %eax + movl %eax, ( VIRTUAL(pdpte) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE) + loop 1b + + /* Initialise PDEs for low 4GB */ + movl $PDE_LOW_PTES, %ecx + leal ( 0 + ( PG_P | PG_RW | PG_US | PG_PS ) ), %eax +1: subl $SIZEOF_2MB_PAGE, %eax + movl %eax, ( VIRTUAL(pde_low) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE) + loop 1b + + /* Initialise PDEs for .textdata */ + movl $_textdata_pdes, %ecx + leal ( VIRTUAL(_etextdata) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax + movl $VIRTUAL(_textdata), %ebx + shrl $( SIZEOF_2MB_PAGE_LOG2 - SIZEOF_PTE_LOG2 ), %ebx + andl $( SIZEOF_PT - 1 ), %ebx +1: subl $SIZEOF_PT, %eax + movl %eax, (VIRTUAL(pde_textdata) - SIZEOF_PTE)(%ebx,%ecx,SIZEOF_PTE) + loop 1b + + /* Initialise PTEs for .textdata */ + movl $_textdata_ptes, %ecx + leal ( VIRTUAL(_textdata) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax + addl $_textdata_paged_len, %eax +1: subl $SIZEOF_4KB_PAGE, %eax + movl %eax, ( VIRTUAL(pte_textdata) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE) + loop 1b + + /* Record PML4 physical address */ + leal VIRTUAL(pml4e)(%edi), %eax + movl VIRTUAL(data16), %ebx + subl %edi, %ebx + movl %eax, pml4(%ebx) + + /* Return */ + ret diff --git a/src/arch/x86_64/Makefile.pcbios b/src/arch/x86_64/Makefile.pcbios index ba4c8d8d..54bc0e48 100644 --- a/src/arch/x86_64/Makefile.pcbios +++ b/src/arch/x86_64/Makefile.pcbios @@ -9,6 +9,10 @@ LDFLAGS += --section-start=.textdata=0xffffffffeb000000 # CFLAGS += -mno-red-zone +# Generate extra space for page tables to cover .textdata +# +LDFLAGS += --defsym=_use_page_tables=1 + # Include generic BIOS Makefile # MAKEDEPS += arch/x86/Makefile.pcbios |