main.js 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883
  1. "use strict";
  2. (function()
  3. {
  4. /** @const */
  5. var ON_LOCALHOST = !location.hostname.endsWith("copy.sh");
  6. /**
  7. * @return {Object.<string, string>}
  8. */
  9. function get_query_arguments()
  10. {
  11. var query = location.search.substr(1).split("&");
  12. var parameters = {};
  13. for(var i = 0; i < query.length; i++)
  14. {
  15. var param = query[i].split("=");
  16. parameters[param[0]] = decodeURIComponent(param.slice(1).join("="));
  17. }
  18. return parameters;
  19. }
  20. function set_title(text)
  21. {
  22. document.title = text + " - Virtual x86" + (DEBUG ? " - debug" : "");
  23. const description = document.querySelector("meta[name=description]");
  24. description && (description.content = "Running " + text);
  25. }
  26. function format_timestamp(time)
  27. {
  28. if(time < 60)
  29. {
  30. return time + "s";
  31. }
  32. else if(time < 3600)
  33. {
  34. return (time / 60 | 0) + "m " + v86util.pad0(time % 60, 2) + "s";
  35. }
  36. else
  37. {
  38. return (time / 3600 | 0) + "h " +
  39. v86util.pad0((time / 60 | 0) % 60, 2) + "m " +
  40. v86util.pad0(time % 60, 2) + "s";
  41. }
  42. }
  43. var progress_ticks = 0;
  44. function show_progress(e)
  45. {
  46. var el = $("loading");
  47. el.style.display = "block";
  48. if(e.file_name.endsWith(".wasm"))
  49. {
  50. const parts = e.file_name.split("/");
  51. el.textContent = "Fetching " + parts[parts.length - 1] + " ...";
  52. return;
  53. }
  54. if(e.file_index === e.file_count - 1 && e.loaded >= e.total - 2048)
  55. {
  56. // last file is (almost) loaded
  57. el.textContent = "Done downloading. Starting now ...";
  58. return;
  59. }
  60. var line = "Downloading images ";
  61. if(typeof e.file_index === "number" && e.file_count)
  62. {
  63. line += "[" + (e.file_index + 1) + "/" + e.file_count + "] ";
  64. }
  65. if(e.total && typeof e.loaded === "number")
  66. {
  67. var per100 = Math.floor(e.loaded / e.total * 100);
  68. per100 = Math.min(100, Math.max(0, per100));
  69. var per50 = Math.floor(per100 / 2);
  70. line += per100 + "% [";
  71. line += "#".repeat(per50);
  72. line += " ".repeat(50 - per50) + "]";
  73. }
  74. else
  75. {
  76. line += ".".repeat(progress_ticks++ % 50);
  77. }
  78. el.textContent = line;
  79. }
  80. function $(id)
  81. {
  82. return document.getElementById(id);
  83. }
  84. function onload()
  85. {
  86. if(!window.WebAssembly)
  87. {
  88. alert("Your browser is not supported because it doesn't support WebAssembly");
  89. return;
  90. }
  91. const script = document.createElement("script");
  92. script.src = "build/xterm.js";
  93. script.async = true;
  94. document.body.appendChild(script);
  95. var settings = {};
  96. $("start_emulation").onclick = function()
  97. {
  98. $("boot_options").style.display = "none";
  99. set_profile("custom");
  100. var images = [];
  101. var last_file;
  102. var floppy_file = $("floppy_image").files[0];
  103. if(floppy_file)
  104. {
  105. last_file = floppy_file;
  106. settings.fda = { buffer: floppy_file };
  107. }
  108. var cd_file = $("cd_image").files[0];
  109. if(cd_file)
  110. {
  111. last_file = cd_file;
  112. settings.cdrom = { buffer: cd_file };
  113. }
  114. var hda_file = $("hda_image").files[0];
  115. if(hda_file)
  116. {
  117. last_file = hda_file;
  118. settings.hda = { buffer: hda_file };
  119. }
  120. var hdb_file = $("hdb_image") && $("hdb_image").files[0];
  121. if(hdb_file)
  122. {
  123. last_file = hdb_file;
  124. settings.hdb = { buffer: hdb_file };
  125. }
  126. if($("multiboot_image"))
  127. {
  128. var multiboot_file = $("multiboot_image").files[0];
  129. if(multiboot_file)
  130. {
  131. last_file = multiboot_file;
  132. settings.multiboot = { buffer: multiboot_file };
  133. }
  134. }
  135. if(last_file)
  136. {
  137. set_title(last_file.name);
  138. }
  139. start_emulation(settings);
  140. };
  141. if(DEBUG)
  142. {
  143. debug_onload(settings);
  144. }
  145. const query_args = get_query_arguments();
  146. const host = query_args["cdn"] || (ON_LOCALHOST ? "images/" : "//k.copy.sh/");
  147. // Abandonware OS images are from https://winworldpc.com/library/operating-systems
  148. var oses = [
  149. {
  150. id: "archlinux",
  151. name: "Arch Linux",
  152. memory_size: 512 * 1024 * 1024,
  153. vga_memory_size: 8 * 1024 * 1024,
  154. state: {
  155. "url": host + "arch_state.bin.zst",
  156. },
  157. filesystem: {
  158. "baseurl": host + "arch/",
  159. },
  160. },
  161. {
  162. id: "archlinux-boot",
  163. name: "Arch Linux",
  164. memory_size: 512 * 1024 * 1024,
  165. vga_memory_size: 8 * 1024 * 1024,
  166. filesystem: {
  167. "baseurl": host + "arch/",
  168. "basefs": { url: host + "fs.json", },
  169. },
  170. cmdline: [
  171. "rw apm=off vga=0x344 video=vesafb:ypan,vremap:8",
  172. "root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose",
  173. "mitigations=off audit=0",
  174. "page_poison=on",
  175. "tsc=reliable",
  176. "random.trust_cpu=on",
  177. "nowatchdog",
  178. "init=/usr/bin/init-openrc net.ifnames=0 biosdevname=0",
  179. ].join(" "),
  180. bzimage_initrd_from_filesystem: true,
  181. },
  182. {
  183. id: "serenity",
  184. name: "SerenityOS",
  185. hda: {
  186. "url": host + "serenity.img",
  187. "async": true,
  188. "size": 876 * 1024 * 1024,
  189. use_parts: !ON_LOCALHOST,
  190. },
  191. memory_size: 512 * 1024 * 1024,
  192. state: { url: host + "serenity_state-v2.bin.zst", },
  193. homepage: "https://serenityos.org/",
  194. },
  195. {
  196. id: "serenity-boot",
  197. name: "SerenityOS",
  198. hda: {
  199. "url": host + "serenity.img",
  200. "async": true,
  201. "size": 876 * 1024 * 1024,
  202. use_parts: !ON_LOCALHOST,
  203. },
  204. memory_size: 512 * 1024 * 1024,
  205. homepage: "https://serenityos.org/",
  206. },
  207. {
  208. id: "helenos",
  209. memory_size: 256 * 1024 * 1024,
  210. cdrom: {
  211. url: host + "HelenOS-0.11.2-ia32.iso",
  212. size: 25765888,
  213. async: false,
  214. },
  215. name: "HelenOS",
  216. homepage: "http://www.helenos.org/",
  217. },
  218. {
  219. id: "haiku",
  220. memory_size: 512 * 1024 * 1024,
  221. hda: {
  222. url: host + "haiku-v2.img",
  223. async: true,
  224. use_parts: !ON_LOCALHOST,
  225. size: 1 * 1024 * 1024 * 1024,
  226. },
  227. state: {
  228. url: host + "haiku_state-v2.bin.zst",
  229. },
  230. name: "Haiku",
  231. homepage: "https://www.haiku-os.org/",
  232. },
  233. {
  234. id: "haiku-boot",
  235. memory_size: 512 * 1024 * 1024,
  236. hda: {
  237. url: host + "haiku-v2.img",
  238. async: true,
  239. use_parts: !ON_LOCALHOST,
  240. size: 1 * 1024 * 1024 * 1024,
  241. },
  242. name: "Haiku",
  243. homepage: "https://www.haiku-os.org/",
  244. },
  245. {
  246. id: "msdos",
  247. hda: {
  248. "url": host + "msdos.img",
  249. "size": 8 * 1024 * 1024,
  250. "async": false,
  251. },
  252. boot_order: 0x132,
  253. name: "MS-DOS",
  254. },
  255. {
  256. id: "freedos",
  257. fda: {
  258. "url": host + "freedos722.img",
  259. "size": 737280,
  260. "async": false,
  261. },
  262. name: "FreeDOS",
  263. },
  264. {
  265. id: "psychdos",
  266. hda: {
  267. "url": host + "psychdos.img",
  268. "size": 549453824,
  269. "async": true,
  270. use_parts: !ON_LOCALHOST,
  271. },
  272. name: "PsychDOS",
  273. homepage: "https://psychoslinux.gitlab.io/DOS/INDEX.HTM",
  274. },
  275. {
  276. id: "oberon",
  277. hda: {
  278. "url": host + "oberon.img",
  279. "size": 24 * 1024 * 1024,
  280. "async": false,
  281. },
  282. name: "Oberon",
  283. },
  284. {
  285. id: "windows1",
  286. fda: {
  287. "url": host + "windows101.img",
  288. "size": 1474560,
  289. "async": false,
  290. },
  291. name: "Windows",
  292. },
  293. {
  294. id: "linux26",
  295. cdrom: {
  296. "url": host + "linux.iso",
  297. "size": 6547456,
  298. "async": false,
  299. },
  300. name: "Linux",
  301. },
  302. {
  303. id: "linux3",
  304. cdrom: {
  305. "url": host + "linux3.iso",
  306. "size": 8624128,
  307. "async": false,
  308. },
  309. name: "Linux",
  310. },
  311. {
  312. id: "linux4",
  313. cdrom: {
  314. "url": host + "linux4.iso",
  315. "size": 7731200,
  316. "async": false,
  317. },
  318. name: "Linux",
  319. filesystem: {},
  320. },
  321. {
  322. id: "buildroot",
  323. bzimage: {
  324. url: host + "buildroot-bzimage.bin",
  325. size: 5166352,
  326. async: false,
  327. },
  328. name: "Buildroot Linux",
  329. filesystem: {},
  330. cmdline: "tsc=reliable mitigations=off random.trust_cpu=on",
  331. },
  332. {
  333. id: "nodeos",
  334. bzimage: {
  335. url: host + "nodeos-kernel.bin",
  336. size: 14452000,
  337. async: false,
  338. },
  339. name: "NodeOS",
  340. cmdline: "tsc=reliable mitigations=off random.trust_cpu=on",
  341. },
  342. {
  343. id: "dsl",
  344. memory_size: 256 * 1024 * 1024,
  345. cdrom: {
  346. url: host + "dsl-4.11.rc2.iso",
  347. size: 52824064,
  348. async: false,
  349. },
  350. name: "Damn Small Linux",
  351. homepage: "http://www.damnsmalllinux.org/",
  352. },
  353. {
  354. id: "minix",
  355. name: "Minix",
  356. memory_size: 256 * 1024 * 1024,
  357. cdrom: {
  358. url: host + "minix-3.3.0.iso",
  359. size: 605581312,
  360. async: true,
  361. use_parts: !ON_LOCALHOST,
  362. },
  363. homepage: "https://www.minix3.org/",
  364. },
  365. {
  366. id: "kolibrios",
  367. fda: {
  368. "url": ON_LOCALHOST ?
  369. host + "kolibri.img" :
  370. "//builds.kolibrios.org/eng/data/data/kolibri.img",
  371. "size": 1474560,
  372. "async": false,
  373. },
  374. name: "KolibriOS",
  375. homepage: "https://kolibrios.org/en/",
  376. },
  377. {
  378. id: "kolibrios-fallback",
  379. fda: {
  380. "url": host + "kolibri.img",
  381. "size": 1474560,
  382. "async": false,
  383. },
  384. name: "KolibriOS",
  385. },
  386. {
  387. id: "openbsd",
  388. hda: {
  389. "url": host + "openbsd.img",
  390. async: true,
  391. use_parts: !ON_LOCALHOST,
  392. size: 1073741824,
  393. },
  394. state: {
  395. url: host + "openbsd_state.bin.zst",
  396. },
  397. memory_size: 256 * 1024 * 1024,
  398. name: "OpenBSD",
  399. },
  400. {
  401. id: "openbsd-boot",
  402. hda: {
  403. url: host + "openbsd.img",
  404. async: true,
  405. use_parts: !ON_LOCALHOST,
  406. size: 1073741824,
  407. },
  408. memory_size: 256 * 1024 * 1024,
  409. name: "OpenBSD",
  410. //acpi: true, // doesn't seem to work
  411. },
  412. {
  413. id: "netbsd",
  414. hda: {
  415. "url": host + "netbsd.img",
  416. async: true,
  417. use_parts: !ON_LOCALHOST,
  418. size: 511000064,
  419. },
  420. memory_size: 256 * 1024 * 1024,
  421. name: "NetBSD",
  422. },
  423. {
  424. id: "solos",
  425. fda: {
  426. "url": host + "os8.img",
  427. "async": false,
  428. "size": 1474560,
  429. },
  430. name: "Sol OS",
  431. homepage: "http://oby.ro/os/",
  432. },
  433. {
  434. id: "bootchess",
  435. fda: {
  436. "url": host + "bootchess.img",
  437. "async": false,
  438. "size": 1474560,
  439. },
  440. name: "BootChess",
  441. homepage: "http://www.pouet.net/prod.php?which=64962",
  442. },
  443. {
  444. id: "bootbasic",
  445. fda: {
  446. "url": host + "bootbasic.img",
  447. "async": false,
  448. "size": 1474560,
  449. },
  450. name: "bootBASIC",
  451. homepage: "https://github.com/nanochess/bootBASIC",
  452. },
  453. {
  454. id: "sectorlisp",
  455. fda: {
  456. "url": host + "sectorlisp-friendly.bin",
  457. "async": false,
  458. "size": 512,
  459. },
  460. name: "SectorLISP",
  461. homepage: "https://justine.lol/sectorlisp2/",
  462. },
  463. {
  464. id: "sectorforth",
  465. fda: {
  466. "url": host + "sectorforth.img",
  467. "async": false,
  468. "size": 512,
  469. },
  470. name: "sectorforth",
  471. homepage: "https://github.com/cesarblum/sectorforth",
  472. },
  473. {
  474. id: "floppybird",
  475. fda: {
  476. "url": host + "floppybird.img",
  477. "async": false,
  478. "size": 1474560,
  479. },
  480. name: "Floppy Bird",
  481. homepage: "http://mihail.co/floppybird",
  482. },
  483. {
  484. id: "windows2000",
  485. memory_size: 512 * 1024 * 1024,
  486. hda: {
  487. "url": host + "windows2k.img",
  488. "size": 2 * 1024 * 1024 * 1024,
  489. "async": true,
  490. use_parts: !ON_LOCALHOST,
  491. },
  492. name: "Windows 2000",
  493. state: {
  494. "url": host + "windows2k_state.bin.zst",
  495. },
  496. preserve_mac_from_state_image: true,
  497. },
  498. {
  499. id: "windows2000-boot",
  500. memory_size: 512 * 1024 * 1024,
  501. hda: {
  502. "url": host + "windows2k.img",
  503. "size": 2 * 1024 * 1024 * 1024,
  504. "async": true,
  505. use_parts: !ON_LOCALHOST,
  506. },
  507. boot_order: 0x132,
  508. name: "Windows 2000",
  509. },
  510. {
  511. id: "windows98",
  512. memory_size: 128 * 1024 * 1024,
  513. hda: {
  514. "url": host + "windows98.img",
  515. "async": true,
  516. use_parts: !ON_LOCALHOST,
  517. "size": 300 * 1024 * 1024,
  518. },
  519. name: "Windows 98",
  520. state: {
  521. "url": host + "windows98_state.bin.zst",
  522. },
  523. preserve_mac_from_state_image: true,
  524. },
  525. {
  526. id: "windows98-boot",
  527. memory_size: 128 * 1024 * 1024,
  528. hda: {
  529. "url": host + "windows98.img",
  530. "async": true,
  531. use_parts: !ON_LOCALHOST,
  532. "size": 300 * 1024 * 1024,
  533. },
  534. name: "Windows 98",
  535. },
  536. {
  537. id: "windows95",
  538. memory_size: 32 * 1024 * 1024,
  539. hda: {
  540. "url": host + "w95.img",
  541. "size": 242049024,
  542. "async": true,
  543. use_parts: !ON_LOCALHOST,
  544. },
  545. name: "Windows 95",
  546. state: {
  547. "url": host + "windows95_state.bin.zst",
  548. },
  549. },
  550. {
  551. id: "windows95-boot",
  552. memory_size: 32 * 1024 * 1024,
  553. hda: {
  554. "url": host + "w95.img",
  555. "size": 242049024,
  556. "async": true,
  557. use_parts: !ON_LOCALHOST,
  558. },
  559. name: "Windows 95",
  560. },
  561. {
  562. id: "windows30",
  563. memory_size: 64 * 1024 * 1024,
  564. cdrom: {
  565. "url": host + "Win30.iso",
  566. "async": false,
  567. },
  568. name: "Windows 3.0",
  569. },
  570. {
  571. id: "windows31",
  572. memory_size: 64 * 1024 * 1024,
  573. hda: {
  574. "url": host + "win31.img",
  575. "async": false,
  576. "size": 34463744,
  577. },
  578. name: "Windows 3.1",
  579. },
  580. {
  581. id: "freebsd",
  582. memory_size: 256 * 1024 * 1024,
  583. hda: {
  584. "url": host + "freebsd.img",
  585. "size": 2147483648,
  586. "async": true,
  587. use_parts: !ON_LOCALHOST,
  588. },
  589. state: {
  590. "url": host + "freebsd_state.bin.zst",
  591. },
  592. name: "FreeBSD",
  593. },
  594. {
  595. id: "freebsd-boot",
  596. memory_size: 256 * 1024 * 1024,
  597. hda: {
  598. "url": host + "freebsd.img",
  599. "size": 2147483648,
  600. "async": true,
  601. use_parts: !ON_LOCALHOST,
  602. },
  603. name: "FreeBSD",
  604. },
  605. {
  606. id: "reactos-livecd",
  607. memory_size: 256 * 1024 * 1024,
  608. hda: {
  609. "url": host + "reactos-livecd-0.4.15-dev-73-g03c09c9-x86-gcc-lin-dbg.iso",
  610. "size": 250609664,
  611. "async": true,
  612. use_parts: !ON_LOCALHOST,
  613. },
  614. name: "ReactOS",
  615. homepage: "https://reactos.org/",
  616. },
  617. {
  618. id: "reactos",
  619. memory_size: 512 * 1024 * 1024,
  620. hda: {
  621. "url": host + "reactos.img",
  622. "size": 500 * 1024 * 1024,
  623. "async": true,
  624. use_parts: !ON_LOCALHOST,
  625. },
  626. state: {
  627. "url": host + "reactos_state.bin.zst",
  628. },
  629. preserve_mac_from_state_image: true,
  630. name: "ReactOS",
  631. homepage: "https://reactos.org/",
  632. },
  633. {
  634. id: "reactos-boot",
  635. memory_size: 512 * 1024 * 1024,
  636. hda: {
  637. "url": host + "reactos.img",
  638. "size": 500 * 1024 * 1024,
  639. "async": true,
  640. use_parts: !ON_LOCALHOST,
  641. },
  642. name: "ReactOS",
  643. homepage: "https://reactos.org/",
  644. },
  645. {
  646. id: "skift",
  647. cdrom: {
  648. "url": host + "skift-20200910.iso",
  649. "size": 64452608,
  650. "async": false,
  651. },
  652. name: "Skift",
  653. homepage: "https://skiftos.org/",
  654. },
  655. {
  656. id: "snowdrop",
  657. fda: {
  658. "url": host + "snowdrop.img",
  659. "size": 1440 * 1024,
  660. "async": false,
  661. },
  662. name: "Snowdrop",
  663. homepage: "http://www.sebastianmihai.com/snowdrop/",
  664. },
  665. {
  666. id: "openwrt",
  667. hda: {
  668. "url": host + "openwrt-18.06.1-x86-legacy-combined-squashfs.img",
  669. "size": 19846474,
  670. "async": false,
  671. },
  672. name: "OpenWrt",
  673. },
  674. {
  675. id: "qnx",
  676. fda: {
  677. url: host + "qnx-demo-network-4.05.img",
  678. size: 1474560,
  679. async: false
  680. },
  681. name: "QNX 4.05",
  682. },
  683. {
  684. id: "9front",
  685. memory_size: 128 * 1024 * 1024,
  686. hda: {
  687. url: host + "9front-8963.f84cf1e60427675514fb056cc1723e45da01e043.386.iso",
  688. size: 477452288,
  689. async: true,
  690. use_parts: !ON_LOCALHOST,
  691. },
  692. state: {
  693. "url": host + "9front_state-v2.bin.zst",
  694. },
  695. acpi: true,
  696. name: "9front",
  697. homepage: "https://9front.org/",
  698. },
  699. {
  700. id: "9front-boot",
  701. memory_size: 128 * 1024 * 1024,
  702. hda: {
  703. url: host + "9front-8963.f84cf1e60427675514fb056cc1723e45da01e043.386.iso",
  704. size: 477452288,
  705. async: true,
  706. use_parts: !ON_LOCALHOST,
  707. },
  708. acpi: true,
  709. name: "9front",
  710. homepage: "https://9front.org/",
  711. },
  712. {
  713. id: "mobius",
  714. fda: {
  715. "url": host + "mobius-fd-release5.img",
  716. "size": 1474560,
  717. "async": false,
  718. },
  719. name: "Mobius",
  720. },
  721. {
  722. id: "android",
  723. memory_size: 512 * 1024 * 1024,
  724. cdrom: {
  725. "url": host + "android-x86-1.6-r2.iso",
  726. "size": 54661120,
  727. "async": true,
  728. use_parts: !ON_LOCALHOST,
  729. },
  730. name: "Android",
  731. },
  732. {
  733. id: "android4",
  734. memory_size: 512 * 1024 * 1024,
  735. cdrom: {
  736. "url": host + "android_x86_nonsse3_4.4r1_20140904.iso",
  737. "size": 247463936,
  738. "async": true,
  739. use_parts: !ON_LOCALHOST,
  740. },
  741. name: "Android",
  742. },
  743. {
  744. id: "tinycore",
  745. memory_size: 256 * 1024 * 1024,
  746. hda: {
  747. "url": host + "TinyCore-11.0.iso",
  748. "async": false,
  749. },
  750. name: "Tinycore",
  751. homepage: "http://www.tinycorelinux.net/",
  752. },
  753. {
  754. id: "freenos",
  755. memory_size: 256 * 1024 * 1024,
  756. cdrom: {
  757. "url": host + "FreeNOS-1.0.3.iso",
  758. "async": false,
  759. "size": 11014144,
  760. },
  761. name: "FreeNOS",
  762. acpi: true,
  763. homepage: "http://www.freenos.org/",
  764. },
  765. ];
  766. if(DEBUG)
  767. {
  768. // see tests/kvm-unit-tests/x86/
  769. var tests = [
  770. "realmode",
  771. // All tests below require an APIC
  772. "cmpxchg8b",
  773. "port80",
  774. "setjmp",
  775. "sieve",
  776. "hypercall", // crashes
  777. "init", // stops execution
  778. "msr", // TODO: Expects 64 bit msrs
  779. "smap", // test stops, SMAP not enabled
  780. "tsc_adjust", // TODO: IA32_TSC_ADJUST
  781. "tsc", // TODO: rdtscp
  782. "rmap_chain", // crashes
  783. "memory", // missing mfence (uninteresting)
  784. "taskswitch", // TODO: Jump
  785. "taskswitch2", // TODO: Call TSS
  786. "eventinj", // Missing #nt
  787. "ioapic",
  788. "apic",
  789. ];
  790. for(let test of tests)
  791. {
  792. oses.push({
  793. name: "Test case: " + test,
  794. id: "test-" + test,
  795. memory_size: 128 * 1024 * 1024,
  796. multiboot: { "url": "tests/kvm-unit-tests/x86/" + test + ".flat", }
  797. });
  798. }
  799. }
  800. var profile = query_args["profile"];
  801. if(!profile && !DEBUG)
  802. {
  803. const link = document.createElement("link");
  804. link.rel = "prefetch";
  805. link.href = "build/v86.wasm";
  806. document.head.appendChild(link);
  807. }
  808. if(query_args["use_bochs_bios"])
  809. {
  810. settings.use_bochs_bios = true;
  811. }
  812. const m = parseInt(query_args["m"], 10);
  813. if(m > 0)
  814. {
  815. settings.memory_size = Math.max(16, m) * 1024 * 1024;
  816. }
  817. const vram = parseInt(query_args["vram"], 10);
  818. if(vram > 0)
  819. {
  820. settings.vga_memory_size = vram * 1024 * 1024;
  821. }
  822. settings.networking_proxy = query_args["networking_proxy"];
  823. settings.audio = query_args["audio"] !== "0";
  824. settings.acpi = query_args["acpi"];
  825. for(var i = 0; i < oses.length; i++)
  826. {
  827. var infos = oses[i];
  828. if(profile === infos.id)
  829. {
  830. start_profile(infos);
  831. return;
  832. }
  833. var element = $("start_" + infos.id);
  834. if(element)
  835. {
  836. element.onclick = function(infos, element, e)
  837. {
  838. e.preventDefault();
  839. set_profile(infos.id);
  840. element.blur();
  841. start_profile(infos);
  842. }.bind(this, infos, element);
  843. }
  844. }
  845. if(profile === "custom")
  846. {
  847. if(query_args["hda.url"])
  848. {
  849. settings.hda = {
  850. "size": parseInt(query_args["hda.size"], 10) || undefined,
  851. "url": query_args["hda.url"],
  852. "async": true,
  853. };
  854. }
  855. if(query_args["cdrom.url"])
  856. {
  857. settings.cdrom = {
  858. "size": parseInt(query_args["cdrom.size"], 10) || undefined,
  859. "url": query_args["cdrom.url"],
  860. "async": true,
  861. };
  862. }
  863. if(query_args["fda.url"])
  864. {
  865. settings.fda = {
  866. "size": parseInt(query_args["fda.size"], 10) || undefined,
  867. "url": query_args["fda.url"],
  868. "async": false,
  869. };
  870. }
  871. if(settings.fda || settings.cdrom || settings.hda)
  872. {
  873. $("boot_options").style.display = "none";
  874. start_emulation(settings, done);
  875. }
  876. }
  877. function start_profile(infos)
  878. {
  879. $("boot_options").style.display = "none";
  880. set_title(infos.name);
  881. settings.filesystem = infos.filesystem;
  882. if(infos.state)
  883. {
  884. $("reset").style.display = "none";
  885. settings.initial_state = infos.state;
  886. }
  887. settings.fda = infos.fda;
  888. settings.cdrom = infos.cdrom;
  889. settings.hda = infos.hda;
  890. settings.multiboot = infos.multiboot;
  891. settings.bzimage = infos.bzimage;
  892. settings.initrd = infos.initrd;
  893. settings.cmdline = infos.cmdline;
  894. settings.bzimage_initrd_from_filesystem = infos.bzimage_initrd_from_filesystem;
  895. settings.preserve_mac_from_state_image = infos.preserve_mac_from_state_image;
  896. settings.acpi = (!infos.state && settings.acpi !== undefined) ? settings.acpi : infos.acpi;
  897. settings.memory_size = (!infos.state && settings.memory_size) ? settings.memory_size : infos.memory_size;
  898. settings.vga_memory_size = (!infos.state && settings.vga_memory_size) ? settings.vga_memory_size : infos.vga_memory_size;
  899. settings.id = infos.id;
  900. if(infos.boot_order !== undefined)
  901. {
  902. settings.boot_order = infos.boot_order;
  903. }
  904. if(!DEBUG && infos.homepage)
  905. {
  906. $("description").style.display = "block";
  907. const link = document.createElement("a");
  908. link.href = infos.homepage;
  909. link.textContent = infos.name;
  910. link.target = "_blank";
  911. $("description").appendChild(document.createTextNode("Running "));
  912. $("description").appendChild(link);
  913. }
  914. start_emulation(settings, done);
  915. }
  916. function done(emulator)
  917. {
  918. if(query_args["c"])
  919. {
  920. setTimeout(function()
  921. {
  922. //emulator.serial0_send(query_args["c"] + "\n");
  923. emulator.keyboard_send_text(query_args["c"] + "\n");
  924. }, 25);
  925. }
  926. }
  927. }
  928. function debug_onload(settings)
  929. {
  930. // called on window.onload, in debug mode
  931. var log_levels = $("log_levels");
  932. if(log_levels)
  933. {
  934. for(var i = 0; i < LOG_NAMES.length; i++)
  935. {
  936. var mask = LOG_NAMES[i][0];
  937. if(mask === 1)
  938. continue;
  939. var name = LOG_NAMES[i][1].toLowerCase(),
  940. input = document.createElement("input"),
  941. label = document.createElement("label");
  942. input.type = "checkbox";
  943. label.htmlFor = input.id = "log_" + name;
  944. if(LOG_LEVEL & mask)
  945. {
  946. input.checked = true;
  947. }
  948. input.mask = mask;
  949. label.appendChild(input);
  950. label.appendChild(document.createTextNode(v86util.pads(name, 4) + " "));
  951. log_levels.appendChild(label);
  952. if(i === Math.floor(LOG_NAMES.length / 2))
  953. {
  954. log_levels.appendChild(document.createTextNode("\n"));
  955. }
  956. }
  957. log_levels.onchange = function(e)
  958. {
  959. var target = e.target,
  960. mask = target.mask;
  961. if(target.checked)
  962. {
  963. LOG_LEVEL |= mask;
  964. }
  965. else
  966. {
  967. LOG_LEVEL &= ~mask;
  968. }
  969. target.blur();
  970. };
  971. }
  972. }
  973. window.addEventListener("load", onload, false);
  974. // old webkit fires popstate on every load, fuck webkit
  975. // https://code.google.com/p/chromium/issues/detail?id=63040
  976. window.addEventListener("load", function()
  977. {
  978. setTimeout(function()
  979. {
  980. window.addEventListener("popstate", onpopstate);
  981. }, 0);
  982. });
  983. // works in firefox and chromium
  984. if(document.readyState === "complete")
  985. {
  986. onload();
  987. }
  988. /** @param {?=} done */
  989. function start_emulation(settings, done)
  990. {
  991. /** @const */
  992. var MB = 1024 * 1024;
  993. var memory_size = settings.memory_size;
  994. if(!memory_size)
  995. {
  996. memory_size = parseInt($("memory_size").value, 10) * MB;
  997. if(!memory_size)
  998. {
  999. alert("Invalid memory size - reset to 128MB");
  1000. memory_size = 128 * MB;
  1001. }
  1002. }
  1003. var vga_memory_size = settings.vga_memory_size;
  1004. if(!vga_memory_size)
  1005. {
  1006. vga_memory_size = parseInt($("video_memory_size").value, 10) * MB;
  1007. if(!vga_memory_size)
  1008. {
  1009. alert("Invalid video memory size - reset to 8MB");
  1010. vga_memory_size = 8 * MB;
  1011. }
  1012. }
  1013. if(!settings.fda)
  1014. {
  1015. var floppy_file = $("floppy_image").files[0];
  1016. if(floppy_file)
  1017. {
  1018. settings.fda = { buffer: floppy_file };
  1019. }
  1020. }
  1021. if(!settings.bzimage)
  1022. {
  1023. var bzimage = $("bzimage").files[0];
  1024. if(bzimage)
  1025. {
  1026. settings.bzimage = { buffer: bzimage };
  1027. }
  1028. }
  1029. if(!settings.initrd)
  1030. {
  1031. var initrd = $("initrd").files[0];
  1032. if(initrd)
  1033. {
  1034. settings.initrd = { buffer: initrd };
  1035. }
  1036. }
  1037. const networking_proxy = settings.networking_proxy === undefined ? $("networking_proxy").value : settings.networking_proxy;
  1038. const disable_audio = settings.audio === undefined ? $("disable_audio").checked : !settings.audio;
  1039. const enable_acpi = settings.acpi === undefined ? $("enable_acpi").checked : settings.acpi;
  1040. /** @const */
  1041. var BIOSPATH = "bios/";
  1042. if(settings.use_bochs_bios)
  1043. {
  1044. var biosfile = "bochs-bios.bin";
  1045. var vgabiosfile = "bochs-vgabios.bin";
  1046. }
  1047. else
  1048. {
  1049. var biosfile = DEBUG ? "seabios-debug.bin" : "seabios.bin";
  1050. var vgabiosfile = DEBUG ? "vgabios-debug.bin" : "vgabios.bin";
  1051. }
  1052. var bios;
  1053. var vga_bios;
  1054. // a bios is only needed if the machine is booted
  1055. if(!settings.initial_state)
  1056. {
  1057. bios = {
  1058. "url": BIOSPATH + biosfile,
  1059. };
  1060. vga_bios = {
  1061. "url": BIOSPATH + vgabiosfile,
  1062. };
  1063. }
  1064. var emulator = new V86Starter({
  1065. "memory_size": memory_size,
  1066. "vga_memory_size": vga_memory_size,
  1067. "screen_container": $("screen_container"),
  1068. "serial_container_xtermjs": $("terminal"),
  1069. "boot_order": settings.boot_order || parseInt($("boot_order").value, 16) || 0,
  1070. "network_relay_url": ON_LOCALHOST ? "ws://localhost:8080/" : networking_proxy,
  1071. "bios": bios,
  1072. "vga_bios": vga_bios,
  1073. "fda": settings.fda,
  1074. "hda": settings.hda,
  1075. "hdb": settings.hdb,
  1076. "cdrom": settings.cdrom,
  1077. "multiboot": settings.multiboot,
  1078. "bzimage": settings.bzimage,
  1079. "initrd": settings.initrd,
  1080. "cmdline": settings.cmdline,
  1081. "bzimage_initrd_from_filesystem": settings.bzimage_initrd_from_filesystem,
  1082. "acpi": enable_acpi,
  1083. "initial_state": settings.initial_state,
  1084. "filesystem": settings.filesystem || {},
  1085. "disable_speaker": disable_audio,
  1086. "preserve_mac_from_state_image": settings.preserve_mac_from_state_image,
  1087. "autostart": true,
  1088. });
  1089. if(DEBUG) window["emulator"] = emulator;
  1090. emulator.add_listener("emulator-ready", function()
  1091. {
  1092. if(DEBUG)
  1093. {
  1094. debug_start(emulator);
  1095. }
  1096. if(emulator.v86.cpu.wm.exports["profiler_is_enabled"]())
  1097. {
  1098. const CLEAR_STATS = false;
  1099. var panel = document.createElement("pre");
  1100. document.body.appendChild(panel);
  1101. setInterval(function()
  1102. {
  1103. if(!emulator.is_running())
  1104. {
  1105. return;
  1106. }
  1107. const text = print_stats.stats_to_string(emulator.v86.cpu);
  1108. panel.textContent = text;
  1109. CLEAR_STATS && emulator.v86.cpu.clear_opstats();
  1110. }, CLEAR_STATS ? 5000 : 1000);
  1111. }
  1112. if(settings.id === "dsl" || settings.id === "helenos")
  1113. {
  1114. setTimeout(() => {
  1115. // hack: Start automatically
  1116. emulator.keyboard_send_text("\n");
  1117. }, 3000);
  1118. }
  1119. else if(settings.id === "android" || settings.id === "android4")
  1120. {
  1121. setTimeout(() => {
  1122. // hack: select vesa mode and start automatically
  1123. emulator.keyboard_send_scancodes([0xe050, 0xe050 | 0x80]);
  1124. emulator.keyboard_send_text("\n");
  1125. }, 3000);
  1126. }
  1127. init_ui(settings, emulator);
  1128. done && done(emulator);
  1129. });
  1130. emulator.add_listener("download-progress", function(e)
  1131. {
  1132. show_progress(e);
  1133. });
  1134. emulator.add_listener("download-error", function(e)
  1135. {
  1136. var el = $("loading");
  1137. el.style.display = "block";
  1138. el.textContent = "Loading " + e.file_name + " failed. Check your connection " +
  1139. "and reload the page to try again.";
  1140. });
  1141. }
  1142. /**
  1143. * @param {Object} settings
  1144. * @param {V86Starter} emulator
  1145. */
  1146. function init_ui(settings, emulator)
  1147. {
  1148. $("boot_options").style.display = "none";
  1149. $("loading").style.display = "none";
  1150. $("runtime_options").style.display = "block";
  1151. $("runtime_infos").style.display = "block";
  1152. $("screen_container").style.display = "block";
  1153. if(settings.filesystem)
  1154. {
  1155. init_filesystem_panel(emulator);
  1156. }
  1157. else
  1158. {
  1159. emulator.add_listener("9p-attach", function()
  1160. {
  1161. init_filesystem_panel(emulator);
  1162. });
  1163. }
  1164. $("run").onclick = function()
  1165. {
  1166. if(emulator.is_running())
  1167. {
  1168. $("run").value = "Run";
  1169. emulator.stop();
  1170. }
  1171. else
  1172. {
  1173. $("run").value = "Pause";
  1174. emulator.run();
  1175. }
  1176. $("run").blur();
  1177. };
  1178. $("exit").onclick = function()
  1179. {
  1180. emulator.stop();
  1181. location.href = location.pathname;
  1182. };
  1183. $("lock_mouse").onclick = function()
  1184. {
  1185. if(!mouse_is_enabled)
  1186. {
  1187. $("toggle_mouse").onclick();
  1188. }
  1189. emulator.lock_mouse();
  1190. $("lock_mouse").blur();
  1191. };
  1192. var mouse_is_enabled = true;
  1193. $("toggle_mouse").onclick = function()
  1194. {
  1195. mouse_is_enabled = !mouse_is_enabled;
  1196. emulator.mouse_set_status(mouse_is_enabled);
  1197. $("toggle_mouse").value = (mouse_is_enabled ? "Dis" : "En") + "able mouse";
  1198. $("toggle_mouse").blur();
  1199. };
  1200. var last_tick = 0;
  1201. var running_time = 0;
  1202. var last_instr_counter = 0;
  1203. var interval = null;
  1204. var os_uses_mouse = false;
  1205. var total_instructions = 0;
  1206. function update_info()
  1207. {
  1208. var now = Date.now();
  1209. var instruction_counter = emulator.get_instruction_counter();
  1210. if(instruction_counter < last_instr_counter)
  1211. {
  1212. // 32-bit wrap-around
  1213. last_instr_counter -= 0x100000000;
  1214. }
  1215. var last_ips = instruction_counter - last_instr_counter;
  1216. last_instr_counter = instruction_counter;
  1217. total_instructions += last_ips;
  1218. var delta_time = now - last_tick;
  1219. if(delta_time)
  1220. {
  1221. running_time += delta_time;
  1222. last_tick = now;
  1223. $("speed").textContent = (last_ips / 1000 / delta_time).toFixed(1);
  1224. $("avg_speed").textContent = (total_instructions / 1000 / running_time).toFixed(1);
  1225. $("running_time").textContent = format_timestamp(running_time / 1000 | 0);
  1226. }
  1227. }
  1228. emulator.add_listener("emulator-started", function()
  1229. {
  1230. last_tick = Date.now();
  1231. interval = setInterval(update_info, 1000);
  1232. });
  1233. emulator.add_listener("emulator-stopped", function()
  1234. {
  1235. update_info();
  1236. if(interval !== null)
  1237. {
  1238. clearInterval(interval);
  1239. }
  1240. });
  1241. var stats_9p = {
  1242. read: 0,
  1243. write: 0,
  1244. files: [],
  1245. };
  1246. emulator.add_listener("9p-read-start", function(args)
  1247. {
  1248. const file = args[0];
  1249. stats_9p.files.push(file);
  1250. $("info_filesystem").style.display = "block";
  1251. $("info_filesystem_status").textContent = "Loading ...";
  1252. $("info_filesystem_last_file").textContent = file;
  1253. });
  1254. emulator.add_listener("9p-read-end", function(args)
  1255. {
  1256. stats_9p.read += args[1];
  1257. $("info_filesystem_bytes_read").textContent = stats_9p.read;
  1258. const file = args[0];
  1259. stats_9p.files = stats_9p.files.filter(f => f !== file);
  1260. if(stats_9p.files[0])
  1261. {
  1262. $("info_filesystem_last_file").textContent = stats_9p.files[0];
  1263. }
  1264. else
  1265. {
  1266. $("info_filesystem_status").textContent = "Idle";
  1267. }
  1268. });
  1269. emulator.add_listener("9p-write-end", function(args)
  1270. {
  1271. stats_9p.write += args[1];
  1272. $("info_filesystem_bytes_written").textContent = stats_9p.write;
  1273. if(!stats_9p.files[0])
  1274. {
  1275. $("info_filesystem_last_file").textContent = args[0];
  1276. }
  1277. });
  1278. var stats_storage = {
  1279. read: 0,
  1280. read_sectors: 0,
  1281. write: 0,
  1282. write_sectors: 0,
  1283. };
  1284. emulator.add_listener("ide-read-start", function()
  1285. {
  1286. $("info_storage").style.display = "block";
  1287. $("info_storage_status").textContent = "Loading ...";
  1288. });
  1289. emulator.add_listener("ide-read-end", function(args)
  1290. {
  1291. stats_storage.read += args[1];
  1292. stats_storage.read_sectors += args[2];
  1293. $("info_storage_status").textContent = "Idle";
  1294. $("info_storage_bytes_read").textContent = stats_storage.read;
  1295. $("info_storage_sectors_read").textContent = stats_storage.read_sectors;
  1296. });
  1297. emulator.add_listener("ide-write-end", function(args)
  1298. {
  1299. stats_storage.write += args[1];
  1300. stats_storage.write_sectors += args[2];
  1301. $("info_storage_bytes_written").textContent = stats_storage.write;
  1302. $("info_storage_sectors_written").textContent = stats_storage.write_sectors;
  1303. });
  1304. var stats_net = {
  1305. bytes_transmitted: 0,
  1306. bytes_received: 0,
  1307. };
  1308. emulator.add_listener("eth-receive-end", function(args)
  1309. {
  1310. stats_net.bytes_received += args[0];
  1311. $("info_network").style.display = "block";
  1312. $("info_network_bytes_received").textContent = stats_net.bytes_received;
  1313. });
  1314. emulator.add_listener("eth-transmit-end", function(args)
  1315. {
  1316. stats_net.bytes_transmitted += args[0];
  1317. $("info_network").style.display = "block";
  1318. $("info_network_bytes_transmitted").textContent = stats_net.bytes_transmitted;
  1319. });
  1320. emulator.add_listener("mouse-enable", function(is_enabled)
  1321. {
  1322. os_uses_mouse = is_enabled;
  1323. $("info_mouse_enabled").textContent = is_enabled ? "Yes" : "No";
  1324. });
  1325. emulator.add_listener("screen-set-mode", function(is_graphical)
  1326. {
  1327. if(is_graphical)
  1328. {
  1329. $("info_vga_mode").textContent = "Graphical";
  1330. }
  1331. else
  1332. {
  1333. $("info_vga_mode").textContent = "Text";
  1334. $("info_res").textContent = "-";
  1335. $("info_bpp").textContent = "-";
  1336. }
  1337. });
  1338. emulator.add_listener("screen-set-size-graphical", function(args)
  1339. {
  1340. $("info_res").textContent = args[0] + "x" + args[1];
  1341. $("info_bpp").textContent = args[4];
  1342. });
  1343. $("reset").onclick = function()
  1344. {
  1345. emulator.restart();
  1346. $("reset").blur();
  1347. };
  1348. add_image_download_button(settings.hda, "hda");
  1349. add_image_download_button(settings.hdb, "hdb");
  1350. add_image_download_button(settings.fda, "fda");
  1351. add_image_download_button(settings.fdb, "fdb");
  1352. add_image_download_button(settings.cdrom, "cdrom");
  1353. function add_image_download_button(obj, type)
  1354. {
  1355. var elem = $("get_" + type + "_image");
  1356. if(!obj || obj.size > 100 * 1024 * 1024)
  1357. {
  1358. elem.style.display = "none";
  1359. return;
  1360. }
  1361. elem.onclick = function(e)
  1362. {
  1363. let buffer = emulator.disk_images[type];
  1364. let filename = settings.id + (type === "cdrom" ? ".iso" : ".img");
  1365. if(buffer.get_as_file)
  1366. {
  1367. var file = buffer.get_as_file(filename);
  1368. download(file, filename);
  1369. }
  1370. else
  1371. {
  1372. buffer.get_buffer(function(b)
  1373. {
  1374. if(b)
  1375. {
  1376. dump_file(b, filename);
  1377. }
  1378. else
  1379. {
  1380. alert("The file could not be loaded. Maybe it's too big?");
  1381. }
  1382. });
  1383. }
  1384. elem.blur();
  1385. };
  1386. }
  1387. $("memory_dump").onclick = function()
  1388. {
  1389. const mem8 = emulator.v86.cpu.mem8;
  1390. dump_file(new Uint8Array(mem8.buffer, mem8.byteOffset, mem8.length), "v86memory.bin");
  1391. $("memory_dump").blur();
  1392. };
  1393. //$("memory_dump_dmp").onclick = function()
  1394. //{
  1395. // var memory = emulator.v86.cpu.mem8;
  1396. // var memory_size = memory.length;
  1397. // var page_size = 4096;
  1398. // var header = new Uint8Array(4096);
  1399. // var header32 = new Int32Array(header.buffer);
  1400. // header32[0] = 0x45474150; // 'PAGE'
  1401. // header32[1] = 0x504D5544; // 'DUMP'
  1402. // header32[0x10 >> 2] = emulator.v86.cpu.cr[3]; // DirectoryTableBase
  1403. // header32[0x24 >> 2] = 1; // NumberProcessors
  1404. // header32[0xf88 >> 2] = 1; // DumpType: full dump
  1405. // header32[0xfa0 >> 2] = header.length + memory_size; // RequiredDumpSpace
  1406. // header32[0x064 + 0 >> 2] = 1; // NumberOfRuns
  1407. // header32[0x064 + 4 >> 2] = memory_size / page_size; // NumberOfPages
  1408. // header32[0x064 + 8 >> 2] = 0; // BasePage
  1409. // header32[0x064 + 12 >> 2] = memory_size / page_size; // PageCount
  1410. // dump_file([header, memory], "v86memory.dmp");
  1411. // $("memory_dump_dmp").blur();
  1412. //};
  1413. $("save_state").onclick = function()
  1414. {
  1415. emulator.save_state(function(error, result)
  1416. {
  1417. if(error)
  1418. {
  1419. console.log(error.stack);
  1420. console.log("Couldn't save state: ", error);
  1421. }
  1422. else
  1423. {
  1424. dump_file(result, "v86state.bin");
  1425. }
  1426. });
  1427. $("save_state").blur();
  1428. };
  1429. $("load_state").onclick = function()
  1430. {
  1431. $("load_state_input").click();
  1432. $("load_state").blur();
  1433. };
  1434. $("load_state_input").onchange = function()
  1435. {
  1436. var file = this.files[0];
  1437. if(!file)
  1438. {
  1439. return;
  1440. }
  1441. var was_running = emulator.is_running();
  1442. if(was_running)
  1443. {
  1444. emulator.stop();
  1445. }
  1446. var filereader = new FileReader();
  1447. filereader.onload = function(e)
  1448. {
  1449. try
  1450. {
  1451. emulator.restore_state(e.target.result);
  1452. }
  1453. catch(err)
  1454. {
  1455. alert("Something bad happened while restoring the state:\n" + err + "\n\n" +
  1456. "Note that the current configuration must be the same as the original");
  1457. throw err;
  1458. }
  1459. if(was_running)
  1460. {
  1461. emulator.run();
  1462. }
  1463. };
  1464. filereader.readAsArrayBuffer(file);
  1465. this.value = "";
  1466. };
  1467. $("ctrlaltdel").onclick = function()
  1468. {
  1469. emulator.keyboard_send_scancodes([
  1470. 0x1D, // ctrl
  1471. 0x38, // alt
  1472. 0x53, // delete
  1473. // break codes
  1474. 0x1D | 0x80,
  1475. 0x38 | 0x80,
  1476. 0x53 | 0x80,
  1477. ]);
  1478. $("ctrlaltdel").blur();
  1479. };
  1480. $("alttab").onclick = function()
  1481. {
  1482. emulator.keyboard_send_scancodes([
  1483. 0x38, // alt
  1484. 0x0F, // tab
  1485. ]);
  1486. setTimeout(function()
  1487. {
  1488. emulator.keyboard_send_scancodes([
  1489. 0x38 | 0x80,
  1490. 0x0F | 0x80,
  1491. ]);
  1492. }, 100);
  1493. $("alttab").blur();
  1494. };
  1495. $("scale").onchange = function()
  1496. {
  1497. var n = parseFloat(this.value);
  1498. if(n || n > 0)
  1499. {
  1500. emulator.screen_set_scale(n, n);
  1501. }
  1502. };
  1503. $("fullscreen").onclick = function()
  1504. {
  1505. emulator.screen_go_fullscreen();
  1506. };
  1507. $("screen_container").onclick = function()
  1508. {
  1509. if(mouse_is_enabled && os_uses_mouse)
  1510. {
  1511. emulator.lock_mouse();
  1512. $("lock_mouse").blur();
  1513. }
  1514. else
  1515. {
  1516. // allow text selection
  1517. if(window.getSelection().isCollapsed)
  1518. {
  1519. let phone_keyboard = document.getElementsByClassName("phone_keyboard")[0];
  1520. // stop mobile browser from scrolling into view when the keyboard is shown
  1521. phone_keyboard.style.top = document.body.scrollTop + 100 + "px";
  1522. phone_keyboard.style.left = document.body.scrollLeft + 100 + "px";
  1523. phone_keyboard.focus();
  1524. }
  1525. }
  1526. };
  1527. const phone_keyboard = document.getElementsByClassName("phone_keyboard")[0];
  1528. phone_keyboard.setAttribute("autocorrect", "off");
  1529. phone_keyboard.setAttribute("autocapitalize", "off");
  1530. phone_keyboard.setAttribute("spellcheck", "false");
  1531. phone_keyboard.tabIndex = 0;
  1532. $("screen_container").addEventListener("mousedown", (e) =>
  1533. {
  1534. e.preventDefault();
  1535. phone_keyboard.focus();
  1536. }, false);
  1537. $("take_screenshot").onclick = function()
  1538. {
  1539. emulator.screen_make_screenshot();
  1540. $("take_screenshot").blur();
  1541. };
  1542. if(emulator.speaker_adapter)
  1543. {
  1544. let is_muted = false;
  1545. $("mute").onclick = function()
  1546. {
  1547. if(is_muted)
  1548. {
  1549. emulator.speaker_adapter.mixer.set_volume(1, undefined);
  1550. is_muted = false;
  1551. $("mute").value = "Mute";
  1552. }
  1553. else
  1554. {
  1555. emulator.speaker_adapter.mixer.set_volume(0, undefined);
  1556. is_muted = true;
  1557. $("mute").value = "Unmute";
  1558. }
  1559. $("mute").blur();
  1560. };
  1561. }
  1562. else
  1563. {
  1564. $("mute").remove();
  1565. }
  1566. window.addEventListener("keydown", ctrl_w_rescue, false);
  1567. window.addEventListener("keyup", ctrl_w_rescue, false);
  1568. window.addEventListener("blur", ctrl_w_rescue, false);
  1569. function ctrl_w_rescue(e)
  1570. {
  1571. if(e.ctrlKey)
  1572. {
  1573. window.onbeforeunload = function()
  1574. {
  1575. window.onbeforeunload = null;
  1576. return "CTRL-W cannot be sent to the emulator.";
  1577. };
  1578. }
  1579. else
  1580. {
  1581. window.onbeforeunload = null;
  1582. }
  1583. }
  1584. }
  1585. function init_filesystem_panel(emulator)
  1586. {
  1587. $("filesystem_panel").style.display = "block";
  1588. $("filesystem_send_file").onchange = function()
  1589. {
  1590. Array.prototype.forEach.call(this.files, function(file)
  1591. {
  1592. var loader = new v86util.SyncFileBuffer(file);
  1593. loader.onload = function()
  1594. {
  1595. loader.get_buffer(function(buffer)
  1596. {
  1597. emulator.create_file("/" + file.name, new Uint8Array(buffer));
  1598. });
  1599. };
  1600. loader.load();
  1601. }, this);
  1602. this.value = "";
  1603. this.blur();
  1604. };
  1605. $("filesystem_get_file").onkeypress = function(e)
  1606. {
  1607. if(e.which !== 13)
  1608. {
  1609. return;
  1610. }
  1611. this.disabled = true;
  1612. emulator.read_file(this.value, function(err, uint8array)
  1613. {
  1614. this.disabled = false;
  1615. if(uint8array)
  1616. {
  1617. var filename = this.value.replace(/\/$/, "").split("/");
  1618. filename = filename[filename.length - 1] || "root";
  1619. dump_file(uint8array, filename);
  1620. this.value = "";
  1621. }
  1622. else
  1623. {
  1624. alert("Can't read file");
  1625. }
  1626. }.bind(this));
  1627. };
  1628. }
  1629. function debug_start(emulator)
  1630. {
  1631. if(!emulator.v86)
  1632. {
  1633. return;
  1634. }
  1635. // called as soon as soon as emulation is started, in debug mode
  1636. var debug = emulator.v86.cpu.debug;
  1637. $("dump_gdt").onclick = debug.dump_gdt_ldt.bind(debug);
  1638. $("dump_idt").onclick = debug.dump_idt.bind(debug);
  1639. $("dump_regs").onclick = debug.dump_regs.bind(debug);
  1640. $("dump_pt").onclick = debug.dump_page_structures.bind(debug);
  1641. $("dump_log").onclick = function()
  1642. {
  1643. dump_file(log_data.join(""), "v86.log");
  1644. };
  1645. var cpu = emulator.v86.cpu;
  1646. $("debug_panel").style.display = "block";
  1647. setInterval(function()
  1648. {
  1649. $("debug_panel").textContent =
  1650. cpu.debug.get_regs_short().join("\n") + "\n" + cpu.debug.get_state();
  1651. $("dump_log").value = "Dump log" + (log_data.length ? " (" + log_data.length + " lines)" : "");
  1652. }, 1000);
  1653. // helps debugging
  1654. window.emulator = emulator;
  1655. window.cpu = cpu;
  1656. window.dump_file = dump_file;
  1657. }
  1658. function onpopstate(e)
  1659. {
  1660. location.reload();
  1661. }
  1662. function set_profile(prof)
  1663. {
  1664. if(window.history.pushState)
  1665. {
  1666. window.history.pushState({ profile: prof }, "", "?profile=" + prof);
  1667. }
  1668. }
  1669. })();