Browse Source

[librm] Generate page tables for 64-bit builds

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
163f8acba0
3 changed files with 197 additions and 2 deletions
  1. 12
    0
      src/arch/x86/scripts/pcbios.lds
  2. 181
    2
      src/arch/x86/transitions/librm.S
  3. 4
    0
      src/arch/x86_64/Makefile.pcbios

+ 12
- 0
src/arch/x86/scripts/pcbios.lds View File

@@ -26,6 +26,12 @@ SECTIONS {
26 26
 
27 27
     PROVIDE ( _max_align = 16 );
28 28
 
29
+    /*
30
+     * Default to not generating space for page tables
31
+     *
32
+     */
33
+    PROVIDE ( _use_page_tables = 0 );
34
+
29 35
     /*
30 36
      * Allow decompressor to require a minimum amount of temporary stack
31 37
      * space.
@@ -127,6 +133,12 @@ SECTIONS {
127 133
 	*(COMMON)
128 134
 	*(.stack)
129 135
 	*(.stack.*)
136
+	*(.pages)
137
+	*(.pages.*)
138
+	_textdata_paged_len = ABSOLUTE ( . - _textdata );
139
+	_textdata_ptes = ABSOLUTE ( ( _textdata_paged_len + 4095 ) / 4096 );
140
+	_textdata_pdes = ABSOLUTE ( ( _textdata_ptes + 511 ) / 512 );
141
+	. += ( _use_page_tables ? ( _textdata_pdes * 4096 ) : 0 );
130 142
 	_etextdata = .;
131 143
     }
132 144
     _textdata_filesz	= ABSOLUTE ( _mtextdata ) - ABSOLUTE ( _textdata );

+ 181
- 2
src/arch/x86/transitions/librm.S View File

@@ -10,8 +10,38 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
10 10
 /* Drag in local definitions */
11 11
 #include "librm.h"
12 12
 
13
-/* For switches to/from protected mode */
14
-#define CR0_PE 1
13
+/* CR0: protection enabled */
14
+#define CR0_PE ( 1 << 0 )
15
+
16
+/* CR0: paging */
17
+#define CR0_PG ( 1 << 31 )
18
+
19
+/* CR4: physical address extensions */
20
+#define CR4_PAE ( 1 << 5 )
21
+
22
+/* Page: present */
23
+#define PG_P 0x01
24
+
25
+/* Page: read/write */
26
+#define PG_RW 0x02
27
+
28
+/* Page: user/supervisor */
29
+#define PG_US 0x04
30
+
31
+/* Page: page size */
32
+#define PG_PS 0x80
33
+
34
+/* Size of various paging-related data structures */
35
+#define SIZEOF_PTE_LOG2 3
36
+#define SIZEOF_PTE ( 1 << SIZEOF_PTE_LOG2 )
37
+#define SIZEOF_PT_LOG2 12
38
+#define SIZEOF_PT ( 1 << SIZEOF_PT_LOG2 )
39
+#define SIZEOF_4KB_PAGE_LOG2 12
40
+#define SIZEOF_4KB_PAGE ( 1 << SIZEOF_4KB_PAGE_LOG2 )
41
+#define SIZEOF_2MB_PAGE_LOG2 21
42
+#define SIZEOF_2MB_PAGE ( 1 << SIZEOF_2MB_PAGE_LOG2 )
43
+#define SIZEOF_LOW_4GB_LOG2 32
44
+#define SIZEOF_LOW_4GB ( 1 << SIZEOF_LOW_4GB_LOG2 )
15 45
 
16 46
 /* Size of various C data structures */
17 47
 #define SIZEOF_I386_SEG_REGS	12
@@ -226,6 +256,10 @@ init_librm:
226 256
 .if32 ;	subl	%edi, %eax ; .endif
227 257
 	movl	%eax, rm_data16
228 258
 
259
+.if64 ;	/* Reset page tables, if applicable */
260
+	xorl	%eax, %eax
261
+	movl	%eax, pml4
262
+.endif
229 263
 	/* Switch to protected mode */
230 264
 	virtcall init_librm_pmode
231 265
 	.section ".text.init_librm", "ax", @progbits
@@ -242,6 +276,10 @@ init_librm_pmode:
242 276
 	rep movsl
243 277
 	popw	%ds
244 278
 
279
+.if64 ;	/* Initialise page tables, if applicable */
280
+	movl	VIRTUAL(virt_offset), %edi
281
+	call	init_pages
282
+.endif
245 283
 	/* Return to real mode */
246 284
 	ret
247 285
 	.section ".text16.init_librm", "ax", @progbits
@@ -714,3 +752,144 @@ interrupt_wrapper:
714 752
 	/* Restore registers and return */
715 753
 	popal
716 754
 	iret
755
+
756
+/****************************************************************************
757
+ * Page tables
758
+ *
759
+ ****************************************************************************
760
+ */
761
+	.section ".pages", "aw", @nobits
762
+	.align	SIZEOF_PT
763
+
764
+	/* Page map level 4 entries (PML4Es)
765
+	 *
766
+	 * This comprises
767
+	 *
768
+	 * - PML4E[0x000] covering [0x0000000000000000-0x0000007fffffffff]
769
+	 * - PML4E[0x1ff] covering [0xffffff8000000000-0xffffffffffffffff]
770
+	 *
771
+	 * These point to the PDPT.  This creates some aliased
772
+	 * addresses within unused portions of the 64-bit address
773
+	 * space, but allows us to use just a single PDPT.
774
+	 */
775
+pml4e:
776
+	.space	SIZEOF_PT
777
+	.size	pml4e, . - pml4e
778
+
779
+	/* Page directory pointer table entries (PDPTEs)
780
+	 *
781
+	 * This comprises:
782
+	 *
783
+	 * - PDPTE[0x000] covering [0x0000000000000000-0x000000003fffffff]
784
+	 * - PDPTE[0x001] covering [0x0000000040000000-0x000000007fffffff]
785
+	 * - PDPTE[0x002] covering [0x0000000080000000-0x00000000bfffffff]
786
+	 * - PDPTE[0x003] covering [0x00000000c0000000-0x00000000ffffffff]
787
+	 *
788
+	 * These point to the appropriate page directories (in pde_low)
789
+	 * used to identity-map the whole of the 32-bit address space.
790
+	 *
791
+	 * - PDPTE[0x1ff] covering [0xffffffffc0000000-0xffffffffffffffff]
792
+	 *
793
+	 * This points back to the PDPT itself, allowing the PDPT to be
794
+	 * (ab)used to hold PDEs covering .textdata.
795
+	 *
796
+	 * - PDE[N-M] covering [_textdata,_end)
797
+	 *
798
+	 * These are used to point to the page tables (in pte_textdata)
799
+	 * used to map our .textdata section.  Note that each PDE
800
+	 * covers 2MB, so we are likely to use only a single PDE in
801
+	 * practice.
802
+	 */
803
+pdpte:
804
+	.space	SIZEOF_PT
805
+	.size	pdpte, . - pdpte
806
+	.equ	pde_textdata, pdpte /* (ab)use */
807
+
808
+	/* Page directory entries (PDEs) for the low 4GB
809
+	 *
810
+	 * This comprises 2048 2MB pages to identity-map the whole of
811
+	 * the 32-bit address space.
812
+	 */
813
+pde_low:
814
+	.equ	PDE_LOW_PTES, ( SIZEOF_LOW_4GB / SIZEOF_2MB_PAGE )
815
+	.equ	PDE_LOW_PTS, ( ( PDE_LOW_PTES * SIZEOF_PTE ) / SIZEOF_PT )
816
+	.space	( PDE_LOW_PTS * SIZEOF_PT )
817
+	.size	pde_low, . - pde_low
818
+
819
+	/* Page table entries (PTEs) for .textdata
820
+	 *
821
+	 * This comprises enough 4kB pages to map the whole of
822
+	 * .textdata.  The required number of PTEs is calculated by
823
+	 * the linker script.
824
+	 *
825
+	 * Note that these mappings do not cover the PTEs themselves.
826
+	 * This does not matter, since code running with paging
827
+	 * enabled never needs to access these PTEs.
828
+	 */
829
+pte_textdata:
830
+	/* Allocated by linker script; must be at the end of .textdata */
831
+
832
+	.section ".bss16.pml4", "aw", @nobits
833
+pml4:	.long	0
834
+
835
+/****************************************************************************
836
+ * init_pages (protected-mode near call)
837
+ *
838
+ * Initialise the page tables ready for long mode.
839
+ *
840
+ * Parameters:
841
+ *   %edi : virt_offset
842
+ ****************************************************************************
843
+ */
844
+	.section ".text.init_pages", "ax", @progbits
845
+	.code32
846
+init_pages:
847
+	/* Initialise PML4Es for low 4GB and negative 2GB */
848
+	leal	( VIRTUAL(pdpte) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax
849
+	movl	%eax, VIRTUAL(pml4e)
850
+	movl	%eax, ( VIRTUAL(pml4e) + SIZEOF_PT - SIZEOF_PTE )
851
+
852
+	/* Initialise PDPTE for negative 1GB */
853
+	movl	%eax, ( VIRTUAL(pdpte) + SIZEOF_PT - SIZEOF_PTE )
854
+
855
+	/* Initialise PDPTEs for low 4GB */
856
+	movl	$PDE_LOW_PTS, %ecx
857
+	leal	( VIRTUAL(pde_low) + ( PDE_LOW_PTS * SIZEOF_PT ) + \
858
+		  ( PG_P | PG_RW | PG_US ) )(%edi), %eax
859
+1:	subl	$SIZEOF_PT, %eax
860
+	movl	%eax, ( VIRTUAL(pdpte) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE)
861
+	loop	1b
862
+
863
+	/* Initialise PDEs for low 4GB */
864
+	movl	$PDE_LOW_PTES, %ecx
865
+	leal	( 0 + ( PG_P | PG_RW | PG_US | PG_PS ) ), %eax
866
+1:	subl	$SIZEOF_2MB_PAGE, %eax
867
+	movl	%eax, ( VIRTUAL(pde_low) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE)
868
+	loop	1b
869
+
870
+	/* Initialise PDEs for .textdata */
871
+	movl	$_textdata_pdes, %ecx
872
+	leal	( VIRTUAL(_etextdata) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax
873
+	movl	$VIRTUAL(_textdata), %ebx
874
+	shrl	$( SIZEOF_2MB_PAGE_LOG2 - SIZEOF_PTE_LOG2 ), %ebx
875
+	andl	$( SIZEOF_PT - 1 ), %ebx
876
+1:	subl	$SIZEOF_PT, %eax
877
+	movl	%eax, (VIRTUAL(pde_textdata) - SIZEOF_PTE)(%ebx,%ecx,SIZEOF_PTE)
878
+	loop	1b
879
+
880
+	/* Initialise PTEs for .textdata */
881
+	movl	$_textdata_ptes, %ecx
882
+	leal	( VIRTUAL(_textdata) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax
883
+	addl	$_textdata_paged_len, %eax
884
+1:	subl	$SIZEOF_4KB_PAGE, %eax
885
+	movl	%eax, ( VIRTUAL(pte_textdata) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE)
886
+	loop	1b
887
+
888
+	/* Record PML4 physical address */
889
+	leal	VIRTUAL(pml4e)(%edi), %eax
890
+	movl	VIRTUAL(data16), %ebx
891
+	subl	%edi, %ebx
892
+	movl	%eax, pml4(%ebx)
893
+
894
+	/* Return */
895
+	ret

+ 4
- 0
src/arch/x86_64/Makefile.pcbios View File

@@ -9,6 +9,10 @@ LDFLAGS		+= --section-start=.textdata=0xffffffffeb000000
9 9
 #
10 10
 CFLAGS		+= -mno-red-zone
11 11
 
12
+# Generate extra space for page tables to cover .textdata
13
+#
14
+LDFLAGS		+= --defsym=_use_page_tables=1
15
+
12 16
 # Include generic BIOS Makefile
13 17
 #
14 18
 MAKEDEPS	+= arch/x86/Makefile.pcbios

Loading…
Cancel
Save