virtio.js 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494
  1. "use strict";
  2. // http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html
  3. const VIRTIO_PCI_VENDOR_ID = 0x1AF4;
  4. // Identifies vendor-specific PCI capability.
  5. const VIRTIO_PCI_CAP_VENDOR = 0x09;
  6. // Length (bytes) of VIRTIO_PCI_CAP linked list entry.
  7. const VIRTIO_PCI_CAP_LENGTH = 16;
  8. // Capability types.
  9. const VIRTIO_PCI_CAP_COMMON_CFG = 1;
  10. const VIRTIO_PCI_CAP_NOTIFY_CFG = 2;
  11. const VIRTIO_PCI_CAP_ISR_CFG = 3;
  12. const VIRTIO_PCI_CAP_DEVICE_CFG = 4;
  13. const VIRTIO_PCI_CAP_PCI_CFG = 5;
  14. // Status bits (device_status values).
  15. const VIRTIO_STATUS_ACKNOWLEDGE = 1;
  16. const VIRTIO_STATUS_DRIVER = 2;
  17. const VIRTIO_STATUS_DRIVER_OK = 4;
  18. const VIRTIO_STATUS_FEATURES_OK = 8;
  19. const VIRTIO_STATUS_DEVICE_NEEDS_RESET = 64;
  20. const VIRTIO_STATUS_FAILED = 128;
  21. // ISR bits (isr_status values).
  22. const VIRTIO_ISR_QUEUE = 1;
  23. const VIRTIO_ISR_DEVICE_CFG = 2;
  24. // Feature bits (bit positions).
  25. const VIRTIO_F_RING_INDIRECT_DESC = 28;
  26. const VIRTIO_F_RING_EVENT_IDX = 29;
  27. const VIRTIO_F_VERSION_1 = 32;
  28. // Queue struct sizes.
  29. // Size (bytes) of the virtq_desc struct per queue size.
  30. const VIRTQ_DESC_ENTRYSIZE = 16;
  31. // Size (bytes) of the virtq_avail struct ignoring ring entries.
  32. const VIRTQ_AVAIL_BASESIZE = 6;
  33. // Size (bytes) of the virtq_avail struct per queue size.
  34. const VIRTQ_AVAIL_ENTRYSIZE = 2;
  35. // Size (bytes) of the virtq_used struct ignoring ring entries.
  36. const VIRTQ_USED_BASESIZE = 6;
  37. // Size (bytes) of the virtq_desc struct per queue size.
  38. const VIRTQ_USED_ENTRYSIZE = 8;
  39. // Mask for wrapping the idx field of the virtq_used struct so that the value
  40. // naturally overflows after 65535 (idx is a word).
  41. const VIRTQ_IDX_MASK = 0xFFFF;
  42. // Queue flags.
  43. const VIRTQ_DESC_F_NEXT = 1;
  44. const VIRTQ_DESC_F_WRITE = 2;
  45. const VIRTQ_DESC_F_INDIRECT = 4;
  46. const VIRTQ_AVAIL_F_NO_INTERRUPT = 1;
  47. const VIRTQ_USED_F_NO_NOTIFY = 1;
  48. // Closure Compiler Types.
  49. /**
  50. * @typedef {!Array<{
  51. * bytes: number,
  52. * name: string,
  53. * read: function():number,
  54. * write: function(number)
  55. * }>}
  56. */
  57. var VirtIO_CapabilityStruct;
  58. /**
  59. * @typedef {
  60. * {
  61. * type: number,
  62. * bar: number,
  63. * port: number,
  64. * use_mmio: boolean,
  65. * offset: number,
  66. * extra: Uint8Array,
  67. * struct: VirtIO_CapabilityStruct,
  68. * }}
  69. */
  70. var VirtIO_CapabilityInfo;
  71. /**
  72. * @typedef {
  73. * {
  74. * size_supported: number,
  75. * notify_offset: number,
  76. * }}
  77. */
  78. var VirtQueue_Options;
  79. /**
  80. * @typedef {
  81. * {
  82. * initial_port: number,
  83. * queues: !Array<VirtQueue_Options>,
  84. * features: !Array<number>,
  85. * on_driver_ok: function(),
  86. * }}
  87. */
  88. var VirtIO_CommonCapabilityOptions;
  89. /**
  90. * @typedef {
  91. * {
  92. * initial_port: number,
  93. * single_handler: boolean,
  94. * handlers: !Array<function()>,
  95. * }}
  96. */
  97. var VirtIO_NotificationCapabilityOptions;
  98. /**
  99. * @typedef {
  100. * {
  101. * initial_port: number,
  102. * }}
  103. */
  104. var VirtIO_ISRCapabilityOptions;
  105. /**
  106. * @typedef {
  107. * {
  108. * initial_port: number,
  109. * struct: VirtIO_CapabilityStruct,
  110. * }}
  111. */
  112. var VirtIO_DeviceSpecificCapabilityOptions;
  113. /**
  114. * @typedef {
  115. * {
  116. * name: string,
  117. * pci_id: number,
  118. * device_id: number,
  119. * subsystem_device_id: number,
  120. * common: VirtIO_CommonCapabilityOptions,
  121. * notification: VirtIO_NotificationCapabilityOptions,
  122. * isr_status: VirtIO_ISRCapabilityOptions,
  123. * device_specific: (undefined | VirtIO_DeviceSpecificCapabilityOptions),
  124. * }}
  125. */
  126. var VirtIO_Options;
  127. /**
  128. * @constructor
  129. * @param {CPU} cpu
  130. * @param {VirtIO_Options} options
  131. */
  132. function VirtIO(cpu, options)
  133. {
  134. const io = cpu.io;
  135. /** @const @type {CPU} */
  136. this.cpu = cpu;
  137. /** @const @type {PCI} */
  138. this.pci = cpu.devices.pci;
  139. this.device_id = options.device_id;
  140. this.pci_space =
  141. [
  142. // Vendor ID
  143. VIRTIO_PCI_VENDOR_ID & 0xFF, VIRTIO_PCI_VENDOR_ID >> 8,
  144. // Device ID
  145. options.device_id & 0xFF, options.device_id >> 8,
  146. // Command
  147. 0x07, 0x05,
  148. // Status - enable capabilities list
  149. 0x10, 0x00,
  150. // Revision ID
  151. 0x01,
  152. // Prof IF, Subclass, Class code
  153. 0x00, 0x02, 0x00,
  154. // Cache line size
  155. 0x00,
  156. // Latency Timer
  157. 0x00,
  158. // Header Type
  159. 0x00,
  160. // Built-in self test
  161. 0x00,
  162. // BAR0
  163. 0x01, 0xa8, 0x00, 0x00,
  164. // BAR1
  165. 0x00, 0x10, 0xbf, 0xfe,
  166. // BAR2
  167. 0x00, 0x00, 0x00, 0x00,
  168. // BAR3
  169. 0x00, 0x00, 0x00, 0x00,
  170. // BAR4
  171. 0x00, 0x00, 0x00, 0x00,
  172. // BAR5
  173. 0x00, 0x00, 0x00, 0x00,
  174. // CardBus CIS pointer
  175. 0x00, 0x00, 0x00, 0x00,
  176. // Subsystem vendor ID
  177. VIRTIO_PCI_VENDOR_ID & 0xFF, VIRTIO_PCI_VENDOR_ID >> 8,
  178. // Subsystem ID
  179. options.subsystem_device_id & 0xFF, options.subsystem_device_id >> 8,
  180. // Expansion ROM base address
  181. 0x00, 0x00, 0x00, 0x00,
  182. // Capabilities pointer
  183. 0x40,
  184. // Reserved
  185. 0x00, 0x00, 0x00,
  186. // Reserved
  187. 0x00, 0x00, 0x00, 0x00,
  188. // Interrupt line
  189. 0x00,
  190. // Interrupt pin
  191. 0x01,
  192. // Min grant
  193. 0x00,
  194. // Max latency
  195. 0x00,
  196. ];
  197. // Prevent sparse arrays by preallocating.
  198. this.pci_space = this.pci_space.concat(v86util.zeros(256 - this.pci_space.length));
  199. // Remaining PCI space is appended by capabilities further below.
  200. this.pci_id = options.pci_id;
  201. // PCI bars gets filled in by capabilities further below.
  202. this.pci_bars = [];
  203. this.name = options.name;
  204. // Feature bits grouped in dwords, dword selected by decive_feature_select.
  205. this.device_feature_select = 0;
  206. this.driver_feature_select = 0;
  207. // Unspecified upper bound. Assume 4*32=128 bits.
  208. this.device_feature = new Uint32Array(4);
  209. this.driver_feature = new Uint32Array(4);
  210. for(const f of options.common.features)
  211. {
  212. dbg_assert(f >= 0,
  213. "VirtIO device<" + this.name + "> feature bit numbers must be non-negative");
  214. dbg_assert(f < 128,
  215. "VirtIO device<" + this.name + "> feature bit numbers assumed less than 128 in implementation");
  216. // Feature bits are grouped in 32 bits.
  217. this.device_feature[f >>> 5] |= 1 << (f & 0x1F);
  218. this.driver_feature[f >>> 5] |= 1 << (f & 0x1F);
  219. }
  220. dbg_assert(options.common.features.includes(VIRTIO_F_VERSION_1),
  221. "VirtIO device<" + this.name + "> only non-transitional devices are supported");
  222. // Indicates whether driver_feature bits is subset of device_feature bits.
  223. this.features_ok = true;
  224. this.device_status = 0;
  225. this.config_has_changed = false;
  226. this.config_generation = 0;
  227. /** @type {!Array<VirtQueue>} */
  228. this.queues = [];
  229. for(const queue_options of options.common.queues)
  230. {
  231. this.queues.push(new VirtQueue(cpu, this, queue_options));
  232. }
  233. this.queue_select = 0;
  234. this.queue_selected = this.queues[0];
  235. this.isr_status = 0;
  236. // Verify notification options.
  237. if(DEBUG)
  238. {
  239. const offsets = new Set();
  240. for(const offset of this.queues.map(q => q.notify_offset))
  241. {
  242. const effective_offset = options.notification.single_handler ? 0 : offset;
  243. offsets.add(effective_offset);
  244. dbg_assert(options.notification.handlers[effective_offset],
  245. "VirtIO device<" + this.name + "> every queue's notifier must exist");
  246. }
  247. for(const [index, handler] of options.notification.handlers.entries())
  248. {
  249. dbg_assert(!handler || offsets.has(index),
  250. "VirtIO device<" + this.name +"> no defined notify handler should be unused");
  251. }
  252. }
  253. /** @type {!Array<VirtIO_CapabilityInfo>} */
  254. const capabilities = [];
  255. capabilities.push(this.create_common_capability(options.common));
  256. capabilities.push(this.create_notification_capability(options.notification));
  257. capabilities.push(this.create_isr_capability(options.isr_status));
  258. if(options.device_specific)
  259. {
  260. capabilities.push(this.create_device_specific_capability(options.device_specific));
  261. }
  262. this.init_capabilities(capabilities);
  263. cpu.devices.pci.register_device(this);
  264. this.reset();
  265. }
  266. /**
  267. * @param {VirtIO_CommonCapabilityOptions} options
  268. * @return {VirtIO_CapabilityInfo}
  269. */
  270. VirtIO.prototype.create_common_capability = function(options)
  271. {
  272. return {
  273. type: VIRTIO_PCI_CAP_COMMON_CFG,
  274. bar: 0,
  275. port: options.initial_port,
  276. use_mmio: false,
  277. offset: 0,
  278. extra: new Uint8Array(0),
  279. struct:
  280. [
  281. {
  282. bytes: 4,
  283. name: "device_feature_select",
  284. read: () => this.device_feature_select,
  285. write: data =>
  286. {
  287. this.device_feature_select = data;
  288. },
  289. },
  290. {
  291. bytes: 4,
  292. name: "device_feature",
  293. read: () => this.device_feature[this.device_feature_select] || 0,
  294. write: data => { /* read only */ },
  295. },
  296. {
  297. bytes: 4,
  298. name: "driver_feature_select",
  299. read: () => this.driver_feature_select,
  300. write: data =>
  301. {
  302. this.driver_feature_select = data;
  303. },
  304. },
  305. {
  306. bytes: 4,
  307. name: "driver_feature",
  308. read: () => this.driver_feature[this.driver_feature_select] || 0,
  309. write: data =>
  310. {
  311. const supported_feature = this.device_feature[this.driver_feature_select];
  312. if(this.driver_feature_select < this.driver_feature.length)
  313. {
  314. // Note: only set subset of device_features is set.
  315. // Required in our implementation for is_feature_negotiated().
  316. this.driver_feature[this.driver_feature_select] = data & supported_feature;
  317. }
  318. // Check that driver features is an inclusive subset of device features.
  319. const invalid_bits = data & ~supported_feature;
  320. this.features_ok = this.features_ok && !invalid_bits;
  321. },
  322. },
  323. {
  324. bytes: 2,
  325. name: "msix_config",
  326. read: () =>
  327. {
  328. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  329. return 0xFFFF;
  330. },
  331. write: data =>
  332. {
  333. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  334. },
  335. },
  336. {
  337. bytes: 2,
  338. name: "num_queues",
  339. read: () => this.queues.length,
  340. write: data => { /* read only */ },
  341. },
  342. {
  343. bytes: 1,
  344. name: "device_status",
  345. read: () => this.device_status,
  346. write: data =>
  347. {
  348. if(data === 0)
  349. {
  350. dbg_log("Reset device<" + this.name + ">", LOG_VIRTIO);
  351. this.reset();
  352. }
  353. else if(data & VIRTIO_STATUS_FAILED)
  354. {
  355. dbg_log("Warning: Device<" + this.name + "> status failed", LOG_VIRTIO);
  356. }
  357. else
  358. {
  359. dbg_log("Device<" + this.name +"> status: " +
  360. ((data & VIRTIO_STATUS_ACKNOWLEDGE) ? "ACKNOWLEDGE " : "") +
  361. ((data & VIRTIO_STATUS_DRIVER) ? "DRIVER " : "") +
  362. ((data & VIRTIO_STATUS_DRIVER_OK) ? "DRIVER_OK" : "") +
  363. ((data & VIRTIO_STATUS_FEATURES_OK) ? "FEATURES_OK " : "") +
  364. ((data & VIRTIO_STATUS_DEVICE_NEEDS_RESET) ? "DEVICE_NEEDS_RESET" : ""),
  365. LOG_VIRTIO);
  366. }
  367. if((data & ~this.device_status & VIRTIO_STATUS_DRIVER_OK) &&
  368. (this.device_status & VIRTIO_STATUS_DEVICE_NEEDS_RESET))
  369. {
  370. // We couldn't notify NEEDS_RESET earlier because DRIVER_OK was not set.
  371. // Now it has been set, notify now.
  372. this.notify_config_changes();
  373. }
  374. // Don't set FEATURES_OK if our device doesn't support requested features.
  375. if(!this.features_ok)
  376. {
  377. if(DEBUG && (data & VIRTIO_STATUS_FEATURES_OK))
  378. {
  379. dbg_log("Removing FEATURES_OK", LOG_VIRTIO);
  380. }
  381. data &= ~VIRTIO_STATUS_FEATURES_OK;
  382. }
  383. this.device_status = data;
  384. if(data & ~this.device_status & VIRTIO_STATUS_DRIVER_OK)
  385. {
  386. options.on_driver_ok();
  387. }
  388. },
  389. },
  390. {
  391. bytes: 1,
  392. name: "config_generation",
  393. read: () => this.config_generation,
  394. write: data => { /* read only */ },
  395. },
  396. {
  397. bytes: 2,
  398. name: "queue_select",
  399. read: () => this.queue_select,
  400. write: data =>
  401. {
  402. this.queue_select = data;
  403. if(this.queue_select < this.queues.length)
  404. {
  405. this.queue_selected = this.queues[this.queue_select];
  406. }
  407. else
  408. {
  409. // Allow queue_select >= num_queues.
  410. this.queue_selected = null;
  411. // Drivers can then detect that the queue is not available
  412. // using the below fields.
  413. }
  414. },
  415. },
  416. {
  417. bytes: 2,
  418. name: "queue_size",
  419. read: () => this.queue_selected ? this.queue_selected.size : 0,
  420. write: data =>
  421. {
  422. if(!this.queue_selected)
  423. {
  424. return;
  425. }
  426. if(data & data - 1)
  427. {
  428. dbg_log("Warning: dev<" + this.name +"> " +
  429. "Given queue size was not a power of 2. " +
  430. "Rounding up to next power of 2.", LOG_VIRTIO);
  431. data = 1 << (v86util.int_log2(data - 1) + 1);
  432. }
  433. if(data > this.queue_selected.size_supported)
  434. {
  435. dbg_log("Warning: dev<" + this.name +"> " +
  436. "Trying to set queue size greater than supported. " +
  437. "Clamping to supported size.", LOG_VIRTIO);
  438. data = this.queue_selected.size_supported;
  439. }
  440. this.queue_selected.set_size(data);
  441. },
  442. },
  443. {
  444. bytes: 2,
  445. name: "queue_msix_vector",
  446. read: () =>
  447. {
  448. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  449. return 0xFFFF;
  450. },
  451. write: data =>
  452. {
  453. dbg_log("No msi-x capability supported.", LOG_VIRTIO);
  454. },
  455. },
  456. {
  457. bytes: 2,
  458. name: "queue_enable",
  459. read: () => this.queue_selected ? this.queue_selected.enabled | 0 : 0,
  460. write: data =>
  461. {
  462. if(!this.queue_selected)
  463. {
  464. return;
  465. }
  466. if(data === 1)
  467. {
  468. if(this.queue_selected.is_configured())
  469. {
  470. this.queue_selected.enable();
  471. }
  472. else
  473. {
  474. dbg_log("Driver bug: tried enabling unconfigured queue", LOG_VIRTIO);
  475. }
  476. }
  477. else if(data === 0)
  478. {
  479. dbg_log("Driver bug: tried writing 0 to queue_enable", LOG_VIRTIO);
  480. }
  481. },
  482. },
  483. {
  484. bytes: 2,
  485. name: "queue_notify_off",
  486. read: () => this.queue_selected ? this.queue_selected.notify_offset : 0,
  487. write: data => { /* read only */ },
  488. },
  489. {
  490. bytes: 4,
  491. name: "queue_desc (low dword)",
  492. read: () => this.queue_selected ? this.queue_selected.desc_addr : 0,
  493. write: data =>
  494. {
  495. if(this.queue_selected) this.queue_selected.desc_addr = data;
  496. },
  497. },
  498. {
  499. bytes: 4,
  500. name: "queue_desc (high dword)",
  501. read: () => 0,
  502. write: data =>
  503. {
  504. dbg_log("Warning: High dword of 64 bit queue_desc ignored", LOG_VIRTIO);
  505. },
  506. },
  507. {
  508. bytes: 4,
  509. name: "queue_avail (low dword)",
  510. read: () => this.queue_selected ? this.queue_selected.avail_addr : 0,
  511. write: data =>
  512. {
  513. if(this.queue_selected) this.queue_selected.avail_addr = data;
  514. },
  515. },
  516. {
  517. bytes: 4,
  518. name: "queue_avail (high dword)",
  519. read: () => 0,
  520. write: data =>
  521. {
  522. dbg_log("Warning: High dword of 64 bit queue_avail ignored", LOG_VIRTIO);
  523. },
  524. },
  525. {
  526. bytes: 4,
  527. name: "queue_used (low dword)",
  528. read: () => this.queue_selected ? this.queue_selected.used_addr : 0,
  529. write: data =>
  530. {
  531. if(this.queue_selected) this.queue_selected.used_addr = data;
  532. },
  533. },
  534. {
  535. bytes: 4,
  536. name: "queue_used (high dword)",
  537. read: () => 0,
  538. write: data =>
  539. {
  540. dbg_log("Warning: High dword of 64 bit queue_used ignored", LOG_VIRTIO);
  541. },
  542. },
  543. ],
  544. };
  545. };
  546. /**
  547. * @param {VirtIO_NotificationCapabilityOptions} options
  548. * @return {VirtIO_CapabilityInfo}
  549. */
  550. VirtIO.prototype.create_notification_capability = function(options)
  551. {
  552. const notify_struct = [];
  553. let notify_off_multiplier;
  554. if(options.single_handler)
  555. {
  556. dbg_assert(options.handlers.length === 1,
  557. "VirtIO device<" + this.name + "> too many notify handlers specified: expected single handler");
  558. // Forces all queues to use the same address for notifying.
  559. notify_off_multiplier = 0;
  560. }
  561. else
  562. {
  563. notify_off_multiplier = 2;
  564. }
  565. for(const [i, handler] of options.handlers.entries())
  566. {
  567. notify_struct.push(
  568. {
  569. bytes: 2,
  570. name: "notify" + i,
  571. read: () => 0xFFFF,
  572. write: handler || (data => {}),
  573. });
  574. }
  575. return {
  576. type: VIRTIO_PCI_CAP_NOTIFY_CFG,
  577. bar: 1,
  578. port: options.initial_port,
  579. use_mmio: false,
  580. offset: 0,
  581. extra: new Uint8Array(
  582. [
  583. notify_off_multiplier & 0xFF,
  584. (notify_off_multiplier >> 8) & 0xFF,
  585. (notify_off_multiplier >> 16) & 0xFF,
  586. notify_off_multiplier >> 24,
  587. ]),
  588. struct: notify_struct,
  589. };
  590. };
  591. /**
  592. * @param {VirtIO_ISRCapabilityOptions} options
  593. * @return {VirtIO_CapabilityInfo}
  594. */
  595. VirtIO.prototype.create_isr_capability = function(options)
  596. {
  597. return {
  598. type: VIRTIO_PCI_CAP_ISR_CFG,
  599. bar: 2,
  600. port: options.initial_port,
  601. use_mmio: false,
  602. offset: 0,
  603. extra: new Uint8Array(0),
  604. struct:
  605. [
  606. {
  607. bytes: 1,
  608. name: "isr_status",
  609. read: () =>
  610. {
  611. const isr_status = this.isr_status;
  612. this.lower_irq();
  613. return isr_status;
  614. },
  615. write: data => { /* read only */ },
  616. },
  617. ],
  618. };
  619. };
  620. /**
  621. * @param {VirtIO_DeviceSpecificCapabilityOptions} options
  622. * @return {VirtIO_CapabilityInfo}
  623. */
  624. VirtIO.prototype.create_device_specific_capability = function(options)
  625. {
  626. dbg_assert(~options.offset & 0x3,
  627. "VirtIO device<" + this.name + "> device specific cap offset must be 4-byte aligned");
  628. return {
  629. type: VIRTIO_PCI_CAP_DEVICE_CFG,
  630. bar: 3,
  631. port: options.initial_port,
  632. use_mmio: false,
  633. offset: 0,
  634. extra: new Uint8Array(0),
  635. struct: options.struct,
  636. };
  637. };
  638. /**
  639. * Writes capabilities into pci_space and hook up IO/MMIO handlers.
  640. * Call only within constructor.
  641. * @param {!Array<VirtIO_CapabilityInfo>} capabilities
  642. */
  643. VirtIO.prototype.init_capabilities = function(capabilities)
  644. {
  645. // Next available offset for capabilities linked list.
  646. let cap_next = this.pci_space[0x34] = 0x40;
  647. // Current offset.
  648. let cap_ptr = cap_next;
  649. for(const cap of capabilities)
  650. {
  651. const cap_len = VIRTIO_PCI_CAP_LENGTH + cap.extra.length;
  652. cap_ptr = cap_next;
  653. cap_next = cap_ptr + cap_len;
  654. dbg_assert(cap_next <= 256,
  655. "VirtIO device<" + this.name + "> can't fit all capabilities into 256byte configspace");
  656. dbg_assert(0 <= cap.bar && cap.bar < 6,
  657. "VirtIO device<" + this.name + "> capability invalid bar number");
  658. let bar_size = cap.struct.reduce((bytes, field) => bytes + field.bytes, 0);
  659. bar_size += cap.offset;
  660. // Round up to next power of 2,
  661. // Minimum 16 bytes for its size to be detectable in general (esp. mmio).
  662. bar_size = bar_size < 16 ? 16 : 1 << (v86util.int_log2(bar_size - 1) + 1);
  663. dbg_assert((cap.port & (bar_size - 1)) === 0,
  664. "VirtIO device<" + this.name + "> capability port should be aligned to pci bar size");
  665. this.pci_bars[cap.bar] =
  666. {
  667. size: bar_size,
  668. };
  669. this.pci_space[cap_ptr] = VIRTIO_PCI_CAP_VENDOR;
  670. this.pci_space[cap_ptr + 1] = cap_next;
  671. this.pci_space[cap_ptr + 2] = cap_len;
  672. this.pci_space[cap_ptr + 3] = cap.type;
  673. this.pci_space[cap_ptr + 4] = cap.bar;
  674. this.pci_space[cap_ptr + 5] = 0; // Padding.
  675. this.pci_space[cap_ptr + 6] = 0; // Padding.
  676. this.pci_space[cap_ptr + 7] = 0; // Padding.
  677. this.pci_space[cap_ptr + 8] = cap.offset & 0xFF;
  678. this.pci_space[cap_ptr + 9] = (cap.offset >>> 8) & 0xFF;
  679. this.pci_space[cap_ptr + 10] = (cap.offset >>> 16) & 0xFF;
  680. this.pci_space[cap_ptr + 11] = cap.offset >>> 24;
  681. this.pci_space[cap_ptr + 12] = bar_size & 0xFF;
  682. this.pci_space[cap_ptr + 13] = (bar_size >>> 8) & 0xFF;
  683. this.pci_space[cap_ptr + 14] = (bar_size >>> 16) & 0xFF;
  684. this.pci_space[cap_ptr + 15] = bar_size >>> 24;
  685. for(const [i, extra_byte] of cap.extra.entries())
  686. {
  687. this.pci_space[cap_ptr + 16 + i] = extra_byte;
  688. }
  689. const bar_offset = 0x10 + 4 * cap.bar;
  690. this.pci_space[bar_offset] = (cap.port & 0xFE) | !cap.use_mmio;
  691. this.pci_space[bar_offset + 1] = (cap.port >>> 8) & 0xFF;
  692. this.pci_space[bar_offset + 2] = (cap.port >>> 16) & 0xFF;
  693. this.pci_space[bar_offset + 3] = (cap.port >>> 24) & 0xFF;
  694. let port = cap.port + cap.offset;
  695. for(const field of cap.struct)
  696. {
  697. let read = field.read;
  698. let write = field.write;
  699. if(DEBUG)
  700. {
  701. read = () =>
  702. {
  703. const val = field.read();
  704. dbg_log("Device<" + this.name + "> " +
  705. "cap[" + cap.type + "] " +
  706. "read[" + field.name + "] " +
  707. "=> " + h(val, field.bytes * 8),
  708. LOG_VIRTIO);
  709. return val;
  710. };
  711. write = data =>
  712. {
  713. dbg_log("Device<" + this.name + "> " +
  714. "cap[" + cap.type + "] " +
  715. "write[" + field.name + "] " +
  716. "<= " + h(data, field.bytes * 8),
  717. LOG_VIRTIO);
  718. field.write(data);
  719. };
  720. }
  721. if(cap.use_mmio)
  722. {
  723. dbg_assert(false, "VirtIO device <" + this.name + "> mmio capability not implemented.");
  724. }
  725. else
  726. {
  727. // DSL (2.4 kernel) does these reads
  728. const shim_read8_on_16 = function(addr)
  729. {
  730. dbg_log("Warning: 8-bit read from 16-bit virtio port", LOG_VIRTIO);
  731. return read(addr & ~1) >> ((addr & 1) << 3) & 0xFF;
  732. };
  733. const shim_read8_on_32 = function(addr)
  734. {
  735. dbg_log("Warning: 8-bit read from 32-bit virtio port", LOG_VIRTIO);
  736. return read(addr & ~3) >> ((addr & 3) << 3) & 0xFF;
  737. };
  738. switch(field.bytes)
  739. {
  740. case 4:
  741. this.cpu.io.register_read(port, this, shim_read8_on_32, undefined, read);
  742. this.cpu.io.register_write(port, this, undefined, undefined, write);
  743. break;
  744. case 2:
  745. this.cpu.io.register_read(port, this, shim_read8_on_16, read);
  746. this.cpu.io.register_write(port, this, undefined, write);
  747. break;
  748. case 1:
  749. this.cpu.io.register_read(port, this, read);
  750. this.cpu.io.register_write(port, this, write);
  751. break;
  752. default:
  753. dbg_assert(false,
  754. "VirtIO device <" + this.name + "> invalid capability field width of " +
  755. field.bytes + " bytes");
  756. break;
  757. }
  758. }
  759. port += field.bytes;
  760. }
  761. }
  762. // Terminate linked list with the pci config access capability.
  763. const cap_len = VIRTIO_PCI_CAP_LENGTH + 4;
  764. dbg_assert(cap_next + cap_len <= 256,
  765. "VirtIO device<" + this.name + "> can't fit all capabilities into 256byte configspace");
  766. this.pci_space[cap_next] = VIRTIO_PCI_CAP_VENDOR;
  767. this.pci_space[cap_next + 1] = 0; // cap next (null terminator)
  768. this.pci_space[cap_next + 2] = cap_len;
  769. this.pci_space[cap_next + 3] = VIRTIO_PCI_CAP_PCI_CFG; // cap type
  770. this.pci_space[cap_next + 4] = 0; // bar (written by device)
  771. this.pci_space[cap_next + 5] = 0; // Padding.
  772. this.pci_space[cap_next + 6] = 0; // Padding.
  773. this.pci_space[cap_next + 7] = 0; // Padding.
  774. // Remaining fields are configured by driver when needed.
  775. // offset
  776. this.pci_space[cap_next + 8] = 0;
  777. this.pci_space[cap_next + 9] = 0;
  778. this.pci_space[cap_next + 10] = 0;
  779. this.pci_space[cap_next + 11] = 0;
  780. // bar size
  781. this.pci_space[cap_next + 12] = 0;
  782. this.pci_space[cap_next + 13] = 0;
  783. this.pci_space[cap_next + 14] = 0;
  784. this.pci_space[cap_next + 15] = 0;
  785. // cfg_data
  786. this.pci_space[cap_next + 16] = 0;
  787. this.pci_space[cap_next + 17] = 0;
  788. this.pci_space[cap_next + 18] = 0;
  789. this.pci_space[cap_next + 19] = 0;
  790. //
  791. // TODO
  792. // The pci config access capability is required by spec, but so far, devices
  793. // seem to work well without it.
  794. // This capability provides a cfg_data field (at cap_next + 16 for 4 bytes)
  795. // that acts like a window to the previous bars. The driver writes the bar number,
  796. // offset, and length values in this capability, and the cfg_data field should
  797. // mirror the data referred by the bar, offset and length. Here, length can be
  798. // 1, 2, or 4.
  799. //
  800. // This requires some sort of pci devicespace read and write handlers.
  801. };
  802. VirtIO.prototype.get_state = function()
  803. {
  804. let state = [];
  805. state[0] = this.device_feature_select;
  806. state[1] = this.driver_feature_select;
  807. state[2] = this.device_feature;
  808. state[3] = this.driver_feature;
  809. state[4] = this.features_ok;
  810. state[5] = this.device_status;
  811. state[6] = this.config_has_changed;
  812. state[7] = this.config_generation;
  813. state[8] = this.isr_status;
  814. state[9] = this.queue_select;
  815. state = state.concat(this.queues);
  816. return state;
  817. };
  818. VirtIO.prototype.set_state = function(state)
  819. {
  820. this.device_feature_select = state[0];
  821. this.driver_feature_select = state[1];
  822. this.device_feature = state[2];
  823. this.driver_feature = state[3];
  824. this.features_ok = state[4];
  825. this.device_status = state[5];
  826. this.config_has_changed = state[6];
  827. this.config_generation = state[7];
  828. this.isr_status = state[8];
  829. this.queue_select = state[9];
  830. let i = 0;
  831. for(let queue of state.slice(10))
  832. {
  833. this.queues[i].set_state(queue);
  834. i++;
  835. }
  836. this.queue_selected = this.queues[this.queue_select] || null;
  837. };
  838. VirtIO.prototype.reset = function()
  839. {
  840. this.device_feature_select = 0;
  841. this.driver_feature_select = 0;
  842. this.driver_feature.set(this.device_feature);
  843. this.features_ok = true;
  844. this.device_status = 0;
  845. this.queue_select = 0;
  846. this.queue_selected = this.queues[0];
  847. for(const queue of this.queues)
  848. {
  849. queue.reset();
  850. }
  851. this.config_has_changed = false;
  852. this.config_generation = 0;
  853. this.lower_irq();
  854. };
  855. /**
  856. * Call this when device-specific configuration state changes.
  857. * Also called when status DEVICE_NEEDS_RESET is set.
  858. */
  859. VirtIO.prototype.notify_config_changes = function()
  860. {
  861. this.config_has_changed = true;
  862. if(this.device_status & VIRTIO_STATUS_DRIVER_OK)
  863. {
  864. this.raise_irq(VIRTIO_ISR_DEVICE_CFG);
  865. }
  866. else
  867. {
  868. dbg_assert(false,
  869. "VirtIO device<" + this.name + "> attempted to notify driver before DRIVER_OK");
  870. }
  871. };
  872. /**
  873. * To be called after reading any field whose write can trigger notify_config_changes().
  874. */
  875. VirtIO.prototype.update_config_generation = function()
  876. {
  877. if(this.config_has_changed)
  878. {
  879. this.config_generation++;
  880. this.config_generation &= 0xFF;
  881. this.config_has_changed = false;
  882. }
  883. };
  884. VirtIO.prototype.is_feature_negotiated = function(feature)
  885. {
  886. // Feature bits are grouped in 32 bits.
  887. // Note: earlier we chose not to set invalid features into driver_feature.
  888. return (this.driver_feature[feature >>> 5] & (1 << (feature & 0x1F))) > 0;
  889. };
  890. /**
  891. * Call this if an irrecoverable error has been occured.
  892. * Notifies driver if DRIVER_OK, or when DRIVER_OK gets set.
  893. */
  894. VirtIO.prototype.needs_reset = function()
  895. {
  896. dbg_log("Device<" + this.name + "> experienced error - requires reset", LOG_VIRTIO);
  897. this.device_status |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
  898. if(this.device_status & VIRTIO_STATUS_DRIVER_OK)
  899. {
  900. this.notify_config_changes();
  901. }
  902. };
  903. VirtIO.prototype.raise_irq = function(type)
  904. {
  905. dbg_log("Raise irq " + h(type), LOG_VIRTIO);
  906. this.isr_status |= type;
  907. this.pci.raise_irq(this.pci_id);
  908. };
  909. VirtIO.prototype.lower_irq = function()
  910. {
  911. dbg_log("Lower irq ", LOG_VIRTIO);
  912. this.isr_status = 0;
  913. this.pci.lower_irq(this.pci_id);
  914. };
  915. /**
  916. * @constructor
  917. * @param {CPU} cpu
  918. * @param {VirtQueue_Options} options
  919. */
  920. function VirtQueue(cpu, virtio, options)
  921. {
  922. /** @const @type {CPU} */
  923. this.cpu = cpu;
  924. /** @const @type {VirtIO} */
  925. this.virtio = virtio;
  926. // Number of entries.
  927. this.size = options.size_supported;
  928. this.size_supported = options.size_supported;
  929. this.mask = this.size - 1;
  930. this.enabled = false;
  931. this.notify_offset = options.notify_offset;
  932. this.desc_addr = 0;
  933. this.avail_addr = 0;
  934. this.avail_last_idx = 0;
  935. this.used_addr = 0;
  936. this.num_staged_replies = 0;
  937. this.reset();
  938. }
  939. VirtQueue.prototype.get_state = function()
  940. {
  941. const state = [];
  942. state[0] = this.size;
  943. state[1] = this.size_supported;
  944. state[2] = this.enabled;
  945. state[3] = this.notify_offset;
  946. state[4] = this.desc_addr;
  947. state[5] = this.avail_addr;
  948. state[6] = this.avail_last_idx;
  949. state[7] = this.used_addr;
  950. state[8] = this.num_staged_replies;
  951. return state;
  952. };
  953. VirtQueue.prototype.set_state = function(state)
  954. {
  955. this.size = state[0];
  956. this.size_supported = state[1];
  957. this.enabled = state[2];
  958. this.notify_offset = state[3];
  959. this.desc_addr = state[4];
  960. this.avail_addr = state[5];
  961. this.avail_last_idx = state[6];
  962. this.used_addr = state[7];
  963. this.num_staged_replies = state[8];
  964. this.mask = this.size - 1;
  965. };
  966. VirtQueue.prototype.reset = function()
  967. {
  968. this.enabled = false;
  969. this.desc_addr = 0;
  970. this.avail_addr = 0;
  971. this.avail_last_idx = 0;
  972. this.used_addr = 0;
  973. this.num_staged_replies = 0;
  974. this.set_size(this.size_supported);
  975. };
  976. VirtQueue.prototype.is_configured = function()
  977. {
  978. return this.desc_addr && this.avail_addr && this.used_addr;
  979. };
  980. VirtQueue.prototype.enable = function()
  981. {
  982. dbg_assert(this.is_configured(), "VirtQueue must be configured before enabled");
  983. this.enabled = true;
  984. };
  985. VirtQueue.prototype.set_size = function(size)
  986. {
  987. dbg_assert((size & size - 1) === 0, "VirtQueue size must be power of 2 or zero");
  988. dbg_assert(size <= this.size_supported, "VirtQueue size must be within supported size");
  989. this.size = size;
  990. this.mask = size - 1;
  991. };
  992. /**
  993. * @return {number}
  994. */
  995. VirtQueue.prototype.count_requests = function()
  996. {
  997. dbg_assert(this.avail_addr, "VirtQueue addresses must be configured before use");
  998. return (this.avail_get_idx() - this.avail_last_idx) & this.mask;
  999. };
  1000. /**
  1001. * @return {boolean}
  1002. */
  1003. VirtQueue.prototype.has_request = function()
  1004. {
  1005. dbg_assert(this.avail_addr, "VirtQueue addresses must be configured before use");
  1006. return (this.avail_get_idx() & this.mask) !== this.avail_last_idx;
  1007. };
  1008. /**
  1009. * @return {VirtQueueBufferChain}
  1010. */
  1011. VirtQueue.prototype.pop_request = function()
  1012. {
  1013. dbg_assert(this.avail_addr, "VirtQueue addresses must be configured before use");
  1014. dbg_assert(this.has_request(), "VirtQueue must not pop nonexistent request");
  1015. const desc_idx = this.avail_get_entry(this.avail_last_idx);
  1016. dbg_log("Pop request: avail_last_idx=" + this.avail_last_idx +
  1017. " desc_idx=" + desc_idx, LOG_VIRTIO);
  1018. const bufchain = new VirtQueueBufferChain(this, desc_idx);
  1019. this.avail_last_idx = this.avail_last_idx + 1 & this.mask;
  1020. return bufchain;
  1021. };
  1022. /**
  1023. * Stage a buffer chain into the used ring.
  1024. * Can call push_reply many times before flushing to batch replies together.
  1025. * Note: this reply is not visible to driver until flush_replies is called.
  1026. * @param {VirtQueueBufferChain} bufchain
  1027. */
  1028. VirtQueue.prototype.push_reply = function(bufchain)
  1029. {
  1030. dbg_assert(this.used_addr, "VirtQueue addresses must be configured before use");
  1031. dbg_assert(this.num_staged_replies < this.size, "VirtQueue replies must not exceed queue size");
  1032. const used_idx = this.used_get_idx() + this.num_staged_replies & this.mask;
  1033. dbg_log("Push reply: used_idx=" + used_idx +
  1034. " desc_idx=" + bufchain.head_idx, LOG_VIRTIO);
  1035. this.used_set_entry(used_idx, bufchain.head_idx, bufchain.length_written);
  1036. this.num_staged_replies++;
  1037. };
  1038. /**
  1039. * Makes replies visible to driver by updating the used ring idx and
  1040. * firing appropriate interrupt if needed.
  1041. */
  1042. VirtQueue.prototype.flush_replies = function()
  1043. {
  1044. dbg_assert(this.used_addr, "VirtQueue addresses must be configured before use");
  1045. if(this.num_staged_replies === 0)
  1046. {
  1047. dbg_log("flush_replies: Nothing to flush", LOG_VIRTIO);
  1048. return;
  1049. }
  1050. dbg_log("Flushing " + this.num_staged_replies + " replies", LOG_VIRTIO);
  1051. const old_idx = this.used_get_idx();
  1052. const new_idx = old_idx + this.num_staged_replies & VIRTQ_IDX_MASK;
  1053. this.used_set_idx(new_idx);
  1054. this.num_staged_replies = 0;
  1055. if(this.virtio.is_feature_negotiated(VIRTIO_F_RING_EVENT_IDX))
  1056. {
  1057. const used_event = this.avail_get_used_event();
  1058. // Fire irq when idx values associated with the pushed reply buffers
  1059. // has reached or gone past used_event.
  1060. let has_passed = old_idx <= used_event && used_event < new_idx;
  1061. // Has overflowed? Assumes num_staged_replies > 0.
  1062. if(new_idx <= old_idx)
  1063. {
  1064. has_passed = used_event < new_idx || old_idx <= used_event;
  1065. }
  1066. // Commented out: Workaround for sometimes loading from the filesystem hangs and the emulator stays idle
  1067. //if(has_passed)
  1068. {
  1069. this.virtio.raise_irq(VIRTIO_ISR_QUEUE);
  1070. }
  1071. }
  1072. else
  1073. {
  1074. if(~this.avail_get_flags() & VIRTQ_AVAIL_F_NO_INTERRUPT)
  1075. {
  1076. this.virtio.raise_irq(VIRTIO_ISR_QUEUE);
  1077. }
  1078. }
  1079. };
  1080. /**
  1081. * If using VIRTIO_F_RING_EVENT_IDX, device must tell driver when
  1082. * to get notifications or else driver won't notify regularly.
  1083. * If not using VIRTIO_F_RING_EVENT_IDX, driver will ignore avail_event
  1084. * and notify every request regardless unless NO_NOTIFY is set (TODO implement when needed).
  1085. * @param {number} num_skipped_requests Zero = get notified in the next request.
  1086. */
  1087. VirtQueue.prototype.notify_me_after = function(num_skipped_requests)
  1088. {
  1089. dbg_assert(num_skipped_requests >= 0, "Must skip a non-negative number of requests");
  1090. // The 16 bit idx field wraps around after 2^16.
  1091. const avail_event = this.avail_get_idx() + num_skipped_requests & 0xFFFF;
  1092. this.used_set_avail_event(avail_event);
  1093. };
  1094. /**
  1095. * @param {number} table_address The physical address of the start of the desc table.
  1096. * @param {number} i
  1097. */
  1098. VirtQueue.prototype.get_descriptor = function(table_address, i)
  1099. {
  1100. return {
  1101. addr_low: this.cpu.read32s(table_address + i * VIRTQ_DESC_ENTRYSIZE),
  1102. addr_high: this.cpu.read32s(table_address + i * VIRTQ_DESC_ENTRYSIZE + 4),
  1103. len: this.cpu.read32s(table_address + i * VIRTQ_DESC_ENTRYSIZE + 8),
  1104. flags: this.cpu.read16(table_address + i * VIRTQ_DESC_ENTRYSIZE + 12),
  1105. next: this.cpu.read16(table_address + i * VIRTQ_DESC_ENTRYSIZE + 14),
  1106. };
  1107. };
  1108. // Avail ring fields
  1109. VirtQueue.prototype.avail_get_flags = function()
  1110. {
  1111. return this.cpu.read16(this.avail_addr);
  1112. };
  1113. VirtQueue.prototype.avail_get_idx = function()
  1114. {
  1115. return this.cpu.read16(this.avail_addr + 2);
  1116. };
  1117. VirtQueue.prototype.avail_get_entry = function(i)
  1118. {
  1119. return this.cpu.read16(this.avail_addr + 4 + VIRTQ_AVAIL_ENTRYSIZE * i);
  1120. };
  1121. VirtQueue.prototype.avail_get_used_event = function()
  1122. {
  1123. return this.cpu.read16(this.avail_addr + 4 + VIRTQ_AVAIL_ENTRYSIZE * this.size);
  1124. };
  1125. // Used ring fields
  1126. VirtQueue.prototype.used_get_flags = function()
  1127. {
  1128. return this.cpu.read16(this.used_addr);
  1129. };
  1130. VirtQueue.prototype.used_set_flags = function(value)
  1131. {
  1132. this.cpu.write16(this.used_addr, value);
  1133. };
  1134. VirtQueue.prototype.used_get_idx = function()
  1135. {
  1136. return this.cpu.read16(this.used_addr + 2);
  1137. };
  1138. VirtQueue.prototype.used_set_idx = function(value)
  1139. {
  1140. this.cpu.write16(this.used_addr + 2, value);
  1141. };
  1142. VirtQueue.prototype.used_set_entry = function(i, desc_idx, length_written)
  1143. {
  1144. this.cpu.write32(this.used_addr + 4 + VIRTQ_USED_ENTRYSIZE * i, desc_idx);
  1145. this.cpu.write32(this.used_addr + 8 + VIRTQ_USED_ENTRYSIZE * i, length_written);
  1146. };
  1147. VirtQueue.prototype.used_set_avail_event = function(value)
  1148. {
  1149. this.cpu.write16(this.used_addr + 4 + VIRTQ_USED_ENTRYSIZE * this.size, value);
  1150. };
  1151. /**
  1152. * Traverses through descriptor chain starting at head_id.
  1153. * Provides means to read/write to buffers represented by the descriptors.
  1154. * @constructor
  1155. * @param {VirtQueue} virtqueue
  1156. * @param {number} head_idx
  1157. */
  1158. function VirtQueueBufferChain(virtqueue, head_idx)
  1159. {
  1160. /** @const @type {CPU} */
  1161. this.cpu = virtqueue.cpu;
  1162. /** @const @type {VirtIO} */
  1163. this.virtio = virtqueue.virtio;
  1164. this.head_idx = head_idx;
  1165. this.read_buffers = [];
  1166. // Pointers for sequential consumption via get_next_blob.
  1167. this.read_buffer_idx = 0;
  1168. this.read_buffer_offset = 0;
  1169. this.length_readable = 0;
  1170. this.write_buffers = [];
  1171. // Pointers for sequential write via set_next_blob.
  1172. this.write_buffer_idx = 0;
  1173. this.write_buffer_offset = 0;
  1174. this.length_written = 0;
  1175. this.length_writable = 0;
  1176. // Traverse chain to discover buffers.
  1177. // - There shouldn't be an excessive amount of descriptor elements.
  1178. let table_address = virtqueue.desc_addr;
  1179. let desc_idx = head_idx;
  1180. let chain_length = 0;
  1181. let chain_max = virtqueue.size;
  1182. let writable_region = false;
  1183. const has_indirect_feature = this.virtio.is_feature_negotiated(VIRTIO_F_RING_INDIRECT_DESC);
  1184. dbg_log("<<< Descriptor chain start", LOG_VIRTIO);
  1185. do
  1186. {
  1187. const desc = virtqueue.get_descriptor(table_address, desc_idx);
  1188. dbg_log("descriptor: idx=" + desc_idx + " addr=" + h(desc.addr_high, 8) + ":" + h(desc.addr_low, 8) +
  1189. " len=" + h(desc.len, 8) + " flags=" + h(desc.flags, 4) + " next=" + h(desc.next, 4), LOG_VIRTIO);
  1190. if(has_indirect_feature && (desc.flags & VIRTQ_DESC_F_INDIRECT))
  1191. {
  1192. if(DEBUG && (desc.flags & VIRTQ_DESC_F_NEXT))
  1193. {
  1194. dbg_log("Driver bug: has set VIRTQ_DESC_F_NEXT flag in an indirect table descriptor", LOG_VIRTIO);
  1195. }
  1196. // Carry on using indirect table, starting at first entry.
  1197. table_address = desc.addr_low;
  1198. desc_idx = 0;
  1199. chain_length = 0;
  1200. chain_max = desc.len / VIRTQ_DESC_ENTRYSIZE;
  1201. dbg_log("start indirect", LOG_VIRTIO);
  1202. continue;
  1203. }
  1204. if(desc.flags & VIRTQ_DESC_F_WRITE)
  1205. {
  1206. writable_region = true;
  1207. this.write_buffers.push(desc);
  1208. this.length_writable += desc.len;
  1209. }
  1210. else
  1211. {
  1212. if(writable_region)
  1213. {
  1214. dbg_log("Driver bug: readonly buffer after writeonly buffer within chain", LOG_VIRTIO);
  1215. break;
  1216. }
  1217. this.read_buffers.push(desc);
  1218. this.length_readable += desc.len;
  1219. }
  1220. chain_length++;
  1221. if(chain_length > chain_max)
  1222. {
  1223. dbg_log("Driver bug: descriptor chain cycle detected", LOG_VIRTIO);
  1224. break;
  1225. }
  1226. if(desc.flags & VIRTQ_DESC_F_NEXT)
  1227. {
  1228. desc_idx = desc.next;
  1229. }
  1230. else
  1231. {
  1232. break;
  1233. }
  1234. }
  1235. while(true);
  1236. dbg_log("Descriptor chain end >>>", LOG_VIRTIO);
  1237. }
  1238. /**
  1239. * Reads the next blob of memory represented by the buffer chain into dest_buffer.
  1240. * @param {Uint8Array} dest_buffer
  1241. * @return {number} Number of bytes successfully read.
  1242. */
  1243. VirtQueueBufferChain.prototype.get_next_blob = function(dest_buffer)
  1244. {
  1245. let dest_offset = 0;
  1246. let remaining = dest_buffer.length;
  1247. while(remaining)
  1248. {
  1249. if(this.read_buffer_idx === this.read_buffers.length)
  1250. {
  1251. dbg_log("Device<" + this.virtio.name + "> Read more than device-readable buffers has", LOG_VIRTIO);
  1252. break;
  1253. }
  1254. const buf = this.read_buffers[this.read_buffer_idx];
  1255. const read_address = buf.addr_low + this.read_buffer_offset;
  1256. let read_length = buf.len - this.read_buffer_offset;
  1257. if(read_length > remaining)
  1258. {
  1259. read_length = remaining;
  1260. this.read_buffer_offset += remaining;
  1261. }
  1262. else
  1263. {
  1264. this.read_buffer_idx++;
  1265. this.read_buffer_offset = 0;
  1266. }
  1267. dest_buffer.set(this.cpu.read_blob(read_address, read_length), dest_offset);
  1268. dest_offset += read_length;
  1269. remaining -= read_length;
  1270. }
  1271. return dest_offset;
  1272. };
  1273. /**
  1274. * Appends contents of src_buffer into the memory represented by the buffer chain.
  1275. * @param {Uint8Array} src_buffer
  1276. * @return {number} Number of bytes successfully written.
  1277. */
  1278. VirtQueueBufferChain.prototype.set_next_blob = function(src_buffer)
  1279. {
  1280. let src_offset = 0;
  1281. let remaining = src_buffer.length;
  1282. while(remaining)
  1283. {
  1284. if(this.write_buffer_idx === this.write_buffers.length)
  1285. {
  1286. dbg_log("Device<" + this.virtio.name + "> Write more than device-writable capacity", LOG_VIRTIO);
  1287. break;
  1288. }
  1289. const buf = this.write_buffers[this.write_buffer_idx];
  1290. const write_address = buf.addr_low + this.write_buffer_offset;
  1291. let write_length = buf.len - this.write_buffer_offset;
  1292. if(write_length > remaining)
  1293. {
  1294. write_length = remaining;
  1295. this.write_buffer_offset += remaining;
  1296. }
  1297. else
  1298. {
  1299. this.write_buffer_idx++;
  1300. this.write_buffer_offset = 0;
  1301. }
  1302. const src_end = src_offset + write_length;
  1303. this.cpu.write_blob(src_buffer.subarray(src_offset, src_end), write_address);
  1304. src_offset += write_length;
  1305. remaining -= write_length;
  1306. }
  1307. this.length_written += src_offset;
  1308. return src_offset;
  1309. };