virtio.js 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. "use strict";
  2. // http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html
  3. /** @const */
  4. var VIRTIO_PCI_VENDOR_ID = 0x1AF4;
  5. /**
  6. * @const
  7. * Identifies vendor-specific PCI capability.
  8. */
  9. var VIRTIO_PCI_CAP_VENDOR = 0x09;
  10. /**
  11. * @const
  12. * Length (bytes) of VIRTIO_PCI_CAP linked list entry.
  13. */
  14. var VIRTIO_PCI_CAP_LENGTH = 16;
  15. // Capability types.
  16. /** @const */
  17. var VIRTIO_PCI_CAP_COMMON_CFG = 1;
  18. /** @const */
  19. var VIRTIO_PCI_CAP_NOTIFY_CFG = 2;
  20. /** @const */
  21. var VIRTIO_PCI_CAP_ISR_CFG = 3;
  22. /** @const */
  23. var VIRTIO_PCI_CAP_DEVICE_CFG = 4;
  24. /** @const */
  25. var VIRTIO_PCI_CAP_PCI_CFG = 5;
  26. // Status bits (device_status values).
  27. /** @const */
  28. var VIRTIO_STATUS_ACKNOWLEDGE = 1;
  29. /** @const */
  30. var VIRTIO_STATUS_DRIVER = 2;
  31. /** @const */
  32. var VIRTIO_STATUS_DRIVER_OK = 4;
  33. /** @const */
  34. var VIRTIO_STATUS_FEATURES_OK = 8;
  35. /** @const */
  36. var VIRTIO_STATUS_DEVICE_NEEDS_RESET = 64;
  37. /** @const */
  38. var VIRTIO_STATUS_FAILED = 128;
  39. // ISR bits (isr_status values).
  40. /** @const */
  41. var VIRTIO_ISR_QUEUE = 1;
  42. /** @const */
  43. var VIRTIO_ISR_DEVICE_CFG = 2;
  44. // Feature bits (bit positions).
  45. /** @const */
  46. var VIRTIO_F_VERSION_1 = 32;
  47. // Queue struct sizes.
  48. /**
  49. * @const
  50. * Size (bytes) of the virtq_desc struct per queue size
  51. */
  52. var VIRTQ_DESC_ENTRYSIZE = 16;
  53. /**
  54. * @const
  55. * Size (bytes) of the virtq_avail struct ignoring ring entries
  56. */
  57. var VIRTQ_AVAIL_BASESIZE = 6;
  58. /**
  59. * @const
  60. * Size (bytes) of the virtq_avail struct per queue size
  61. */
  62. var VIRTQ_AVAIL_ENTRYSIZE = 2;
  63. /**
  64. * @const
  65. * Size (bytes) of the virtq_used struct ignoring ring entries
  66. */
  67. var VIRTQ_USED_BASESIZE = 6;
  68. /**
  69. * @const
  70. * Size (bytes) of the virtq_desc struct per queue size
  71. */
  72. var VIRTQ_USED_ENTRYSIZE = 8;
  73. // Closure Compiler Types.
  74. /**
  75. * @typedef {!Array<{
  76. * bytes: number,
  77. * name: string,
  78. * read: function():number,
  79. * write: function(number)
  80. * }>}
  81. */
  82. var VirtIO_CapabilityStruct;
  83. /**
  84. * @typedef {
  85. * {
  86. * type: number,
  87. * bar: number,
  88. * port: number,
  89. * use_mmio: boolean,
  90. * offset: number,
  91. * length: number,
  92. * extra: Uint8Array,
  93. * struct: VirtIO_CapabilityStruct,
  94. * }}
  95. */
  96. var VirtIO_CapabilityInfo;
  97. /**
  98. * @typedef {
  99. * {
  100. * size_supported: number,
  101. * notify_offset: number,
  102. * }}
  103. */
  104. var VirtQueue_Options;
  105. /**
  106. * @typedef {
  107. * {
  108. * initial_port: number,
  109. * queues: !Array<VirtQueue_Options>,
  110. * features: !Array<number>,
  111. * }}
  112. */
  113. var VirtIO_CommonCapabilityOptions;
  114. /**
  115. * @typedef {
  116. * {
  117. * initial_port: number,
  118. * share_handler: boolean,
  119. * handlers: !Array<function()>,
  120. * }}
  121. */
  122. var VirtIO_NotificationCapabilityOptions;
  123. /**
  124. * @typedef {
  125. * {
  126. * initial_port: number,
  127. * }}
  128. */
  129. var VirtIO_ISRCapabilityOptions;
  130. /**
  131. * @typedef {
  132. * {
  133. * initial_port: number,
  134. * length: number,
  135. * struct: VirtIO_CapabilityStruct,
  136. * }}
  137. */
  138. var VirtIO_DeviceSpecificCapabilityOptions;
  139. /**
  140. * @typedef {
  141. * {
  142. * name: string,
  143. * pci_id: number,
  144. * device_id: number,
  145. * subsystem_device_id: number,
  146. * common: VirtIO_CommonCapabilityOptions,
  147. * notification: (undefined | VirtIO_NotificationCapabilityOptions),
  148. * isr_status: (undefined | VirtIO_ISRCapabilityOptions),
  149. * device_specific: (undefined | VirtIO_DeviceSpecificCapabilityOptions),
  150. * }}
  151. */
  152. var VirtIO_Options;
  153. /**
  154. * @constructor
  155. * @param {CPU} cpu
  156. * @param {VirtIO_Options} options
  157. */
  158. function VirtIO(cpu, options)
  159. {
  160. var io = cpu.io;
  161. /** @const @type {CPU} */
  162. this.cpu = cpu;
  163. /** @const @type {PCI} */
  164. this.pci = cpu.devices.pci;
  165. this.device_id = options.device_id;
  166. this.pci_space =
  167. [
  168. // Vendor ID
  169. VIRTIO_PCI_VENDOR_ID & 0xFF, VIRTIO_PCI_VENDOR_ID >> 8,
  170. // Device ID
  171. options.device_id & 0xFF, options.device_id >> 8,
  172. // Command
  173. 0x07, 0x05,
  174. // Status - enable capabilities list
  175. 0x10, 0x00,
  176. // Revision ID
  177. 0x00,
  178. // Prof IF, Subclass, Class code
  179. 0x00, 0x02, 0x00,
  180. // Cache line size
  181. 0x00,
  182. // Latency Timer
  183. 0x00,
  184. // Header Type
  185. 0x00,
  186. // Built-in self test
  187. 0x00,
  188. // BAR0
  189. 0x01, 0xa8, 0x00, 0x00,
  190. // BAR1
  191. 0x00, 0x10, 0xbf, 0xfe,
  192. // BAR2
  193. 0x00, 0x00, 0x00, 0x00,
  194. // BAR3
  195. 0x00, 0x00, 0x00, 0x00,
  196. // BAR4
  197. 0x00, 0x00, 0x00, 0x00,
  198. // BAR5
  199. 0x00, 0x00, 0x00, 0x00,
  200. // CardBus CIS pointer
  201. 0x00, 0x00, 0x00, 0x00,
  202. // Subsystem vendor ID
  203. VIRTIO_PCI_VENDOR_ID & 0xFF, VIRTIO_PCI_VENDOR_ID >> 8,
  204. // Subsystem ID
  205. options.subsystem_device_id & 0xFF, options.subsystem_device_id >> 8,
  206. // Expansion ROM base address
  207. 0x00, 0x00, 0x00, 0x00,
  208. // Capabilities pointer
  209. 0x40,
  210. // Reserved
  211. 0x00, 0x00, 0x00,
  212. // Reserved
  213. 0x00, 0x00, 0x00, 0x00,
  214. // Interrupt line
  215. 0x00,
  216. // Interrupt pin
  217. 0x01,
  218. // Min grant
  219. 0x00,
  220. // Max latency
  221. 0x00,
  222. ];
  223. // Remaining PCI space is appended by capabilities below.
  224. this.pci_id = options.pci_id;
  225. // PCI bars gets filled in by capabilities below.
  226. this.pci_bars = [];
  227. this.name = options.name;
  228. // Feature bits grouped in dwords, dword selected by decive_feature_select.
  229. this.device_feature_select = 0;
  230. this.driver_feature_select = 0;
  231. // Unspecified upper bound. Assume 4*32=128 bits.
  232. this.device_feature = new Uint32Array(4);
  233. this.driver_feature = new Uint32Array(4);
  234. options.common.features.forEach((f) =>
  235. {
  236. dbg_assert(f >= 0,
  237. "VirtIO device<" + this.name + "> feature bit numbers must be non-negative");
  238. dbg_assert(f < 128,
  239. "VirtIO device<" + this.name + "> feature bit numbers assumed less than 128 in implementation");
  240. // Feature bits are grouped in 32 bits.
  241. this.device_feature[f >>> 5] |= 1 << (f & 0x1F);
  242. this.driver_feature[f >>> 5] |= 1 << (f & 0x1F);
  243. });
  244. dbg_assert(options.common.features.indexOf(VIRTIO_F_VERSION_1) !== -1,
  245. "VirtIO device<" + this.name + "> only non-transitional devices are supported");
  246. // Indicates whether driver_feature bits is subset of device_feature bits.
  247. this.features_ok = true;
  248. this.device_status = 0;
  249. this.config_has_changed = false;
  250. this.config_generation = 0;
  251. /** @type {!Array<VirtQueue>} */
  252. this.queues = [];
  253. for(var queue_options of options.common.queues)
  254. {
  255. this.queues.push(new VirtQueue(cpu, queue_options));
  256. }
  257. this.isr_status = 0;
  258. this.reset();
  259. /** @type {!Array<VirtIO_CapabilityInfo>} */
  260. var capabilities = [];
  261. capabilities.push(this.create_common_capability(options.common));
  262. if(options.notification)
  263. {
  264. capabilities.push(this.create_notification_capability(options.notification));
  265. }
  266. if(options.isr_status)
  267. {
  268. capabilities.push(this.create_isr_capability(options.isr_status));
  269. }
  270. if(options.device_specific)
  271. {
  272. capabilities.push(this.create_device_specific_capability(options.device_specific));
  273. }
  274. this.init_capabilities(capabilities);
  275. // TODO: upgrade the following.
  276. io.register_write(0xA810, this, undefined, function(data)
  277. {
  278. dbg_log("Write queue notify: " + h(data, 4), LOG_VIRTIO);
  279. // only queue 0 supported
  280. dbg_assert(data === 0);
  281. var queue_start = this.queue_address << 12;
  282. var ring_start = queue_start + 16 * this.queue_size;
  283. var ring_desc_start = ring_start + 4;
  284. var //flags = this.cpu.read16(ring_start),
  285. // index of the next free ring
  286. idx = this.cpu.read16(ring_start + 2);
  287. dbg_log("idx=" + h(idx, 4), LOG_VIRTIO);
  288. //dbg_assert(idx < this.queue_size);
  289. var mask = this.queue_size - 1;
  290. idx &= mask;
  291. while(this.last_idx !== idx)
  292. {
  293. var desc_idx = this.cpu.read16(ring_desc_start + this.last_idx * 2);
  294. this.handle_descriptor(desc_idx);
  295. this.last_idx = this.last_idx + 1 & mask;
  296. }
  297. });
  298. cpu.devices.pci.register_device(this);
  299. }
  300. /**
  301. * @param {VirtIO_CommonCapabilityOptions} options
  302. * @return {VirtIO_CapabilityInfo}
  303. */
  304. VirtIO.prototype.create_common_capability = function(options)
  305. {
  306. var cap =
  307. {
  308. type: VIRTIO_PCI_CAP_COMMON_CFG,
  309. bar: 0,
  310. port: options.initial_port,
  311. use_mmio: false,
  312. offset: 0,
  313. length: 0,
  314. extra: new Uint8Array(0),
  315. struct:
  316. [
  317. {
  318. bytes: 4,
  319. name: "device_feature_select",
  320. read: () => this.device_feature_select,
  321. write: data =>
  322. {
  323. this.device_feature_select = data;
  324. },
  325. },
  326. {
  327. bytes: 4,
  328. name: "device_feature",
  329. read: () => this.device_feature[this.device_feature_select],
  330. write: data =>
  331. {
  332. this.device_feature[this.device_feature_select] = data;
  333. },
  334. },
  335. {
  336. bytes: 4,
  337. name: "driver_feature_select",
  338. read: () => this.driver_feature_select,
  339. write: data =>
  340. {
  341. this.driver_feature_select = data;
  342. },
  343. },
  344. {
  345. bytes: 4,
  346. name: "driver_feature",
  347. read: () => this.driver_feature[this.driver_feature_select],
  348. write: data =>
  349. {
  350. var supported_feature = this.device_feature[this.driver_feature_select];
  351. this.driver_feature[this.driver_feature_select] = data & supported_feature;
  352. // Check that driver features is an inclusive subset of device features.
  353. var invalid_bits = data & ~supported_feature;
  354. this.features_ok = this.features_ok && !invalid_bits;
  355. },
  356. },
  357. {
  358. bytes: 2,
  359. name: "msix_config",
  360. read: () =>
  361. {
  362. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  363. return 0xFFFF;
  364. },
  365. write: data =>
  366. {
  367. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  368. },
  369. },
  370. {
  371. bytes: 2,
  372. name: "num_queues",
  373. read: () => this.queues.length,
  374. write: data => { /* read only */ },
  375. },
  376. {
  377. bytes: 1,
  378. name: "device_status",
  379. read: () => this.device_status,
  380. write: data =>
  381. {
  382. if(data === 0)
  383. {
  384. dbg_log("Reset device<" + this.name + ">", LOG_VIRTIO);
  385. this.reset();
  386. }
  387. else if(data | VIRTIO_STATUS_FAILED)
  388. {
  389. dbg_log("Warning: Device<" + this.name + "> status failed", LOG_VIRTIO);
  390. }
  391. else if(((data & ~this.device_status) | VIRTIO_STATUS_DRIVER_OK) &&
  392. (this.device_status & VIRTIO_STATUS_DEVICE_NEEDS_RESET))
  393. {
  394. this.notify_config_changes();
  395. }
  396. else
  397. {
  398. dbg_log(((data & VIRTIO_STATUS_ACKNOWLEDGE) ? "ACKNOWLEDGE " : "") +
  399. ((data & VIRTIO_STATUS_DRIVER) ? "DRIVER " : "") +
  400. ((data & VIRTIO_STATUS_DRIVER_OK) ? "DRIVER_OK" : "") +
  401. ((data & VIRTIO_STATUS_FEATURES_OK) ? "FEATURES_OK" : "") +
  402. ((data & VIRTIO_STATUS_DEVICE_NEEDS_RESET) ? "DEVICE_NEEDS_RESET" : ""),
  403. LOG_VIRTIO);
  404. }
  405. // Don't set FEATURES_OK if our device doesn't support requested features.
  406. if(!this.features_ok)
  407. {
  408. data &= ~VIRTIO_STATUS_FEATURES_OK;
  409. }
  410. this.device_status = data;
  411. },
  412. },
  413. {
  414. bytes: 1,
  415. name: "config_generation",
  416. read: () => this.config_generation,
  417. write: data => { /* read only */ },
  418. },
  419. {
  420. bytes: 2,
  421. name: "queue_select",
  422. read: () => this.queue_select,
  423. write: data =>
  424. {
  425. this.queue_select = data;
  426. if(this.queue_select < this.queues.length)
  427. {
  428. this.queues_selected = this.queues[this.queue_select];
  429. }
  430. else
  431. {
  432. // Allow queue_select >= num_queues.
  433. this.queue_selected = null;
  434. // Drivers can then detect that the queue is not available
  435. // using the below fields.
  436. }
  437. },
  438. },
  439. {
  440. bytes: 2,
  441. name: "queue_size",
  442. read: () => this.queue_selected ? this.queue_selected.size : 0,
  443. write: data =>
  444. {
  445. dbg_assert((data & data - 1) === 0,
  446. "VirtIO device<" + this.name + "> queue size needs to be power of 2 or zero");
  447. if(this.queue_selected) this.queue_selected.size = data;
  448. },
  449. },
  450. {
  451. bytes: 2,
  452. name: "queue_msix_vector",
  453. read: () =>
  454. {
  455. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  456. return 0xFFFF;
  457. },
  458. write: data =>
  459. {
  460. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  461. },
  462. },
  463. {
  464. bytes: 2,
  465. name: "queue_enable",
  466. read: () => this.queue_selected ? this.queue_selected.enable : 0,
  467. write: data =>
  468. {
  469. if(this.queue_selected) this.queue_selected.enable = data;
  470. },
  471. },
  472. {
  473. bytes: 2,
  474. name: "queue_notify_off",
  475. read: () => this.queue_selected ? this.queue_selected.notify_offset : 0,
  476. write: data => { /* read only */ },
  477. },
  478. {
  479. bytes: 2,
  480. name: "queue_desc",
  481. read: () => this.queue_selected ? this.queue_selected.desc_table_addr : 0,
  482. write: data =>
  483. {
  484. if(this.queue_selected) this.queue_selected.set_desc_table_addr(data);
  485. },
  486. },
  487. {
  488. bytes: 2,
  489. name: "queue_avail",
  490. read: () => this.queue_selected ? this.queue_selected.avail_ring_addr : 0,
  491. write: data =>
  492. {
  493. if(this.queue_selected) this.queue_selected.set_avail_ring_addr(data);
  494. },
  495. },
  496. {
  497. bytes: 2,
  498. name: "queue_used",
  499. read: () => this.queue_selected ? this.queue_selected.used_ring_addr : 0,
  500. write: data =>
  501. {
  502. if(this.queue_selected) this.queue_selected.set_used_ring_addr(data);
  503. },
  504. },
  505. ],
  506. };
  507. return cap;
  508. };
  509. /**
  510. * @param {VirtIO_NotificationCapabilityOptions} options
  511. * @return {VirtIO_CapabilityInfo}
  512. */
  513. VirtIO.prototype.create_notification_capability = function(options)
  514. {
  515. var notify_struct = [];
  516. var notify_off_multiplier;
  517. if(options.share_handler)
  518. {
  519. dbg_assert(options.handlers.length === 1,
  520. "VirtIO device<" + this.name + "> too many notify handlers specified: expected single handler");
  521. // All queues use the same address for notifying.
  522. notify_off_multiplier = 0;
  523. }
  524. else
  525. {
  526. dbg_assert(options.handlers.length === this.queues.length,
  527. "Virtio device<" + this.name + "> each queue has exactly one notify handler");
  528. // Each queue uses its own 2 bytes for notifying.
  529. notify_off_multiplier = 2;
  530. }
  531. for (var i = 0; i < options.handlers.length; i++)
  532. {
  533. notify_struct.push(
  534. {
  535. bytes: 2,
  536. name: "notify" + i,
  537. read: () => 0xFFFF, // Write only? TODO
  538. write: options.handlers[i],
  539. });
  540. }
  541. var cap =
  542. {
  543. type: VIRTIO_PCI_CAP_NOTIFY_CFG,
  544. bar: 1,
  545. port: options.initial_port,
  546. use_mmio: false,
  547. offset: 0,
  548. length: notify_struct.length * 2,
  549. extra: new Uint8Array(
  550. [
  551. notify_off_multiplier & 0xFF,
  552. (notify_off_multiplier >> 8) & 0xFF,
  553. (notify_off_multiplier >> 16) & 0xFF,
  554. notify_off_multiplier >> 24,
  555. ]),
  556. struct: notify_struct,
  557. };
  558. return cap;
  559. };
  560. /**
  561. * @param {VirtIO_ISRCapabilityOptions} options
  562. * @return {VirtIO_CapabilityInfo}
  563. */
  564. VirtIO.prototype.create_isr_capability = function(options)
  565. {
  566. var cap =
  567. {
  568. type: VIRTIO_PCI_CAP_ISR_CFG,
  569. bar: 2,
  570. port: options.initial_port,
  571. use_mmio: false,
  572. offset: 0,
  573. length: 1,
  574. extra: new Uint8Array(0),
  575. struct:
  576. [
  577. {
  578. bytes: 1,
  579. name: "isr_status",
  580. read: () =>
  581. {
  582. var isr_status = this.isr_status;
  583. this.lower_irq();
  584. return isr_status;
  585. },
  586. write: data => { /* read only */ },
  587. },
  588. ],
  589. };
  590. return cap;
  591. };
  592. /**
  593. * @param {VirtIO_DeviceSpecificCapabilityOptions} options
  594. * @return {VirtIO_CapabilityInfo}
  595. */
  596. VirtIO.prototype.create_device_specific_capability = function(options)
  597. {
  598. var cap =
  599. {
  600. type: VIRTIO_PCI_CAP_DEVICE_CFG,
  601. bar: 5,
  602. port: options.initial_port,
  603. use_mmio: false,
  604. offset: 0,
  605. length: options.length,
  606. extra: new Uint8Array(0),
  607. struct: options.struct,
  608. };
  609. return cap;
  610. };
  611. /**
  612. * Writes capabilities into pci_space and hook up IO/MMIO handlers.
  613. * Call only within constructor.
  614. * @param {!Array<VirtIO_CapabilityInfo>} capabilities
  615. */
  616. VirtIO.prototype.init_capabilities = function(capabilities)
  617. {
  618. // Next available offset for capabilities linked list.
  619. var cap_next = this.pci_space[0x34] = 0x40;
  620. // Current offset.
  621. var cap_ptr = cap_next;
  622. capabilities.forEach((cap) =>
  623. {
  624. var cap_len = VIRTIO_PCI_CAP_LENGTH + cap.extra.length;
  625. cap_ptr = cap_next;
  626. cap_next = cap_ptr + cap_len;
  627. dbg_assert(cap_next <= 256,
  628. "VirtIO device<" + this.name + "> can't fit all capabilities into 256byte configspace");
  629. dbg_assert(0 <= cap.bar && cap.bar < 6,
  630. "VirtIO device<" + this.name + "> capability invalid bar number");
  631. var bar_size = cap.struct.reduce((field) => field.bytes, 0);
  632. bar_size += cap.offset;
  633. // Round up to next power of 2.
  634. bar_size = 1 << (v86util.int_log2(bar_size - 1) + 1);
  635. dbg_assert((cap.port & (bar_size - 1)) === 0,
  636. "VirtIO device<" + this.name + "> capability port should be aligned to pci bar size");
  637. this.pci_bars[cap.bar] =
  638. {
  639. size: bar_size,
  640. };
  641. this.pci_space[cap_ptr] = VIRTIO_PCI_CAP_VENDOR;
  642. this.pci_space[cap_ptr + 1] = cap_next;
  643. this.pci_space[cap_ptr + 2] = cap_len;
  644. this.pci_space[cap_ptr + 3] = cap.type;
  645. this.pci_space[cap_ptr + 4] = cap.bar;
  646. this.pci_space[cap_ptr + 5] = 0; // Padding.
  647. this.pci_space[cap_ptr + 6] = 0; // Padding.
  648. this.pci_space[cap_ptr + 7] = 0; // Padding.
  649. this.pci_space[cap_ptr + 8] = cap.offset & 0xFF;
  650. this.pci_space[cap_ptr + 9] = (cap.offset >>> 8) & 0xFF;
  651. this.pci_space[cap_ptr + 10] = (cap.offset >>> 16) & 0xFF;
  652. this.pci_space[cap_ptr + 11] = cap.offset >>> 24;
  653. this.pci_space[cap_ptr + 12] = bar_size & 0xFF;
  654. this.pci_space[cap_ptr + 13] = (bar_size >>> 8) & 0xFF;
  655. this.pci_space[cap_ptr + 14] = (bar_size >>> 16) & 0xFF;
  656. this.pci_space[cap_ptr + 15] = bar_size >>> 24;
  657. for(var i = 0; i < cap.extra.length; i++)
  658. {
  659. this.pci_space[cap_ptr + 16 + i] = cap.extra[i];
  660. }
  661. var bar_offset = 0x10 + 4 * cap.bar;
  662. this.pci_space[bar_offset] = (cap.port & 0xFE) | !cap.use_mmio;
  663. this.pci_space[bar_offset + 1] = (cap.port >>> 8) & 0xFF;
  664. this.pci_space[bar_offset + 2] = (cap.port >>> 16) & 0xFF;
  665. this.pci_space[bar_offset + 3] = (cap.port >>> 24) & 0xFF;
  666. var port = cap.port + cap.offset;
  667. cap.struct.forEach((field) =>
  668. {
  669. var read = field.read;
  670. var write = field.write;
  671. if(DEBUG)
  672. {
  673. read = () =>
  674. {
  675. var val = field.read();
  676. dbg_log("Device<" + this.name + "> " +
  677. "cap[" + cap.type + "] " +
  678. "read[" + field.name + "] " +
  679. "=> " + h(val, field.bytes * 8),
  680. LOG_VIRTIO);
  681. return val;
  682. };
  683. write = data =>
  684. {
  685. field.write(data);
  686. dbg_log("Device<" + this.name + "> " +
  687. "cap[" + cap.type + "] " +
  688. "write[" + field.name + "] " +
  689. "<= " + h(data, field.bytes * 8),
  690. LOG_VIRTIO);
  691. };
  692. }
  693. if(cap.use_mmio)
  694. {
  695. dbg_assert(false, "VirtIO device <" + this.name + "> mmio capability not implemented.");
  696. }
  697. else
  698. {
  699. switch(field.bytes)
  700. {
  701. case 4:
  702. this.cpu.io.register_read(port, this, undefined, undefined, read);
  703. this.cpu.io.register_write(port, this, undefined, undefined, write);
  704. break;
  705. case 2:
  706. this.cpu.io.register_read(port, this, undefined, read);
  707. this.cpu.io.register_write(port, this, undefined, write);
  708. break;
  709. case 1:
  710. this.cpu.io.register_read(port, this, read);
  711. this.cpu.io.register_write(port, this, write);
  712. break;
  713. default:
  714. dbg_assert(false,
  715. "VirtIO device <" + this.name + "> invalid capability field width");
  716. break;
  717. }
  718. }
  719. port += field.bytes;
  720. });
  721. });
  722. // Terminate linked list with null pointer.
  723. // The field cap_next is at offset 1.
  724. this.pci_space[cap_ptr + 1] = 0;
  725. };
  726. VirtIO.prototype.get_state = function()
  727. {
  728. var state = [];
  729. // TODO: Upgrade
  730. state[0] = 0; // unused
  731. state[1] = this.queue_select;
  732. state[2] = this.device_status;
  733. state[3] = this.isr;
  734. state[4] = this.last_idx;
  735. state[5] = this.queue_size;
  736. state[6] = this.queue_address;
  737. state[7] = this.device;
  738. return state;
  739. };
  740. VirtIO.prototype.set_state = function(state)
  741. {
  742. // TODO: Upgrade
  743. this.queue_select = state[1];
  744. this.device_status = state[2];
  745. this.isr = state[3];
  746. this.last_idx = state[4];
  747. this.queue_size = state[5];
  748. this.queue_address = state[6];
  749. this.device = state[7];
  750. this.device.SendReply = this.device_reply.bind(this);
  751. };
  752. VirtIO.prototype.reset = function()
  753. {
  754. this.device_feature_select = 0;
  755. this.driver_feature_select = 0;
  756. this.driver_feature.set(this.device_feature);
  757. this.features_ok = true;
  758. this.device_status = 0;
  759. this.queue_select = 0;
  760. this.queue_selected = this.queues[0];
  761. for(var queue of this.queues)
  762. {
  763. queue.reset();
  764. }
  765. this.config_has_changed = false;
  766. this.config_generation = 0;
  767. this.lower_irq();
  768. // Old:
  769. this.queue_select = 0;
  770. this.device_status = 0;
  771. this.isr = 0;
  772. this.last_idx = 0;
  773. this.queue_size = 32;
  774. this.queue_address = 0;
  775. };
  776. /**
  777. * Call this when device-specific configuration state changes.
  778. * Also called when status DEVICE_NEEDS_RESET is set.
  779. */
  780. VirtIO.prototype.notify_config_changes = function()
  781. {
  782. this.config_has_changed = true;
  783. if(this.device_status & VIRTIO_STATUS_DRIVER_OK)
  784. {
  785. this.raise_irq(VIRTIO_ISR_DEVICE_CFG);
  786. }
  787. else
  788. {
  789. dbg_assert(false,
  790. "VirtIO device<" + this.name + "> attempted to notify driver before DRIVER_OK");
  791. }
  792. };
  793. /**
  794. * To be called after reading any field whose write can trigger notify_config_changes().
  795. */
  796. VirtIO.prototype.update_config_generation = function()
  797. {
  798. if(this.config_has_changed)
  799. {
  800. this.config_generation++;
  801. this.config_generation &= 0xFF;
  802. this.config_has_changed = false;
  803. }
  804. };
  805. VirtIO.prototype.does_driver_support = function(feature)
  806. {
  807. // Feature bits are grouped in 32 bits.
  808. return this.driver_feature[feature >>> 5] & (1 << (feature & 0x1F)) === 1;
  809. };
  810. VirtIO.prototype.pop_request = function(queue_id)
  811. {
  812. // TODO
  813. };
  814. VirtIO.prototype.push_reply = function()
  815. {
  816. // TODO
  817. };
  818. /**
  819. * Call this if an irrecoverable error has been occured.
  820. * Notifies driver if DRIVER_OK, or when DRIVER_OK gets set.
  821. */
  822. VirtIO.prototype.needs_reset = function()
  823. {
  824. dbg_log("Device<" + this.name + "> experienced error - requires reset", LOG_VIRTIO);
  825. this.device_status |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
  826. if(this.device_status & VIRTIO_STATUS_DRIVER_OK)
  827. {
  828. this.notify_config_changes();
  829. }
  830. };
  831. VirtIO.prototype.raise_irq = function(type)
  832. {
  833. this.isr_status |= type;
  834. this.pci.raise_irq(this.pci_id);
  835. };
  836. VirtIO.prototype.lower_irq = function()
  837. {
  838. this.isr_status = 0;
  839. this.pci.lower_irq(this.pci_id);
  840. };
  841. // TODO: upgrade the following.
  842. VirtIO.prototype.handle_descriptor = function(idx)
  843. {
  844. var next = idx;
  845. var desc_start = this.queue_address << 12;
  846. var buffer_idx = 0;
  847. var buffers = [];
  848. do
  849. {
  850. var addr = desc_start + next * 16;
  851. var flags = this.cpu.read16(addr + 12);
  852. if(flags & VRING_DESC_F_WRITE)
  853. {
  854. break;
  855. }
  856. if(flags & VRING_DESC_F_INDIRECT) {
  857. dbg_assert(false, "unsupported");
  858. }
  859. var addr_low = this.cpu.read32s(addr);
  860. var addr_high = this.cpu.read32s(addr + 4);
  861. var len = this.cpu.read32s(addr + 8) >>> 0;
  862. buffers.push({
  863. addr_low: addr_low,
  864. addr_high: addr_high,
  865. len: len,
  866. });
  867. dbg_log("descriptor: addr=" + h(addr_high, 8) + ":" + h(addr_low, 8) +
  868. " len=" + h(len, 8) + " flags=" + h(flags, 4) + " next=" + h(next, 4), LOG_VIRTIO);
  869. if(flags & VRING_DESC_F_NEXT)
  870. {
  871. next = this.cpu.read16(addr + 14);
  872. dbg_assert(next < this.queue_size);
  873. }
  874. else
  875. {
  876. next = -1;
  877. break;
  878. }
  879. }
  880. while(true);
  881. var infos = {
  882. start: idx,
  883. next: next,
  884. };
  885. let total_length = 0;
  886. for(let i = 0; i < buffers.length; i++)
  887. {
  888. total_length += buffers[i].len;
  889. }
  890. // TODO: Remove this unnecessary copy. Instead, pass list of memory views
  891. const memory_buffer = new Uint8Array(total_length);
  892. let pointer = 0;
  893. for(let i = 0; i < buffers.length; i++)
  894. {
  895. const buf = buffers[i];
  896. memory_buffer.set(this.cpu.read_blob(buf.addr_low, buf.len), pointer);
  897. pointer += buf.len;
  898. }
  899. this.device.ReceiveRequest(infos, memory_buffer);
  900. };
  901. // TODO: upgrade the following.
  902. VirtIO.prototype.device_reply = function(queueidx, infos)
  903. {
  904. if(infos.next === -1)
  905. {
  906. dbg_log("Reply to invalid index", LOG_VIRTIO);
  907. return;
  908. }
  909. var mask = this.queue_size - 1;
  910. var result_length = this.device.replybuffersize;
  911. var next = infos.next;
  912. var desc_start = this.queue_address << 12;
  913. var buffers = [];
  914. do
  915. {
  916. var addr = desc_start + next * 16;
  917. var flags = this.cpu.read16(addr + 12);
  918. if((flags & VRING_DESC_F_WRITE) === 0)
  919. {
  920. dbg_log("Bug: Readonly ring after writeonly ring", LOG_VIRTIO);
  921. break;
  922. }
  923. var addr_low = this.cpu.read32s(addr);
  924. var addr_high = this.cpu.read32s(addr + 4);
  925. var len = this.cpu.read32s(addr + 8) >>> 0;
  926. buffers.push({
  927. addr_low: addr_low,
  928. addr_high: addr_high,
  929. len: len,
  930. });
  931. dbg_log("descriptor: addr=" + h(addr_high, 8) + ":" + h(addr_low, 8) +
  932. " len=" + h(len, 8) + " flags=" + h(flags, 4) + " next=" + h(next, 4), LOG_VIRTIO);
  933. if(flags & VRING_DESC_F_NEXT)
  934. {
  935. next = this.cpu.read16(addr + 14);
  936. dbg_assert(next < this.queue_size);
  937. }
  938. else
  939. {
  940. break;
  941. }
  942. }
  943. while(true);
  944. var buffer_idx = 0;
  945. for(var i = 0; i < result_length; )
  946. {
  947. if(buffer_idx === buffers.length)
  948. {
  949. dbg_log("Write more data than descriptor has", LOG_VIRTIO);
  950. return 0;
  951. }
  952. const buf = buffers[buffer_idx++];
  953. const slice = this.device.replybuffer.subarray(i, i + buf.len);
  954. this.cpu.write_blob(slice, buf.addr_low);
  955. i += buf.len;
  956. }
  957. var used_desc_start = (this.queue_address << 12) + 16 * this.queue_size + 4 + 2 * this.queue_size;
  958. used_desc_start = used_desc_start + 4095 & ~4095;
  959. var flags = this.cpu.read16(used_desc_start);
  960. var used_idx = this.cpu.read16(used_desc_start + 2);
  961. this.cpu.write16(used_desc_start + 2, used_idx + 1);
  962. dbg_log("used descriptor: addr=" + h(used_desc_start, 8) + " flags=" + h(flags, 4) + " idx=" + h(used_idx, 4), LOG_VIRTIO);
  963. used_idx &= mask;
  964. var used_desc_offset = used_desc_start + 4 + used_idx * 8;
  965. this.cpu.write32(used_desc_offset, infos.start);
  966. this.cpu.write32(used_desc_offset + 4, result_length);
  967. this.isr |= 1;
  968. this.pci.raise_irq(this.pci_id);
  969. };
  970. /**
  971. * @constructor
  972. * @param {CPU} cpu
  973. * @param {VirtQueue_Options} options
  974. */
  975. function VirtQueue(cpu, options)
  976. {
  977. /** @type {CPU} */
  978. this.cpu = cpu;
  979. // Number of entries.
  980. this.size = options.size_supported;
  981. this.size_supported = options.size_supported;
  982. this.enable = 0;
  983. this.notify_offset = options.notify_offset;
  984. this.desc_table = null;
  985. this.desc_table_addr = 0;
  986. this.avail_ring = null;
  987. this.avail_ring_addr = 0;
  988. this.used_ring = null;
  989. this.used_ring_addr = 0;
  990. this.reset();
  991. }
  992. VirtQueue.prototype.reset = function()
  993. {
  994. this.size = this.size_supported;
  995. this.enable = 0;
  996. this.desc_table = null;
  997. this.desc_table_addr = 0;
  998. this.avail_ring = null;
  999. this.avail_ring_addr = 0;
  1000. this.used_ring = null;
  1001. this.used_ring_addr = 0;
  1002. };
  1003. VirtQueue.prototype.push_reply = function()
  1004. {
  1005. // TODO
  1006. };
  1007. VirtQueue.prototype.pop_request = function()
  1008. {
  1009. // TODO
  1010. };
  1011. /**
  1012. * @param {number} address
  1013. */
  1014. VirtQueue.prototype.set_desc_table_address = function(address)
  1015. {
  1016. var table_size = this.size * VIRTQ_DESC_ENTRYSIZE;
  1017. var data_view = new DataView(this.cpu.mem8.buffer, address, address + table_size);
  1018. this.desc_table_addr = address;
  1019. this.desc_table =
  1020. {
  1021. get_addr_low: i => data_view.getUint32(i * VIRTQ_DESC_ENTRYSIZE, true),
  1022. get_addr_high: i => data_view.getUint32(i * VIRTQ_DESC_ENTRYSIZE + 4, true),
  1023. get_len: i => data_view.getUint32(i * VIRTQ_DESC_ENTRYSIZE + 8, true),
  1024. get_flags: i => data_view.getUint16(i * VIRTQ_DESC_ENTRYSIZE + 12, true),
  1025. get_next: i => data_view.getUint16(i * VIRTQ_DESC_ENTRYSIZE + 14, true),
  1026. };
  1027. };
  1028. /**
  1029. * @param {number} address
  1030. */
  1031. VirtQueue.prototype.set_avail_ring_address = function(address)
  1032. {
  1033. var ring_size = VIRTQ_AVAIL_BASESIZE + this.size * VIRTQ_AVAIL_ENTRYSIZE;
  1034. var data_view = new DataView(this.cpu.mem8.buffer, address, address + ring_size);
  1035. this.avail_ring_addr = address;
  1036. this.avail_ring =
  1037. {
  1038. get_flags: () => data_view.getUint16(0, true),
  1039. get_idx: () => data_view.getUint16(2, true),
  1040. get_entry: i => data_view.getUint16(2 + VIRTQ_AVAIL_ENTRYSIZE * i, true),
  1041. get_used_event: () => data_view.getUint16(2 + VIRTQ_AVAIL_ENTRYSIZE * this.size, true),
  1042. };
  1043. };
  1044. /**
  1045. * @param {number} address
  1046. */
  1047. VirtQueue.prototype.set_used_ring_address = function(address)
  1048. {
  1049. var ring_size = VIRTQ_USED_BASESIZE + this.size * VIRTQ_USED_ENTRYSIZE;
  1050. var data_view = new DataView(this.cpu.mem8.buffer, address, address + ring_size);
  1051. this.used_ring_addr = address;
  1052. this.used_ring =
  1053. {
  1054. get_flags: () => data_view.getUint16(0, true),
  1055. get_idx: () => data_view.getUint16(2, true),
  1056. get_entry_id: i => data_view.getUint16(2 + VIRTQ_USED_ENTRYSIZE * i, true),
  1057. set_entry_id: (i, value) => data_view.setUint32(2 + VIRTQ_USED_ENTRYSIZE * i, value, true),
  1058. get_entry_len: i => data_view.getUint16(6 + VIRTQ_USED_ENTRYSIZE * i, true),
  1059. set_entry_len: (i, value) => data_view.setUint32(6 + VIRTQ_USED_ENTRYSIZE * i, value, true),
  1060. get_avail_event: () => data_view.getUint16(2 + VIRTQ_AVAIL_ENTRYSIZE * this.size, true),
  1061. };
  1062. };