apic.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. "use strict";
  2. // See Intel's System Programming Guide
  3. /** @const */
  4. var APIC_LOG_VERBOSE = false;
  5. /** @const */
  6. var APIC_ADDRESS = 0xFEE00000;
  7. /** @const */
  8. var APIC_TIMER_MODE_MASK = 3 << 17;
  9. /** @const */
  10. var APIC_TIMER_MODE_ONE_SHOT = 0;
  11. /** @const */
  12. var APIC_TIMER_MODE_PERIODIC = 1 << 17;
  13. /** @const */
  14. var APIC_TIMER_MODE_TSC = 2 << 17;
  15. /** @const */
  16. var DELIVERY_MODES = [
  17. "Fixed (0)",
  18. "Lowest Prio (1)",
  19. "SMI (2)",
  20. "Reserved (3)",
  21. "NMI (4)",
  22. "INIT (5)",
  23. "Reserved (6)",
  24. "ExtINT (7)",
  25. ];
  26. /** @const */
  27. var DESTINATION_MODES = ["physical", "logical"];
  28. /**
  29. * @constructor
  30. * @param {CPU} cpu
  31. */
  32. function APIC(cpu)
  33. {
  34. /** @type {CPU} */
  35. this.cpu = cpu;
  36. this.apic_id = 0;
  37. this.timer_divider = 0;
  38. this.timer_divider_shift = 1;
  39. this.timer_initial_count = 0;
  40. this.timer_current_count = 0;
  41. this.next_tick = v86.microtick();
  42. this.lvt_timer = IOAPIC_CONFIG_MASKED;
  43. this.lvt_perf_counter = IOAPIC_CONFIG_MASKED;
  44. this.lvt_int0 = IOAPIC_CONFIG_MASKED;
  45. this.lvt_int1 = IOAPIC_CONFIG_MASKED;
  46. this.lvt_error = IOAPIC_CONFIG_MASKED;
  47. this.tpr = 0;
  48. this.icr0 = 0;
  49. this.icr1 = 0;
  50. this.irr = new Int32Array(8);
  51. this.isr = new Int32Array(8);
  52. this.tmr = new Int32Array(8);
  53. this.spurious_vector = 0xFE;
  54. this.destination_format = -1;
  55. this.local_destination = 0;
  56. this.error = 0;
  57. this.read_error = 0;
  58. cpu.io.mmap_register(APIC_ADDRESS, 0x100000,
  59. (addr) =>
  60. {
  61. dbg_log("Unsupported read8 from apic: " + h(addr >>> 0), LOG_APIC);
  62. var off = addr & 3;
  63. addr &= ~3;
  64. return this.read32(addr) >> (off * 8) & 0xFF;
  65. },
  66. (addr, value) =>
  67. {
  68. dbg_log("Unsupported write8 from apic: " + h(addr) + " <- " + h(value), LOG_APIC);
  69. dbg_trace();
  70. dbg_assert(false);
  71. },
  72. (addr) => this.read32(addr),
  73. (addr, value) => this.write32(addr, value)
  74. );
  75. }
  76. APIC.prototype.read32 = function(addr)
  77. {
  78. addr = addr - APIC_ADDRESS | 0;
  79. switch(addr)
  80. {
  81. case 0x20:
  82. dbg_log("APIC read id", LOG_APIC);
  83. return this.apic_id;
  84. case 0x30:
  85. // version
  86. dbg_log("APIC read version", LOG_APIC);
  87. return 0x50014;
  88. case 0x80:
  89. APIC_LOG_VERBOSE && dbg_log("APIC read tpr", LOG_APIC);
  90. return this.tpr;
  91. case 0xD0:
  92. dbg_log("Read local destination", LOG_APIC);
  93. return this.local_destination;
  94. case 0xE0:
  95. dbg_log("Read destination format", LOG_APIC);
  96. return this.destination_format;
  97. case 0xF0:
  98. return this.spurious_vector;
  99. case 0x100:
  100. case 0x110:
  101. case 0x120:
  102. case 0x130:
  103. case 0x140:
  104. case 0x150:
  105. case 0x160:
  106. case 0x170:
  107. var index = addr - 0x100 >> 4;
  108. dbg_log("Read isr " + index + ": " + h(this.isr[index] >>> 0, 8), LOG_APIC);
  109. return this.isr[index];
  110. case 0x180:
  111. case 0x190:
  112. case 0x1A0:
  113. case 0x1B0:
  114. case 0x1C0:
  115. case 0x1D0:
  116. case 0x1E0:
  117. case 0x1F0:
  118. var index = addr - 0x180 >> 4;
  119. dbg_log("Read tmr " + index + ": " + h(this.tmr[index] >>> 0, 8), LOG_APIC);
  120. return this.tmr[index];
  121. case 0x200:
  122. case 0x210:
  123. case 0x220:
  124. case 0x230:
  125. case 0x240:
  126. case 0x250:
  127. case 0x260:
  128. case 0x270:
  129. var index = addr - 0x200 >> 4;
  130. dbg_log("Read irr " + index + ": " + h(this.irr[index] >>> 0, 8), LOG_APIC);
  131. return this.irr[index];
  132. case 0x280:
  133. dbg_log("Read error: " + h(this.read_error >>> 0, 8), LOG_APIC);
  134. return this.read_error;
  135. case 0x300:
  136. APIC_LOG_VERBOSE && dbg_log("APIC read icr0", LOG_APIC);
  137. return this.icr0;
  138. case 0x310:
  139. dbg_log("APIC read icr1", LOG_APIC);
  140. return this.icr1;
  141. case 0x320:
  142. dbg_log("read timer lvt", LOG_APIC);
  143. return this.lvt_timer;
  144. case 0x340:
  145. dbg_log("read lvt perf counter", LOG_APIC);
  146. return this.lvt_perf_counter;
  147. case 0x350:
  148. dbg_log("read lvt int0", LOG_APIC);
  149. return this.lvt_int0;
  150. case 0x360:
  151. dbg_log("read lvt int1", LOG_APIC);
  152. return this.lvt_int1;
  153. case 0x370:
  154. dbg_log("read lvt error", LOG_APIC);
  155. return this.lvt_error;
  156. case 0x3E0:
  157. // divider
  158. dbg_log("read timer divider", LOG_APIC);
  159. return this.timer_divider;
  160. case 0x380:
  161. dbg_log("read timer initial count", LOG_APIC);
  162. return this.timer_initial_count;
  163. case 0x390:
  164. dbg_log("read timer current count: " + h(this.timer_current_count >>> 0, 8), LOG_APIC);
  165. return this.timer_current_count;
  166. default:
  167. dbg_log("APIC read " + h(addr), LOG_APIC);
  168. dbg_assert(false);
  169. return 0;
  170. }
  171. };
  172. APIC.prototype.write32 = function(addr, value)
  173. {
  174. addr = addr - APIC_ADDRESS | 0;
  175. switch(addr)
  176. {
  177. case 0x30:
  178. // version
  179. dbg_log("APIC write version: " + h(value >>> 0, 8) + ", ignored", LOG_APIC);
  180. break;
  181. case 0x80:
  182. APIC_LOG_VERBOSE && dbg_log("Set tpr: " + h(value & 0xFF, 2), LOG_APIC);
  183. this.tpr = value & 0xFF;
  184. this.check_vector();
  185. break;
  186. case 0xB0:
  187. var highest_isr = this.highest_isr();
  188. if(highest_isr !== -1)
  189. {
  190. APIC_LOG_VERBOSE && dbg_log("eoi: " + h(value >>> 0, 8) + " for vector " + h(highest_isr), LOG_APIC);
  191. this.register_clear_bit(this.isr, highest_isr);
  192. if(this.register_get_bit(this.tmr, highest_isr))
  193. {
  194. // Send eoi to all IO APICs
  195. this.cpu.devices.ioapic.remote_eoi(highest_isr);
  196. }
  197. this.check_vector();
  198. }
  199. else
  200. {
  201. dbg_log("Bad eoi: No isr set", LOG_APIC);
  202. }
  203. break;
  204. case 0xD0:
  205. dbg_log("Set local destination: " + h(value >>> 0, 8), LOG_APIC);
  206. this.local_destination = value & 0xFF000000;
  207. break;
  208. case 0xE0:
  209. dbg_log("Set destination format: " + h(value >>> 0, 8), LOG_APIC);
  210. this.destination_format = value | 0xFFFFFF;
  211. break;
  212. case 0xF0:
  213. dbg_log("Set spurious vector: " + h(value >>> 0, 8), LOG_APIC);
  214. this.spurious_vector = value;
  215. break;
  216. case 0x280:
  217. // updated readable error register with real error
  218. dbg_log("Write error: " + h(value >>> 0, 8), LOG_APIC);
  219. this.read_error = this.error;
  220. this.error = 0;
  221. break;
  222. case 0x300:
  223. var vector = value & 0xFF;
  224. var delivery_mode = value >> 8 & 7;
  225. var destination_mode = value >> 11 & 1;
  226. var is_level = value >> 15 & 1;
  227. var destination_shorthand = value >> 18 & 3;
  228. var destination = this.icr1 >>> 24;
  229. dbg_log("APIC write icr0: " + h(value, 8) + " vector=" + h(vector, 2) + " " +
  230. "destination_mode=" + DESTINATION_MODES[destination_mode] + " delivery_mode=" + DELIVERY_MODES[delivery_mode] + " " +
  231. "destination_shorthand=" + ["no", "self", "all with self", "all without self"][destination_shorthand], LOG_APIC);
  232. value &= ~(1 << 12);
  233. this.icr0 = value;
  234. if(destination_shorthand === 0)
  235. {
  236. // no shorthand
  237. this.route(vector, delivery_mode, is_level, destination, destination_mode);
  238. }
  239. else if(destination_shorthand === 1)
  240. {
  241. // self
  242. this.deliver(vector, IOAPIC_DELIVERY_FIXED, is_level);
  243. }
  244. else if(destination_shorthand === 2)
  245. {
  246. // all including self
  247. this.deliver(vector, delivery_mode, is_level);
  248. }
  249. else if(destination_shorthand === 3)
  250. {
  251. // all but self
  252. }
  253. else
  254. {
  255. dbg_assert(false);
  256. }
  257. break;
  258. case 0x310:
  259. dbg_log("APIC write icr1: " + h(value >>> 0, 8), LOG_APIC);
  260. this.icr1 = value;
  261. break;
  262. case 0x320:
  263. dbg_log("timer lvt: " + h(value >>> 0, 8), LOG_APIC);
  264. this.lvt_timer = value;
  265. break;
  266. case 0x340:
  267. dbg_log("lvt perf counter: " + h(value >>> 0, 8), LOG_APIC);
  268. this.lvt_perf_counter = value;
  269. break;
  270. case 0x350:
  271. dbg_log("lvt int0: " + h(value >>> 0, 8), LOG_APIC);
  272. this.lvt_int0 = value;
  273. break;
  274. case 0x360:
  275. dbg_log("lvt int1: " + h(value >>> 0, 8), LOG_APIC);
  276. this.lvt_int1 = value;
  277. break;
  278. case 0x370:
  279. dbg_log("lvt error: " + h(value >>> 0, 8), LOG_APIC);
  280. this.lvt_error = value;
  281. break;
  282. case 0x3E0:
  283. dbg_log("timer divider: " + h(value >>> 0, 8), LOG_APIC);
  284. this.timer_divider = value;
  285. var divide_shift = value & 0b11 | (value & 0b1000) >> 1;
  286. this.timer_divider_shift = divide_shift === 0b111 ? 0 : divide_shift + 1;
  287. break;
  288. case 0x380:
  289. dbg_log("timer initial: " + h(value >>> 0, 8), LOG_APIC);
  290. this.timer_initial_count = value >>> 0;
  291. this.timer_current_count = value >>> 0;
  292. this.next_tick = v86.microtick();
  293. this.timer_active = true;
  294. break;
  295. case 0x390:
  296. dbg_log("timer current: " + h(value >>> 0, 8), LOG_APIC);
  297. dbg_assert(false, "read-only register");
  298. break;
  299. default:
  300. dbg_log("APIC write32 " + h(addr) + " <- " + h(value >>> 0, 8), LOG_APIC);
  301. dbg_assert(false);
  302. }
  303. };
  304. APIC.prototype.timer = function(now)
  305. {
  306. if(this.timer_current_count === 0)
  307. {
  308. return 100;
  309. }
  310. const freq = APIC_TIMER_FREQ / (1 << this.timer_divider_shift);
  311. const steps = (now - this.next_tick) * freq >>> 0;
  312. this.next_tick += steps / freq;
  313. this.timer_current_count -= steps;
  314. if(this.timer_current_count <= 0)
  315. {
  316. var mode = this.lvt_timer & APIC_TIMER_MODE_MASK;
  317. if(mode === APIC_TIMER_MODE_PERIODIC)
  318. {
  319. this.timer_current_count = this.timer_current_count % this.timer_initial_count;
  320. if(this.timer_current_count <= 0)
  321. {
  322. this.timer_current_count += this.timer_initial_count;
  323. }
  324. dbg_assert(this.timer_current_count !== 0);
  325. if((this.lvt_timer & IOAPIC_CONFIG_MASKED) === 0)
  326. {
  327. this.deliver(this.lvt_timer & 0xFF, IOAPIC_DELIVERY_FIXED, false);
  328. }
  329. }
  330. else if(mode === APIC_TIMER_MODE_ONE_SHOT)
  331. {
  332. this.timer_current_count = 0;
  333. dbg_log("APIC timer one shot end", LOG_APIC);
  334. if((this.lvt_timer & IOAPIC_CONFIG_MASKED) === 0)
  335. {
  336. this.deliver(this.lvt_timer & 0xFF, IOAPIC_DELIVERY_FIXED, false);
  337. }
  338. }
  339. }
  340. return Math.max(0, this.timer_current_count / freq);
  341. };
  342. APIC.prototype.route = function(vector, mode, is_level, destination, destination_mode)
  343. {
  344. // TODO
  345. this.deliver(vector, mode, is_level);
  346. };
  347. APIC.prototype.deliver = function(vector, mode, is_level)
  348. {
  349. APIC_LOG_VERBOSE && dbg_log("Deliver " + h(vector, 2) + " mode=" + mode + " level=" + is_level, LOG_APIC);
  350. if(mode === IOAPIC_DELIVERY_INIT)
  351. {
  352. // TODO
  353. return;
  354. }
  355. if(mode === IOAPIC_DELIVERY_NMI)
  356. {
  357. // TODO
  358. return;
  359. }
  360. if(vector < 0x10 || vector === 0xFF)
  361. {
  362. dbg_assert(false, "TODO: Invalid vector");
  363. }
  364. if(this.register_get_bit(this.irr, vector))
  365. {
  366. dbg_log("Not delivered: irr already set, vector=" + h(vector, 2), LOG_APIC);
  367. return;
  368. }
  369. this.register_set_bit(this.irr, vector);
  370. if(is_level)
  371. {
  372. this.register_set_bit(this.tmr, vector);
  373. }
  374. else
  375. {
  376. this.register_clear_bit(this.tmr, vector);
  377. }
  378. this.check_vector();
  379. };
  380. APIC.prototype.highest_irr = function()
  381. {
  382. var highest = this.register_get_highest_bit(this.irr);
  383. dbg_assert(highest !== 0xFF);
  384. dbg_assert(highest >= 0x10 || highest === -1);
  385. return highest;
  386. };
  387. APIC.prototype.highest_isr = function()
  388. {
  389. var highest = this.register_get_highest_bit(this.isr);
  390. dbg_assert(highest !== 0xFF);
  391. dbg_assert(highest >= 0x10 || highest === -1);
  392. return highest;
  393. };
  394. APIC.prototype.check_vector = function()
  395. {
  396. var highest_irr = this.highest_irr();
  397. if(highest_irr === -1)
  398. {
  399. return;
  400. }
  401. var highest_isr = this.highest_isr();
  402. if(highest_isr >= highest_irr)
  403. {
  404. APIC_LOG_VERBOSE && dbg_log("Higher isr, isr=" + h(highest_isr) + " irr=" + h(highest_irr), LOG_APIC);
  405. return;
  406. }
  407. if((highest_irr & 0xF0) <= (this.tpr & 0xF0))
  408. {
  409. APIC_LOG_VERBOSE && dbg_log("Higher tpr, tpr=" + h(this.tpr & 0xF0) + " irr=" + h(highest_irr), LOG_APIC);
  410. return;
  411. }
  412. this.cpu.handle_irqs();
  413. };
  414. APIC.prototype.acknowledge_irq = function()
  415. {
  416. var highest_irr = this.highest_irr();
  417. if(highest_irr === -1)
  418. {
  419. //dbg_log("Spurious", LOG_APIC);
  420. return -1;
  421. }
  422. var highest_isr = this.highest_isr();
  423. if(highest_isr >= highest_irr)
  424. {
  425. APIC_LOG_VERBOSE && dbg_log("Higher isr, isr=" + h(highest_isr) + " irr=" + h(highest_irr), LOG_APIC);
  426. return -1;
  427. }
  428. if((highest_irr & 0xF0) <= (this.tpr & 0xF0))
  429. {
  430. APIC_LOG_VERBOSE && dbg_log("Higher tpr, tpr=" + h(this.tpr & 0xF0) + " irr=" + h(highest_irr), LOG_APIC);
  431. return -1;
  432. }
  433. this.register_clear_bit(this.irr, highest_irr);
  434. this.register_set_bit(this.isr, highest_irr);
  435. APIC_LOG_VERBOSE && dbg_log("Calling vector " + h(highest_irr), LOG_APIC);
  436. this.check_vector();
  437. return highest_irr;
  438. };
  439. APIC.prototype.get_state = function()
  440. {
  441. var state = [];
  442. state[0] = this.apic_id;
  443. state[1] = this.timer_divider;
  444. state[2] = this.timer_divider_shift;
  445. state[3] = this.timer_initial_count;
  446. state[4] = this.timer_current_count;
  447. state[5] = this.next_tick;
  448. state[6] = this.lvt_timer;
  449. state[7] = this.lvt_perf_counter;
  450. state[8] = this.lvt_int0;
  451. state[9] = this.lvt_int1;
  452. state[10] = this.lvt_error;
  453. state[11] = this.tpr;
  454. state[12] = this.icr0;
  455. state[13] = this.icr1;
  456. state[14] = this.irr;
  457. state[15] = this.isr;
  458. state[16] = this.tmr;
  459. state[17] = this.spurious_vector;
  460. state[18] = this.destination_format;
  461. state[19] = this.local_destination;
  462. state[20] = this.error;
  463. state[21] = this.read_error;
  464. return state;
  465. };
  466. APIC.prototype.set_state = function(state)
  467. {
  468. this.apic_id = state[0];
  469. this.timer_divider = state[1];
  470. this.timer_divider_shift = state[2];
  471. this.timer_initial_count = state[3];
  472. this.timer_current_count = state[4];
  473. this.next_tick = state[5];
  474. this.lvt_timer = state[6];
  475. this.lvt_perf_counter = state[7];
  476. this.lvt_int0 = state[8];
  477. this.lvt_int1 = state[9];
  478. this.lvt_error = state[10];
  479. this.tpr = state[11];
  480. this.icr0 = state[12];
  481. this.icr1 = state[13];
  482. this.irr = state[14];
  483. this.isr = state[15];
  484. this.tmr = state[16];
  485. this.spurious_vector = state[17];
  486. this.destination_format = state[18];
  487. this.local_destination = state[19];
  488. this.error = state[20];
  489. this.read_error = state[21];
  490. };
  491. // functions operating on 256-bit registers (for irr, isr, tmr)
  492. APIC.prototype.register_get_bit = function(v, bit)
  493. {
  494. dbg_assert(bit >= 0 && bit < 256);
  495. return v[bit >> 5] >> (bit & 31) & 1;
  496. };
  497. APIC.prototype.register_set_bit = function(v, bit)
  498. {
  499. dbg_assert(bit >= 0 && bit < 256);
  500. v[bit >> 5] |= 1 << (bit & 31);
  501. };
  502. APIC.prototype.register_clear_bit = function(v, bit)
  503. {
  504. dbg_assert(bit >= 0 && bit < 256);
  505. v[bit >> 5] &= ~(1 << (bit & 31));
  506. };
  507. APIC.prototype.register_get_highest_bit = function(v)
  508. {
  509. for(var i = 7; i >= 0; i--)
  510. {
  511. var word = v[i];
  512. if(word)
  513. {
  514. return v86util.int_log2(word >>> 0) | i << 5;
  515. }
  516. }
  517. return -1;
  518. };