available_ring.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package virtqueue
  2. import (
  3. "fmt"
  4. "unsafe"
  5. )
  6. // availableRingFlag is a flag that describes an [AvailableRing].
  7. type availableRingFlag uint16
  8. const (
  9. // availableRingFlagNoInterrupt is used by the guest to advise the host to
  10. // not interrupt it when consuming a buffer. It's unreliable, so it's simply
  11. // an optimization.
  12. availableRingFlagNoInterrupt availableRingFlag = 1 << iota
  13. )
  14. // availableRingSize is the number of bytes needed to store an [AvailableRing]
  15. // with the given queue size in memory.
  16. func availableRingSize(queueSize int) int {
  17. return 6 + 2*queueSize
  18. }
  19. // availableRingAlignment is the minimum alignment of an [AvailableRing]
  20. // in memory, as required by the virtio spec.
  21. const availableRingAlignment = 2
  22. // AvailableRing is used by the driver to offer descriptor chains to the device.
  23. // Each ring entry refers to the head of a descriptor chain. It is only written
  24. // to by the driver and read by the device.
  25. //
  26. // Because the size of the ring depends on the queue size, we cannot define a
  27. // Go struct with a static size that maps to the memory of the ring. Instead,
  28. // this struct only contains pointers to the corresponding memory areas.
  29. type AvailableRing struct {
  30. initialized bool
  31. // flags that describe this ring.
  32. flags *availableRingFlag
  33. // ringIndex indicates where the driver would put the next entry into the
  34. // ring (modulo the queue size).
  35. ringIndex *uint16
  36. // ring references buffers using the index of the head of the descriptor
  37. // chain in the [DescriptorTable]. It wraps around at queue size.
  38. ring []uint16
  39. // usedEvent is not used by this implementation, but we reserve it anyway to
  40. // avoid issues in case a device may try to access it, contrary to the
  41. // virtio specification.
  42. usedEvent *uint16
  43. }
  44. // newAvailableRing creates an available ring that uses the given underlying
  45. // memory. The length of the memory slice must match the size needed for the
  46. // ring (see [availableRingSize]) for the given queue size.
  47. func newAvailableRing(queueSize int, mem []byte) *AvailableRing {
  48. ringSize := availableRingSize(queueSize)
  49. if len(mem) != ringSize {
  50. panic(fmt.Sprintf("memory size (%v) does not match required size "+
  51. "for available ring: %v", len(mem), ringSize))
  52. }
  53. return &AvailableRing{
  54. initialized: true,
  55. flags: (*availableRingFlag)(unsafe.Pointer(&mem[0])),
  56. ringIndex: (*uint16)(unsafe.Pointer(&mem[2])),
  57. ring: unsafe.Slice((*uint16)(unsafe.Pointer(&mem[4])), queueSize),
  58. usedEvent: (*uint16)(unsafe.Pointer(&mem[ringSize-2])),
  59. }
  60. }
  61. // Address returns the pointer to the beginning of the ring in memory.
  62. // Do not modify the memory directly to not interfere with this implementation.
  63. func (r *AvailableRing) Address() uintptr {
  64. if !r.initialized {
  65. panic("available ring is not initialized")
  66. }
  67. return uintptr(unsafe.Pointer(r.flags))
  68. }
  69. // offer adds the given descriptor chain heads to the available ring and
  70. // advances the ring index accordingly to make the device process the new
  71. // descriptor chains.
  72. func (r *AvailableRing) offerElements(chains []UsedElement) {
  73. //always called under lock
  74. //r.mu.Lock()
  75. //defer r.mu.Unlock()
  76. // Add descriptor chain heads to the ring.
  77. for offset, x := range chains {
  78. // The 16-bit ring index may overflow. This is expected and is not an
  79. // issue because the size of the ring array (which equals the queue
  80. // size) is always a power of 2 and smaller than the highest possible
  81. // 16-bit value.
  82. insertIndex := int(*r.ringIndex+uint16(offset)) % len(r.ring)
  83. r.ring[insertIndex] = x.GetHead()
  84. }
  85. // Increase the ring index by the number of descriptor chains added to the
  86. // ring.
  87. *r.ringIndex += uint16(len(chains))
  88. }
  89. func (r *AvailableRing) offer(chains []uint16) {
  90. //always called under lock
  91. //r.mu.Lock()
  92. //defer r.mu.Unlock()
  93. // Add descriptor chain heads to the ring.
  94. for offset, x := range chains {
  95. // The 16-bit ring index may overflow. This is expected and is not an
  96. // issue because the size of the ring array (which equals the queue
  97. // size) is always a power of 2 and smaller than the highest possible
  98. // 16-bit value.
  99. insertIndex := int(*r.ringIndex+uint16(offset)) % len(r.ring)
  100. r.ring[insertIndex] = x
  101. }
  102. // Increase the ring index by the number of descriptor chains added to the
  103. // ring.
  104. *r.ringIndex += uint16(len(chains))
  105. }
  106. func (r *AvailableRing) offerSingle(x uint16) {
  107. //always called under lock
  108. //r.mu.Lock()
  109. //defer r.mu.Unlock()
  110. offset := 0
  111. // Add descriptor chain heads to the ring.
  112. // The 16-bit ring index may overflow. This is expected and is not an
  113. // issue because the size of the ring array (which equals the queue
  114. // size) is always a power of 2 and smaller than the highest possible
  115. // 16-bit value.
  116. insertIndex := int(*r.ringIndex+uint16(offset)) % len(r.ring)
  117. r.ring[insertIndex] = x
  118. // Increase the ring index by the number of descriptor chains added to the ring.
  119. *r.ringIndex += 1
  120. }