Coverage Report

Created: 2025-12-09 07:02

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