Properly load pdptes when cr3 is loaded (fixes Ubuntu 16)

This commit is contained in:
Fabian 2022-01-17 17:19:34 -06:00
parent 700225bb6b
commit 229310e686
5 changed files with 64 additions and 22 deletions

View file

@ -233,7 +233,7 @@
use_parts: !ON_LOCALHOST,
},
memory_size: 512 * 1024 * 1024,
state: { url: host + "serenity_state.bin.zst", },
state: { url: host + "serenity_state-v2.bin.zst", },
homepage: "https://serenityos.org/",
},
{

View file

@ -158,6 +158,8 @@ function CPU(bus, wm)
// debug registers
this.dreg = v86util.view(Int32Array, memory, 684, 8);
this.reg_pdpte = v86util.view(Int32Array, memory, 968, 8);
this.fw_value = [];
this.fw_pointer = 0;
this.option_roms = [];
@ -341,6 +343,7 @@ CPU.prototype.get_state = function()
state[39] = this.reg32;
state[40] = this.sreg;
state[41] = this.dreg;
state[42] = this.reg_pdpte;
this.store_current_tsc();
state[43] = this.current_tsc;
@ -437,6 +440,7 @@ CPU.prototype.set_state = function(state)
this.reg32.set(state[39]);
this.sreg.set(state[40]);
this.dreg.set(state[41]);
state[42] && this.reg_pdpte.set(state[42]);
this.set_tsc(state[43][0], state[43][1]);

View file

@ -165,6 +165,7 @@ pub const CR4_PAE: i32 = 1 << 5;
pub const CR4_PGE: i32 = 1 << 7;
pub const CR4_OSFXSR: i32 = 1 << 9;
pub const CR4_OSXMMEXCPT: i32 = 1 << 10;
pub const CR4_SMEP: i32 = 1 << 20;
pub const TSR_BACKLINK: i32 = 0x00;
pub const TSR_CR3: i32 = 0x1C;
@ -1695,9 +1696,7 @@ pub unsafe fn do_task_switch(selector: i32, error_code: Option<i32>) {
*segment_limits.offset(TR as isize) = descriptor.effective_limit();
*sreg.offset(TR as isize) = selector.raw;
*cr.offset(3) = new_cr3;
dbg_assert!((*cr.offset(3) & 0xFFF) == 0);
clear_tlb();
set_cr3(new_cr3);
*cr.offset(0) |= CR0_TS;
@ -1831,9 +1830,7 @@ pub unsafe fn do_page_walk(
let pae = cr4 & CR4_PAE != 0;
let (page_dir_addr, page_dir_entry) = if pae {
// XXX: This should execute when cr3 is loaded
let pdpt_addr = *cr.offset(3) as u32 + (((addr as u32) >> 30) << 3);
let pdpt_entry = read64s(pdpt_addr);
let pdpt_entry = *reg_pdpte.offset(((addr as u32) >> 30) as isize);
if pdpt_entry as i32 & PAGE_TABLE_PRESENT_MASK == 0 {
return Err(PageFault {
addr,
@ -1842,10 +1839,6 @@ pub unsafe fn do_page_walk(
present: false,
});
}
dbg_assert!(
pdpt_entry as u64 & 0xFFFF_FFFF_0000_0000 == 0,
"Unsupported: PDPT entry larger than 32 bits"
);
let page_dir_addr =
(pdpt_entry as u32 & 0xFFFFF000) + ((((addr as u32) >> 21) & 0x1FF) << 3);
@ -2680,9 +2673,51 @@ pub unsafe fn set_cr0(cr0: i32) {
full_clear_tlb();
}
if *cr.offset(4) & CR4_PAE != 0
&& old_cr0 & (CR0_CD | CR0_NW | CR0_PG) != cr0 & (CR0_CD | CR0_NW | CR0_PG)
{
load_pdpte(*cr.offset(3))
}
*protected_mode = (*cr & CR0_PE) == CR0_PE;
}
pub unsafe fn set_cr3(mut cr3: i32) {
if false {
dbg_log!("cr3 <- {:x}", cr3);
}
if *cr.offset(4) & CR4_PAE != 0 {
cr3 &= !0b1111;
load_pdpte(cr3);
}
else {
cr3 &= !0b111111100111;
dbg_assert!(cr3 & 0xFFF == 0, "TODO");
}
*cr.offset(3) = cr3;
clear_tlb();
}
pub unsafe fn load_pdpte(cr3: i32) {
dbg_assert!(cr3 & 0b1111 == 0);
for i in 0..4 {
let mut pdpt_entry = read64s(cr3 as u32 + 8 * i as u32) as u64;
pdpt_entry &= !0b1110_0000_0000;
dbg_assert!(pdpt_entry & 0b11000 == 0, "TODO");
dbg_assert!(
pdpt_entry as u64 & 0xFFFF_FFFF_0000_0000 == 0,
"Unsupported: PDPT entry larger than 32 bits"
);
if pdpt_entry as i32 & PAGE_TABLE_PRESENT_MASK != 0 {
dbg_assert!(
pdpt_entry & 0b1_1110_0110 == 0,
"TODO: #gp reserved bit in pdpte"
);
}
*reg_pdpte.offset(i) = pdpt_entry;
}
}
pub unsafe fn cpl_changed() { *last_virt_eip = -1; }
pub unsafe fn update_cs_size(new_size: bool) {
@ -4144,6 +4179,10 @@ pub unsafe fn reset_cpu() {
*fpu_st.offset(i) = ::softfloat::F80::ZERO;
}
for i in 0..4 {
*reg_pdpte.offset(i) = 0
}
*fpu_stack_empty = 0xFF;
*fpu_stack_ptr = 0;
*fpu_control_word = 0x37F;

View file

@ -53,6 +53,8 @@ pub const mxcsr: *mut i32 = 824 as *mut i32;
pub const reg_xmm: *mut reg128 = 832 as *mut reg128;
pub const current_tsc: *mut u64 = 960 as *mut u64;
pub const reg_pdpte: *mut u64 = 968 as *mut u64; // 4 64-bit entries
pub const fpu_stack_ptr: *mut u8 = 1032 as *mut u8;
pub const fpu_control_word: *mut u16 = 1036 as *mut u16;
pub const fpu_status_word: *mut u16 = 1040 as *mut u16;

View file

@ -766,7 +766,7 @@ pub unsafe fn instr_0F22(r: i32, creg: i32) {
return;
}
let mut data: i32 = read_reg32(r);
let data = read_reg32(r);
// mov cr, addr
match creg {
0 => {
@ -779,17 +779,9 @@ pub unsafe fn instr_0F22(r: i32, creg: i32) {
dbg_log!("cr2 <- {:x}", data);
*cr.offset(2) = data
},
3 => {
if false {
dbg_log!("cr3 <- {:x}", data);
}
data &= !0b111111100111;
dbg_assert!(data & 0xFFF == 0, "TODO");
*cr.offset(3) = data;
clear_tlb();
},
3 => set_cr3(data),
4 => {
dbg_log!("cr4 <- {:x}", *cr.offset(4));
dbg_log!("cr4 <- {:x}", data);
if 0 != data as u32
& ((1 << 11 | 1 << 12 | 1 << 15 | 1 << 16 | 1 << 19) as u32 | 0xFFC00000)
{
@ -801,6 +793,11 @@ pub unsafe fn instr_0F22(r: i32, creg: i32) {
if 0 != (*cr.offset(4) ^ data) & (CR4_PGE | CR4_PSE | CR4_PAE) {
full_clear_tlb();
}
if data & CR4_PAE != 0
&& 0 != (*cr.offset(4) ^ data) & (CR4_PGE | CR4_PSE | CR4_SMEP)
{
load_pdpte(*cr.offset(3));
}
*cr.offset(4) = data;
}
},