]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - wimboot/wimboot-2.7.3/src/paging.c
2 * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35 /** Virtual address used as a 2MB window during relocation */
36 #define COPY_WINDOW 0x200000
38 /** Paging is available */
41 /** Page directory pointer table */
42 static uint64_t pdpt
[4] __attribute__ (( aligned ( PAGE_SIZE
) ));
44 /** Page directories */
45 static uint64_t pd
[2048] __attribute__ (( aligned ( PAGE_SIZE
) ));
48 * Check that paging can be supported
50 * @ret supported Paging can be supported on this CPU
52 static int paging_supported ( void ) {
58 /* Get CPU features */
60 : "=a" ( eax
), "=b" ( ebx
), "=c" ( ecx
), "=d" ( edx
)
61 : "0" ( CPUID_FEATURES
) );
63 return ( edx
& CPUID_FEATURE_EDX_PAE
);
67 * Map 2MB page directory entry containing address
69 * @v vaddr Virtual address
70 * @v paddr Physical address
72 static void map_page ( uint32_t vaddr
, uint64_t paddr
) {
73 char *byte
= ( ( char * ) ( intptr_t ) vaddr
);
77 assert ( ( vaddr
& ( PAGE_SIZE_2MB
- 1 ) ) == 0 );
78 assert ( ( paddr
& ( PAGE_SIZE_2MB
- 1 ) ) == 0 );
80 /* Populate page directory entry */
81 index
= ( vaddr
/ PAGE_SIZE_2MB
);
82 pd
[index
] = ( paddr
| PG_P
| PG_RW
| PG_US
| PG_PS
);
85 __asm__
__volatile__ ( "invlpg %0" : : "m" ( *byte
) );
92 void init_paging ( void ) {
96 /* Do nothing if paging is disabled */
97 if ( cmdline_linear
) {
98 DBG ( "Paging disabled\n" );
103 if ( ! paging_supported() ) {
104 DBG ( "Paging not possible on this CPU\n" );
108 /* Initialise page directory entries */
111 map_page ( addr
, addr
);
112 addr
+= PAGE_SIZE_2MB
;
115 /* Initialise page directory pointer table */
116 for ( i
= 0 ; i
< ( sizeof ( pdpt
) / sizeof ( pdpt
[0] ) ) ; i
++ ) {
117 addr
= ( ( intptr_t ) &pd
[ i
* PAGE_SIZE
/ sizeof ( pd
[0] ) ] );
118 pdpt
[i
] = ( addr
| PG_P
);
121 /* Mark paging as available */
128 * @v state Saved paging state to fill in
130 void enable_paging ( struct paging_state
*state
) {
135 /* Do nothing if paging is unavailable */
139 /* Save paging state */
140 __asm__
__volatile__ ( "mov %%cr0, %0\n\t"
143 : "=r" ( cr0
), "=r" ( cr3
), "=r" ( cr4
) );
148 /* Disable any existing paging */
149 __asm__
__volatile__ ( "mov %0, %%cr0" : : "r" ( cr0
& ~CR0_PG
) );
152 __asm__
__volatile__ ( "mov %0, %%cr4" : : "r" ( cr4
| CR4_PAE
) );
154 /* Load page directory pointer table */
155 __asm__
__volatile__ ( "mov %0, %%cr3" : : "r" ( pdpt
) );
158 __asm__
__volatile__ ( "mov %0, %%cr0" : : "r" ( cr0
| CR0_PG
) );
164 * @v state Previously saved paging state
166 void disable_paging ( struct paging_state
*state
) {
167 unsigned long cr0
= state
->cr0
;
168 unsigned long cr3
= state
->cr3
;
169 unsigned long cr4
= state
->cr4
;
171 /* Do nothing if paging is unavailable */
176 __asm__
__volatile__ ( "mov %0, %%cr0" : : "r" ( cr0
& ~CR0_PG
) );
178 /* Restore saved paging state */
179 __asm__
__volatile__ ( "mov %2, %%cr4\n\t"
182 : : "r" ( cr0
), "r" ( cr3
), "r" ( cr4
) );
186 * Relocate data out of 32-bit address space, if possible
188 * @v data Start of data
189 * @v len Length of data
190 * @ret start Physical start address
192 uint64_t relocate_memory_high ( void *data
, size_t len
) {
193 intptr_t end
= ( ( ( intptr_t ) data
) + len
);
194 struct e820_entry
*e820
= NULL
;
200 /* Do nothing if paging is unavailable */
202 return ( ( intptr_t ) data
);
204 /* Read system memory map */
205 while ( ( e820
= memmap_next ( e820
) ) != NULL
) {
207 /* Find highest compatible placement within this region */
208 start
= ( e820
->start
+ e820
->len
);
209 if ( start
< ADDR_4GB
)
211 start
= ( ( ( start
- end
) & ~( PAGE_SIZE_2MB
- 1 ) ) + end
);
213 if ( start
< e820
->start
)
215 if ( start
< ADDR_4GB
)
218 /* Relocate to this region */
222 /* Calculate length within this 2MB page */
223 offset
= ( ( ( intptr_t ) data
) &
224 ( PAGE_SIZE_2MB
- 1 ) );
225 frag_len
= ( PAGE_SIZE_2MB
- offset
);
226 if ( frag_len
> len
)
229 /* Map copy window to destination */
230 map_page ( COPY_WINDOW
,
231 ( dest
& ~( PAGE_SIZE_2MB
- 1 ) ) );
233 /* Copy data through copy window */
234 memcpy ( ( ( ( void * ) COPY_WINDOW
) + offset
),
237 /* Map original page to destination */
238 map_page ( ( ( ( intptr_t ) data
) - offset
),
239 ( dest
& ~( PAGE_SIZE_2MB
- 1 ) ) );
241 /* Move to next 2MB page */
247 /* Remap copy window */
248 map_page ( COPY_WINDOW
, COPY_WINDOW
);
253 /* Leave at original location */
254 return ( ( intptr_t ) data
);