Port writable_or_pagefault, do_page_translation and trigger_pagefault to C

This commit is contained in:
Fabian 2018-01-25 13:33:35 -06:00
parent e9f803e148
commit 5c2eb24832
7 changed files with 221 additions and 16 deletions

View file

@ -175,7 +175,6 @@ function V86Starter(options)
"_int_log2": function(val) { return v86util.int_log2(val); },
"_math_pow": function(x, y) { return Math.pow(x, y); },
"_do_page_translation": function() { return cpu.do_page_translation.apply(cpu, arguments); },
"_popa16": function() { return cpu.popa16.apply(cpu, arguments); },
"_popa32": function() { return cpu.popa32.apply(cpu, arguments); },
"_arpl": function() { return cpu.arpl.apply(cpu, arguments); },
@ -191,7 +190,6 @@ function V86Starter(options)
"_full_clear_tlb": function() { return cpu.full_clear_tlb.apply(cpu, arguments); },
"_invlpg": function() { return cpu.invlpg.apply(cpu, arguments); },
"_writable_or_pagefault": function() { return cpu.writable_or_pagefault.apply(cpu, arguments); },
"_cpl_changed": function() { return cpu.cpl_changed.apply(cpu, arguments); },
"_set_cr0": function() { return cpu.set_cr0.apply(cpu, arguments); },
@ -209,7 +207,6 @@ function V86Starter(options)
"_loop": function() { return cpu.loop.apply(cpu, arguments); },
"_loope": function() { return cpu.loope.apply(cpu, arguments); },
"_loopne": function() { return cpu.loopne.apply(cpu, arguments); },
"_task_switch_test": function() { return cpu.task_switch_test.apply(cpu, arguments); },
"_jcxz": function() { return cpu.jcxz.apply(cpu, arguments); },
"_test_privileges_for_io": function() { return cpu.test_privileges_for_io.apply(cpu, arguments); },

View file

@ -78,7 +78,7 @@ function CPU(bus, wm, codegen)
/*
* whether or not a page fault occured
*/
this.page_fault = false;
this.page_fault = new Uint32Array(wm.memory.buffer, 540, 8);
this.cr = new Int32Array(wm.memory.buffer, 580, 8);
@ -444,7 +444,7 @@ CPU.prototype.get_state = function()
state[6] = this.idtr_size[0];
state[7] = this.gdtr_offset[0];
state[8] = this.gdtr_size[0];
state[9] = this.page_fault;
state[9] = this.page_fault[0];
state[10] = this.cr;
state[11] = this.cpl[0];
state[12] = this.page_size_extensions[0];
@ -526,7 +526,7 @@ CPU.prototype.set_state = function(state)
this.idtr_size[0] = state[6];
this.gdtr_offset[0] = state[7];
this.gdtr_size[0] = state[8];
this.page_fault = state[9];
this.page_fault[0] = state[9];
this.cr.set(state[10]);
this.cpl[0] = state[11];
this.page_size_extensions[0] = state[12];
@ -639,7 +639,7 @@ CPU.prototype.exception_cleanup = function(e)
// call_interrupt_vector has already been called at this point,
// so we just need to reset some state
this.page_fault = false;
this.page_fault[0] = 0;
// restore state from prefixes
this.clear_prefixes();
@ -698,7 +698,7 @@ CPU.prototype.reset = function()
this.gdtr_size[0] = 0;
this.gdtr_offset[0] = 0;
this.page_fault = false;
this.page_fault[0] = 0;
this.cr[0] = 1 << 30 | 1 << 29 | 1 << 4;
this.cr[2] = 0;
this.cr[3] = 0;
@ -2330,7 +2330,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, ha
}
else
{
if(!this.page_fault) // XXX
if(!this.page_fault[0]) // XXX
{
this.handle_irqs();
}
@ -3611,12 +3611,12 @@ CPU.prototype.pic_call_irq = function(int)
CPU.prototype.handle_irqs = function()
{
dbg_assert(!this.page_fault);
dbg_assert(!this.page_fault[0]);
//dbg_assert(this.prefixes[0] === 0);
this.diverged();
if((this.flags[0] & flag_interrupt) && !this.page_fault)
if((this.flags[0] & flag_interrupt) && !this.page_fault[0])
{
if(this.devices.pic)
{
@ -4645,7 +4645,7 @@ CPU.prototype.trigger_pagefault = function(write, user, present)
dbg_trace(LOG_CPU);
}
if(this.page_fault)
if(this.page_fault[0])
{
dbg_trace(LOG_CPU);
throw this.debug.unimpl("Double fault");
@ -4657,7 +4657,7 @@ CPU.prototype.trigger_pagefault = function(write, user, present)
this.tlb_info_global[page] = 0;
this.instruction_pointer[0] = this.previous_ip[0];
this.page_fault = true;
this.page_fault[0] = 1;
this.call_interrupt_vector(14, false, true, user << 2 | write << 1 | present);
throw MAGIC_CPU_EXCEPTION;

View file

@ -179,3 +179,5 @@
#define ENABLE_JIT 1
#define ENABLE_PROFILER 0
#define ENABLE_PROFILER_TIMES 0
#define LOG_PAGE_FAULTS 0

View file

@ -49,6 +49,209 @@ int32_t get_eflags()
!!getzf() << 6 | !!getsf() << 7 | !!getof() << 11;
}
void trigger_pagefault(bool write, bool user, bool present)
{
if(LOG_PAGE_FAULTS)
{
dbg_log("page fault w=%d u=%d p=%d eip=%x cr2=%x",
write, user, present, *previous_ip, cr[2]);
dbg_trace();
}
if(*page_fault)
{
dbg_log("double fault");
dbg_trace();
assert(false);
}
// invalidate tlb entry
int32_t page = (uint32_t)cr[2] >> 12;
tlb_info[page] = 0;
tlb_info_global[page] = 0;
instruction_pointer[0] = previous_ip[0];
*page_fault = true;
call_interrupt_vector(14, false, true, user << 2 | write << 1 | present);
throw_cpu_exception();
}
int32_t do_page_translation(int32_t addr, bool for_writing, bool user)
{
int32_t page = (uint32_t)addr >> 12;
int32_t page_dir_addr = ((uint32_t)cr[3] >> 2) + (page >> 10);
int32_t page_dir_entry = mem32s[page_dir_addr];
int32_t high;
bool can_write = true;
bool global;
bool allow_user = true;
if(!(page_dir_entry & 1))
{
// to do at this place:
//
// - set cr2 = addr (which caused the page fault)
// - call_interrupt_vector with id 14, error code 0-7 (requires information if read or write)
// - prevent execution of the function that triggered this call
//dbg_log("#PF not present", LOG_CPU);
cr[2] = addr;
trigger_pagefault(for_writing, user, 0);
// never reached as trigger_pagefault throws
dbg_assert(false);
}
if((page_dir_entry & 2) == 0)
{
can_write = false;
if(for_writing && (user || (cr[0] & CR0_WP)))
{
cr[2] = addr;
trigger_pagefault(for_writing, user, 1);
dbg_assert(false);
}
}
if((page_dir_entry & 4) == 0)
{
allow_user = false;
if(user)
{
// "Page Fault: page table accessed by non-supervisor";
//dbg_log("#PF supervisor", LOG_CPU);
cr[2] = addr;
trigger_pagefault(for_writing, user, 1);
dbg_assert(false);
}
}
if(page_dir_entry & page_size_extensions[0])
{
// size bit is set
// set the accessed and dirty bits
mem32s[page_dir_addr] = page_dir_entry | 0x20 | for_writing << 6;
high = (page_dir_entry & 0xFFC00000) | (addr & 0x3FF000);
global = (page_dir_entry & 0x100) == 0x100;
}
else
{
int32_t page_table_addr = ((uint32_t)(page_dir_entry & 0xFFFFF000) >> 2) + (page & 0x3FF);
int32_t page_table_entry = mem32s[page_table_addr];
if((page_table_entry & 1) == 0)
{
//dbg_log("#PF not present table", LOG_CPU);
cr[2] = addr;
trigger_pagefault(for_writing, user, 0);
dbg_assert(false);
}
if((page_table_entry & 2) == 0)
{
can_write = false;
if(for_writing && (user || (cr[0] & CR0_WP)))
{
//dbg_log("#PF not writable page", LOG_CPU);
cr[2] = addr;
trigger_pagefault(for_writing, user, 1);
dbg_assert(false);
}
}
if((page_table_entry & 4) == 0)
{
allow_user = false;
if(user)
{
//dbg_log("#PF not supervisor page", LOG_CPU);
cr[2] = addr;
trigger_pagefault(for_writing, user, 1);
dbg_assert(false);
}
}
// set the accessed and dirty bits
write_aligned32(page_dir_addr, page_dir_entry | 0x20);
write_aligned32(page_table_addr, page_table_entry | 0x20 | for_writing << 6);
high = page_table_entry & 0xFFFFF000;
global = (page_table_entry & 0x100) == 0x100;
}
tlb_data[page] = high ^ page << 12;
int32_t allowed_flag;
if(allow_user)
{
if(can_write)
{
allowed_flag = TLB_SYSTEM_READ | TLB_SYSTEM_WRITE | TLB_USER_READ | TLB_USER_WRITE;
}
else
{
// TODO: Consider if cr0.wp is not set
allowed_flag = TLB_SYSTEM_READ | TLB_USER_READ;
}
}
else
{
if(can_write)
{
allowed_flag = TLB_SYSTEM_READ | TLB_SYSTEM_WRITE;
}
else
{
allowed_flag = TLB_SYSTEM_READ;
}
}
tlb_info[page] = allowed_flag;
if(global && (cr[4] & CR4_PGE))
{
tlb_info_global[page] = allowed_flag;
}
return high;
}
void writable_or_pagefault(int32_t addr, int32_t size)
{
dbg_assert(size < 0x1000);
dbg_assert(size > 0);
if(!paging[0])
{
return;
}
bool user = cpl[0] == 3 ? true : false;
int32_t mask = user ? TLB_USER_WRITE : TLB_SYSTEM_WRITE;
int32_t page = (uint32_t)addr >> 12;
if((tlb_info[page] & mask) == 0)
{
do_page_translation(addr, true, user);
}
if((addr & 0xFFF) + size - 1 >= 0x1000)
{
if((tlb_info[page + 1] & mask) == 0)
{
do_page_translation(addr + size - 1, true, user);
}
}
}
int32_t translate_address_read(int32_t address)
{
if(!*paging) return address;
@ -291,6 +494,7 @@ static void jit_generate(int32_t address_hash, uint32_t phys_addr, struct code_c
profiler_stat_increment(S_CACHE_DROP);
}
// no page was crossed
assert(((end_addr ^ phys_addr) & ~0xFFF) == 0);
gen_increment_timestamp_counter(len);

View file

@ -11,6 +11,7 @@ void branch_not_taken(void);
int32_t get_eflags(void);
int32_t translate_address_read(int32_t address);
int32_t translate_address_write(int32_t address);
void writable_or_pagefault(int32_t addr, int32_t size);
int32_t read_imm8(void);
int32_t read_imm8s(void);
int32_t read_imm16(void);

View file

@ -20,7 +20,10 @@ static int32_t* const last_add_result = (int32_t* const) 524;
static int32_t* const last_result = (int32_t* const) 528;
static int32_t* const flags_changed = (int32_t* const) 532;
static int32_t* const flags = (int32_t* const) 536;
// gap 16
static bool* const page_fault = (bool* const) 540;
// gap 12
static bool* const a20_enabled = (bool* const) 552;
static int32_t* const instruction_pointer = (int32_t* const) 556;

View file

@ -12,7 +12,6 @@ extern bool cpu_exception_hook(int32_t);
extern bool has_rand_int(void);
extern int32_t arpl(int32_t, int32_t);
extern int32_t bswap(int32_t);
extern int32_t do_page_translation(int32_t, bool, bool);
extern int32_t get_rand_int(void);
extern int32_t getiopl(void);
extern int32_t int_log2(int32_t);
@ -57,7 +56,6 @@ extern void switch_seg(int32_t, int32_t);
extern bool vm86_mode(void);
extern void lss16(int32_t, int32_t, int32_t);
extern void lss32(int32_t, int32_t, int32_t);
extern void writable_or_pagefault(int32_t, int32_t);
extern void test_privileges_for_io(int32_t, int32_t);
extern int32_t io_port_read8(int32_t);
extern int32_t io_port_read16(int32_t);