Minor apic update
This commit is contained in:
parent
8266de747f
commit
e8109ba973
236
src/apic.js
236
src/apic.js
|
@ -19,6 +19,21 @@ var IOAPIC_IRQ_COUNT = 24;
|
|||
/** @const */
|
||||
var IOAPIC_ID = 0; // must match value in seabios
|
||||
|
||||
/** @const */
|
||||
var APIC_TIMER_FREQ = 1 * 1024;
|
||||
|
||||
/** @const */
|
||||
var APIC_TIMER_MODE_MASK = 3 << 17;
|
||||
|
||||
/** @const */
|
||||
var APIC_TIMER_MODE_ONE_SHOT = 0;
|
||||
|
||||
/** @const */
|
||||
var APIC_TIMER_MODE_PERIODIC = 1 << 17;
|
||||
|
||||
/** @const */
|
||||
var APIC_TIMER_MODE_TSC = 2 << 17;
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
|
@ -38,7 +53,15 @@ function APIC(cpu)
|
|||
this.ioredtlb[i] = 1 << 16;
|
||||
}
|
||||
|
||||
this.timer_divider = 0;
|
||||
this.timer_divider_shift = 1;
|
||||
this.timer_initial_count = 0;
|
||||
this.timer_current_count = 0;
|
||||
this.lvt_timer = 0x10000;
|
||||
this.next_tick = v86.microtick();
|
||||
|
||||
this.irqs = [];
|
||||
this.irqs_set = 0;
|
||||
this.ioapic_id = IOAPIC_ID;
|
||||
|
||||
this.lapic_tpr = 0;
|
||||
|
@ -47,37 +70,18 @@ function APIC(cpu)
|
|||
io.mmap_register(APIC_ADDRESS, 0x100000,
|
||||
function(addr)
|
||||
{
|
||||
dbg_trace();
|
||||
dbg_log("unsupported read8 from apic: " + h(addr), LOG_APIC);
|
||||
return 0;
|
||||
//dbg_trace();
|
||||
dbg_log("unsupported read8 from apic: " + h(addr >>> 0), LOG_APIC);
|
||||
var off = addr & 3;
|
||||
addr &= ~3;
|
||||
return read32(addr) >> (off * 8) & 0xFF;
|
||||
},
|
||||
function(addr, value)
|
||||
{
|
||||
dbg_trace();
|
||||
dbg_log("unsupported write8 from apic: " + h(addr) + " <- " + h(value), LOG_APIC);
|
||||
},
|
||||
function(addr)
|
||||
{
|
||||
addr = addr - APIC_ADDRESS | 0;
|
||||
|
||||
switch(addr)
|
||||
{
|
||||
case 0x30:
|
||||
// version
|
||||
return 0x50011
|
||||
|
||||
case 0x80:
|
||||
// tpr
|
||||
return me.lapic_tpr;
|
||||
|
||||
case 0x300:
|
||||
return me.lapic_icr[0];
|
||||
|
||||
default:
|
||||
dbg_log("APIC read32 " + h(addr), LOG_APIC);
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
read32,
|
||||
function(addr, value)
|
||||
{
|
||||
addr = addr - APIC_ADDRESS | 0;
|
||||
|
@ -89,15 +93,110 @@ function APIC(cpu)
|
|||
me.lapic_tpr = value;
|
||||
break;
|
||||
|
||||
case 0xb0:
|
||||
//dbg_log("APIC write eoi: " + h(value, 8), LOG_APIC);
|
||||
break;
|
||||
|
||||
case 0x300:
|
||||
var vector = value & 0xFF;
|
||||
var delivery_mode = value >> 8 & 7;
|
||||
var destination_mode = value >> 11 & 1;
|
||||
var destination_shorthand = value >> 18 & 3;
|
||||
var destination = me.lapic_icr[1] >>> 24;
|
||||
dbg_log("APIC write icr0: " + h(value, 8) + " vector=" + h(vector, 2) + " " +
|
||||
"destination_mode=" + destination_mode + " delivery_mode=" + delivery_mode + " " +
|
||||
"destination_shorthand=" + ["no", "self", "all with self", "all without self"][destination_shorthand], LOG_APIC);
|
||||
|
||||
//value |= 0x1000;
|
||||
me.lapic_icr[0] = value;
|
||||
if(delivery_mode === 0 || delivery_mode === 1)
|
||||
{
|
||||
me.do_irq(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x310:
|
||||
dbg_log("APIC write icr1: " + h(value, 8), LOG_APIC);
|
||||
me.lapic_icr[1] = value;
|
||||
break;
|
||||
|
||||
case 0x320:
|
||||
dbg_log("timer lvt: " + h(value >>> 0, 8), LOG_APIC);
|
||||
me.lvt_timer = value;
|
||||
break;
|
||||
|
||||
case 0x3E0:
|
||||
dbg_log("timer divider: " + h(value >>> 0, 8), LOG_APIC);
|
||||
me.timer_divider = value;
|
||||
|
||||
var divide_shift = value & 0b11 | (value & 0b1000) >> 1;
|
||||
me.timer_divider_shift = divide_shift === 7 ? 0 : divide_shift + 1;
|
||||
break;
|
||||
|
||||
case 0x380:
|
||||
//dbg_log("timer initial: " + h(value >>> 0, 8), LOG_APIC);
|
||||
me.timer_initial_count = value >>> 0;
|
||||
me.timer_current_count = value >>> 0;
|
||||
me.next_tick = v86.microtick();
|
||||
break;
|
||||
|
||||
case 0x390:
|
||||
dbg_log("timer current: " + h(value >>> 0, 8), LOG_APIC);
|
||||
me.timer_current_count = value >>> 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
dbg_log("APIC write32 " + h(addr) + " <- " + h(value, 8), LOG_APIC);
|
||||
dbg_log("APIC write32 " + h(addr) + " <- " + h(value >>> 0, 8), LOG_APIC);
|
||||
}
|
||||
});
|
||||
|
||||
function read32(addr)
|
||||
{
|
||||
addr = addr - APIC_ADDRESS | 0;
|
||||
|
||||
switch(addr)
|
||||
{
|
||||
case 0x30:
|
||||
// version
|
||||
dbg_log("APIC read version", LOG_APIC);
|
||||
return 0x50011
|
||||
|
||||
case 0x80:
|
||||
// tpr
|
||||
//dbg_log("APIC read tpr", LOG_APIC);
|
||||
return me.lapic_tpr;
|
||||
|
||||
case 0x300:
|
||||
dbg_log("APIC read icr0", LOG_APIC);
|
||||
return me.lapic_icr[0];
|
||||
|
||||
case 0x310:
|
||||
dbg_log("APIC read icr1", LOG_APIC);
|
||||
return me.lapic_icr[1];
|
||||
|
||||
case 0x320:
|
||||
dbg_log("read timer lvt", LOG_APIC);
|
||||
return me.lvt_timer;
|
||||
|
||||
case 0x3E0:
|
||||
// divider
|
||||
dbg_log("read timer divider", LOG_APIC);
|
||||
return me.timer_divider;
|
||||
|
||||
case 0x380:
|
||||
dbg_log("read timer initial count", LOG_APIC);
|
||||
return me.timer_initial_count;
|
||||
|
||||
case 0x390:
|
||||
//dbg_log("read timer current count: " + h(me.timer_current_count >>> 0, 8), LOG_APIC);
|
||||
return me.timer_current_count;
|
||||
|
||||
default:
|
||||
dbg_log("APIC read " + h(addr), LOG_APIC);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.iotable = new Int32Array(IOAPIC_IRQ_COUNT * 2);
|
||||
|
||||
// IOAPIC register selection
|
||||
|
@ -106,14 +205,16 @@ function APIC(cpu)
|
|||
var me = this;
|
||||
|
||||
dbg_assert(MMAP_BLOCK_SIZE >= 0x20);
|
||||
|
||||
io.mmap_register(IOAPIC_ADDRESS, MMAP_BLOCK_SIZE,
|
||||
function(addr)
|
||||
{
|
||||
throw "unsupported read8 from ioapic";
|
||||
dbg_assert(false, "unsupported read8 from ioapic: " + h(addr));
|
||||
return 0;
|
||||
},
|
||||
function(addr, value)
|
||||
{
|
||||
throw "unsupported write8 from ioapic";
|
||||
dbg_assert(false, "unsupported write8 from ioapic: " + h(addr));
|
||||
},
|
||||
function(addr)
|
||||
{
|
||||
|
@ -148,11 +249,51 @@ function APIC(cpu)
|
|||
}
|
||||
else
|
||||
{
|
||||
dbg_log("Unexpected IOAPIC register write: " + h(addr) + " <- " + h(value, 8), LOG_APIC);
|
||||
dbg_log("Unexpected IOAPIC register write: " + h(addr) + " <- " + h(value >>> 0, 8), LOG_APIC);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
APIC.prototype.timer = function(now)
|
||||
{
|
||||
if(this.timer_current_count === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//dbg_log(now + " " + this.next_tick, LOG_APIC);
|
||||
|
||||
var steps = (now - this.next_tick) * APIC_TIMER_FREQ / (1 << this.timer_divider_shift) >>> 0;
|
||||
|
||||
if(steps === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.next_tick += steps / APIC_TIMER_FREQ * (1 << this.timer_divider_shift);
|
||||
|
||||
this.timer_current_count -= steps;
|
||||
var mode = this.lvt_timer & APIC_TIMER_MODE_MASK;
|
||||
|
||||
if(mode === APIC_TIMER_MODE_PERIODIC)
|
||||
{
|
||||
while(this.timer_current_count <= 0)
|
||||
{
|
||||
this.timer_current_count = this.timer_initial_count + this.timer_current_count % this.timer_initial_count;
|
||||
}
|
||||
|
||||
this.do_irq(this.lvt_timer);
|
||||
}
|
||||
else if(mode === APIC_TIMER_MODE_ONE_SHOT)
|
||||
{
|
||||
if(this.timer_current_count < 0)
|
||||
{
|
||||
this.timer_current_count = 0;
|
||||
dbg_log("XXX one shot end");
|
||||
}
|
||||
this.do_irq(this.lvt_timer);
|
||||
}
|
||||
};
|
||||
|
||||
APIC.prototype.check_irqs = function()
|
||||
{
|
||||
if(!this.irqs.length)
|
||||
|
@ -161,24 +302,41 @@ APIC.prototype.check_irqs = function()
|
|||
}
|
||||
|
||||
var irq_number = this.irqs.pop();
|
||||
dbg_log("Handle irq " + h(irq_number), LOG_APIC);
|
||||
this.irqs_set &= ~(1 << irq_number);
|
||||
|
||||
//if(irq_number !== 0x30) // timer interrupt on linux
|
||||
//{
|
||||
// dbg_log("Handle irq " + h(irq_number), LOG_APIC);
|
||||
//}
|
||||
|
||||
this.cpu.previous_ip = this.cpu.instruction_pointer;
|
||||
this.cpu.call_interrupt_vector(irq_number, false, false);
|
||||
};
|
||||
|
||||
APIC.prototype.raise_irq = function(i)
|
||||
APIC.prototype.set_irq = function(i)
|
||||
{
|
||||
//dbg_log("apic raise irq " + h(i), LOG_APIC);
|
||||
|
||||
var infos = this.ioredtlb[0x10 + (i << 1)]
|
||||
this.do_irq(infos);
|
||||
};
|
||||
|
||||
APIC.prototype.clear_irq = function(i)
|
||||
{
|
||||
};
|
||||
|
||||
APIC.prototype.do_irq = function(infos)
|
||||
{
|
||||
if(infos & (1 << 16))
|
||||
{
|
||||
//dbg_log("irq " + h(i, 2) + " disabled", LOG_APIC);
|
||||
return;
|
||||
}
|
||||
|
||||
this.irqs.push(infos & 0xFF);
|
||||
var irq = infos & 0xFF;
|
||||
|
||||
this.irqs.push(irq);
|
||||
this.irqs_set |= 1 << irq;
|
||||
this.cpu.handle_irqs();
|
||||
};
|
||||
|
||||
|
@ -202,16 +360,17 @@ APIC.prototype.ioapic_read = function(reg)
|
|||
var irq = reg - 0x10 >> 1;
|
||||
var index = reg & 1;
|
||||
|
||||
var value = this.ioredtlb[reg];
|
||||
|
||||
if(index)
|
||||
{
|
||||
dbg_log("Read destination irq=" + h(irq), LOG_APIC);
|
||||
dbg_log("Read destination irq=" + h(irq) + " -> " + h(value, 8), LOG_APIC);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_log("Read config irq=" + h(irq), LOG_APIC);
|
||||
dbg_log("Read config irq=" + h(irq) + " -> " + h(value, 8), LOG_APIC);
|
||||
}
|
||||
|
||||
return this.ioredtlb[reg];
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -248,13 +407,15 @@ APIC.prototype.ioapic_write = function(reg, value)
|
|||
var vector = value & 0xFF;
|
||||
var delivery_mode = value >> 8 & 7;
|
||||
var destination_mode = value >> 11 & 1;
|
||||
var is_level = value >> 15 & 1;
|
||||
var disabled = value >> 16 & 1;
|
||||
|
||||
dbg_log("Write config " + h(value >>> 0, 8) +
|
||||
" irq=" + h(irq) +
|
||||
" vector=" + h(vector, 2) +
|
||||
" delivery=" + h(delivery_mode) +
|
||||
" dmode=" + destination_mode +
|
||||
" destmode=" + destination_mode +
|
||||
" is_level=" + is_level +
|
||||
" disabled=" + disabled, LOG_APIC);
|
||||
}
|
||||
}
|
||||
|
@ -264,4 +425,3 @@ APIC.prototype.ioapic_write = function(reg, value)
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue