Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions src/rust/cpu/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ pub const PAGE_TABLE_ACCESSED_MASK: i32 = 1 << 5;
pub const PAGE_TABLE_DIRTY_MASK: i32 = 1 << 6;
pub const PAGE_TABLE_PSE_MASK: i32 = 1 << 7;
pub const PAGE_TABLE_GLOBAL_MASK: i32 = 1 << 8;
pub const PAGE_TABLE_NX_MASK: i64 = 1 << 63;
pub const MMAP_BLOCK_BITS: i32 = 17;
pub const MMAP_BLOCK_SIZE: i32 = 1 << MMAP_BLOCK_BITS;
pub const CR0_PE: i32 = 1;
Expand Down Expand Up @@ -236,9 +237,12 @@ pub const IA32_PAT: i32 = 0x277;
pub const IA32_RTIT_CTL: i32 = 0x570;
pub const MSR_PKG_C2_RESIDENCY: i32 = 0x60D;
pub const IA32_KERNEL_GS_BASE: i32 = 0xC0000101u32 as i32;
pub const IA32_EFER: i32 = 0xC0000080u32 as i32;
pub const MSR_AMD64_LS_CFG: i32 = 0xC0011020u32 as i32;
pub const MSR_AMD64_DE_CFG: i32 = 0xC0011029u32 as i32;

pub const EFER_NXE: i32 = 1 << 11;

pub const IA32_APIC_BASE_BSP: i32 = 1 << 8;
pub const IA32_APIC_BASE_EXTD: i32 = 1 << 10;
pub const IA32_APIC_BASE_EN: i32 = 1 << 11;
Expand All @@ -260,6 +264,7 @@ pub const TLB_NO_USER: i32 = 1 << 2;
pub const TLB_IN_MAPPED_RANGE: i32 = 1 << 3;
pub const TLB_GLOBAL: i32 = 1 << 4;
pub const TLB_HAS_CODE: i32 = 1 << 5;
pub const TLB_NO_EXECUTE: i32 = 1 << 6;
pub const IVT_SIZE: u32 = 0x400;
pub const CPU_EXCEPTION_DE: i32 = 0;
pub const CPU_EXCEPTION_DB: i32 = 1;
Expand Down Expand Up @@ -1947,7 +1952,9 @@ pub unsafe fn do_page_walk(
side_effects: bool,
) -> OrPageFault<std::num::NonZeroI32> {
let global;
let for_execute = false;
let mut allow_user = true;
let mut has_nx_bit = false;
let page = (addr as u32 >> 12) as i32;
let high;

Expand All @@ -1968,7 +1975,7 @@ pub unsafe fn do_page_walk(
let pdpt_entry = *reg_pdpte.offset(((addr as u32) >> 30) as isize);
if pdpt_entry as i32 & PAGE_TABLE_PRESENT_MASK == 0 {
if side_effects {
trigger_pagefault(addr, false, for_writing, user, jit);
trigger_pagefault(addr, false, for_writing, user, false, jit);
}
return Err(());
}
Expand All @@ -1980,10 +1987,7 @@ pub unsafe fn do_page_walk(
page_dir_entry as u64 & 0x7FFF_FFFF_0000_0000 == 0,
"Unsupported: Page directory entry larger than 32 bits"
);
dbg_assert!(
page_dir_entry & 0x8000_0000_0000_0000u64 as i64 == 0,
"Unsupported: NX bit"
);
has_nx_bit = (*efer & EFER_NXE != 0) && (page_dir_entry & PAGE_TABLE_NX_MASK != 0);

(page_dir_addr, page_dir_entry as i32)
}
Expand All @@ -1995,7 +1999,7 @@ pub unsafe fn do_page_walk(

if page_dir_entry & PAGE_TABLE_PRESENT_MASK == 0 {
if side_effects {
trigger_pagefault(addr, false, for_writing, user, jit);
trigger_pagefault(addr, false, for_writing, user, false, jit);
}
return Err(());
}
Expand All @@ -2007,9 +2011,9 @@ pub unsafe fn do_page_walk(
if 0 != page_dir_entry & PAGE_TABLE_PSE_MASK && 0 != cr4 & CR4_PSE {
// size bit is set

if for_writing && !allow_write && !kernel_write_override || user && !allow_user {
if for_writing && !allow_write && !kernel_write_override || user && !allow_user || for_execute && has_nx_bit {
if side_effects {
trigger_pagefault(addr, true, for_writing, user, jit);
trigger_pagefault(addr, true, for_writing, user, for_execute, jit);
}
return Err(());
}
Expand Down Expand Up @@ -2041,10 +2045,7 @@ pub unsafe fn do_page_walk(
page_table_entry as u64 & 0x7FFF_FFFF_0000_0000 == 0,
"Unsupported: Page table entry larger than 32 bits"
);
dbg_assert!(
page_table_entry & 0x8000_0000_0000_0000u64 as i64 == 0,
"Unsupported: NX bit"
);
has_nx_bit |= (*efer & EFER_NXE != 0) && (page_table_entry & PAGE_TABLE_NX_MASK != 0);

(page_table_addr, page_table_entry as i32)
}
Expand All @@ -2062,9 +2063,10 @@ pub unsafe fn do_page_walk(
if !present
|| for_writing && !allow_write && !kernel_write_override
|| user && !allow_user
|| for_execute && has_nx_bit
{
if side_effects {
trigger_pagefault(addr, present, for_writing, user, jit);
trigger_pagefault(addr, present, for_writing, user, for_execute, jit);
}
return Err(());
}
Expand Down Expand Up @@ -2130,7 +2132,8 @@ pub unsafe fn do_page_walk(
| if allow_user { 0 } else { TLB_NO_USER }
| if is_in_mapped_range { TLB_IN_MAPPED_RANGE } else { 0 }
| if global && 0 != cr4 & CR4_PGE { TLB_GLOBAL } else { 0 }
| if has_code { TLB_HAS_CODE } else { 0 };
| if has_code { TLB_HAS_CODE } else { 0 }
| if has_nx_bit { TLB_NO_EXECUTE } else { 0 };

let tlb_entry = (high + memory::mem8 as u32) as i32 ^ page << 12 | info_bits as i32;

Expand Down Expand Up @@ -2256,14 +2259,15 @@ pub unsafe fn trigger_fault_end_jit() {
/// and finally calls trigger_fault_end_jit, which does the interrupt
///
/// Non-jit resets the instruction pointer and does the PF interrupt directly
pub unsafe fn trigger_pagefault(addr: i32, present: bool, write: bool, user: bool, jit: bool) {
pub unsafe fn trigger_pagefault(addr: i32, present: bool, write: bool, user: bool, execut: bool, jit: bool) {
if config::LOG_PAGE_FAULTS {
dbg_log!(
"page fault{} w={} u={} p={} eip={:x} cr2={:x}",
"page fault{} w={} u={} p={} e={} eip={:x} cr2={:x}",
if jit { "jit" } else { "" },
write as i32,
user as i32,
present as i32,
execut as i32,
*previous_ip,
addr
);
Expand All @@ -2275,7 +2279,7 @@ pub unsafe fn trigger_pagefault(addr: i32, present: bool, write: bool, user: boo
let page = ((addr as u32) >> 12) as i32;
clear_tlb_code(page);
tlb_data[page as usize] = 0;
let error_code = (user as i32) << 2 | (write as i32) << 1 | present as i32;
let error_code = (execut as i32) << 4 | (user as i32) << 2 | (write as i32) << 1 | present as i32;
if jit {
jit_fault = Some((CPU_EXCEPTION_PF, Some(error_code)));
}
Expand Down Expand Up @@ -4484,6 +4488,8 @@ pub unsafe fn reset_cpu() {
*last_op1 = 0;
*last_op_size = 0;

*efer = 0;

set_tsc(0, 0);

*instruction_pointer = 0xFFFF0;
Expand Down
2 changes: 2 additions & 0 deletions src/rust/cpu/global_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub const sse_scratch_register: *mut reg128 = 1136 as *mut reg128;

pub const fpu_st: *mut F80 = 1152 as *mut F80;

pub const efer: *mut i32 = 1280 as *mut i32;

pub fn get_reg32_offset(r: u32) -> u32 {
dbg_assert!(r < 8);
(unsafe { reg32.offset(r as isize) }) as u32
Expand Down
25 changes: 24 additions & 1 deletion src/rust/cpu/instructions_0f.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,20 @@ pub unsafe fn instr_0F30() {
IA32_SYSENTER_ESP => *sysenter_esp = low,
IA32_FEAT_CTL => {}, // linux 5.x
MSR_TEST_CTRL => {}, // linux 5.x
IA32_EFER => {
let supported_bits = EFER_NXE as i32;

if (low & !supported_bits) != 0 {
dbg_log!("Writing unsupported bits to EFER: {:x}", low & !supported_bits);
dbg_assert!(false);
}

if (low & EFER_NXE) != (*efer & EFER_NXE) {
full_clear_tlb();
}

*efer = (low & supported_bits) as i32;
},
IA32_APIC_BASE => {
dbg_assert!(
high == 0,
Expand Down Expand Up @@ -1277,6 +1291,7 @@ pub unsafe fn instr_0F32() {
low = tsc as i32;
high = (tsc >> 32) as i32
},
IA32_EFER => low = *efer,
IA32_FEAT_CTL => {}, // linux 5.x
MSR_TEST_CTRL => {}, // linux 5.x
IA32_PLATFORM_ID => {},
Expand Down Expand Up @@ -3309,10 +3324,18 @@ pub unsafe fn instr_0FA2() {

0x80000000 => {
// maximum supported extended level
eax = 5;
eax = 0x80000001u32 as i32;
// other registers are reserved
},

0x80000001 => {
let vme = 0 << 1;
edx = (if true /* have fpu */ { 1 } else { 0 }) | // fpu
vme | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | // vme, pse, tsc, msr, pae
1 << 8 | 1 << 11 | 1 << 13 | 1 << 15 | 1 << 20 | // cx8, sep, pge, cmov, nx
1 << 23 | 1 << 24 | 1 << 25 | 1 << 26; // mmx, fxsr, sse1, sse2
},

0x40000000 => {
// hypervisor
if config::VMWARE_HYPERVISOR_PORT {
Expand Down
Loading