Coverage Report

Created: 2026-03-21 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hbfa-fl/HBFA/UefiHostFuzzTestCasePkg/TestStub/VirtioBlkStubLib/VirtioBlkStubLib.c
Line
Count
Source
1
/** @file
2
3
Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
4
SPDX-License-Identifier: BSD-2-Clause-Patent
5
6
**/
7
#include <Uefi.h>
8
9
#include <Library/BaseLib.h>
10
#include <Library/DebugLib.h>
11
#include <Library/BaseMemoryLib.h>
12
#include <Library/MemoryAllocationLib.h>
13
#include <Library/VirtioLib.h>
14
15
#include <IndustryStandard/VirtioBlk.h>
16
#include <Library/VirtioBlkStubLib.h>
17
18
EFI_STATUS
19
EFIAPI
20
VirtioBlkReset (
21
  IN EFI_BLOCK_IO_PROTOCOL *This,
22
  IN BOOLEAN               ExtendedVerification
23
  );
24
25
EFI_STATUS
26
EFIAPI
27
VirtioBlkReadBlocks (
28
  IN  EFI_BLOCK_IO_PROTOCOL *This,
29
  IN  UINT32                MediaId,
30
  IN  EFI_LBA               Lba,
31
  IN  UINTN                 BufferSize,
32
  OUT VOID                  *Buffer
33
  );
34
35
EFI_STATUS
36
EFIAPI
37
VirtioBlkWriteBlocks (
38
  IN EFI_BLOCK_IO_PROTOCOL *This,
39
  IN UINT32                MediaId,
40
  IN EFI_LBA               Lba,
41
  IN UINTN                 BufferSize,
42
  IN VOID                  *Buffer
43
  );
44
45
46
EFI_STATUS
47
EFIAPI
48
VirtioBlkFlushBlocks (
49
  IN EFI_BLOCK_IO_PROTOCOL *This
50
  );
51
52
#define VIRTIO_CFG_WRITE(Dev, Field, Value)  ((Dev)->VirtIo->WriteDevice ( \
53
                                                (Dev)->VirtIo,             \
54
                                                OFFSET_OF_VBLK (Field),    \
55
                                                SIZE_OF_VBLK (Field),      \
56
                                                (Value)                    \
57
                                                ))
58
59
692
#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice (  \
60
692
                                                (Dev)->VirtIo,             \
61
692
                                                OFFSET_OF_VBLK (Field),    \
62
692
                                                SIZE_OF_VBLK (Field),      \
63
692
                                                sizeof *(Pointer),         \
64
692
                                                (Pointer)                  \
65
692
                                                ))
66
67
EFI_STATUS
68
EFIAPI
69
VirtioBlkInit (
70
  IN OUT VBLK_DEV        *Dev
71
) 
72
323
{
73
323
  UINT8       NextDevStat;
74
323
  EFI_STATUS  Status;
75
  
76
323
  UINT64  Features;
77
323
  UINT64  NumSectors;
78
323
  UINT32  BlockSize;
79
323
  UINT8   PhysicalBlockExp;
80
323
  UINT8   AlignmentOffset;
81
323
  UINT32  OptIoSize;
82
323
  UINT16  QueueSize;
83
323
  UINT64  RingBaseShift;
84
85
323
  PhysicalBlockExp = 0;
86
323
  AlignmentOffset  = 0;
87
323
  OptIoSize        = 0;
88
  //
89
  // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
90
  //
91
323
  NextDevStat = 0;             // step 1 -- reset device
92
323
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
93
323
  if (EFI_ERROR (Status)) {
94
0
    goto Failed;
95
0
  }
96
97
323
  NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
98
323
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
99
323
  if (EFI_ERROR (Status)) {
100
0
    goto Failed;
101
0
  }
102
103
323
  NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
104
323
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
105
323
  if (EFI_ERROR (Status)) {
106
0
    goto Failed;
107
0
  }
108
  // printf ("Set page size\n");
109
  //
110
  // Set Page Size - MMIO VirtIo Specific
111
  //
112
323
  Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
113
323
  if (EFI_ERROR (Status)) {
114
0
    goto Failed;
115
0
  }
116
  // printf ("get device features\n");
117
  //
118
  // step 4a -- retrieve and validate features
119
  //
120
323
  Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
121
323
  if (EFI_ERROR (Status)) {
122
0
    goto Failed;
123
0
  }
124
  // printf ("read device features\n");
125
323
  Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
126
323
  if (EFI_ERROR (Status)) {
127
0
    goto Failed;
128
0
  }
129
323
  if (NumSectors == 0) {
130
2
    Status = EFI_UNSUPPORTED;
131
2
    goto Failed;
132
2
  }
133
321
  if (Features & VIRTIO_BLK_F_BLK_SIZE) {
134
213
    Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
135
213
    if (EFI_ERROR (Status)) {
136
0
      goto Failed;
137
0
    }
138
213
    if (BlockSize == 0 || BlockSize % 512 != 0 ||
139
165
        ModU64x32 (NumSectors, BlockSize / 512) != 0) {
140
      //
141
      // We can only handle a logical block consisting of whole sectors,
142
      // and only a disk composed of whole logical blocks.
143
      //
144
165
      Status = EFI_UNSUPPORTED;
145
165
      goto Failed;
146
165
    }
147
213
  }
148
108
  else {
149
108
    BlockSize = 512;
150
108
  }
151
156
  if (Features & VIRTIO_BLK_F_TOPOLOGY) {
152
64
    Status = VIRTIO_CFG_READ (Dev, Topology.PhysicalBlockExp,
153
64
               &PhysicalBlockExp);
154
64
    if (EFI_ERROR (Status)) {
155
0
      goto Failed;
156
0
    }
157
64
    if (PhysicalBlockExp >= 32) {
158
18
      Status = EFI_UNSUPPORTED;
159
18
      goto Failed;
160
18
    }
161
162
46
    Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);
163
46
    if (EFI_ERROR (Status)) {
164
0
      goto Failed;
165
0
    }
166
167
46
    Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);
168
46
    if (EFI_ERROR (Status)) {
169
0
      goto Failed;
170
0
    }
171
46
  }
172
173
138
  Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |
174
138
              VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |
175
138
              VIRTIO_F_IOMMU_PLATFORM;
176
  
177
  // printf ("write features\n");
178
  //
179
  // In virtio-1.0, feature negotiation is expected to complete before queue
180
  // discovery, and the device can also reject the selected set of features.
181
  //
182
138
  if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
183
69
    Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
184
69
    if (EFI_ERROR (Status)) {
185
0
      goto Failed;
186
0
    }
187
69
  }
188
  //
189
  // step 4b -- allocate virtqueue
190
  //
191
138
  Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
192
138
  if (EFI_ERROR (Status)) {
193
0
    goto Failed;
194
0
  }
195
138
  Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
196
138
  if (EFI_ERROR (Status)) {
197
0
    goto Failed;
198
0
  }
199
138
  if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors
200
8
    Status = EFI_UNSUPPORTED;
201
8
    goto Failed;
202
8
  }
203
204
130
  Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);
205
130
  if (EFI_ERROR (Status)) {
206
0
    goto Failed;
207
0
  }
208
  //
209
  // If anything fails from here on, we must release the ring resources
210
  //
211
130
  Status = VirtioRingMap (
212
130
             Dev->VirtIo,
213
130
             &Dev->Ring,
214
130
             &RingBaseShift,
215
130
             &Dev->RingMap
216
130
             );
217
130
  if (EFI_ERROR (Status)) {
218
0
    goto ReleaseQueue;
219
0
  }
220
221
  //
222
  // Additional steps for MMIO: align the queue appropriately, and set the
223
  // size. If anything fails from here on, we must unmap the ring resources.
224
  //
225
130
  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
226
130
  if (EFI_ERROR (Status)) {
227
0
    goto UnmapQueue;
228
0
  }
229
230
130
  Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
231
130
  if (EFI_ERROR (Status)) {
232
0
    goto UnmapQueue;
233
0
  }
234
  //
235
  // step 4c -- Report GPFN (guest-physical frame number) of queue.
236
  //
237
130
  Status = Dev->VirtIo->SetQueueAddress (
238
130
                          Dev->VirtIo,
239
130
                          &Dev->Ring,
240
130
                          RingBaseShift
241
130
                          );
242
130
  if (EFI_ERROR (Status)) {
243
0
    goto UnmapQueue;
244
0
  }
245
 
246
247
  //
248
  // step 5 -- Report understood features.
249
  //
250
130
  if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
251
65
    Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
252
65
    Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
253
65
    if (EFI_ERROR (Status)) {
254
0
      goto UnmapQueue;
255
0
    }
256
65
  }
257
258
  //
259
  // step 6 -- initialization complete
260
  //
261
130
  NextDevStat |= VSTAT_DRIVER_OK;
262
130
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
263
130
  if (EFI_ERROR (Status)) {
264
0
    goto UnmapQueue;
265
0
  }
266
267
  
268
269
  //
270
  // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI
271
  // Block I/O Protocol.
272
  //
273
130
  Dev->BlockIo.Revision              = 0;
274
130
  Dev->BlockIo.Media                 = &Dev->BlockIoMedia;
275
130
  Dev->BlockIo.Reset                 = &VirtioBlkReset;
276
130
  Dev->BlockIo.ReadBlocks            = &VirtioBlkReadBlocks;
277
130
  Dev->BlockIo.WriteBlocks           = &VirtioBlkWriteBlocks;
278
130
  Dev->BlockIo.FlushBlocks           = &VirtioBlkFlushBlocks;
279
130
  Dev->BlockIoMedia.MediaId          = 0;
280
130
  Dev->BlockIoMedia.RemovableMedia   = FALSE;
281
130
  Dev->BlockIoMedia.MediaPresent     = TRUE;
282
130
  Dev->BlockIoMedia.LogicalPartition = FALSE;
283
130
  Dev->BlockIoMedia.ReadOnly         = (BOOLEAN) ((Features & VIRTIO_BLK_F_RO) != 0);
284
130
  Dev->BlockIoMedia.WriteCaching     = (BOOLEAN) ((Features & VIRTIO_BLK_F_FLUSH) != 0);
285
130
  Dev->BlockIoMedia.BlockSize        = BlockSize;
286
130
  Dev->BlockIoMedia.IoAlign          = 0;
287
130
  Dev->BlockIoMedia.LastBlock        = DivU64x32 (NumSectors,
288
130
                                         BlockSize / 512) - 1;
289
290
130
  DEBUG ((DEBUG_INFO, "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",
291
130
    __FUNCTION__, Dev->BlockIoMedia.BlockSize,
292
130
    Dev->BlockIoMedia.LastBlock + 1));
293
294
130
  if (Features & VIRTIO_BLK_F_TOPOLOGY) {
295
42
    Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
296
297
42
    Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;
298
42
    Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;
299
42
    Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;
300
301
42
    DEBUG ((DEBUG_INFO, "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",
302
42
      __FUNCTION__, Dev->BlockIoMedia.LowestAlignedLba,
303
42
      Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock));
304
42
    DEBUG ((DEBUG_INFO, "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",
305
42
      __FUNCTION__, Dev->BlockIoMedia.OptimalTransferLengthGranularity));
306
42
  }
307
130
  return EFI_SUCCESS;
308
309
0
UnmapQueue:
310
0
  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
311
312
0
ReleaseQueue:
313
0
  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
314
315
193
Failed:
316
  //
317
  // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
318
  // Status. VirtIo access failure here should not mask the original error.
319
  //
320
193
  NextDevStat |= VSTAT_FAILED;
321
193
  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
322
323
193
  return Status; // reached only via Failed above
324
0
}