cpu.js 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529
  1. "use strict";
  2. /** @const */
  3. var CPU_LOG_VERBOSE = false;
  4. // Resources:
  5. // https://pdos.csail.mit.edu/6.828/2006/readings/i386/toc.htm
  6. // https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
  7. // http://ref.x86asm.net/geek32.html
  8. /** @constructor */
  9. function CPU(bus, wm, next_tick_immediately)
  10. {
  11. this.next_tick_immediately = next_tick_immediately;
  12. this.wm = wm;
  13. this.wasm_patch();
  14. this.create_jit_imports();
  15. const memory = this.wm.exports.memory;
  16. this.wasm_memory = memory;
  17. this.memory_size = v86util.view(Uint32Array, memory, 812, 1);
  18. this.mem8 = new Uint8Array(0);
  19. this.mem32s = new Int32Array(this.mem8.buffer);
  20. this.segment_is_null = v86util.view(Uint8Array, memory, 724, 8);
  21. this.segment_offsets = v86util.view(Int32Array, memory, 736, 8);
  22. this.segment_limits = v86util.view(Uint32Array, memory, 768, 8);
  23. /**
  24. * Wheter or not in protected mode
  25. */
  26. this.protected_mode = v86util.view(Int32Array, memory, 800, 1);
  27. this.idtr_size = v86util.view(Int32Array, memory, 564, 1);
  28. this.idtr_offset = v86util.view(Int32Array, memory, 568, 1);
  29. /**
  30. * global descriptor table register
  31. */
  32. this.gdtr_size = v86util.view(Int32Array, memory, 572, 1);
  33. this.gdtr_offset = v86util.view(Int32Array, memory, 576, 1);
  34. this.tss_size_32 = v86util.view(Int32Array, memory, 1128, 1);
  35. /*
  36. * whether or not a page fault occured
  37. */
  38. this.page_fault = v86util.view(Uint32Array, memory, 540, 8);
  39. this.cr = v86util.view(Int32Array, memory, 580, 8);
  40. // current privilege level
  41. this.cpl = v86util.view(Uint8Array, memory, 612, 1);
  42. // current operand/address size
  43. this.is_32 = v86util.view(Int32Array, memory, 804, 1);
  44. this.stack_size_32 = v86util.view(Int32Array, memory, 808, 1);
  45. /**
  46. * Was the last instruction a hlt?
  47. */
  48. this.in_hlt = v86util.view(Uint8Array, memory, 616, 1);
  49. this.last_virt_eip = v86util.view(Int32Array, memory, 620, 1);
  50. this.eip_phys = v86util.view(Int32Array, memory, 624, 1);
  51. this.sysenter_cs = v86util.view(Int32Array, memory, 636, 1);
  52. this.sysenter_esp = v86util.view(Int32Array, memory, 640, 1);
  53. this.sysenter_eip = v86util.view(Int32Array, memory, 644, 1);
  54. this.prefixes = v86util.view(Int32Array, memory, 648, 1);
  55. this.flags = v86util.view(Int32Array, memory, 120, 1);
  56. /**
  57. * bitmap of flags which are not updated in the flags variable
  58. * changed by arithmetic instructions, so only relevant to arithmetic flags
  59. */
  60. this.flags_changed = v86util.view(Int32Array, memory, 100, 1);
  61. /**
  62. * enough infos about the last arithmetic operation to compute eflags
  63. */
  64. this.last_op_size = v86util.view(Int32Array, memory, 96, 1);
  65. this.last_op1 = v86util.view(Int32Array, memory, 104, 1);
  66. this.last_result = v86util.view(Int32Array, memory, 112, 1);
  67. this.current_tsc = v86util.view(Uint32Array, memory, 960, 2); // 64 bit
  68. /** @type {!Object} */
  69. this.devices = {};
  70. this.instruction_pointer = v86util.view(Int32Array, memory, 556, 1);
  71. this.previous_ip = v86util.view(Int32Array, memory, 560, 1);
  72. // configured by guest
  73. this.apic_enabled = v86util.view(Uint8Array, memory, 548, 1);
  74. // configured when the emulator starts (changes bios initialisation)
  75. this.acpi_enabled = v86util.view(Uint8Array, memory, 552, 1);
  76. // managed in io.js
  77. /** @const */ this.memory_map_read8 = [];
  78. /** @const */ this.memory_map_write8 = [];
  79. /** @const */ this.memory_map_read32 = [];
  80. /** @const */ this.memory_map_write32 = [];
  81. /**
  82. * @const
  83. * @type {{main: ArrayBuffer, vga: ArrayBuffer}}
  84. */
  85. this.bios = {
  86. main: null,
  87. vga: null,
  88. };
  89. this.instruction_counter = v86util.view(Uint32Array, memory, 664, 1);
  90. // registers
  91. this.reg32 = v86util.view(Int32Array, memory, 64, 8);
  92. this.fpu_st = v86util.view(Int32Array, memory, 1152, 4 * 8);
  93. this.fpu_stack_empty = v86util.view(Uint8Array, memory, 816, 1);
  94. this.fpu_stack_empty[0] = 0xFF;
  95. this.fpu_stack_ptr = v86util.view(Uint8Array, memory, 1032, 1);
  96. this.fpu_stack_ptr[0] = 0;
  97. this.fpu_control_word = v86util.view(Uint16Array, memory, 1036, 1);
  98. this.fpu_control_word[0] = 0x37F;
  99. this.fpu_status_word = v86util.view(Uint16Array, memory, 1040, 1);
  100. this.fpu_status_word[0] = 0;
  101. this.fpu_ip = v86util.view(Int32Array, memory, 1048, 1);
  102. this.fpu_ip[0] = 0;
  103. this.fpu_ip_selector = v86util.view(Int32Array, memory, 1052, 1);
  104. this.fpu_ip_selector[0] = 0;
  105. this.fpu_opcode = v86util.view(Int32Array, memory, 1044, 1);
  106. this.fpu_opcode[0] = 0;
  107. this.fpu_dp = v86util.view(Int32Array, memory, 1056, 1);
  108. this.fpu_dp[0] = 0;
  109. this.fpu_dp_selector = v86util.view(Int32Array, memory, 1060, 1);
  110. this.fpu_dp_selector[0] = 0;
  111. this.reg_xmm32s = v86util.view(Int32Array, memory, 832, 8 * 4);
  112. this.mxcsr = v86util.view(Int32Array, memory, 824, 1);
  113. // segment registers, tr and ldtr
  114. this.sreg = v86util.view(Uint16Array, memory, 668, 8);
  115. // debug registers
  116. this.dreg = v86util.view(Int32Array, memory, 684, 8);
  117. this.reg_pdpte = v86util.view(Int32Array, memory, 968, 8);
  118. this.svga_dirty_bitmap_min_offset = v86util.view(Uint32Array, memory, 716, 1);
  119. this.svga_dirty_bitmap_max_offset = v86util.view(Uint32Array, memory, 720, 1);
  120. this.fw_value = [];
  121. this.fw_pointer = 0;
  122. this.option_roms = [];
  123. this.io = undefined;
  124. this.bus = bus;
  125. this.set_tsc(0, 0);
  126. this.debug_init();
  127. if(DEBUG)
  128. {
  129. this.do_many_cycles_count = 0;
  130. this.do_many_cycles_total = 0;
  131. this.seen_code = {};
  132. this.seen_code_uncompiled = {};
  133. }
  134. //Object.seal(this);
  135. }
  136. CPU.prototype.clear_opstats = function()
  137. {
  138. new Uint8Array(this.wasm_memory.buffer, 0x8000, 0x20000).fill(0);
  139. this.wm.exports["profiler_init"]();
  140. };
  141. CPU.prototype.create_jit_imports = function()
  142. {
  143. // Set this.jit_imports as generated WASM modules will expect
  144. const jit_imports = Object.create(null);
  145. jit_imports["m"] = this.wm.exports["memory"];
  146. for(let name of Object.keys(this.wm.exports))
  147. {
  148. if(name.startsWith("_") || name.startsWith("zstd") || name.endsWith("_js"))
  149. {
  150. continue;
  151. }
  152. jit_imports[name] = this.wm.exports[name];
  153. }
  154. this.jit_imports = jit_imports;
  155. };
  156. CPU.prototype.wasm_patch = function()
  157. {
  158. const get_optional_import = (name) => {
  159. return this.wm.exports[name];
  160. };
  161. const get_import = (name) =>
  162. {
  163. const f = get_optional_import(name);
  164. console.assert(f, "Missing import: " + name);
  165. return f;
  166. };
  167. this.reset_cpu = get_import("reset_cpu");
  168. this.getiopl = get_import("getiopl");
  169. this.get_eflags = get_import("get_eflags");
  170. this.get_eflags_no_arith = get_import("get_eflags_no_arith");
  171. this.pic_call_irq = get_import("pic_call_irq");
  172. this.do_many_cycles_native = get_import("do_many_cycles_native");
  173. this.cycle_internal = get_import("cycle_internal");
  174. this.read8 = get_import("read8");
  175. this.read16 = get_import("read16");
  176. this.read32s = get_import("read32s");
  177. this.write8 = get_import("write8");
  178. this.write16 = get_import("write16");
  179. this.write32 = get_import("write32");
  180. this.in_mapped_range = get_import("in_mapped_range");
  181. // used by nasmtests
  182. this.fpu_load_tag_word = get_import("fpu_load_tag_word");
  183. this.fpu_load_status_word = get_import("fpu_load_status_word");
  184. this.fpu_get_sti_f64 = get_import("fpu_get_sti_f64");
  185. this.translate_address_system_read = get_import("translate_address_system_read_js");
  186. this.get_seg_cs = get_import("get_seg_cs");
  187. this.get_real_eip = get_import("get_real_eip");
  188. this.clear_tlb = get_import("clear_tlb");
  189. this.full_clear_tlb = get_import("full_clear_tlb");
  190. this.update_state_flags = get_import("update_state_flags");
  191. this.set_tsc = get_import("set_tsc");
  192. this.store_current_tsc = get_import("store_current_tsc");
  193. this.set_cpuid_level = get_import("set_cpuid_level");
  194. if(DEBUG)
  195. {
  196. this.jit_force_generate_unsafe = get_optional_import("jit_force_generate_unsafe");
  197. }
  198. this.jit_clear_cache = get_import("jit_clear_cache_js");
  199. this.jit_dirty_cache = get_import("jit_dirty_cache");
  200. this.codegen_finalize_finished = get_import("codegen_finalize_finished");
  201. this.allocate_memory = get_import("allocate_memory");
  202. this.zero_memory = get_import("zero_memory");
  203. this.svga_allocate_memory = get_import("svga_allocate_memory");
  204. this.svga_allocate_dest_buffer = get_import("svga_allocate_dest_buffer");
  205. this.svga_fill_pixel_buffer = get_import("svga_fill_pixel_buffer");
  206. this.svga_mark_dirty = get_import("svga_mark_dirty");
  207. this.zstd_create_ctx = get_import("zstd_create_ctx");
  208. this.zstd_get_src_ptr = get_import("zstd_get_src_ptr");
  209. this.zstd_free_ctx = get_import("zstd_free_ctx");
  210. this.zstd_read = get_import("zstd_read");
  211. this.zstd_read_free = get_import("zstd_read_free");
  212. };
  213. CPU.prototype.jit_force_generate = function(addr)
  214. {
  215. if(!this.jit_force_generate_unsafe)
  216. {
  217. dbg_assert(false, "Not supported in this wasm build: jit_force_generate_unsafe");
  218. return;
  219. }
  220. this.jit_force_generate_unsafe(addr);
  221. };
  222. CPU.prototype.jit_clear_func = function(index)
  223. {
  224. dbg_assert(index >= 0 && index < WASM_TABLE_SIZE);
  225. this.wm.wasm_table.set(index + WASM_TABLE_OFFSET, null);
  226. };
  227. CPU.prototype.jit_clear_all_funcs = function()
  228. {
  229. const table = this.wm.wasm_table;
  230. for(let i = 0; i < WASM_TABLE_SIZE; i++)
  231. {
  232. table.set(WASM_TABLE_OFFSET + i, null);
  233. }
  234. };
  235. CPU.prototype.get_state = function()
  236. {
  237. var state = [];
  238. state[0] = this.memory_size[0];
  239. state[1] = this.segment_is_null;
  240. state[2] = this.segment_offsets;
  241. state[3] = this.segment_limits;
  242. state[4] = this.protected_mode[0];
  243. state[5] = this.idtr_offset[0];
  244. state[6] = this.idtr_size[0];
  245. state[7] = this.gdtr_offset[0];
  246. state[8] = this.gdtr_size[0];
  247. state[9] = this.page_fault[0];
  248. state[10] = this.cr;
  249. state[11] = this.cpl[0];
  250. state[13] = this.is_32[0];
  251. state[16] = this.stack_size_32[0];
  252. state[17] = this.in_hlt[0];
  253. state[18] = this.last_virt_eip[0];
  254. state[19] = this.eip_phys[0];
  255. state[22] = this.sysenter_cs[0];
  256. state[23] = this.sysenter_eip[0];
  257. state[24] = this.sysenter_esp[0];
  258. state[25] = this.prefixes[0];
  259. state[26] = this.flags[0];
  260. state[27] = this.flags_changed[0];
  261. state[28] = this.last_op1[0];
  262. state[30] = this.last_op_size[0];
  263. state[37] = this.instruction_pointer[0];
  264. state[38] = this.previous_ip[0];
  265. state[39] = this.reg32;
  266. state[40] = this.sreg;
  267. state[41] = this.dreg;
  268. state[42] = this.reg_pdpte;
  269. this.store_current_tsc();
  270. state[43] = this.current_tsc;
  271. state[45] = this.devices.virtio_9p;
  272. state[46] = this.devices.apic;
  273. state[47] = this.devices.rtc;
  274. state[48] = this.devices.pci;
  275. state[49] = this.devices.dma;
  276. state[50] = this.devices.acpi;
  277. state[51] = this.devices.hpet;
  278. state[52] = this.devices.vga;
  279. state[53] = this.devices.ps2;
  280. state[54] = this.devices.uart0;
  281. state[55] = this.devices.fdc;
  282. state[56] = this.devices.cdrom;
  283. state[57] = this.devices.hda;
  284. state[58] = this.devices.pit;
  285. state[59] = this.devices.net;
  286. state[60] = this.devices.pic;
  287. state[61] = this.devices.sb16;
  288. state[62] = this.fw_value;
  289. state[63] = this.devices.ioapic;
  290. state[64] = this.tss_size_32[0];
  291. state[66] = this.reg_xmm32s;
  292. state[67] = this.fpu_st;
  293. state[68] = this.fpu_stack_empty[0];
  294. state[69] = this.fpu_stack_ptr[0];
  295. state[70] = this.fpu_control_word[0];
  296. state[71] = this.fpu_ip[0];
  297. state[72] = this.fpu_ip_selector[0];
  298. state[73] = this.fpu_dp[0];
  299. state[74] = this.fpu_dp_selector[0];
  300. state[75] = this.fpu_opcode[0];
  301. const { packed_memory, bitmap } = this.pack_memory();
  302. state[77] = packed_memory;
  303. state[78] = new Uint8Array(bitmap.get_buffer());
  304. state[79] = this.devices.uart1;
  305. state[80] = this.devices.uart2;
  306. state[81] = this.devices.uart3;
  307. return state;
  308. };
  309. CPU.prototype.set_state = function(state)
  310. {
  311. this.memory_size[0] = state[0];
  312. if(this.mem8.length !== this.memory_size[0])
  313. {
  314. console.warn("Note: Memory size mismatch. we=" + this.mem8.length + " state=" + this.memory_size[0]);
  315. }
  316. this.segment_is_null.set(state[1]);
  317. this.segment_offsets.set(state[2]);
  318. this.segment_limits.set(state[3]);
  319. this.protected_mode[0] = state[4];
  320. this.idtr_offset[0] = state[5];
  321. this.idtr_size[0] = state[6];
  322. this.gdtr_offset[0] = state[7];
  323. this.gdtr_size[0] = state[8];
  324. this.page_fault[0] = state[9];
  325. this.cr.set(state[10]);
  326. this.cpl[0] = state[11];
  327. this.is_32[0] = state[13];
  328. this.stack_size_32[0] = state[16];
  329. this.in_hlt[0] = state[17];
  330. this.last_virt_eip[0] = state[18];
  331. this.eip_phys[0] = state[19];
  332. this.sysenter_cs[0] = state[22];
  333. this.sysenter_eip[0] = state[23];
  334. this.sysenter_esp[0] = state[24];
  335. this.prefixes[0] = state[25];
  336. this.flags[0] = state[26];
  337. this.flags_changed[0] = state[27];
  338. this.last_op1[0] = state[28];
  339. this.last_op_size[0] = state[30];
  340. this.instruction_pointer[0] = state[37];
  341. this.previous_ip[0] = state[38];
  342. this.reg32.set(state[39]);
  343. this.sreg.set(state[40]);
  344. this.dreg.set(state[41]);
  345. state[42] && this.reg_pdpte.set(state[42]);
  346. this.set_tsc(state[43][0], state[43][1]);
  347. this.devices.virtio_9p && this.devices.virtio_9p.set_state(state[45]);
  348. this.devices.apic && this.devices.apic.set_state(state[46]);
  349. this.devices.rtc && this.devices.rtc.set_state(state[47]);
  350. this.devices.pci && this.devices.pci.set_state(state[48]);
  351. this.devices.dma && this.devices.dma.set_state(state[49]);
  352. this.devices.acpi && this.devices.acpi.set_state(state[50]);
  353. this.devices.hpet && this.devices.hpet.set_state(state[51]);
  354. this.devices.vga && this.devices.vga.set_state(state[52]);
  355. this.devices.ps2 && this.devices.ps2.set_state(state[53]);
  356. this.devices.uart0 && this.devices.uart0.set_state(state[54]);
  357. this.devices.fdc && this.devices.fdc.set_state(state[55]);
  358. this.devices.cdrom && this.devices.cdrom.set_state(state[56]);
  359. this.devices.hda && this.devices.hda.set_state(state[57]);
  360. this.devices.pit && this.devices.pit.set_state(state[58]);
  361. this.devices.net && this.devices.net.set_state(state[59]);
  362. this.devices.pic && this.devices.pic.set_state(state[60]);
  363. this.devices.sb16 && this.devices.sb16.set_state(state[61]);
  364. this.devices.uart1 && this.devices.uart1.set_state(state[79]);
  365. this.devices.uart2 && this.devices.uart2.set_state(state[80]);
  366. this.devices.uart3 && this.devices.uart3.set_state(state[81]);
  367. this.fw_value = state[62];
  368. this.devices.ioapic && this.devices.ioapic.set_state(state[63]);
  369. this.tss_size_32[0] = state[64];
  370. this.reg_xmm32s.set(state[66]);
  371. this.fpu_st.set(state[67]);
  372. this.fpu_stack_empty[0] = state[68];
  373. this.fpu_stack_ptr[0] = state[69];
  374. this.fpu_control_word[0] = state[70];
  375. this.fpu_ip[0] = state[71];
  376. this.fpu_ip_selector[0] = state[72];
  377. this.fpu_dp[0] = state[73];
  378. this.fpu_dp_selector[0] = state[74];
  379. this.fpu_opcode[0] = state[75];
  380. const bitmap = new v86util.Bitmap(state[78].buffer);
  381. const packed_memory = state[77];
  382. this.unpack_memory(bitmap, packed_memory);
  383. this.update_state_flags();
  384. this.full_clear_tlb();
  385. this.jit_clear_cache();
  386. };
  387. CPU.prototype.pack_memory = function()
  388. {
  389. dbg_assert((this.mem8.length & 0xFFF) === 0);
  390. const page_count = this.mem8.length >> 12;
  391. const nonzero_pages = [];
  392. for(let page = 0; page < page_count; page++)
  393. {
  394. const offset = page << 12;
  395. const view = this.mem32s.subarray(offset >> 2, offset + 0x1000 >> 2);
  396. let is_zero = true;
  397. for(let i = 0; i < view.length; i++)
  398. {
  399. if(view[i] !== 0)
  400. {
  401. is_zero = false;
  402. break;
  403. }
  404. }
  405. if(!is_zero)
  406. {
  407. nonzero_pages.push(page);
  408. }
  409. }
  410. const bitmap = new v86util.Bitmap(page_count);
  411. const packed_memory = new Uint8Array(nonzero_pages.length << 12);
  412. for(let [i, page] of nonzero_pages.entries())
  413. {
  414. bitmap.set(page, 1);
  415. const offset = page << 12;
  416. const page_contents = this.mem8.subarray(offset, offset + 0x1000);
  417. packed_memory.set(page_contents, i << 12);
  418. }
  419. return { bitmap, packed_memory };
  420. };
  421. CPU.prototype.unpack_memory = function(bitmap, packed_memory)
  422. {
  423. this.zero_memory(this.memory_size[0]);
  424. const page_count = this.memory_size[0] >> 12;
  425. let packed_page = 0;
  426. for(let page = 0; page < page_count; page++)
  427. {
  428. if(bitmap.get(page))
  429. {
  430. let offset = packed_page << 12;
  431. let view = packed_memory.subarray(offset, offset + 0x1000);
  432. this.mem8.set(view, page << 12);
  433. packed_page++;
  434. }
  435. }
  436. };
  437. /**
  438. * @return {number} time in ms until this method should becalled again
  439. */
  440. CPU.prototype.main_run = function()
  441. {
  442. if(this.in_hlt[0])
  443. {
  444. const t = this.hlt_loop();
  445. if(this.in_hlt[0])
  446. {
  447. return t;
  448. }
  449. }
  450. const start = v86.microtick();
  451. let now = start;
  452. for(; now - start < TIME_PER_FRAME;)
  453. {
  454. this.do_many_cycles();
  455. now = v86.microtick();
  456. const t = this.run_hardware_timers(now);
  457. this.handle_irqs();
  458. if(this.in_hlt[0])
  459. {
  460. return t;
  461. }
  462. }
  463. return 0;
  464. };
  465. CPU.prototype.reboot_internal = function()
  466. {
  467. this.reset_cpu();
  468. this.fw_value = [];
  469. if(this.devices.virtio)
  470. {
  471. this.devices.virtio.reset();
  472. }
  473. this.load_bios();
  474. };
  475. CPU.prototype.reset_memory = function()
  476. {
  477. this.mem8.fill(0);
  478. };
  479. /** @export */
  480. CPU.prototype.create_memory = function(size)
  481. {
  482. if(size < 1024 * 1024)
  483. {
  484. size = 1024 * 1024;
  485. }
  486. else if((size | 0) < 0)
  487. {
  488. size = Math.pow(2, 31) - MMAP_BLOCK_SIZE;
  489. }
  490. size = ((size - 1) | (MMAP_BLOCK_SIZE - 1)) + 1 | 0;
  491. dbg_assert((size | 0) > 0);
  492. dbg_assert((size & MMAP_BLOCK_SIZE - 1) === 0);
  493. console.assert(this.memory_size[0] === 0, "Expected uninitialised memory");
  494. this.memory_size[0] = size;
  495. const memory_offset = this.allocate_memory(size);
  496. this.mem8 = v86util.view(Uint8Array, this.wasm_memory, memory_offset, size);
  497. this.mem32s = v86util.view(Uint32Array, this.wasm_memory, memory_offset, size >> 2);
  498. };
  499. CPU.prototype.init = function(settings, device_bus)
  500. {
  501. if(typeof settings.log_level === "number")
  502. {
  503. // XXX: Shared between all emulator instances
  504. LOG_LEVEL = settings.log_level;
  505. }
  506. this.create_memory(typeof settings.memory_size === "number" ?
  507. settings.memory_size : 1024 * 1024 * 64);
  508. settings.cpuid_level && this.set_cpuid_level(settings.cpuid_level);
  509. this.acpi_enabled[0] = +settings.acpi;
  510. this.reset_cpu();
  511. var io = new IO(this);
  512. this.io = io;
  513. this.bios.main = settings.bios;
  514. this.bios.vga = settings.vga_bios;
  515. this.load_bios();
  516. if(settings.bzimage)
  517. {
  518. const { option_rom } = load_kernel(this.mem8, settings.bzimage, settings.initrd, settings.cmdline || "");
  519. if(option_rom)
  520. {
  521. this.option_roms.push(option_rom);
  522. }
  523. }
  524. io.register_read(0xB3, this, function()
  525. {
  526. // seabios smm_relocate_and_restore
  527. dbg_log("port 0xB3 read");
  528. return 0;
  529. });
  530. var a20_byte = 0;
  531. io.register_read(0x92, this, function()
  532. {
  533. return a20_byte;
  534. });
  535. io.register_write(0x92, this, function(out_byte)
  536. {
  537. a20_byte = out_byte;
  538. });
  539. io.register_read(0x511, this, function()
  540. {
  541. // bios config port (used by seabios and kvm-unit-test)
  542. if(this.fw_pointer < this.fw_value.length)
  543. {
  544. return this.fw_value[this.fw_pointer++];
  545. }
  546. else
  547. {
  548. dbg_assert(false, "config port: Read past value");
  549. return 0;
  550. }
  551. });
  552. io.register_write(0x510, this, undefined, function(value)
  553. {
  554. // https://wiki.osdev.org/QEMU_fw_cfg
  555. // https://github.com/qemu/qemu/blob/master/docs/specs/fw_cfg.txt
  556. dbg_log("bios config port, index=" + h(value));
  557. function i32(x)
  558. {
  559. return new Uint8Array(new Int32Array([x]).buffer);
  560. }
  561. function to_be16(x)
  562. {
  563. return x >> 8 | x << 8 & 0xFF00;
  564. }
  565. function to_be32(x)
  566. {
  567. return x << 24 | x << 8 & 0xFF0000 | x >> 8 & 0xFF00 | x >>> 24;
  568. }
  569. this.fw_pointer = 0;
  570. if(value === FW_CFG_SIGNATURE)
  571. {
  572. // Pretend to be qemu (for seabios)
  573. this.fw_value = i32(FW_CFG_SIGNATURE_QEMU);
  574. }
  575. else if(value === FW_CFG_ID)
  576. {
  577. this.fw_value = i32(0);
  578. }
  579. else if(value === FW_CFG_RAM_SIZE)
  580. {
  581. this.fw_value = i32(this.memory_size[0]);
  582. }
  583. else if(value === FW_CFG_NB_CPUS)
  584. {
  585. this.fw_value = i32(1);
  586. }
  587. else if(value === FW_CFG_MAX_CPUS)
  588. {
  589. this.fw_value = i32(1);
  590. }
  591. else if(value === FW_CFG_NUMA)
  592. {
  593. this.fw_value = new Uint8Array(16);
  594. }
  595. else if(value === FW_CFG_FILE_DIR)
  596. {
  597. const buffer_size = 4 + 64 * this.option_roms.length;
  598. const buffer32 = new Int32Array(buffer_size);
  599. const buffer8 = new Uint8Array(buffer32.buffer);
  600. buffer32[0] = to_be32(this.option_roms.length);
  601. for(let i = 0; i < this.option_roms.length; i++)
  602. {
  603. const { name, data } = this.option_roms[i];
  604. const file_struct_ptr = 4 + 64 * i;
  605. dbg_assert(FW_CFG_FILE_START + i < 0x10000);
  606. buffer32[file_struct_ptr + 0 >> 2] = to_be32(data.length);
  607. buffer32[file_struct_ptr + 4 >> 2] = to_be16(FW_CFG_FILE_START + i);
  608. dbg_assert(name.length < 64 - 8);
  609. for(let j = 0; j < name.length; j++)
  610. {
  611. buffer8[file_struct_ptr + 8 + j] = name.charCodeAt(j);
  612. }
  613. }
  614. this.fw_value = buffer8;
  615. }
  616. else if(value >= FW_CFG_CUSTOM_START && value < FW_CFG_FILE_START)
  617. {
  618. this.fw_value = i32(0);
  619. }
  620. else if(value >= FW_CFG_FILE_START && value - FW_CFG_FILE_START < this.option_roms.length)
  621. {
  622. const i = value - FW_CFG_FILE_START;
  623. this.fw_value = this.option_roms[i].data;
  624. }
  625. else
  626. {
  627. dbg_log("Warning: Unimplemented fw index: " + h(value));
  628. this.fw_value = i32(0);
  629. }
  630. });
  631. if(DEBUG)
  632. {
  633. // Avoid logging noisey ports
  634. io.register_write(0x80, this, function(out_byte) {});
  635. io.register_read(0x80, this, function() { return 0xFF; });
  636. io.register_write(0xE9, this, function(out_byte) {});
  637. }
  638. this.devices = {};
  639. // TODO: Make this more configurable
  640. if(settings.load_devices)
  641. {
  642. this.devices.pic = new PIC(this);
  643. this.devices.pci = new PCI(this);
  644. if(this.acpi_enabled[0])
  645. {
  646. this.devices.ioapic = new IOAPIC(this);
  647. this.devices.apic = new APIC(this);
  648. this.devices.acpi = new ACPI(this);
  649. }
  650. this.devices.rtc = new RTC(this);
  651. this.fill_cmos(this.devices.rtc, settings);
  652. this.devices.dma = new DMA(this);
  653. if(ENABLE_HPET)
  654. {
  655. this.devices.hpet = new HPET(this);
  656. }
  657. this.devices.vga = new VGAScreen(this, device_bus,
  658. settings.vga_memory_size || 8 * 1024 * 1024);
  659. this.devices.ps2 = new PS2(this, device_bus);
  660. this.devices.uart0 = new UART(this, 0x3F8, device_bus);
  661. if(settings.uart1)
  662. {
  663. this.devices.uart1 = new UART(this, 0x2F8, device_bus);
  664. }
  665. if(settings.uart2)
  666. {
  667. this.devices.uart2 = new UART(this, 0x3E8, device_bus);
  668. }
  669. if(settings.uart3)
  670. {
  671. this.devices.uart3 = new UART(this, 0x2E8, device_bus);
  672. }
  673. this.devices.fdc = new FloppyController(this, settings.fda, settings.fdb);
  674. var ide_device_count = 0;
  675. if(settings.hda)
  676. {
  677. this.devices.hda = new IDEDevice(this, settings.hda, settings.hdb, false, ide_device_count++, device_bus);
  678. }
  679. if(settings.cdrom)
  680. {
  681. this.devices.cdrom = new IDEDevice(this, settings.cdrom, undefined, true, ide_device_count++, device_bus);
  682. }
  683. this.devices.pit = new PIT(this, device_bus);
  684. if(settings.enable_ne2k)
  685. {
  686. this.devices.net = new Ne2k(this, device_bus, settings.preserve_mac_from_state_image, settings.mac_address_translation);
  687. }
  688. if(settings.fs9p)
  689. {
  690. this.devices.virtio_9p = new Virtio9p(settings.fs9p, this, device_bus);
  691. }
  692. if(true)
  693. {
  694. this.devices.sb16 = new SB16(this, device_bus);
  695. }
  696. }
  697. if(settings.multiboot)
  698. {
  699. this.load_multiboot(settings.multiboot);
  700. }
  701. if(DEBUG)
  702. {
  703. this.debug.init();
  704. }
  705. };
  706. CPU.prototype.load_multiboot = function(buffer)
  707. {
  708. // https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
  709. dbg_log("Trying multiboot from buffer of size " + buffer.byteLength, LOG_CPU);
  710. const MAGIC = 0x1BADB002;
  711. const ELF_MAGIC = 0x464C457F;
  712. const MULTIBOOT_HEADER_ADDRESS = 0x10000;
  713. const MULTIBOOT_SEARCH_BYTES = 8192;
  714. if(buffer.byteLength < MULTIBOOT_SEARCH_BYTES)
  715. {
  716. var buf32 = new Int32Array(MULTIBOOT_SEARCH_BYTES / 4);
  717. new Uint8Array(buf32.buffer).set(new Uint8Array(buffer));
  718. }
  719. else
  720. {
  721. var buf32 = new Int32Array(buffer, 0, MULTIBOOT_SEARCH_BYTES / 4);
  722. }
  723. for(var offset = 0; offset < MULTIBOOT_SEARCH_BYTES; offset += 4)
  724. {
  725. if(buf32[offset >> 2] === MAGIC)
  726. {
  727. var flags = buf32[offset + 4 >> 2];
  728. var checksum = buf32[offset + 8 >> 2];
  729. var total = MAGIC + flags + checksum | 0;
  730. if(total)
  731. {
  732. dbg_log("Multiboot checksum check failed", LOG_CPU);
  733. continue;
  734. }
  735. }
  736. else
  737. {
  738. continue;
  739. }
  740. dbg_log("Multiboot magic found, flags: " + h(flags >>> 0, 8), LOG_CPU);
  741. dbg_assert((flags & ~MULTIBOOT_HEADER_ADDRESS) === 0, "TODO");
  742. this.reg32[REG_EAX] = 0x2BADB002;
  743. let multiboot_info_addr = 0x7C00;
  744. this.reg32[REG_EBX] = multiboot_info_addr;
  745. this.write32(multiboot_info_addr, 0);
  746. this.cr[0] = 1;
  747. this.protected_mode[0] = +true;
  748. this.flags[0] = FLAGS_DEFAULT;
  749. this.is_32[0] = +true;
  750. this.stack_size_32[0] = +true;
  751. for(var i = 0; i < 6; i++)
  752. {
  753. this.segment_is_null[i] = 0;
  754. this.segment_offsets[i] = 0;
  755. this.segment_limits[i] = 0xFFFFFFFF;
  756. // Value doesn't matter, OS isn't allowed to reload without setting
  757. // up a proper GDT
  758. this.sreg[i] = 0xB002;
  759. }
  760. if(flags & MULTIBOOT_HEADER_ADDRESS)
  761. {
  762. dbg_log("Multiboot specifies its own address table", LOG_CPU);
  763. var header_addr = buf32[offset + 12 >> 2];
  764. var load_addr = buf32[offset + 16 >> 2];
  765. var load_end_addr = buf32[offset + 20 >> 2];
  766. var bss_end_addr = buf32[offset + 24 >> 2];
  767. var entry_addr = buf32[offset + 28 >> 2];
  768. dbg_log("header=" + h(header_addr, 8) +
  769. " load=" + h(load_addr, 8) +
  770. " load_end=" + h(load_end_addr, 8) +
  771. " bss_end=" + h(bss_end_addr, 8) +
  772. " entry=" + h(entry_addr, 8));
  773. dbg_assert(load_addr <= header_addr);
  774. var file_start = offset - (header_addr - load_addr);
  775. if(load_end_addr === 0)
  776. {
  777. var length = undefined;
  778. }
  779. else
  780. {
  781. dbg_assert(load_end_addr >= load_addr);
  782. var length = load_end_addr - load_addr;
  783. }
  784. let blob = new Uint8Array(buffer, file_start, length);
  785. this.write_blob(blob, load_addr);
  786. this.instruction_pointer[0] = this.get_seg_cs() + entry_addr | 0;
  787. }
  788. else if(buf32[0] === ELF_MAGIC)
  789. {
  790. dbg_log("Multiboot image is in elf format", LOG_CPU);
  791. let elf = read_elf(buffer);
  792. this.instruction_pointer[0] = this.get_seg_cs() + elf.header.entry | 0;
  793. for(let program of elf.program_headers)
  794. {
  795. if(program.type === 0)
  796. {
  797. // null
  798. }
  799. else if(program.type === 1)
  800. {
  801. // load
  802. // Since multiboot specifies that paging is disabled,
  803. // virtual and physical address must be equal
  804. dbg_assert(program.paddr === program.vaddr);
  805. dbg_assert(program.filesz <= program.memsz);
  806. if(program.paddr + program.memsz < this.memory_size[0])
  807. {
  808. if(program.filesz) // offset might be outside of buffer if filesz is 0
  809. {
  810. let blob = new Uint8Array(buffer, program.offset, program.filesz);
  811. this.write_blob(blob, program.paddr);
  812. }
  813. }
  814. else
  815. {
  816. dbg_log("Warning: Skipped loading section, paddr=" + h(program.paddr) + " memsz=" + program.memsz, LOG_CPU);
  817. }
  818. }
  819. else if(
  820. program.type === 2 ||
  821. program.type === 3 ||
  822. program.type === 4 ||
  823. program.type === 6 ||
  824. program.type === 0x6474e550 ||
  825. program.type === 0x6474e551 ||
  826. program.type === 0x6474e553)
  827. {
  828. // ignore for now
  829. }
  830. else
  831. {
  832. dbg_assert(false, "unimplemented elf section type: " + h(program.type));
  833. }
  834. }
  835. }
  836. else
  837. {
  838. dbg_assert(false, "Not a bootable multiboot format");
  839. }
  840. // only for kvm-unit-test
  841. this.io.register_write_consecutive(0xF4, this,
  842. function(value)
  843. {
  844. console.log("Test exited with code " + h(value, 2));
  845. throw "HALT";
  846. },
  847. function() {},
  848. function() {},
  849. function() {});
  850. // only for kvm-unit-test
  851. for(let i = 0; i <= 0xF; i++)
  852. {
  853. function handle_write(value)
  854. {
  855. dbg_log("kvm-unit-test: Set irq " + h(i) + " to " + h(value, 2));
  856. if(value)
  857. {
  858. this.device_raise_irq(i);
  859. }
  860. else
  861. {
  862. this.device_lower_irq(i);
  863. }
  864. }
  865. this.io.register_write(0x2000 + i, this, handle_write, handle_write, handle_write);
  866. }
  867. this.update_state_flags();
  868. dbg_log("Starting multiboot kernel at:", LOG_CPU);
  869. this.debug.dump_state();
  870. this.debug.dump_regs();
  871. break;
  872. }
  873. };
  874. CPU.prototype.fill_cmos = function(rtc, settings)
  875. {
  876. var boot_order = settings.boot_order || 0x213;
  877. // Used by seabios to determine the boot order
  878. // Nibble
  879. // 1: FloppyPrio
  880. // 2: HDPrio
  881. // 3: CDPrio
  882. // 4: BEVPrio
  883. // bootflag 1, high nibble, lowest priority
  884. // Low nibble: Disable floppy signature check (1)
  885. rtc.cmos_write(CMOS_BIOS_BOOTFLAG1 , 1 | boot_order >> 4 & 0xF0);
  886. // bootflag 2, both nibbles, high and middle priority
  887. rtc.cmos_write(CMOS_BIOS_BOOTFLAG2, boot_order & 0xFF);
  888. // 640k or less if less memory is used
  889. rtc.cmos_write(CMOS_MEM_BASE_LOW, 640 & 0xFF);
  890. rtc.cmos_write(CMOS_MEM_BASE_HIGH, 640 >> 8);
  891. var memory_above_1m = 0; // in k
  892. if(this.memory_size[0] >= 1024 * 1024)
  893. {
  894. memory_above_1m = (this.memory_size[0] - 1024 * 1024) >> 10;
  895. memory_above_1m = Math.min(memory_above_1m, 0xFFFF);
  896. }
  897. rtc.cmos_write(CMOS_MEM_OLD_EXT_LOW, memory_above_1m & 0xFF);
  898. rtc.cmos_write(CMOS_MEM_OLD_EXT_HIGH, memory_above_1m >> 8 & 0xFF);
  899. rtc.cmos_write(CMOS_MEM_EXTMEM_LOW, memory_above_1m & 0xFF);
  900. rtc.cmos_write(CMOS_MEM_EXTMEM_HIGH, memory_above_1m >> 8 & 0xFF);
  901. var memory_above_16m = 0; // in 64k blocks
  902. if(this.memory_size[0] >= 16 * 1024 * 1024)
  903. {
  904. memory_above_16m = (this.memory_size[0] - 16 * 1024 * 1024) >> 16;
  905. memory_above_16m = Math.min(memory_above_16m, 0xFFFF);
  906. }
  907. rtc.cmos_write(CMOS_MEM_EXTMEM2_LOW, memory_above_16m & 0xFF);
  908. rtc.cmos_write(CMOS_MEM_EXTMEM2_HIGH, memory_above_16m >> 8 & 0xFF);
  909. // memory above 4G (not supported by this emulator)
  910. rtc.cmos_write(CMOS_MEM_HIGHMEM_LOW, 0);
  911. rtc.cmos_write(CMOS_MEM_HIGHMEM_MID, 0);
  912. rtc.cmos_write(CMOS_MEM_HIGHMEM_HIGH, 0);
  913. rtc.cmos_write(CMOS_EQUIPMENT_INFO, 0x2F);
  914. rtc.cmos_write(CMOS_BIOS_SMP_COUNT, 0);
  915. // Used by bochs BIOS to skip the boot menu delay.
  916. if (settings.fastboot) rtc.cmos_write(0x3f, 0x01);
  917. };
  918. CPU.prototype.load_bios = function()
  919. {
  920. var bios = this.bios.main;
  921. var vga_bios = this.bios.vga;
  922. if(!bios)
  923. {
  924. dbg_log("Warning: No BIOS");
  925. return;
  926. }
  927. // load bios
  928. var data = new Uint8Array(bios),
  929. start = 0x100000 - bios.byteLength;
  930. this.write_blob(data, start);
  931. if(vga_bios)
  932. {
  933. // load vga bios
  934. var vga_bios8 = new Uint8Array(vga_bios);
  935. // older versions of seabios
  936. this.write_blob(vga_bios8, 0xC0000);
  937. // newer versions of seabios (needs to match pci rom address, see vga.js)
  938. this.io.mmap_register(0xFEB00000, 0x100000,
  939. function(addr)
  940. {
  941. addr = (addr - 0xFEB00000) | 0;
  942. if(addr < vga_bios8.length)
  943. {
  944. return vga_bios8[addr];
  945. }
  946. else
  947. {
  948. return 0;
  949. }
  950. },
  951. function(addr, value)
  952. {
  953. dbg_assert(false, "Unexpected write to VGA rom");
  954. });
  955. }
  956. else
  957. {
  958. dbg_log("Warning: No VGA BIOS");
  959. }
  960. // seabios expects the bios to be mapped to 0xFFF00000 also
  961. this.io.mmap_register(0xFFF00000, 0x100000,
  962. function(addr)
  963. {
  964. addr &= 0xFFFFF;
  965. return this.mem8[addr];
  966. }.bind(this),
  967. function(addr, value)
  968. {
  969. addr &= 0xFFFFF;
  970. this.mem8[addr] = value;
  971. }.bind(this));
  972. };
  973. CPU.prototype.do_many_cycles = function()
  974. {
  975. if(DEBUG)
  976. {
  977. var start_time = v86.microtick();
  978. }
  979. this.do_many_cycles_native();
  980. if(DEBUG)
  981. {
  982. this.do_many_cycles_total += v86.microtick() - start_time;
  983. this.do_many_cycles_count++;
  984. }
  985. };
  986. /** @export */
  987. CPU.prototype.cycle = function()
  988. {
  989. // XXX: May do several cycles
  990. this.cycle_internal();
  991. };
  992. CPU.prototype.codegen_finalize = function(wasm_table_index, start, state_flags, ptr, len)
  993. {
  994. ptr >>>= 0;
  995. len >>>= 0;
  996. dbg_assert(wasm_table_index >= 0 && wasm_table_index < WASM_TABLE_SIZE);
  997. const code = new Uint8Array(this.wasm_memory.buffer, ptr, len);
  998. if(DEBUG)
  999. {
  1000. if(DUMP_GENERATED_WASM && !this.seen_code[start])
  1001. {
  1002. this.debug.dump_wasm(code);
  1003. const DUMP_ASSEMBLY = false;
  1004. if(DUMP_ASSEMBLY)
  1005. {
  1006. let end = 0;
  1007. if((start ^ end) & ~0xFFF)
  1008. {
  1009. dbg_log("truncated disassembly start=" + h(start >>> 0) + " end=" + h(end >>> 0));
  1010. end = (start | 0xFFF) + 1; // until the end of the page
  1011. }
  1012. dbg_assert(end >= start);
  1013. const buffer = new Uint8Array(end - start);
  1014. for(let i = start; i < end; i++)
  1015. {
  1016. buffer[i - start] = this.read8(i);
  1017. }
  1018. this.debug.dump_code(this.is_32[0] ? 1 : 0, buffer, start);
  1019. }
  1020. }
  1021. this.seen_code[start] = (this.seen_code[start] || 0) + 1;
  1022. if(this.test_hook_did_generate_wasm)
  1023. {
  1024. this.test_hook_did_generate_wasm(code);
  1025. }
  1026. }
  1027. const SYNC_COMPILATION = false;
  1028. if(SYNC_COMPILATION)
  1029. {
  1030. const module = new WebAssembly.Module(code);
  1031. const result = new WebAssembly.Instance(module, { "e": this.jit_imports });
  1032. const f = result.exports["f"];
  1033. this.wm.wasm_table.set(wasm_table_index + WASM_TABLE_OFFSET, f);
  1034. this.codegen_finalize_finished(wasm_table_index, start, state_flags);
  1035. if(this.test_hook_did_finalize_wasm)
  1036. {
  1037. this.test_hook_did_finalize_wasm(code);
  1038. }
  1039. return;
  1040. }
  1041. const result = WebAssembly.instantiate(code, { "e": this.jit_imports }).then(result => {
  1042. const f = result.instance.exports["f"];
  1043. this.wm.wasm_table.set(wasm_table_index + WASM_TABLE_OFFSET, f);
  1044. this.codegen_finalize_finished(wasm_table_index, start, state_flags);
  1045. if(this.test_hook_did_finalize_wasm)
  1046. {
  1047. this.test_hook_did_finalize_wasm(code);
  1048. }
  1049. });
  1050. if(DEBUG)
  1051. {
  1052. result.catch(e => {
  1053. console.log(e);
  1054. debugger;
  1055. throw e;
  1056. });
  1057. }
  1058. };
  1059. CPU.prototype.log_uncompiled_code = function(start, end)
  1060. {
  1061. if(!DEBUG || !DUMP_UNCOMPILED_ASSEMBLY)
  1062. {
  1063. return;
  1064. }
  1065. if((this.seen_code_uncompiled[start] || 0) < 100)
  1066. {
  1067. this.seen_code_uncompiled[start] = (this.seen_code_uncompiled[start] || 0) + 1;
  1068. end += 8; // final jump is not included
  1069. if((start ^ end) & ~0xFFF)
  1070. {
  1071. dbg_log("truncated disassembly start=" + h(start >>> 0) + " end=" + h(end >>> 0));
  1072. end = (start | 0xFFF) + 1; // until the end of the page
  1073. }
  1074. if(end < start) end = start;
  1075. dbg_assert(end >= start);
  1076. const buffer = new Uint8Array(end - start);
  1077. for(let i = start; i < end; i++)
  1078. {
  1079. buffer[i - start] = this.read8(i);
  1080. }
  1081. dbg_log("Uncompiled code:");
  1082. this.debug.dump_code(this.is_32[0] ? 1 : 0, buffer, start);
  1083. }
  1084. };
  1085. CPU.prototype.dump_function_code = function(block_ptr, count)
  1086. {
  1087. if(!DEBUG || !DUMP_GENERATED_WASM)
  1088. {
  1089. return;
  1090. }
  1091. const SIZEOF_BASIC_BLOCK_IN_DWORDS = 7;
  1092. const mem32 = new Int32Array(this.wasm_memory.buffer);
  1093. dbg_assert((block_ptr & 3) === 0);
  1094. const is_32 = this.is_32[0];
  1095. for(let i = 0; i < count; i++)
  1096. {
  1097. const struct_start = (block_ptr >> 2) + i * SIZEOF_BASIC_BLOCK_IN_DWORDS;
  1098. const start = mem32[struct_start + 0];
  1099. const end = mem32[struct_start + 1];
  1100. const is_entry_block = mem32[struct_start + 6] & 0xFF00;
  1101. const buffer = new Uint8Array(end - start);
  1102. for(let i = start; i < end; i++)
  1103. {
  1104. buffer[i - start] = this.read8(this.translate_address_system_read(i));
  1105. }
  1106. dbg_log("---" + (is_entry_block ? " entry" : ""));
  1107. this.debug.dump_code(is_32 ? 1 : 0, buffer, start);
  1108. }
  1109. };
  1110. CPU.prototype.hlt_loop = function()
  1111. {
  1112. if(this.get_eflags_no_arith() & FLAG_INTERRUPT)
  1113. {
  1114. const t = this.run_hardware_timers(v86.microtick());
  1115. this.handle_irqs();
  1116. return t;
  1117. }
  1118. else
  1119. {
  1120. return 100;
  1121. }
  1122. };
  1123. CPU.prototype.run_hardware_timers = function(now)
  1124. {
  1125. if(ENABLE_HPET)
  1126. {
  1127. var pit_time = this.devices.pit.timer(now, this.devices.hpet.legacy_mode);
  1128. var rtc_time = this.devices.rtc.timer(now, this.devices.hpet.legacy_mode);
  1129. var hpet_time = this.devices.hpet.timer(now);
  1130. }
  1131. else
  1132. {
  1133. var pit_time = this.devices.pit.timer(now, false);
  1134. var rtc_time = this.devices.rtc.timer(now, false);
  1135. var hpet_time = 100;
  1136. }
  1137. let acpi_time = 100;
  1138. let apic_time = 100;
  1139. if(this.acpi_enabled[0])
  1140. {
  1141. acpi_time = this.devices.acpi.timer(now);
  1142. apic_time = this.devices.apic.timer(now);
  1143. }
  1144. return Math.min(pit_time, rtc_time, hpet_time, acpi_time, apic_time);
  1145. };
  1146. CPU.prototype.hlt_op = function()
  1147. {
  1148. if((this.get_eflags_no_arith() & FLAG_INTERRUPT) === 0)
  1149. {
  1150. // execution can never resume (until NMIs are supported)
  1151. this.bus.send("cpu-event-halt");
  1152. }
  1153. // get out of here and into hlt_loop
  1154. this.in_hlt[0] = +true;
  1155. // Try an hlt loop right now: This will run timer interrupts, and if one is
  1156. // due it will immediately call call_interrupt_vector and continue
  1157. // execution without an unnecessary cycle through do_run
  1158. this.hlt_loop();
  1159. };
  1160. CPU.prototype.handle_irqs = function()
  1161. {
  1162. //dbg_assert(this.prefixes[0] === 0);
  1163. if(this.get_eflags_no_arith() & FLAG_INTERRUPT)
  1164. {
  1165. this.pic_acknowledge();
  1166. this.next_tick_immediately();
  1167. }
  1168. };
  1169. CPU.prototype.pic_acknowledge = function()
  1170. {
  1171. dbg_assert(this.get_eflags_no_arith() & FLAG_INTERRUPT);
  1172. if(this.devices.pic)
  1173. {
  1174. this.devices.pic.acknowledge_irq();
  1175. }
  1176. if(this.devices.apic)
  1177. {
  1178. this.devices.apic.acknowledge_irq();
  1179. }
  1180. };
  1181. CPU.prototype.device_raise_irq = function(i)
  1182. {
  1183. dbg_assert(arguments.length === 1);
  1184. if(this.devices.pic)
  1185. {
  1186. this.devices.pic.set_irq(i);
  1187. }
  1188. if(this.devices.ioapic)
  1189. {
  1190. this.devices.ioapic.set_irq(i);
  1191. }
  1192. };
  1193. CPU.prototype.device_lower_irq = function(i)
  1194. {
  1195. if(this.devices.pic)
  1196. {
  1197. this.devices.pic.clear_irq(i);
  1198. }
  1199. if(this.devices.ioapic)
  1200. {
  1201. this.devices.ioapic.clear_irq(i);
  1202. }
  1203. };
  1204. // Closure Compiler's way of exporting
  1205. if(typeof window !== "undefined")
  1206. {
  1207. window["CPU"] = CPU;
  1208. }
  1209. else if(typeof module !== "undefined" && typeof module.exports !== "undefined")
  1210. {
  1211. module.exports["CPU"] = CPU;
  1212. }
  1213. else if(typeof importScripts === "function")
  1214. {
  1215. self["CPU"] = CPU;
  1216. }