ne2k.js 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  1. "use strict";
  2. // http://www.ethernut.de/pdf/8019asds.pdf
  3. const NE2K_LOG_VERBOSE = false;
  4. const NE2K_LOG_PACKETS = false;
  5. /** @const */ var E8390_CMD = 0x00; /* The command register (for all pages) */
  6. /* Page 0 register offsets. */
  7. /** @const */ var EN0_CLDALO = 0x01; /* Low byte of current local dma addr RD */
  8. /** @const */ var EN0_STARTPG = 0x01; /* Starting page of ring bfr WR */
  9. /** @const */ var EN0_CLDAHI = 0x02; /* High byte of current local dma addr RD */
  10. /** @const */ var EN0_STOPPG = 0x02; /* Ending page +1 of ring bfr WR */
  11. /** @const */ var EN0_BOUNDARY = 0x03; /* Boundary page of ring bfr RD WR */
  12. /** @const */ var EN0_TSR = 0x04; /* Transmit status reg RD */
  13. /** @const */ var EN0_TPSR = 0x04; /* Transmit starting page WR */
  14. /** @const */ var EN0_NCR = 0x05; /* Number of collision reg RD */
  15. /** @const */ var EN0_TCNTLO = 0x05; /* Low byte of tx byte count WR */
  16. /** @const */ var EN0_FIFO = 0x06; /* FIFO RD */
  17. /** @const */ var EN0_TCNTHI = 0x06; /* High byte of tx byte count WR */
  18. /** @const */ var EN0_ISR = 0x07; /* Interrupt status reg RD WR */
  19. /** @const */ var EN0_CRDALO = 0x08; /* low byte of current remote dma address RD */
  20. /** @const */ var EN0_RSARLO = 0x08; /* Remote start address reg 0 */
  21. /** @const */ var EN0_CRDAHI = 0x09; /* high byte, current remote dma address RD */
  22. /** @const */ var EN0_RSARHI = 0x09; /* Remote start address reg 1 */
  23. /** @const */ var EN0_RCNTLO = 0x0a; /* Remote byte count reg WR */
  24. /** @const */ var EN0_RCNTHI = 0x0b; /* Remote byte count reg WR */
  25. /** @const */ var EN0_RSR = 0x0c; /* rx status reg RD */
  26. /** @const */ var EN0_RXCR = 0x0c; /* RX configuration reg WR */
  27. /** @const */ var EN0_TXCR = 0x0d; /* TX configuration reg WR */
  28. /** @const */ var EN0_COUNTER0 = 0x0d; /* Rcv alignment error counter RD */
  29. /** @const */ var EN0_DCFG = 0x0e; /* Data configuration reg WR */
  30. /** @const */ var EN0_COUNTER1 = 0x0e; /* Rcv CRC error counter RD */
  31. /** @const */ var EN0_IMR = 0x0f; /* Interrupt mask reg WR */
  32. /** @const */ var EN0_COUNTER2 = 0x0f; /* Rcv missed frame error counter RD */
  33. /** @const */ var NE_DATAPORT = 0x10; /* NatSemi-defined port window offset. */
  34. /** @const */ var NE_RESET = 0x1f; /* Issue a read to reset, a write to clear. */
  35. /* Bits in EN0_ISR - Interrupt status register */
  36. /** @const */ var ENISR_RX = 0x01; /* Receiver, no error */
  37. /** @const */ var ENISR_TX = 0x02; /* Transmitter, no error */
  38. /** @const */ var ENISR_RX_ERR = 0x04; /* Receiver, with error */
  39. /** @const */ var ENISR_TX_ERR = 0x08; /* Transmitter, with error */
  40. /** @const */ var ENISR_OVER = 0x10; /* Receiver overwrote the ring */
  41. /** @const */ var ENISR_COUNTERS = 0x20; /* Counters need emptying */
  42. /** @const */ var ENISR_RDC = 0x40; /* remote dma complete */
  43. /** @const */ var ENISR_RESET = 0x80; /* Reset completed */
  44. /** @const */ var ENISR_ALL = 0x3f; /* Interrupts we will enable */
  45. /** @const */ var ENRSR_RXOK = 0x01; /* Received a good packet */
  46. /** @const */ var START_PAGE = 0x40;
  47. /** @const */ var START_RX_PAGE = 0x40 + 12;
  48. /** @const */ var STOP_PAGE = 0x80;
  49. // Search and replace MAC addresses in ethernet, arp and dhcp packets.
  50. // Used after restoring an OS from memory dump, so that multiple instances of
  51. // that OS can run at the same time with different external MAC addresses.
  52. // Crude but seems to work.
  53. function translate_mac_address(packet, search_mac, replacement_mac)
  54. {
  55. if(packet[0] === search_mac[0] &&
  56. packet[1] === search_mac[1] &&
  57. packet[2] === search_mac[2] &&
  58. packet[3] === search_mac[3] &&
  59. packet[4] === search_mac[4] &&
  60. packet[5] === search_mac[5])
  61. {
  62. dbg_log("Replace mac in eth destination field", LOG_NET);
  63. packet[0] = replacement_mac[0];
  64. packet[1] = replacement_mac[1];
  65. packet[2] = replacement_mac[2];
  66. packet[3] = replacement_mac[3];
  67. packet[4] = replacement_mac[4];
  68. packet[5] = replacement_mac[5];
  69. }
  70. if(packet[6 + 0] === search_mac[0] &&
  71. packet[6 + 1] === search_mac[1] &&
  72. packet[6 + 2] === search_mac[2] &&
  73. packet[6 + 3] === search_mac[3] &&
  74. packet[6 + 4] === search_mac[4] &&
  75. packet[6 + 5] === search_mac[5])
  76. {
  77. dbg_log("Replace mac in eth source field", LOG_NET);
  78. packet[6 + 0] = replacement_mac[0];
  79. packet[6 + 1] = replacement_mac[1];
  80. packet[6 + 2] = replacement_mac[2];
  81. packet[6 + 3] = replacement_mac[3];
  82. packet[6 + 4] = replacement_mac[4];
  83. packet[6 + 5] = replacement_mac[5];
  84. }
  85. const ethertype = packet[12] << 8 | packet[13];
  86. if(ethertype === 0x0800)
  87. {
  88. // ipv4
  89. const ipv4_packet = packet.subarray(14);
  90. const ipv4_version = ipv4_packet[0] >> 4;
  91. if(ipv4_version !== 4)
  92. {
  93. dbg_log("Expected ipv4.version==4 but got: " + ipv4_version, LOG_NET);
  94. return;
  95. }
  96. const ipv4_ihl = ipv4_packet[0] & 0xF;
  97. dbg_assert(ipv4_ihl === 5, "TODO: ihl!=5");
  98. const ipv4_proto = ipv4_packet[9];
  99. if(ipv4_proto === 0x11)
  100. {
  101. // udp
  102. const udp_packet = ipv4_packet.subarray(5 * 4);
  103. const source_port = udp_packet[0] << 8 | udp_packet[1];
  104. const destination_port = udp_packet[2] << 8 | udp_packet[3];
  105. const checksum = udp_packet[6] << 8 | udp_packet[7];
  106. dbg_log("udp srcport=" + source_port + " dstport=" + destination_port + " checksum=" + h(checksum, 4), LOG_NET);
  107. if(source_port === 67 || destination_port === 67)
  108. {
  109. // dhcp
  110. const dhcp_packet = udp_packet.subarray(8);
  111. const dhcp_magic = dhcp_packet[0xEC] << 24 | dhcp_packet[0xED] << 16 | dhcp_packet[0xEE] << 8 | dhcp_packet[0xEF];
  112. if(dhcp_magic !== 0x63825363)
  113. {
  114. dbg_log("dhcp packet didn't match magic: " + h(dhcp_magic, 8));
  115. return;
  116. }
  117. if(dhcp_packet[28 + 0] === search_mac[0] &&
  118. dhcp_packet[28 + 1] === search_mac[1] &&
  119. dhcp_packet[28 + 2] === search_mac[2] &&
  120. dhcp_packet[28 + 3] === search_mac[3] &&
  121. dhcp_packet[28 + 4] === search_mac[4] &&
  122. dhcp_packet[28 + 5] === search_mac[5])
  123. {
  124. dbg_log("Replace mac in dhcp.chaddr", LOG_NET);
  125. dhcp_packet[28 + 0] = replacement_mac[0];
  126. dhcp_packet[28 + 1] = replacement_mac[1];
  127. dhcp_packet[28 + 2] = replacement_mac[2];
  128. dhcp_packet[28 + 3] = replacement_mac[3];
  129. dhcp_packet[28 + 4] = replacement_mac[4];
  130. dhcp_packet[28 + 5] = replacement_mac[5];
  131. udp_packet[6] = udp_packet[7] = 0; // zero udp checksum
  132. }
  133. let offset = 0xF0;
  134. while(offset < dhcp_packet.length)
  135. {
  136. const dhcp_option_type = dhcp_packet[offset++];
  137. if(dhcp_option_type === 0xFF)
  138. {
  139. break;
  140. }
  141. const length = dhcp_packet[offset++];
  142. if(dhcp_option_type === 0x3D && // client identifier
  143. dhcp_packet[offset + 0] === 0x01 && // ethernet
  144. dhcp_packet[offset + 1] === search_mac[0] &&
  145. dhcp_packet[offset + 2] === search_mac[1] &&
  146. dhcp_packet[offset + 3] === search_mac[2] &&
  147. dhcp_packet[offset + 4] === search_mac[3] &&
  148. dhcp_packet[offset + 5] === search_mac[4] &&
  149. dhcp_packet[offset + 6] === search_mac[5])
  150. {
  151. dbg_log("Replace mac in dhcp.clientidentifier", LOG_NET);
  152. dhcp_packet[offset + 1] = replacement_mac[0];
  153. dhcp_packet[offset + 2] = replacement_mac[1];
  154. dhcp_packet[offset + 3] = replacement_mac[2];
  155. dhcp_packet[offset + 4] = replacement_mac[3];
  156. dhcp_packet[offset + 5] = replacement_mac[4];
  157. dhcp_packet[offset + 6] = replacement_mac[5];
  158. udp_packet[6] = udp_packet[7] = 0; // zero udp checksum
  159. }
  160. offset += length;
  161. }
  162. }
  163. }
  164. else
  165. {
  166. // tcp, ...
  167. }
  168. }
  169. else if(ethertype === 0x0806)
  170. {
  171. // arp
  172. const arp_packet = packet.subarray(14);
  173. dbg_log("arp oper=" + arp_packet[7] + " " + format_mac(arp_packet.subarray(8, 8+6)) + " " + format_mac(arp_packet.subarray(18, 18+6)), LOG_NET);
  174. if(arp_packet[8 + 0] === search_mac[0] &&
  175. arp_packet[8 + 1] === search_mac[1] &&
  176. arp_packet[8 + 2] === search_mac[2] &&
  177. arp_packet[8 + 3] === search_mac[3] &&
  178. arp_packet[8 + 4] === search_mac[4] &&
  179. arp_packet[8 + 5] === search_mac[5])
  180. {
  181. dbg_log("Replace mac in arp.sha", LOG_NET);
  182. arp_packet[8 + 0] = replacement_mac[0];
  183. arp_packet[8 + 1] = replacement_mac[1];
  184. arp_packet[8 + 2] = replacement_mac[2];
  185. arp_packet[8 + 3] = replacement_mac[3];
  186. arp_packet[8 + 4] = replacement_mac[4];
  187. arp_packet[8 + 5] = replacement_mac[5];
  188. }
  189. }
  190. else
  191. {
  192. // TODO: ipv6, ...
  193. }
  194. }
  195. function format_mac(mac)
  196. {
  197. return [
  198. mac[0].toString(16).padStart(2, "0"),
  199. mac[1].toString(16).padStart(2, "0"),
  200. mac[2].toString(16).padStart(2, "0"),
  201. mac[3].toString(16).padStart(2, "0"),
  202. mac[4].toString(16).padStart(2, "0"),
  203. mac[5].toString(16).padStart(2, "0"),
  204. ].join(":");
  205. }
  206. function dump_packet(packet, prefix)
  207. {
  208. const ethertype = packet[12] << 8 | packet[13] << 0;
  209. if(ethertype === 0x0800)
  210. {
  211. const ipv4_packet = packet.subarray(14);
  212. const ipv4_len = ipv4_packet[2] << 8 | ipv4_packet[3];
  213. const ipv4_proto = ipv4_packet[9];
  214. if(ipv4_proto === 0x11)
  215. {
  216. const udp_packet = ipv4_packet.subarray(5 * 4);
  217. const source_port = udp_packet[0] << 8 | udp_packet[1];
  218. const destination_port = udp_packet[2] << 8 | udp_packet[3];
  219. const checksum = udp_packet[6] << 8 | udp_packet[7];
  220. if(source_port === 67 || destination_port === 67)
  221. {
  222. const dhcp_packet = udp_packet.subarray(8);
  223. const dhcp_chaddr = dhcp_packet.subarray(28, 28+6);
  224. dbg_log(prefix + " len=" + packet.length + " ethertype=" + h(ethertype) + " ipv4.len=" + ipv4_len + " ipv4.proto=" + h(packet[14 + 9]) + " udp.srcport=" + source_port + " udp.dstport=" + destination_port + " udp.chksum=" + h(checksum, 4) + " dhcp.chaddr=" + format_mac(dhcp_chaddr));
  225. }
  226. else
  227. {
  228. dbg_log(prefix + " len=" + packet.length + " ethertype=" + h(ethertype) + " ipv4.len=" + ipv4_len + " ipv4.proto=" + h(packet[14 + 9]) + " udp.srcport=" + source_port + " udp.dstport=" + destination_port + " udp.chksum=" + h(checksum, 4));
  229. }
  230. }
  231. else if(ipv4_proto === 0x01)
  232. {
  233. }
  234. else
  235. {
  236. dbg_log(prefix + " len=" + packet.length + " ethertype=" + h(ethertype) + " ipv4.len=" + ipv4_len + " ipv4.proto=" + h(packet[14 + 9]));
  237. }
  238. }
  239. else
  240. {
  241. const arp_packet = packet.subarray(14);
  242. dbg_log(prefix + " len=" + packet.length + " ethertype=" + h(ethertype) + " arp");
  243. }
  244. dbg_log(hex_dump(packet));
  245. }
  246. /**
  247. * @constructor
  248. * @param {CPU} cpu
  249. * @param {BusConnector} bus
  250. * @param {Boolean} preserve_mac_from_state_image
  251. * @param {Boolean} mac_address_translation
  252. */
  253. function Ne2k(cpu, bus, preserve_mac_from_state_image, mac_address_translation)
  254. {
  255. /** @const @type {CPU} */
  256. this.cpu = cpu;
  257. /** @const @type {PCI} */
  258. this.pci = cpu.devices.pci;
  259. this.preserve_mac_from_state_image = preserve_mac_from_state_image;
  260. this.mac_address_translation = mac_address_translation;
  261. /** @const @type {BusConnector} */
  262. this.bus = bus;
  263. this.bus.register("net0-receive", function(data)
  264. {
  265. this.receive(data);
  266. }, this);
  267. this.port = 0x300;
  268. this.name = "ne2k";
  269. /** @const */
  270. var use_pci = true;
  271. if(use_pci)
  272. {
  273. this.pci_space = [
  274. 0xec, 0x10, 0x29, 0x80, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
  275. this.port & 0xFF | 1, this.port >> 8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  276. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x1a, 0x00, 0x11,
  277. 0x00, 0x00, 0xb8, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
  278. ];
  279. this.pci_id = 0x05 << 3;
  280. this.pci_bars = [
  281. {
  282. size: 32,
  283. },
  284. ];
  285. }
  286. this.isr = 0;
  287. this.imr = 0; // interrupt mask register
  288. this.cr = 1;
  289. this.dcfg = 0;
  290. this.rcnt = 0;
  291. this.tcnt = 0;
  292. this.tpsr = 0;
  293. this.memory = new Uint8Array(256 * 0x80);
  294. this.rxcr = 0;
  295. this.txcr = 0;
  296. this.tsr = 1;
  297. // mac address
  298. this.mac = new Uint8Array([
  299. 0x00, 0x22, 0x15,
  300. Math.random() * 255 | 0,
  301. Math.random() * 255 | 0,
  302. Math.random() * 255 | 0,
  303. ]);
  304. // Used for mac address translation
  305. // The mac the OS thinks it has
  306. this.mac_address_in_state = null;
  307. for(var i = 0; i < 6; i++)
  308. {
  309. this.memory[i << 1] = this.memory[i << 1 | 1] = this.mac[i];
  310. }
  311. // the PROM signature of 0x57, 0x57 is also doubled
  312. // resulting in setting the 4 bytes at the end, 28, 29, 30 and 31 to 0x57
  313. this.memory[14 << 1] = this.memory[14 << 1 | 1] = 0x57;
  314. this.memory[15 << 1] = this.memory[15 << 1 | 1] = 0x57;
  315. dbg_log("Mac: " + format_mac(this.mac), LOG_NET);
  316. this.rsar = 0;
  317. this.pstart = START_PAGE;
  318. this.pstop = STOP_PAGE;
  319. this.curpg = START_RX_PAGE;
  320. this.boundary = START_RX_PAGE;
  321. var io = cpu.io;
  322. io.register_read(this.port | E8390_CMD, this, function()
  323. {
  324. dbg_log("Read cmd", LOG_NET);
  325. return this.cr;
  326. });
  327. io.register_write(this.port | E8390_CMD, this, function(data_byte)
  328. {
  329. this.cr = data_byte;
  330. dbg_log("Write command: " + h(data_byte, 2) + " newpg=" + (this.cr >> 6) + " txcr=" + h(this.txcr, 2), LOG_NET);
  331. if(this.cr & 1)
  332. {
  333. return;
  334. }
  335. if((data_byte & 0x18) && this.rcnt === 0)
  336. {
  337. this.do_interrupt(ENISR_RDC);
  338. }
  339. if(data_byte & 4)
  340. {
  341. var start = this.tpsr << 8;
  342. var data = this.memory.subarray(start, start + this.tcnt);
  343. if(NE2K_LOG_PACKETS)
  344. {
  345. dump_packet(data, "send");
  346. }
  347. if(this.mac_address_in_state)
  348. {
  349. data = new Uint8Array(data); // make a copy
  350. translate_mac_address(data, this.mac_address_in_state, this.mac);
  351. }
  352. this.bus.send("net0-send", data);
  353. this.bus.send("eth-transmit-end", [data.length]);
  354. this.cr &= ~4;
  355. this.do_interrupt(ENISR_TX);
  356. dbg_log("Command: Transfer. length=" + h(data.byteLength), LOG_NET);
  357. }
  358. });
  359. io.register_read(this.port | EN0_COUNTER0, this, function()
  360. {
  361. dbg_log("Read counter0", LOG_NET);
  362. return 0;
  363. });
  364. io.register_read(this.port | EN0_COUNTER1, this, function()
  365. {
  366. dbg_log("Read8 counter1", LOG_NET);
  367. return 0;
  368. }, function()
  369. {
  370. dbg_log("Read16 counter1", LOG_NET);
  371. // openbsd
  372. return 0;
  373. }
  374. );
  375. io.register_read(this.port | EN0_COUNTER2, this, function()
  376. {
  377. dbg_log("Read counter2", LOG_NET);
  378. return 0;
  379. });
  380. io.register_read(this.port | NE_RESET, this, function()
  381. {
  382. var pg = this.get_page();
  383. dbg_log("Read reset", LOG_NET);
  384. this.do_interrupt(ENISR_RESET);
  385. return 0;
  386. });
  387. io.register_write(this.port | NE_RESET, this, function(data_byte)
  388. {
  389. var pg = this.get_page();
  390. dbg_log("Write reset: " + h(data_byte, 2), LOG_NET);
  391. //this.isr &= ~ENISR_RESET;
  392. });
  393. io.register_read(this.port | EN0_STARTPG, this, function()
  394. {
  395. var pg = this.get_page();
  396. if(pg === 0)
  397. {
  398. return this.pstart;
  399. }
  400. else if(pg === 1)
  401. {
  402. dbg_log("Read pg1/01 (mac[0])", LOG_NET);
  403. return this.mac[0];
  404. }
  405. else if(pg === 2)
  406. {
  407. return this.pstart;
  408. }
  409. else
  410. {
  411. dbg_log("Read pg" + pg + "/01");
  412. dbg_assert(false);
  413. return 0;
  414. }
  415. });
  416. io.register_write(this.port | EN0_STARTPG, this, function(data_byte)
  417. {
  418. var pg = this.get_page();
  419. if(pg === 0)
  420. {
  421. dbg_log("start page: " + h(data_byte, 2), LOG_NET);
  422. this.pstart = data_byte;
  423. }
  424. else if(pg === 1)
  425. {
  426. dbg_log("mac[0] = " + h(data_byte), LOG_NET);
  427. this.mac[0] = data_byte;
  428. }
  429. else if(pg === 3)
  430. {
  431. dbg_log("Unimplemented: Write pg3/01 (9346CR): " + h(data_byte), LOG_NET);
  432. }
  433. else
  434. {
  435. dbg_log("Write pg" + pg + "/01: " + h(data_byte), LOG_NET);
  436. dbg_assert(false);
  437. }
  438. });
  439. io.register_read(this.port | EN0_STOPPG, this, function()
  440. {
  441. var pg = this.get_page();
  442. if(pg === 0)
  443. {
  444. return this.pstop;
  445. }
  446. else if(pg === 1)
  447. {
  448. dbg_log("Read pg1/02 (mac[1])", LOG_NET);
  449. return this.mac[1];
  450. }
  451. else if(pg === 2)
  452. {
  453. return this.pstop;
  454. }
  455. else
  456. {
  457. dbg_log("Read pg" + pg + "/02", LOG_NET);
  458. dbg_assert(false);
  459. return 0;
  460. }
  461. });
  462. io.register_write(this.port | EN0_STOPPG, this, function(data_byte)
  463. {
  464. var pg = this.get_page();
  465. if(pg === 0)
  466. {
  467. dbg_log("stop page: " + h(data_byte, 2), LOG_NET);
  468. if(data_byte > (this.memory.length >> 8))
  469. {
  470. data_byte = this.memory.length >> 8;
  471. dbg_log("XXX: Adjusting stop page to " + h(data_byte), LOG_NET);
  472. }
  473. this.pstop = data_byte;
  474. }
  475. else if(pg === 1)
  476. {
  477. dbg_log("mac[1] = " + h(data_byte), LOG_NET);
  478. this.mac[1] = data_byte;
  479. }
  480. else
  481. {
  482. dbg_log("Write pg" + pg + "/02: " + h(data_byte), LOG_NET);
  483. dbg_assert(false);
  484. }
  485. });
  486. io.register_read(this.port | EN0_ISR, this, function()
  487. {
  488. var pg = this.get_page();
  489. if(pg === 0)
  490. {
  491. dbg_log("Read isr: " + h(this.isr, 2), LOG_NET);
  492. return this.isr;
  493. }
  494. else if(pg === 1)
  495. {
  496. dbg_log("Read curpg: " + h(this.curpg, 2), LOG_NET);
  497. return this.curpg;
  498. }
  499. else
  500. {
  501. dbg_assert(false);
  502. }
  503. });
  504. io.register_write(this.port | EN0_ISR, this, function(data_byte)
  505. {
  506. var pg = this.get_page();
  507. if(pg === 0)
  508. {
  509. // acknowledge interrupts where bit is set
  510. dbg_log("Write isr: " + h(data_byte, 2), LOG_NET);
  511. this.isr &= ~data_byte;
  512. this.update_irq();
  513. }
  514. else if(pg === 1)
  515. {
  516. dbg_log("Write curpg: " + h(data_byte, 2), LOG_NET);
  517. this.curpg = data_byte;
  518. }
  519. else
  520. {
  521. dbg_assert(false);
  522. }
  523. });
  524. io.register_write(this.port | EN0_TXCR, this, function(data_byte)
  525. {
  526. var pg = this.get_page();
  527. if(pg === 0)
  528. {
  529. this.txcr = data_byte;
  530. dbg_log("Write tx config: " + h(data_byte, 2), LOG_NET);
  531. }
  532. else
  533. {
  534. dbg_log("Unimplemented: Write pg" + pg + "/0d " + h(data_byte, 2), LOG_NET);
  535. }
  536. });
  537. io.register_write(this.port | EN0_DCFG, this, function(data_byte)
  538. {
  539. var pg = this.get_page();
  540. if(pg === 0)
  541. {
  542. dbg_log("Write data configuration: " + h(data_byte, 2), LOG_NET);
  543. this.dcfg = data_byte;
  544. }
  545. else
  546. {
  547. dbg_log("Unimplemented: Write pg" + pg + "/0e " + h(data_byte, 2), LOG_NET);
  548. }
  549. });
  550. io.register_read(this.port | EN0_RCNTLO, this, function()
  551. {
  552. var pg = this.get_page();
  553. if(pg === 0)
  554. {
  555. dbg_log("Read pg0/0a", LOG_NET);
  556. return 0x50;
  557. }
  558. else
  559. {
  560. dbg_assert(false, "TODO");
  561. return 0;
  562. }
  563. });
  564. io.register_write(this.port | EN0_RCNTLO, this, function(data_byte)
  565. {
  566. var pg = this.get_page();
  567. if(pg === 0)
  568. {
  569. dbg_log("Write remote byte count low: " + h(data_byte, 2), LOG_NET);
  570. this.rcnt = this.rcnt & 0xFF00 | data_byte & 0xFF;
  571. }
  572. else
  573. {
  574. dbg_log("Unimplemented: Write pg" + pg + "/0a " + h(data_byte, 2), LOG_NET);
  575. }
  576. });
  577. io.register_read(this.port | EN0_RCNTHI, this, function()
  578. {
  579. var pg = this.get_page();
  580. if(pg === 0)
  581. {
  582. dbg_log("Read pg0/0b", LOG_NET);
  583. return 0x43;
  584. }
  585. else
  586. {
  587. dbg_assert(false, "TODO");
  588. return 0;
  589. }
  590. });
  591. io.register_write(this.port | EN0_RCNTHI, this, function(data_byte)
  592. {
  593. var pg = this.get_page();
  594. if(pg === 0)
  595. {
  596. dbg_log("Write remote byte count high: " + h(data_byte, 2), LOG_NET);
  597. this.rcnt = this.rcnt & 0xFF | data_byte << 8 & 0xFF00;
  598. }
  599. else
  600. {
  601. dbg_log("Unimplemented: Write pg" + pg + "/0b " + h(data_byte, 2), LOG_NET);
  602. }
  603. });
  604. io.register_read(this.port | EN0_RSARLO, this, function()
  605. {
  606. var pg = this.get_page();
  607. if(pg === 0)
  608. {
  609. dbg_log("Read remote start address low", LOG_NET);
  610. return this.rsar & 0xFF;
  611. }
  612. else
  613. {
  614. dbg_log("Unimplemented: Read pg" + pg + "/08", LOG_NET);
  615. dbg_assert(false);
  616. }
  617. });
  618. io.register_write(this.port | EN0_RSARLO, this, function(data_byte)
  619. {
  620. var pg = this.get_page();
  621. if(pg === 0)
  622. {
  623. dbg_log("Write remote start address low: " + h(data_byte, 2), LOG_NET);
  624. this.rsar = this.rsar & 0xFF00 | data_byte & 0xFF;
  625. }
  626. else
  627. {
  628. dbg_log("Unimplemented: Write pg" + pg + "/08 " + h(data_byte, 2), LOG_NET);
  629. }
  630. });
  631. io.register_read(this.port | EN0_RSARHI, this, function()
  632. {
  633. var pg = this.get_page();
  634. if(pg === 0)
  635. {
  636. dbg_log("Read remote start address high", LOG_NET);
  637. return this.rsar >> 8 & 0xFF;
  638. }
  639. else
  640. {
  641. dbg_log("Unimplemented: Read pg" + pg + "/09", LOG_NET);
  642. dbg_assert(false);
  643. }
  644. });
  645. io.register_write(this.port | EN0_RSARHI, this, function(data_byte)
  646. {
  647. var pg = this.get_page();
  648. if(pg === 0)
  649. {
  650. dbg_log("Write remote start address low: " + h(data_byte, 2), LOG_NET);
  651. this.rsar = this.rsar & 0xFF | data_byte << 8 & 0xFF00;
  652. }
  653. else
  654. {
  655. dbg_log("Unimplemented: Write pg" + pg + "/09 " + h(data_byte, 2), LOG_NET);
  656. }
  657. });
  658. io.register_write(this.port | EN0_IMR, this, function(data_byte)
  659. {
  660. var pg = this.get_page();
  661. if(pg === 0)
  662. {
  663. dbg_log("Write interrupt mask register: " + h(data_byte, 2) + " isr=" + h(this.isr, 2), LOG_NET);
  664. this.imr = data_byte;
  665. this.update_irq();
  666. }
  667. else
  668. {
  669. dbg_log("Unimplemented: Write pg" + pg + "/0f " + h(data_byte, 2), LOG_NET);
  670. }
  671. });
  672. io.register_read(this.port | EN0_BOUNDARY, this, function()
  673. {
  674. var pg = this.get_page();
  675. if(pg === 0)
  676. {
  677. dbg_log("Read boundary: " + h(this.boundary, 2), LOG_NET);
  678. return this.boundary;
  679. }
  680. else if(pg === 1)
  681. {
  682. dbg_log("Read pg1/03 (mac[2])", LOG_NET);
  683. return this.mac[2];
  684. }
  685. else if(pg === 3)
  686. {
  687. dbg_log("Unimplemented: Read pg3/03 (CONFIG0)", LOG_NET);
  688. return 0;
  689. }
  690. else
  691. {
  692. dbg_log("Read pg" + pg + "/03", LOG_NET);
  693. dbg_assert(false);
  694. return 0;
  695. }
  696. });
  697. io.register_write(this.port | EN0_BOUNDARY, this, function(data_byte)
  698. {
  699. var pg = this.get_page();
  700. if(pg === 0)
  701. {
  702. dbg_log("Write boundary: " + h(data_byte, 2), LOG_NET);
  703. this.boundary = data_byte;
  704. }
  705. else if(pg === 1)
  706. {
  707. dbg_log("mac[2] = " + h(data_byte), LOG_NET);
  708. this.mac[2] = data_byte;
  709. }
  710. else
  711. {
  712. dbg_log("Write pg" + pg + "/03: " + h(data_byte), LOG_NET);
  713. dbg_assert(false);
  714. }
  715. });
  716. io.register_read(this.port | EN0_TSR, this, function()
  717. {
  718. var pg = this.get_page();
  719. if(pg === 0)
  720. {
  721. return this.tsr;
  722. }
  723. else if(pg === 1)
  724. {
  725. dbg_log("Read pg1/04 (mac[3])", LOG_NET);
  726. return this.mac[3];
  727. }
  728. else
  729. {
  730. dbg_log("Read pg" + pg + "/04", LOG_NET);
  731. dbg_assert(false);
  732. return 0;
  733. }
  734. });
  735. io.register_write(this.port | EN0_TPSR, this, function(data_byte)
  736. {
  737. var pg = this.get_page();
  738. if(pg === 0)
  739. {
  740. dbg_log("Write tpsr: " + h(data_byte, 2), LOG_NET);
  741. this.tpsr = data_byte;
  742. }
  743. else if(pg === 1)
  744. {
  745. dbg_log("mac[3] = " + h(data_byte), LOG_NET);
  746. this.mac[3] = data_byte;
  747. }
  748. else
  749. {
  750. dbg_log("Write pg" + pg + "/04: " + h(data_byte), LOG_NET);
  751. dbg_assert(false);
  752. }
  753. });
  754. io.register_read(this.port | EN0_TCNTLO, this, function()
  755. {
  756. var pg = this.get_page();
  757. if(pg === 0)
  758. {
  759. dbg_log("Unimplemented: Read pg0/05 (NCR: Number of Collisions Register)", LOG_NET);
  760. return 0;
  761. }
  762. else if(pg === 1)
  763. {
  764. dbg_log("Read pg1/05 (mac[4])", LOG_NET);
  765. return this.mac[4];
  766. }
  767. else if(pg === 3)
  768. {
  769. dbg_log("Unimplemented: Read pg3/05 (CONFIG2)", LOG_NET);
  770. return 0;
  771. }
  772. else
  773. {
  774. dbg_log("Read pg" + pg + "/05", LOG_NET);
  775. dbg_assert(false);
  776. return 0;
  777. }
  778. });
  779. io.register_write(this.port | EN0_TCNTLO, this, function(data_byte)
  780. {
  781. var pg = this.get_page();
  782. if(pg === 0)
  783. {
  784. dbg_log("Write tcnt low: " + h(data_byte, 2), LOG_NET);
  785. this.tcnt = this.tcnt & ~0xFF | data_byte;
  786. }
  787. else if(pg === 1)
  788. {
  789. dbg_log("mac[4] = " + h(data_byte), LOG_NET);
  790. this.mac[4] = data_byte;
  791. }
  792. else if(pg === 3)
  793. {
  794. dbg_log("Unimplemented: Write pg3/05 (CONFIG2): " + h(data_byte), LOG_NET);
  795. }
  796. else
  797. {
  798. dbg_log("Write pg" + pg + "/05: " + h(data_byte), LOG_NET);
  799. dbg_assert(false);
  800. }
  801. });
  802. io.register_read(this.port | EN0_TCNTHI, this, function()
  803. {
  804. var pg = this.get_page();
  805. if(pg === 0)
  806. {
  807. dbg_assert(false, "TODO");
  808. return 0;
  809. }
  810. else if(pg === 1)
  811. {
  812. dbg_log("Read pg1/06 (mac[5])", LOG_NET);
  813. return this.mac[5];
  814. }
  815. else if(pg === 3)
  816. {
  817. dbg_log("Unimplemented: Read pg3/06 (CONFIG3)", LOG_NET);
  818. return 0;
  819. }
  820. else
  821. {
  822. dbg_log("Read pg" + pg + "/06", LOG_NET);
  823. dbg_assert(false);
  824. return 0;
  825. }
  826. });
  827. io.register_write(this.port | EN0_TCNTHI, this, function(data_byte)
  828. {
  829. var pg = this.get_page();
  830. if(pg === 0)
  831. {
  832. dbg_log("Write tcnt high: " + h(data_byte, 2), LOG_NET);
  833. this.tcnt = this.tcnt & 0xFF | data_byte << 8;
  834. }
  835. else if(pg === 1)
  836. {
  837. dbg_log("mac[5] = " + h(data_byte), LOG_NET);
  838. this.mac[5] = data_byte;
  839. }
  840. else if(pg === 3)
  841. {
  842. dbg_log("Unimplemented: Write pg3/06 (CONFIG3): " + h(data_byte), LOG_NET);
  843. }
  844. else
  845. {
  846. dbg_log("Write pg" + pg + "/06: " + h(data_byte), LOG_NET);
  847. dbg_assert(false);
  848. }
  849. });
  850. io.register_read(this.port | EN0_RSR, this, function()
  851. {
  852. var pg = this.get_page();
  853. if(pg === 0)
  854. {
  855. return 1 | 1 << 3; // receive status ok
  856. }
  857. else
  858. {
  859. dbg_log("Unimplemented: Read pg" + pg + "/0c", LOG_NET);
  860. dbg_assert(false);
  861. return 0;
  862. }
  863. });
  864. io.register_write(this.port | EN0_RXCR, this, function(data_byte)
  865. {
  866. var pg = this.get_page();
  867. if(pg === 0)
  868. {
  869. dbg_log("RX configuration reg write: " + h(data_byte, 2), LOG_NET);
  870. this.rxcr = data_byte;
  871. }
  872. else
  873. {
  874. dbg_log("Unimplemented: Write pg" + pg + "/0c: " + h(data_byte), LOG_NET);
  875. }
  876. });
  877. io.register_read(this.port | NE_DATAPORT | 0, this,
  878. this.data_port_read8,
  879. this.data_port_read16,
  880. this.data_port_read32);
  881. io.register_write(this.port | NE_DATAPORT | 0, this,
  882. this.data_port_write16,
  883. this.data_port_write16,
  884. this.data_port_write32);
  885. if(use_pci)
  886. {
  887. cpu.devices.pci.register_device(this);
  888. }
  889. }
  890. Ne2k.prototype.get_state = function()
  891. {
  892. var state = [];
  893. state[0] = this.isr;
  894. state[1] = this.imr;
  895. state[2] = this.cr;
  896. state[3] = this.dcfg;
  897. state[4] = this.rcnt;
  898. state[5] = this.tcnt;
  899. state[6] = this.tpsr;
  900. state[7] = this.rsar;
  901. state[8] = this.pstart;
  902. state[9] = this.curpg;
  903. state[10] = this.boundary;
  904. state[11] = this.pstop;
  905. state[12] = this.rxcr;
  906. state[13] = this.txcr;
  907. state[14] = this.tsr;
  908. state[15] = this.mac;
  909. state[16] = this.memory;
  910. return state;
  911. };
  912. Ne2k.prototype.set_state = function(state)
  913. {
  914. this.isr = state[0];
  915. this.imr = state[1];
  916. this.cr = state[2];
  917. this.dcfg = state[3];
  918. this.rcnt = state[4];
  919. this.tcnt = state[5];
  920. this.tpsr = state[6];
  921. this.rsar = state[7];
  922. this.pstart = state[8];
  923. this.curpg = state[9];
  924. this.boundary = state[10];
  925. this.pstop = state[11];
  926. this.rxcr = state[12];
  927. this.txcr = state[13];
  928. this.tsr = state[14];
  929. if(this.preserve_mac_from_state_image)
  930. {
  931. this.mac = state[15];
  932. this.memory = state[16];
  933. }
  934. else if(this.mac_address_translation)
  935. {
  936. this.mac_address_in_state = state[15];
  937. this.memory = state[16];
  938. dbg_log("Using mac address translation" +
  939. " guest_os_mac=" + format_mac(this.mac_address_in_state) +
  940. " real_mac=" + format_mac(this.mac), LOG_NET);
  941. }
  942. };
  943. Ne2k.prototype.do_interrupt = function(ir_mask)
  944. {
  945. dbg_log("Do interrupt " + h(ir_mask, 2), LOG_NET);
  946. this.isr |= ir_mask;
  947. this.update_irq();
  948. };
  949. Ne2k.prototype.update_irq = function()
  950. {
  951. if(this.imr & this.isr)
  952. {
  953. this.pci.raise_irq(this.pci_id);
  954. }
  955. else
  956. {
  957. this.pci.lower_irq(this.pci_id);
  958. }
  959. };
  960. Ne2k.prototype.data_port_write = function(data_byte)
  961. {
  962. if(NE2K_LOG_VERBOSE)
  963. {
  964. dbg_log("Write data port: data=" + h(data_byte & 0xFF, 2) +
  965. " rsar=" + h(this.rsar, 4) +
  966. " rcnt=" + h(this.rcnt, 4), LOG_NET);
  967. }
  968. if(this.rsar <= 0x10 || this.rsar >= (START_PAGE << 8) && this.rsar < (STOP_PAGE << 8))
  969. {
  970. this.memory[this.rsar] = data_byte;
  971. }
  972. this.rsar++;
  973. this.rcnt--;
  974. if(this.rsar >= (this.pstop << 8))
  975. {
  976. this.rsar += (this.pstart - this.pstop) << 8;
  977. }
  978. if(this.rcnt === 0)
  979. {
  980. this.do_interrupt(ENISR_RDC);
  981. }
  982. };
  983. Ne2k.prototype.data_port_write16 = function(data)
  984. {
  985. this.data_port_write(data);
  986. if(this.dcfg & 1)
  987. {
  988. this.data_port_write(data >> 8);
  989. }
  990. };
  991. Ne2k.prototype.data_port_write32 = function(data)
  992. {
  993. this.data_port_write(data);
  994. this.data_port_write(data >> 8);
  995. this.data_port_write(data >> 16);
  996. this.data_port_write(data >> 24);
  997. };
  998. Ne2k.prototype.data_port_read = function()
  999. {
  1000. let data = 0;
  1001. if(this.rsar < (STOP_PAGE << 8))
  1002. {
  1003. data = this.memory[this.rsar];
  1004. }
  1005. if(NE2K_LOG_VERBOSE)
  1006. {
  1007. dbg_log("Read data port: data=" + h(data, 2) +
  1008. " rsar=" + h(this.rsar, 4) +
  1009. " rcnt=" + h(this.rcnt, 4), LOG_NET);
  1010. }
  1011. this.rsar++;
  1012. this.rcnt--;
  1013. if(this.rsar >= (this.pstop << 8))
  1014. {
  1015. this.rsar += (this.pstart - this.pstop) << 8;
  1016. }
  1017. if(this.rcnt === 0)
  1018. {
  1019. this.do_interrupt(ENISR_RDC);
  1020. }
  1021. return data;
  1022. };
  1023. Ne2k.prototype.data_port_read8 = function()
  1024. {
  1025. return this.data_port_read16() & 0xFF;
  1026. };
  1027. Ne2k.prototype.data_port_read16 = function()
  1028. {
  1029. if(this.dcfg & 1)
  1030. {
  1031. return this.data_port_read() | this.data_port_read() << 8;
  1032. }
  1033. else
  1034. {
  1035. return this.data_port_read();
  1036. }
  1037. };
  1038. Ne2k.prototype.data_port_read32 = function()
  1039. {
  1040. return this.data_port_read() | this.data_port_read() << 8 |
  1041. this.data_port_read() << 16 | this.data_port_read() << 24;
  1042. };
  1043. Ne2k.prototype.receive = function(data)
  1044. {
  1045. // called from the adapter when data is received over the network
  1046. if(this.cr & 1)
  1047. {
  1048. // stop bit set
  1049. return;
  1050. }
  1051. if(NE2K_LOG_PACKETS)
  1052. {
  1053. dump_packet(data, "receive");
  1054. }
  1055. this.bus.send("eth-receive-end", [data.length]);
  1056. if(this.rxcr & 0x10)
  1057. {
  1058. // promiscuous
  1059. }
  1060. else if((this.rxcr & 4) &&
  1061. data[0] === 0xFF && data[1] === 0xFF && data[2] === 0xFF &&
  1062. data[3] === 0xFF && data[4] === 0xFF && data[5] === 0xFF)
  1063. {
  1064. // broadcast
  1065. }
  1066. else if((this.rxcr & 8) && (data[0] & 1) === 1)
  1067. {
  1068. // multicast
  1069. // XXX
  1070. return;
  1071. }
  1072. else if(data[0] === this.mac[0] && data[1] === this.mac[1] &&
  1073. data[2] === this.mac[2] && data[3] === this.mac[3] &&
  1074. data[4] === this.mac[4] && data[5] === this.mac[5])
  1075. {
  1076. }
  1077. else
  1078. {
  1079. return;
  1080. }
  1081. if(this.mac_address_in_state)
  1082. {
  1083. data = new Uint8Array(data); // make a copy
  1084. translate_mac_address(data, this.mac, this.mac_address_in_state);
  1085. }
  1086. var packet_length = Math.max(60, data.length);
  1087. var offset = this.curpg << 8;
  1088. var total_length = packet_length + 4;
  1089. var data_start = offset + 4;
  1090. var next = this.curpg + 1 + (total_length >> 8);
  1091. var end = offset + total_length;
  1092. const needed = 1 + (total_length >> 8);
  1093. // boundary == curpg interpreted as ringbuffer empty
  1094. const available = this.boundary > this.curpg ?
  1095. this.boundary - this.curpg :
  1096. this.pstop - this.curpg + this.boundary - this.pstart;
  1097. if(available < needed &&
  1098. this.boundary !== 0 // XXX: ReactOS sets this to 0 initially and never updates it unless it receives a packet
  1099. )
  1100. {
  1101. dbg_log("Buffer full, dropping packet pstart=" + h(this.pstart) + " pstop=" + h(this.pstop) +
  1102. " curpg=" + h(this.curpg) + " needed=" + h(needed) + " boundary=" + h(this.boundary) + " available=" + h(available), LOG_NET);
  1103. return;
  1104. }
  1105. if(end > (this.pstop << 8))
  1106. {
  1107. // Shouldn't happen because at this size it can't cross a page,
  1108. // so we can skip filling with zeroes
  1109. dbg_assert(data.length >= 60);
  1110. var cut = (this.pstop << 8) - data_start;
  1111. dbg_assert(cut >= 0);
  1112. this.memory.set(data.subarray(0, cut), data_start);
  1113. this.memory.set(data.subarray(cut), this.pstart << 8);
  1114. dbg_log("rcv cut=" + h(cut), LOG_NET);
  1115. }
  1116. else
  1117. {
  1118. this.memory.set(data, data_start);
  1119. if(data.length < 60)
  1120. {
  1121. this.memory.fill(0, data_start + data.length, data_start + 60);
  1122. }
  1123. }
  1124. if(next >= this.pstop)
  1125. {
  1126. next += this.pstart - this.pstop;
  1127. }
  1128. // write packet header
  1129. this.memory[offset] = ENRSR_RXOK; // status
  1130. this.memory[offset + 1] = next;
  1131. this.memory[offset + 2] = total_length;
  1132. this.memory[offset + 3] = total_length >> 8;
  1133. this.curpg = next;
  1134. dbg_log("rcv offset=" + h(offset) + " len=" + h(total_length) + " next=" + h(next), LOG_NET);
  1135. this.do_interrupt(ENISR_RX);
  1136. };
  1137. Ne2k.prototype.get_page = function()
  1138. {
  1139. return this.cr >> 6 & 3;
  1140. };