cpu.js 42 KB

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