Coverage Report

Created: 2025-10-21 06:48

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
652
#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice (  \
60
652
                                                (Dev)->VirtIo,             \
61
652
                                                OFFSET_OF_VBLK (Field),    \
62
652
                                                SIZE_OF_VBLK (Field),      \
63
652
                                                sizeof *(Pointer),         \
64
652
                                                (Pointer)                  \
65
652
                                                ))
66
67
EFI_STATUS
68
EFIAPI
69
VirtioBlkInit (
70
  IN OUT VBLK_DEV        *Dev
71
) 
72
308
{
73
308
  UINT8       NextDevStat;
74
308
  EFI_STATUS  Status;
75
  
76
308
  UINT64  Features;
77
308
  UINT64  NumSectors;
78
308
  UINT32  BlockSize;
79
308
  UINT8   PhysicalBlockExp;
80
308
  UINT8   AlignmentOffset;
81
308
  UINT32  OptIoSize;
82
308
  UINT16  QueueSize;
83
308
  UINT64  RingBaseShift;
84
85
308
  PhysicalBlockExp = 0;
86
308
  AlignmentOffset  = 0;
87
308
  OptIoSize        = 0;
88
  //
89
  // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
90
  //
91
308
  NextDevStat = 0;             // step 1 -- reset device
92
308
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
93
308
  if (EFI_ERROR (Status)) {
94
0
    goto Failed;
95
0
  }
96
97
308
  NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
98
308
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
99
308
  if (EFI_ERROR (Status)) {
100
0
    goto Failed;
101
0
  }
102
103
308
  NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
104
308
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
105
308
  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
308
  Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
113
308
  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
308
  Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
121
308
  if (EFI_ERROR (Status)) {
122
0
    goto Failed;
123
0
  }
124
  // printf ("read device features\n");
125
308
  Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
126
308
  if (EFI_ERROR (Status)) {
127
0
    goto Failed;
128
0
  }
129
308
  if (NumSectors == 0) {
130
2
    Status = EFI_UNSUPPORTED;
131
2
    goto Failed;
132
2
  }
133
306
  if (Features & VIRTIO_BLK_F_BLK_SIZE) {
134
212
    Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
135
212
    if (EFI_ERROR (Status)) {
136
0
      goto Failed;
137
0
    }
138
212
    if (BlockSize == 0 || BlockSize % 512 != 0 ||
139
160
        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
160
      Status = EFI_UNSUPPORTED;
145
160
      goto Failed;
146
160
    }
147
212
  }
148
94
  else {
149
94
    BlockSize = 512;
150
94
  }
151
146
  if (Features & VIRTIO_BLK_F_TOPOLOGY) {
152
58
    Status = VIRTIO_CFG_READ (Dev, Topology.PhysicalBlockExp,
153
58
               &PhysicalBlockExp);
154
58
    if (EFI_ERROR (Status)) {
155
0
      goto Failed;
156
0
    }
157
58
    if (PhysicalBlockExp >= 32) {
158
21
      Status = EFI_UNSUPPORTED;
159
21
      goto Failed;
160
21
    }
161
162
37
    Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);
163
37
    if (EFI_ERROR (Status)) {
164
0
      goto Failed;
165
0
    }
166
167
37
    Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);
168
37
    if (EFI_ERROR (Status)) {
169
0
      goto Failed;
170
0
    }
171
37
  }
172
173
125
  Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |
174
125
              VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |
175
125
              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
125
  if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
183
63
    Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
184
63
    if (EFI_ERROR (Status)) {
185
0
      goto Failed;
186
0
    }
187
63
  }
188
  //
189
  // step 4b -- allocate virtqueue
190
  //
191
125
  Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
192
125
  if (EFI_ERROR (Status)) {
193
0
    goto Failed;
194
0
  }
195
125
  Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
196
125
  if (EFI_ERROR (Status)) {
197
0
    goto Failed;
198
0
  }
199
125
  if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors
200
6
    Status = EFI_UNSUPPORTED;
201
6
    goto Failed;
202
6
  }
203
204
119
  Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);
205
119
  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
119
  Status = VirtioRingMap (
212
119
             Dev->VirtIo,
213
119
             &Dev->Ring,
214
119
             &RingBaseShift,
215
119
             &Dev->RingMap
216
119
             );
217
119
  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
119
  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
226
119
  if (EFI_ERROR (Status)) {
227
0
    goto UnmapQueue;
228
0
  }
229
230
119
  Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
231
119
  if (EFI_ERROR (Status)) {
232
0
    goto UnmapQueue;
233
0
  }
234
  //
235
  // step 4c -- Report GPFN (guest-physical frame number) of queue.
236
  //
237
119
  Status = Dev->VirtIo->SetQueueAddress (
238
119
                          Dev->VirtIo,
239
119
                          &Dev->Ring,
240
119
                          RingBaseShift
241
119
                          );
242
119
  if (EFI_ERROR (Status)) {
243
0
    goto UnmapQueue;
244
0
  }
245
 
246
247
  //
248
  // step 5 -- Report understood features.
249
  //
250
119
  if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
251
59
    Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
252
59
    Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
253
59
    if (EFI_ERROR (Status)) {
254
0
      goto UnmapQueue;
255
0
    }
256
59
  }
257
258
  //
259
  // step 6 -- initialization complete
260
  //
261
119
  NextDevStat |= VSTAT_DRIVER_OK;
262
119
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
263
119
  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
119
  Dev->BlockIo.Revision              = 0;
274
119
  Dev->BlockIo.Media                 = &Dev->BlockIoMedia;
275
119
  Dev->BlockIo.Reset                 = &VirtioBlkReset;
276
119
  Dev->BlockIo.ReadBlocks            = &VirtioBlkReadBlocks;
277
119
  Dev->BlockIo.WriteBlocks           = &VirtioBlkWriteBlocks;
278
119
  Dev->BlockIo.FlushBlocks           = &VirtioBlkFlushBlocks;
279
119
  Dev->BlockIoMedia.MediaId          = 0;
280
119
  Dev->BlockIoMedia.RemovableMedia   = FALSE;
281
119
  Dev->BlockIoMedia.MediaPresent     = TRUE;
282
119
  Dev->BlockIoMedia.LogicalPartition = FALSE;
283
119
  Dev->BlockIoMedia.ReadOnly         = (BOOLEAN) ((Features & VIRTIO_BLK_F_RO) != 0);
284
119
  Dev->BlockIoMedia.WriteCaching     = (BOOLEAN) ((Features & VIRTIO_BLK_F_FLUSH) != 0);
285
119
  Dev->BlockIoMedia.BlockSize        = BlockSize;
286
119
  Dev->BlockIoMedia.IoAlign          = 0;
287
119
  Dev->BlockIoMedia.LastBlock        = DivU64x32 (NumSectors,
288
119
                                         BlockSize / 512) - 1;
289
290
119
  DEBUG ((DEBUG_INFO, "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",
291
119
    __FUNCTION__, Dev->BlockIoMedia.BlockSize,
292
119
    Dev->BlockIoMedia.LastBlock + 1));
293
294
119
  if (Features & VIRTIO_BLK_F_TOPOLOGY) {
295
36
    Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
296
297
36
    Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;
298
36
    Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;
299
36
    Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;
300
301
36
    DEBUG ((DEBUG_INFO, "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",
302
36
      __FUNCTION__, Dev->BlockIoMedia.LowestAlignedLba,
303
36
      Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock));
304
36
    DEBUG ((DEBUG_INFO, "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",
305
36
      __FUNCTION__, Dev->BlockIoMedia.OptimalTransferLengthGranularity));
306
36
  }
307
119
  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
189
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
189
  NextDevStat |= VSTAT_FAILED;
321
189
  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
322
323
189
  return Status; // reached only via Failed above
324
0
}