Port writable_or_pagefault, do_page_translation and trigger_pagefault to C
This commit is contained in:
parent
e9f803e148
commit
5c2eb24832
|
@ -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); },
|
||||
|
||||
|
|
20
src/cpu.js
20
src/cpu.js
|
@ -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;
|
||||
|
|
|
@ -179,3 +179,5 @@
|
|||
#define ENABLE_JIT 1
|
||||
#define ENABLE_PROFILER 0
|
||||
#define ENABLE_PROFILER_TIMES 0
|
||||
|
||||
#define LOG_PAGE_FAULTS 0
|
||||
|
|
204
src/native/cpu.c
204
src/native/cpu.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue