Coverage Report

Created: 2024-10-17 06:29

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