Coverage Report

Created: 2025-12-05 07:03

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