Port far_ret to Rust

This commit is contained in:
Fabian 2020-12-31 19:14:31 -06:00
parent d735d5d34e
commit 3b5aff7d43
4 changed files with 146 additions and 158 deletions

View file

@ -117,7 +117,6 @@ function V86Starter(options)
dbg_trace();
},
"far_return": function(eip, selector, stack_adjust, is_osize_32) { return cpu.far_return(eip, selector, stack_adjust, !!is_osize_32); },
"pic_acknowledge": function() { cpu.pic_acknowledge(); },
"io_port_read8": function(addr) { return cpu.io.port_read8(addr); },

View file

@ -1571,155 +1571,6 @@ CPU.prototype.cpl_changed = function()
this.last_virt_esp[0] = -1;
};
CPU.prototype.far_return = function(eip, selector, stack_adjust, is_osize_32)
{
dbg_assert(typeof selector === "number" && selector < 0x10000 && selector >= 0);
//dbg_log("far return eip=" + h(eip >>> 0, 8) + " cs=" + h(selector, 4) + " stack_adjust=" + h(stack_adjust), LOG_CPU);
CPU_LOG_VERBOSE && this.debug.dump_state("far ret start");
if(!this.protected_mode[0])
{
dbg_assert(!this.is_32[0]);
//dbg_assert(!this.stack_size_32[0]);
}
if(!this.protected_mode[0] || this.vm86_mode())
{
this.switch_cs_real_mode(selector);
this.instruction_pointer[0] = this.get_seg_cs() + eip | 0;
this.adjust_stack_reg(2 * (is_osize_32 ? 4 : 2) + stack_adjust);
return;
}
var info = this.lookup_segment_selector(selector);
if(info.is_null)
{
dbg_log("null cs", LOG_CPU);
this.trigger_gp(0);
return;
}
if(!info.is_valid)
{
dbg_log("invalid cs: " + h(selector), LOG_CPU);
this.trigger_gp(selector & ~3);
return;
}
if(info.is_system)
{
dbg_assert(false, "is system in far return");
this.trigger_gp(selector & ~3);
return;
}
if(!info.is_executable)
{
dbg_log("non-executable cs: " + h(selector), LOG_CPU);
this.trigger_gp(selector & ~3);
return;
}
if(info.rpl < this.cpl[0])
{
dbg_log("cs rpl < cpl: " + h(selector), LOG_CPU);
this.trigger_gp(selector & ~3);
return;
}
if(info.dc_bit && info.dpl > info.rpl)
{
dbg_log("cs conforming and dpl > rpl: " + h(selector), LOG_CPU);
this.trigger_gp(selector & ~3);
return;
}
if(!info.dc_bit && info.dpl !== info.rpl)
{
dbg_log("cs non-conforming and dpl != rpl: " + h(selector), LOG_CPU);
this.trigger_gp(selector & ~3);
return;
}
if(!info.is_present)
{
dbg_log("#NP for loading not-present in cs sel=" + h(selector, 4), LOG_CPU);
dbg_trace(LOG_CPU);
this.trigger_np(selector & ~3);
return;
}
if(info.rpl > this.cpl[0])
{
dbg_log("far return privilege change cs: " + h(selector) + " from=" + this.cpl[0] + " to=" + info.rpl + " is_16=" + is_osize_32, LOG_CPU);
if(is_osize_32)
{
//dbg_log("esp read from " + h(this.translate_address_system_read(this.get_stack_pointer(stack_adjust + 8))))
var temp_esp = this.safe_read32s(this.get_stack_pointer(stack_adjust + 8));
//dbg_log("esp=" + h(temp_esp));
var temp_ss = this.safe_read16(this.get_stack_pointer(stack_adjust + 12));
}
else
{
//dbg_log("esp read from " + h(this.translate_address_system_read(this.get_stack_pointer(stack_adjust + 4))));
var temp_esp = this.safe_read16(this.get_stack_pointer(stack_adjust + 4));
//dbg_log("esp=" + h(temp_esp));
var temp_ss = this.safe_read16(this.get_stack_pointer(stack_adjust + 6));
}
this.cpl[0] = info.rpl;
this.cpl_changed();
// XXX: This failure should be checked before side effects
if(!this.switch_seg(reg_ss, temp_ss)) dbg_assert(false);
this.set_stack_reg(temp_esp + stack_adjust);
//if(is_osize_32)
//{
// this.adjust_stack_reg(2 * 4);
//}
//else
//{
// this.adjust_stack_reg(2 * 2);
//}
//throw this.debug.unimpl("privilege change");
//this.adjust_stack_reg(stack_adjust);
}
else
{
if(is_osize_32)
{
this.adjust_stack_reg(2 * 4 + stack_adjust);
}
else
{
this.adjust_stack_reg(2 * 2 + stack_adjust);
}
}
//dbg_assert(this.cpl[0] === info.dpl);
this.update_cs_size(info.size);
this.segment_is_null[reg_cs] = 0;
this.segment_limits[reg_cs] = info.effective_limit;
//this.segment_infos[reg_cs] = 0; // TODO
this.segment_offsets[reg_cs] = info.base;
this.sreg[reg_cs] = selector;
dbg_assert((selector & 3) === this.cpl[0]);
this.instruction_pointer[0] = this.get_seg_cs() + eip | 0;
//dbg_log("far return to:", LOG_CPU)
CPU_LOG_VERBOSE && this.debug.dump_state("far ret end");
};
CPU.prototype.do_task_switch = function(selector, has_error_code, error_code)
{
dbg_assert(this.tss_size_32[0], "TODO");

View file

@ -870,7 +870,7 @@ pub unsafe fn call_interrupt_vector(
//dbg_log!("Intra privilege interrupt gate=" + h(selector, 4) + ":" + h(offset >>> 0, 8) +
// " gate_type=" + gate_type + " 16bit=" + descriptor.is_32() +
// " cpl=" + *cpl + " dpl=" + segment_descriptor.dpl() + " conforming=" + +segment_descriptor.dc_bit(), );
// " cpl=" + *cpl + " dpl=" + segment_descriptor.dpl() + " conforming=" + +segment_descriptor.is_dc(), );
//debug.dump_regs_short();
if *flags & FLAG_VM != 0 {
@ -1176,7 +1176,7 @@ pub unsafe fn far_jump(eip: i32, selector: i32, is_call: bool, is_osize_32: bool
if is_call {
if is_16 {
for i in (0..parameter_count).rev() {
//for(var i = parameter_count - 1; i >= 0; i--)
//for(let i = parameter_count - 1; i >= 0; i--)
let parameter = safe_read16(old_stack_pointer + 2 * i).unwrap();
push16(parameter).unwrap();
}
@ -1187,7 +1187,7 @@ pub unsafe fn far_jump(eip: i32, selector: i32, is_call: bool, is_osize_32: bool
}
else {
for i in (0..parameter_count).rev() {
//for(var i = parameter_count - 1; i >= 0; i--)
//for(let i = parameter_count - 1; i >= 0; i--)
let parameter = safe_read32s(old_stack_pointer + 4 * i).unwrap();
push32(parameter).unwrap();
}
@ -1250,7 +1250,7 @@ pub unsafe fn far_jump(eip: i32, selector: i32, is_call: bool, is_osize_32: bool
}
else {
dbg_assert!(false);
//var types = { 9: "Available 386 TSS", 0xb: "Busy 386 TSS", 4: "286 Call Gate", 0xc: "386 Call Gate" };
//let types = { 9: "Available 386 TSS", 0xb: "Busy 386 TSS", 4: "286 Call Gate", 0xc: "386 Call Gate" };
//throw debug.unimpl("load system segment descriptor, type = " + (info.access & 15) + " (" + types[info.access & 15] + ")");
}
}
@ -1318,7 +1318,148 @@ pub unsafe fn far_jump(eip: i32, selector: i32, is_call: bool, is_osize_32: bool
//CPU_LOG_VERBOSE && debug.dump_state("far " + ["jump", "call"][+is_call] + " end");
}
//pub fn call_indirect1(f: fn(u16), x: u16) { f(x); }
pub unsafe fn far_return(eip: i32, selector: i32, stack_adjust: i32, is_osize_32: bool) {
dbg_assert!(selector < 0x10000 && selector >= 0);
//dbg_log("far return eip=" + h(eip >>> 0, 8) + " cs=" + h(selector, 4) + " stack_adjust=" + h(stack_adjust), LOG_CPU);
//CPU_LOG_VERBOSE && this.debug.dump_state("far ret start");
if !*protected_mode {
dbg_assert!(!*is_32);
//dbg_assert(!this.stack_size_32[0]);
}
if !*protected_mode || vm86_mode() {
switch_cs_real_mode(selector);
*instruction_pointer = get_seg_cs() + eip;
adjust_stack_reg(2 * (if is_osize_32 { 4 } else { 2 }) + stack_adjust);
return;
}
let (info, cs_selector) = match return_on_pagefault!(lookup_segment_selector(selector)) {
Ok((desc, sel)) => (desc, sel),
Err(selector_unusable) => match selector_unusable {
SelectorNullOrInvalid::IsNull => {
dbg_log!("far return: #gp null cs");
trigger_gp(0);
return;
},
SelectorNullOrInvalid::IsInvalid => {
dbg_log!("far return: #gp invalid cs: {:x}", selector);
trigger_gp(selector & !3);
return;
},
},
};
if info.is_system() {
dbg_assert!(false, "is system in far return");
trigger_gp(selector & !3);
return;
}
if !info.is_executable() {
dbg_log!("non-executable cs: {:x}", selector);
trigger_gp(selector & !3);
return;
}
if cs_selector.rpl() < *cpl {
dbg_log!("cs rpl < cpl: {:x}", selector);
trigger_gp(selector & !3);
return;
}
if info.is_dc() && info.dpl() > cs_selector.rpl() {
dbg_log!("cs conforming and dpl > rpl: {:x}", selector);
trigger_gp(selector & !3);
return;
}
if !info.is_dc() && info.dpl() != cs_selector.rpl() {
dbg_log!("cs non-conforming and dpl != rpl: {:x}", selector);
trigger_gp(selector & !3);
return;
}
if !info.is_present() {
dbg_log!("#NP for loading not-present in cs sel={:x}", selector);
dbg_trace();
trigger_np(selector & !3);
return;
}
if cs_selector.rpl() > *cpl {
dbg_log!(
"far return privilege change cs: {:x} from={} to={} is_16={}",
selector,
*cpl,
cs_selector.rpl(),
is_osize_32
);
let temp_esp;
let temp_ss;
if is_osize_32 {
//dbg_log!("esp read from " + h(translate_address_system_read(get_stack_pointer(stack_adjust + 8))))
temp_esp = safe_read32s(get_stack_pointer(stack_adjust + 8)).unwrap();
//dbg_log!("esp=" + h(temp_esp));
temp_ss = safe_read16(get_stack_pointer(stack_adjust + 12)).unwrap();
}
else {
//dbg_log!("esp read from " + h(translate_address_system_read(get_stack_pointer(stack_adjust + 4))));
temp_esp = safe_read16(get_stack_pointer(stack_adjust + 4)).unwrap();
//dbg_log!("esp=" + h(temp_esp));
temp_ss = safe_read16(get_stack_pointer(stack_adjust + 6)).unwrap();
}
*cpl = cs_selector.rpl();
cpl_changed();
// XXX: This failure should be checked before side effects
if !switch_seg(SS, temp_ss) {
dbg_assert!(false);
}
set_stack_reg(temp_esp + stack_adjust);
//if(is_osize_32)
//{
// adjust_stack_reg(2 * 4);
//}
//else
//{
// adjust_stack_reg(2 * 2);
//}
//throw debug.unimpl("privilege change");
//adjust_stack_reg(stack_adjust);
}
else {
if is_osize_32 {
adjust_stack_reg(2 * 4 + stack_adjust);
}
else {
adjust_stack_reg(2 * 2 + stack_adjust);
}
}
//dbg_assert(*cpl === info.dpl);
update_cs_size(info.is_32());
*segment_is_null.offset(CS as isize) = false;
*segment_limits.offset(CS as isize) = info.effective_limit();
*segment_offsets.offset(CS as isize) = info.base();
*sreg.offset(CS as isize) = selector as u16;
dbg_assert!(selector & 3 == *cpl as i32);
*instruction_pointer = get_seg_cs() + eip;
//dbg_log("far return to:", LOG_CPU)
//CPU_LOG_VERBOSE && debug.dump_state("far ret end");
}
pub unsafe fn after_block_boundary() { jit_block_boundary = true; }

View file

@ -3,9 +3,6 @@
extern "C" {
#[no_mangle]
fn arpl(seg: i32, r: i32) -> i32;
#[no_mangle]
fn far_return(eip: i32, selector: i32, stack_adjust: i32, is_osize_32: bool);
#[no_mangle]
fn hlt_op();
}