123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- "use strict";
- // http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf
- /** @const */
- var PMTIMER_FREQ_SECONDS = 3579545;
- /**
- * @constructor
- * @param {CPU} cpu
- */
- function ACPI(cpu)
- {
- /** @type {CPU} */
- this.cpu = cpu;
- 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: [],
- name: "acpi",
- };
- // 00:07.0 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08)
- cpu.devices.pci.register_device(acpi);
- this.timer_last_value = 0;
- this.timer_imprecision_offset = 0;
- this.status = 1;
- this.pm1_status = 0;
- this.pm1_enable = 0;
- this.last_timer = this.get_timer(v86.microtick());
- this.gpe = new Uint8Array(4);
- 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;
- });
- // ACPI status
- io.register_read(0xB004, this, undefined, function()
- {
- dbg_log("ACPI status read", LOG_ACPI);
- return this.status;
- });
- io.register_write(0xB004, this, undefined, function(value)
- {
- dbg_log("ACPI status write: " + h(value), LOG_ACPI);
- this.status = value;
- });
- // ACPI, pmtimer
- io.register_read(0xB008, this, undefined, undefined, function()
- {
- var value = this.get_timer(v86.microtick()) & 0xFFFFFF;
- //dbg_log("pmtimer read: " + h(value >>> 0), LOG_ACPI);
- return value;
- });
- // 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;
- });
- }
- 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;
- return 100; // TODO
- };
- ACPI.prototype.get_timer = function(now)
- {
- 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;
- };
- ACPI.prototype.get_state = function()
- {
- var state = [];
- state[0] = this.status;
- state[1] = this.pm1_status;
- state[2] = this.pm1_enable;
- state[3] = this.gpe;
- return state;
- };
- ACPI.prototype.set_state = function(state)
- {
- this.status = state[0];
- this.pm1_status = state[1];
- this.pm1_enable = state[2];
- this.gpe = state[3];
- };
|