2 Initialization and helper routines for the Virtio Filesystem device.
4 Copyright (C) 2020, Red Hat, Inc.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/VirtioLib.h> // Virtio10WriteFeatures()
11 #include "VirtioFsDxe.h"
14 Read the Virtio Filesystem device configuration structure in full.
16 @param[in] Virtio The Virtio protocol underlying the VIRTIO_FS object.
18 @param[out] Config The fully populated VIRTIO_FS_CONFIG structure.
20 @retval EFI_SUCCESS Config has been filled in.
22 @return Error codes propagated from Virtio->ReadDevice(). The
23 contents of Config are indeterminate.
28 IN VIRTIO_DEVICE_PROTOCOL
*Virtio
,
29 OUT VIRTIO_FS_CONFIG
*Config
35 for (Idx
= 0; Idx
< VIRTIO_FS_TAG_BYTES
; Idx
++) {
36 Status
= Virtio
->ReadDevice (
38 OFFSET_OF (VIRTIO_FS_CONFIG
, Tag
[Idx
]), // FieldOffset
39 sizeof Config
->Tag
[Idx
], // FieldSize
40 sizeof Config
->Tag
[Idx
], // BufferSize
41 &Config
->Tag
[Idx
] // Buffer
43 if (EFI_ERROR (Status
)) {
48 Status
= Virtio
->ReadDevice (
50 OFFSET_OF (VIRTIO_FS_CONFIG
, NumReqQueues
), // FieldOffset
51 sizeof Config
->NumReqQueues
, // FieldSize
52 sizeof Config
->NumReqQueues
, // BufferSize
53 &Config
->NumReqQueues
// Buffer
59 Configure the Virtio Filesystem device underlying VirtioFs.
61 @param[in,out] VirtioFs The VIRTIO_FS object for which Virtio communication
62 should be set up. On input, the caller is
63 responsible for VirtioFs->Virtio having been
64 initialized. On output, synchronous Virtio
65 Filesystem commands (primitives) may be submitted to
68 @retval EFI_SUCCESS Virtio machinery has been set up.
70 @retval EFI_UNSUPPORTED The host-side configuration of the Virtio Filesystem
71 is not supported by this driver.
73 @return Error codes from underlying functions.
77 IN OUT VIRTIO_FS
*VirtioFs
83 VIRTIO_FS_CONFIG Config
;
88 // Execute virtio-v1.1-cs01-87fa6b5d8155, 3.1.1 Driver Requirements: Device
91 // 1. Reset the device.
94 Status
= VirtioFs
->Virtio
->SetDeviceStatus (VirtioFs
->Virtio
, NextDevStat
);
95 if (EFI_ERROR (Status
)) {
100 // 2. Set the ACKNOWLEDGE status bit [...]
102 NextDevStat
|= VSTAT_ACK
;
103 Status
= VirtioFs
->Virtio
->SetDeviceStatus (VirtioFs
->Virtio
, NextDevStat
);
104 if (EFI_ERROR (Status
)) {
109 // 3. Set the DRIVER status bit [...]
111 NextDevStat
|= VSTAT_DRIVER
;
112 Status
= VirtioFs
->Virtio
->SetDeviceStatus (VirtioFs
->Virtio
, NextDevStat
);
113 if (EFI_ERROR (Status
)) {
118 // 4. Read device feature bits...
120 Status
= VirtioFs
->Virtio
->GetDeviceFeatures (VirtioFs
->Virtio
, &Features
);
121 if (EFI_ERROR (Status
)) {
124 if ((Features
& VIRTIO_F_VERSION_1
) == 0) {
125 Status
= EFI_UNSUPPORTED
;
129 // No device-specific feature bits have been defined in file "virtio-fs.tex"
130 // of the virtio spec at <https://github.com/oasis-tcs/virtio-spec.git>, as
131 // of commit 87fa6b5d8155.
133 Features
&= VIRTIO_F_VERSION_1
| VIRTIO_F_IOMMU_PLATFORM
;
136 // ... and write the subset of feature bits understood by the [...] driver to
138 // 5. Set the FEATURES_OK status bit.
139 // 6. Re-read device status to ensure the FEATURES_OK bit is still set [...]
141 Status
= Virtio10WriteFeatures (VirtioFs
->Virtio
, Features
, &NextDevStat
);
142 if (EFI_ERROR (Status
)) {
147 // 7. Perform device-specific setup, including discovery of virtqueues for
148 // the device, [...] reading [...] the device's virtio configuration space
150 Status
= VirtioFsReadConfig (VirtioFs
->Virtio
, &Config
);
151 if (EFI_ERROR (Status
)) {
156 // 7.a. Convert the filesystem label from UTF-8 to UCS-2. Only labels with
157 // printable ASCII code points (U+0020 through U+007E) are supported.
158 // NUL-terminate at either the terminator we find, or right after the
161 for (Idx
= 0; Idx
< VIRTIO_FS_TAG_BYTES
&& Config
.Tag
[Idx
] != '\0'; Idx
++) {
162 if (Config
.Tag
[Idx
] < 0x20 || Config
.Tag
[Idx
] > 0x7E) {
163 Status
= EFI_UNSUPPORTED
;
166 VirtioFs
->Label
[Idx
] = Config
.Tag
[Idx
];
168 VirtioFs
->Label
[Idx
] = L
'\0';
171 // 7.b. We need one queue for sending normal priority requests.
173 if (Config
.NumReqQueues
< 1) {
174 Status
= EFI_UNSUPPORTED
;
179 // 7.c. Fetch and remember the number of descriptors we can place on the
180 // queue at once. We'll need two descriptors per request, as a minimum --
181 // request header, response header.
183 Status
= VirtioFs
->Virtio
->SetQueueSel (VirtioFs
->Virtio
,
184 VIRTIO_FS_REQUEST_QUEUE
);
185 if (EFI_ERROR (Status
)) {
188 Status
= VirtioFs
->Virtio
->GetQueueNumMax (VirtioFs
->Virtio
,
189 &VirtioFs
->QueueSize
);
190 if (EFI_ERROR (Status
)) {
193 if (VirtioFs
->QueueSize
< 2) {
194 Status
= EFI_UNSUPPORTED
;
199 // 7.d. [...] population of virtqueues [...]
201 Status
= VirtioRingInit (VirtioFs
->Virtio
, VirtioFs
->QueueSize
,
203 if (EFI_ERROR (Status
)) {
207 Status
= VirtioRingMap (VirtioFs
->Virtio
, &VirtioFs
->Ring
, &RingBaseShift
,
209 if (EFI_ERROR (Status
)) {
213 Status
= VirtioFs
->Virtio
->SetQueueAddress (VirtioFs
->Virtio
,
214 &VirtioFs
->Ring
, RingBaseShift
);
215 if (EFI_ERROR (Status
)) {
220 // 8. Set the DRIVER_OK status bit.
222 NextDevStat
|= VSTAT_DRIVER_OK
;
223 Status
= VirtioFs
->Virtio
->SetDeviceStatus (VirtioFs
->Virtio
, NextDevStat
);
224 if (EFI_ERROR (Status
)) {
231 VirtioFs
->Virtio
->UnmapSharedBuffer (VirtioFs
->Virtio
, VirtioFs
->RingMap
);
234 VirtioRingUninit (VirtioFs
->Virtio
, &VirtioFs
->Ring
);
238 // If any of these steps go irrecoverably wrong, the driver SHOULD set the
239 // FAILED status bit to indicate that it has given up on the device (it can
240 // reset the device later to restart if desired). [...]
242 // Virtio access failure here should not mask the original error.
244 NextDevStat
|= VSTAT_FAILED
;
245 VirtioFs
->Virtio
->SetDeviceStatus (VirtioFs
->Virtio
, NextDevStat
);
251 De-configure the Virtio Filesystem device underlying VirtioFs.
253 @param[in] VirtioFs The VIRTIO_FS object for which Virtio communication
254 should be torn down. On input, the caller is responsible
255 for having called VirtioFsInit(). On output, Virtio
256 Filesystem commands (primitives) must no longer be
257 submitted to the device.
261 IN OUT VIRTIO_FS
*VirtioFs
265 // Resetting the Virtio device makes it release its resources and forget its
268 VirtioFs
->Virtio
->SetDeviceStatus (VirtioFs
->Virtio
, 0);
269 VirtioFs
->Virtio
->UnmapSharedBuffer (VirtioFs
->Virtio
, VirtioFs
->RingMap
);
270 VirtioRingUninit (VirtioFs
->Virtio
, &VirtioFs
->Ring
);
274 ExitBootServices event notification function for a Virtio Filesystem object.
276 This function resets the VIRTIO_FS.Virtio device, causing it to release all
277 references to guest-side resources. The function may only be called after
278 VirtioFsInit() returns successfully and before VirtioFsUninit() is called.
280 @param[in] ExitBootEvent The VIRTIO_FS.ExitBoot event that has been
283 @param[in] VirtioFsAsVoid Pointer to the VIRTIO_FS object, passed in as
289 IN EFI_EVENT ExitBootEvent
,
290 IN VOID
*VirtioFsAsVoid
295 VirtioFs
= VirtioFsAsVoid
;
296 DEBUG ((DEBUG_VERBOSE
, "%a: VirtioFs=0x%p Label=\"%s\"\n", __FUNCTION__
,
297 VirtioFsAsVoid
, VirtioFs
->Label
));
298 VirtioFs
->Virtio
->SetDeviceStatus (VirtioFs
->Virtio
, 0);