Fixed some problems with the IO bus

This commit is contained in:
copy 2013-11-25 19:57:46 +01:00
parent 9240dc669f
commit 81fe7ad9ca
3 changed files with 146 additions and 117 deletions

View file

@ -1560,92 +1560,6 @@ function handle_irqs()
}
}
// any two consecutive 8-bit ports can be treated as a 16-bit port;
// and four consecutive 8-bit ports can be treated as a 32-bit port
//
// http://css.csail.mit.edu/6.858/2012/readings/i386/s08_01.htm
function out8(port_addr, out_byte)
{
if(privileges_for_io())
{
io.port_write(port_addr, out_byte);
}
else
{
trigger_gp(0);
}
}
function out16(port_addr, out_word)
{
if(privileges_for_io())
{
io.port_write(port_addr, out_word & 0xFF);
io.port_write(port_addr + 1, out_word >> 8 & 0xFF);
}
else
{
trigger_gp(0);
}
}
function out32(port_addr, out_dword)
{
if(privileges_for_io())
{
io.port_write(port_addr, out_dword & 0xFF);
io.port_write(port_addr + 1, out_dword >> 8 & 0xFF);
io.port_write(port_addr + 2, out_dword >> 16 & 0xFF);
io.port_write(port_addr + 3, out_dword >> 24 & 0xFF);
}
else
{
trigger_gp(0);
}
}
function in8(port_addr)
{
if(privileges_for_io())
{
return io.port_read(port_addr);
}
else
{
trigger_gp(0);
}
}
function in16(port_addr)
{
if(privileges_for_io())
{
return io.port_read(port_addr) |
io.port_read(port_addr + 1) << 8;
}
else
{
trigger_gp(0);
}
}
function in32(port_addr)
{
if(privileges_for_io())
{
return io.port_read(port_addr) |
io.port_read(port_addr + 1) << 8 |
io.port_read(port_addr + 2) << 16 |
io.port_read(port_addr + 3) << 24;
}
else
{
trigger_gp(0);
}
}
/**
* returns the current iopl from the eflags register
*/
@ -1654,9 +1568,12 @@ function getiopl()
return flags >> 12 & 3;
}
function privileges_for_io()
function test_privileges_for_io()
{
return !protected_mode || cpl <= getiopl();
if(protected_mode && cpl > getiopl())
{
trigger_gp(0);
}
}
function cpuid()

View file

@ -1103,10 +1103,28 @@ op(0xE1, { loope(); });
op(0xE2, { loop(); });
op(0xE3, { jcxz(); });
op(0xE4, { reg8[reg_al] = in8(read_imm8()); });
op2(0xE5, { reg16[reg_ax] = in16(read_imm8()); }, { reg32[reg_eax] = in32(read_imm8()); });
op(0xE6, { out8(read_imm8(), reg8[reg_al]); });
op2(0xE7, { out16(read_imm8(), reg16[reg_ax]); }, { out32(read_imm8(), reg32s[reg_eax]); });
op(0xE4, {
test_privileges_for_io();
reg8[reg_al] = io.port_read8(read_imm8());
});
op2(0xE5, {
test_privileges_for_io();
reg16[reg_ax] = io.port_read16(read_imm8());
}, {
test_privileges_for_io();
reg32[reg_eax] = io.port_read32(read_imm8());
});
op(0xE6, {
test_privileges_for_io();
io.port_write8(read_imm8(), reg8[reg_al]);
});
op2(0xE7, {
test_privileges_for_io();
io.port_write16(read_imm8(), reg16[reg_ax]);
}, {
test_privileges_for_io();
io.port_write32(read_imm8(), reg32s[reg_eax]);
});
op2(0xE8, {
// call
@ -1149,10 +1167,28 @@ op(0xEB, {
instruction_pointer = instruction_pointer + imm8 | 0;
});
op(0xEC, { reg8[reg_al] = in8(reg16[reg_dx]); });
op2(0xED, { reg16[reg_ax] = in16(reg16[reg_dx]); }, { reg32[reg_eax] = in32(reg16[reg_dx]); });
op(0xEE, { out8(reg16[reg_dx], reg8[reg_al]); });
op2(0xEF, { out16(reg16[reg_dx], reg16[reg_ax]); }, { out32(reg16[reg_dx], reg32s[reg_eax]); });
op(0xEC, {
test_privileges_for_io();
reg8[reg_al] = io.port_read8(reg16[reg_dx]);
});
op2(0xED, {
test_privileges_for_io();
reg16[reg_ax] = io.port_read16(reg16[reg_dx]);
}, {
test_privileges_for_io();
reg32[reg_eax] = io.port_read32(reg16[reg_dx]);
});
op(0xEE, {
test_privileges_for_io();
io.port_write8(reg16[reg_dx], reg8[reg_al]);
});
op2(0xEF, {
test_privileges_for_io();
io.port_write16(reg16[reg_dx], reg16[reg_ax]);
}, {
test_privileges_for_io();
io.port_write32(reg16[reg_dx], reg32s[reg_eax]);
});
op(0xF0, {
// lock
@ -1264,27 +1300,15 @@ op(0xF9, {
op(0xFA, {
// cli
//dbg_log("interrupts off");
if(!privileges_for_io())
{
trigger_gp(0);
}
else
{
flags &= ~flag_interrupt;
}
test_privileges_for_io();
flags &= ~flag_interrupt;
});
op(0xFB, {
// sti
//dbg_log("interrupts on");
if(!privileges_for_io())
{
trigger_gp(0);
}
else
{
flags |= flag_interrupt;
handle_irqs();
}
test_privileges_for_io();
flags |= flag_interrupt;
handle_irqs();
});

View file

@ -164,15 +164,103 @@ function IO()
});
}
this.port_write = function(port_addr, out_byte)
// any two consecutive 8-bit ports can be treated as a 16-bit port;
// and four consecutive 8-bit ports can be treated as a 32-bit port
//
// http://css.csail.mit.edu/6.858/2012/readings/i386/s08_01.htm
//
// This info seems to be incorrect, at least some multibyte ports are next
// to each other, such as 1CE and 1CF (VBE dispi) or the 170 (ATA data port).
//
// As a workaround, we pass the original port to the callback as the last argument.
this.port_write8 = function(port_addr, out_byte)
{
write_callbacks[port_addr](out_byte);
write_callbacks[port_addr](out_byte, port_addr);
};
this.port_write16 = function(port_addr, out_byte)
{
dbg_log(
"write port16 #" + h(port_addr, 3) + " <- " + h(out_byte, 2) + get_port_description(port_addr),
LOG_IO
);
if(port_addr <= 0xFFFE)
{
write_callbacks[port_addr](out_byte & 0xFF, port_addr);
write_callbacks[port_addr + 1](out_byte >> 8, port_addr);
}
else
{
dbg_log("Ignored 2 byte write to port " + h(port_addr), LOG_IO);
}
};
this.port_write32 = function(port_addr, out_byte)
{
dbg_log(
"write port32 #" + h(port_addr, 3) + " <- " + h(out_byte, 2) + get_port_description(port_addr),
LOG_IO
);
if(port_addr <= 0xFFFC)
{
write_callbacks[port_addr](out_byte & 0xFF, port_addr);
write_callbacks[port_addr + 1](out_byte >> 8 & 0xFF, port_addr);
write_callbacks[port_addr + 2](out_byte >> 16 & 0xFF, port_addr);
write_callbacks[port_addr + 3](out_byte >>> 24, port_addr);
}
else
{
dbg_log("Ignored 4 byte write to port " + h(port_addr), LOG_IO);
}
};
// read byte from port
this.port_read = function(port_addr)
this.port_read8 = function(port_addr)
{
return read_callbacks[port_addr]();
return read_callbacks[port_addr](port_addr);
};
this.port_read16 = function(port_addr)
{
dbg_log(
"read port16 #" + h(port_addr, 3) + get_port_description(port_addr),
LOG_IO
);
if(port_addr <= 0xFFFE)
{
return read_callbacks[port_addr](port_addr) |
read_callbacks[port_addr + 1](port_addr) << 8;
}
else
{
dbg_log("Ignored 2 byte read from port " + h(port_addr), LOG_IO);
}
};
this.port_read32 = function(port_addr)
{
dbg_log(
"read port32 #" + h(port_addr, 3) + get_port_description(port_addr),
LOG_IO
);
if(port_addr <= 0xFFFC)
{
return read_callbacks[port_addr](port_addr) |
read_callbacks[port_addr + 1](port_addr) << 8 |
read_callbacks[port_addr + 2](port_addr) << 16 |
read_callbacks[port_addr + 3](port_addr) << 24;
}
else
{
dbg_log("Ignored 4 byte read from port " + h(port_addr), LOG_IO);
}
};
}