2014-06-15 22:25:17 +02:00
|
|
|
"use strict";
|
|
|
|
|
2017-04-01 00:16:43 +02:00
|
|
|
// http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf
|
|
|
|
|
2015-12-31 00:31:08 +01:00
|
|
|
/** @const */
|
2018-03-22 21:28:09 +01:00
|
|
|
var PMTIMER_FREQ_SECONDS = 3579545;
|
2014-06-15 22:25:17 +02:00
|
|
|
|
2015-12-31 00:31:08 +01:00
|
|
|
/**
|
|
|
|
* @constructor
|
2015-02-25 18:21:54 +01:00
|
|
|
* @param {CPU} cpu
|
|
|
|
*/
|
2014-06-15 22:25:17 +02:00
|
|
|
function ACPI(cpu)
|
|
|
|
{
|
2017-04-01 00:16:43 +02:00
|
|
|
/** @type {CPU} */
|
|
|
|
this.cpu = cpu;
|
|
|
|
|
2014-06-15 22:25:17 +02:00
|
|
|
var io = cpu.io;
|
|
|
|
|
|
|
|
var acpi = {
|
|
|
|
pci_id: 0x07 << 3,
|
|
|
|
pci_space: [
|
|
|
|
0x86, 0x80, 0x13, 0x71, 0x07, 0x00, 0x80, 0x02, 0x08, 0x00, 0x80, 0x06, 0x00, 0x00, 0x80, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00,
|
|
|
|
],
|
|
|
|
pci_bars: [],
|
2016-01-01 17:49:21 +01:00
|
|
|
name: "acpi",
|
2014-06-15 22:25:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// 00:07.0 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08)
|
|
|
|
cpu.devices.pci.register_device(acpi);
|
|
|
|
|
2018-03-22 21:28:09 +01:00
|
|
|
this.timer_last_value = 0;
|
|
|
|
this.timer_imprecision_offset = 0;
|
|
|
|
|
2017-04-01 00:16:43 +02:00
|
|
|
this.status = 1;
|
|
|
|
this.pm1_status = 0;
|
|
|
|
this.pm1_enable = 0;
|
|
|
|
this.last_timer = this.get_timer(v86.microtick());
|
|
|
|
|
2017-06-05 17:11:50 +02:00
|
|
|
this.gpe = new Uint8Array(4);
|
|
|
|
|
2017-04-01 00:16:43 +02:00
|
|
|
io.register_read(0xB000, this, undefined, function()
|
|
|
|
{
|
|
|
|
dbg_log("ACPI pm1_status read", LOG_ACPI);
|
|
|
|
return this.pm1_status;
|
|
|
|
});
|
|
|
|
io.register_write(0xB000, this, undefined, function(value)
|
|
|
|
{
|
|
|
|
dbg_log("ACPI pm1_status write: " + h(value, 4), LOG_ACPI);
|
|
|
|
this.pm1_status &= ~value;
|
|
|
|
});
|
|
|
|
|
|
|
|
io.register_read(0xB002, this, undefined, function()
|
|
|
|
{
|
|
|
|
dbg_log("ACPI pm1_enable read", LOG_ACPI);
|
|
|
|
return this.pm1_enable;
|
|
|
|
});
|
|
|
|
io.register_write(0xB002, this, undefined, function(value)
|
|
|
|
{
|
|
|
|
dbg_log("ACPI pm1_enable write: " + h(value), LOG_ACPI);
|
|
|
|
this.pm1_enable = value;
|
|
|
|
});
|
|
|
|
|
2014-06-15 22:25:17 +02:00
|
|
|
// ACPI status
|
2015-12-31 00:31:08 +01:00
|
|
|
io.register_read(0xB004, this, undefined, function()
|
2014-06-15 22:25:17 +02:00
|
|
|
{
|
2015-12-31 00:31:08 +01:00
|
|
|
dbg_log("ACPI status read", LOG_ACPI);
|
2017-04-01 00:16:43 +02:00
|
|
|
return this.status;
|
|
|
|
});
|
|
|
|
io.register_write(0xB004, this, undefined, function(value)
|
|
|
|
{
|
|
|
|
dbg_log("ACPI status write: " + h(value), LOG_ACPI);
|
|
|
|
this.status = value;
|
2014-06-15 22:25:17 +02:00
|
|
|
});
|
2015-12-31 00:31:08 +01:00
|
|
|
|
|
|
|
// ACPI, pmtimer
|
|
|
|
io.register_read(0xB008, this, undefined, undefined, function()
|
2014-06-15 22:25:17 +02:00
|
|
|
{
|
2017-04-01 00:16:43 +02:00
|
|
|
var value = this.get_timer(v86.microtick()) & 0xFFFFFF;
|
2015-12-31 00:31:08 +01:00
|
|
|
//dbg_log("pmtimer read: " + h(value >>> 0), LOG_ACPI);
|
|
|
|
return value;
|
2014-06-15 22:25:17 +02:00
|
|
|
});
|
2017-06-05 17:11:50 +02:00
|
|
|
|
|
|
|
// ACPI, gpe
|
|
|
|
io.register_read(0xAFE0, this, function()
|
|
|
|
{
|
|
|
|
dbg_log("Read gpe#0", LOG_ACPI);
|
|
|
|
return this.gpe[0];
|
|
|
|
});
|
|
|
|
io.register_read(0xAFE1, this, function()
|
|
|
|
{
|
|
|
|
dbg_log("Read gpe#1", LOG_ACPI);
|
|
|
|
return this.gpe[1];
|
|
|
|
});
|
|
|
|
io.register_read(0xAFE2, this, function()
|
|
|
|
{
|
|
|
|
dbg_log("Read gpe#2", LOG_ACPI);
|
|
|
|
return this.gpe[2];
|
|
|
|
});
|
|
|
|
io.register_read(0xAFE3, this, function()
|
|
|
|
{
|
|
|
|
dbg_log("Read gpe#3", LOG_ACPI);
|
|
|
|
return this.gpe[3];
|
|
|
|
});
|
|
|
|
|
|
|
|
io.register_write(0xAFE0, this, function(value)
|
|
|
|
{
|
|
|
|
dbg_log("Write gpe#0: " + h(value), LOG_ACPI);
|
|
|
|
this.gpe[0] = value;
|
|
|
|
});
|
|
|
|
io.register_write(0xAFE1, this, function(value)
|
|
|
|
{
|
|
|
|
dbg_log("Write gpe#1: " + h(value), LOG_ACPI);
|
|
|
|
this.gpe[1] = value;
|
|
|
|
});
|
|
|
|
io.register_write(0xAFE2, this, function(value)
|
|
|
|
{
|
|
|
|
dbg_log("Write gpe#2: " + h(value), LOG_ACPI);
|
|
|
|
this.gpe[2] = value;
|
|
|
|
});
|
|
|
|
io.register_write(0xAFE3, this, function(value)
|
|
|
|
{
|
|
|
|
dbg_log("Write gpe#3: " + h(value), LOG_ACPI);
|
|
|
|
this.gpe[3] = value;
|
|
|
|
});
|
2014-06-15 22:25:17 +02:00
|
|
|
}
|
2017-04-01 00:16:43 +02:00
|
|
|
|
|
|
|
ACPI.prototype.timer = function(now)
|
|
|
|
{
|
|
|
|
var timer = this.get_timer(now);
|
|
|
|
var highest_bit_changed = ((timer ^ this.last_timer) & (1 << 23)) !== 0;
|
|
|
|
|
|
|
|
if((this.pm1_enable & 1) && highest_bit_changed)
|
|
|
|
{
|
|
|
|
dbg_log("ACPI raise irq", LOG_ACPI);
|
|
|
|
this.pm1_status |= 1;
|
|
|
|
this.cpu.device_raise_irq(9);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.cpu.device_lower_irq(9);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.last_timer = timer;
|
|
|
|
};
|
|
|
|
|
|
|
|
ACPI.prototype.get_timer = function(now)
|
|
|
|
{
|
2018-03-22 21:28:09 +01:00
|
|
|
const t = Math.round(now * (PMTIMER_FREQ_SECONDS / 1000));
|
|
|
|
|
|
|
|
// Due to the low precision of JavaScript's time functions we increment the
|
|
|
|
// returned timer value every time it is read
|
|
|
|
|
|
|
|
if(t === this.timer_last_value)
|
|
|
|
{
|
|
|
|
// don't go past 1ms
|
|
|
|
|
|
|
|
if(this.timer_imprecision_offset < PMTIMER_FREQ_SECONDS / 1000)
|
|
|
|
{
|
|
|
|
this.timer_imprecision_offset++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbg_assert(t > this.timer_last_value);
|
|
|
|
|
|
|
|
const previous_timer = this.timer_last_value + this.timer_imprecision_offset;
|
|
|
|
|
|
|
|
// don't go back in time
|
|
|
|
|
|
|
|
if(previous_timer <= t)
|
|
|
|
{
|
|
|
|
this.timer_imprecision_offset = 0;
|
|
|
|
this.timer_last_value = t;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbg_log("Warning: Overshot pmtimer, waiting;" +
|
|
|
|
" current=" + t +
|
|
|
|
" last=" + this.timer_last_value +
|
|
|
|
" offset=" + this.timer_imprecision_offset, LOG_ACPI);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.timer_last_value + this.timer_imprecision_offset;
|
2017-04-01 00:16:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
ACPI.prototype.get_state = function()
|
|
|
|
{
|
|
|
|
var state = [];
|
|
|
|
state[0] = this.status;
|
|
|
|
state[1] = this.pm1_status;
|
|
|
|
state[2] = this.pm1_enable;
|
2021-01-01 02:14:33 +01:00
|
|
|
state[3] = this.gpe;
|
2017-04-01 00:16:43 +02:00
|
|
|
return state;
|
|
|
|
};
|
|
|
|
|
2017-04-29 04:30:05 +02:00
|
|
|
ACPI.prototype.set_state = function(state)
|
2017-04-01 00:16:43 +02:00
|
|
|
{
|
|
|
|
this.status = state[0];
|
|
|
|
this.pm1_status = state[1];
|
|
|
|
this.pm1_enable = state[2];
|
2021-01-01 02:14:33 +01:00
|
|
|
this.gpe = state[3];
|
2017-04-01 00:16:43 +02:00
|
|
|
};
|