Coverage Report

Created: 2026-02-03 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hbfa-fl/HBFA/UefiHostFuzzTestCasePkg/TestStub/VirtioPciDevice10StubLib/VirtioPciDevice10StubLib.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
#include <stdio.h>
9
#include <stdlib.h>
10
11
#include <Library/BaseLib.h>
12
#include <Library/DebugLib.h>
13
#include <Library/BaseMemoryLib.h>
14
#include <Library/MemoryAllocationLib.h>
15
#include <Protocol/BlockIo.h>
16
#include <Protocol/VirtioDevice.h>
17
#include <Protocol/PciIo.h>
18
#include <Protocol/PciRootBridgeIo.h>
19
#include <Library/VirtioPciDeviceStubLib.h>
20
#include <IndustryStandard/Virtio10.h>
21
#include <Library/PciCapPciIoLib.h>
22
#include <Library/PciCapLib.h>
23
24
PCI_CFG_SPACE *PciCfg;
25
26
// VOID
27
// EFIAPI
28
// PrintByByte(UINT8* Content, UINT32 Len) {
29
//   UINT32 i;
30
//   for (i = 0; i < Len; i++) {
31
//     if (i % 16 == 0) printf ("\n");
32
//     printf ("%02x ", Content[i]);
33
//   }
34
//   printf ("\n");
35
// }
36
37
EFI_STATUS
38
EFIAPI
39
PciCapPciIoDeviceInit (
40
  IN  EFI_PCI_IO_PROTOCOL *PciIo,
41
  OUT PCI_CAP_DEV         **PciDevice
42
  );
43
44
VOID
45
EFIAPI
46
PciCapPciIoDeviceUninit (
47
  IN PCI_CAP_DEV *PciDevice
48
  );
49
50
RETURN_STATUS
51
EFIAPI
52
PciCapListInit (
53
  IN  PCI_CAP_DEV  *PciDevice,
54
  OUT PCI_CAP_LIST **CapList
55
  );
56
57
RETURN_STATUS
58
EFIAPI
59
PciCapListFindCap (
60
  IN  PCI_CAP_LIST   *CapList,
61
  IN  PCI_CAP_DOMAIN Domain,
62
  IN  UINT16         CapId,
63
  IN  UINT16         Instance,
64
  OUT PCI_CAP        **Cap    OPTIONAL
65
  );
66
67
RETURN_STATUS
68
EFIAPI
69
PciCapRead (
70
  IN  PCI_CAP_DEV *PciDevice,
71
  IN  PCI_CAP     *Cap,
72
  IN  UINT16      SourceOffsetInCap,
73
  OUT VOID        *DestinationBuffer,
74
  IN  UINT16      Size
75
  );
76
77
VOID
78
EFIAPI
79
PciCapListUninit (
80
  IN PCI_CAP_LIST *CapList
81
  );
82
83
EFI_STATUS
84
GetBarType (
85
  IN  EFI_PCI_IO_PROTOCOL  *PciIo,
86
  IN  UINT8                BarIndex,
87
  OUT VIRTIO_1_0_BAR_TYPE  *BarType
88
  )
89
174
{
90
174
  if (BarIndex >= sizeof(PciCfg->PciBasicCfg.Device.Bar)/sizeof(UINT32)) {
91
24
    return EFI_INVALID_PARAMETER;
92
24
  }
93
94
150
  if (PciCfg->PciBasicCfg.Device.Bar[BarIndex] & BIT0) {
95
62
    *BarType = Virtio10BarTypeIo;
96
62
  }
97
88
  else {
98
88
    *BarType = Virtio10BarTypeMem;
99
88
  }
100
101
150
  return EFI_SUCCESS;
102
174
}
103
104
STATIC
105
EFI_STATUS
106
Virtio10Transfer (
107
  IN     EFI_PCI_IO_PROTOCOL  *PciIo,
108
  IN     VIRTIO_1_0_CONFIG    *Config,
109
  IN     BOOLEAN              Write,
110
  IN     UINTN                FieldOffset,
111
  IN     UINTN                FieldSize,
112
  IN OUT VOID                 *Buffer
113
  )
114
2.41k
{
115
2.41k
  if (!Config->Exists ||
116
2.41k
      (FieldSize > Config->Length) ||
117
2.41k
      (FieldOffset > Config->Length - FieldSize))
118
0
  {
119
0
    return EFI_INVALID_PARAMETER;
120
0
  }
121
  
122
2.41k
  if (Write) {
123
1.59k
    CopyMem ((void *) (((UINT64) PciCfg->PciBasicCfg.Device.Bar[1] << 32) | PciCfg->PciBasicCfg.Device.Bar[0] + Config->Offset + FieldOffset), Buffer, FieldSize);
124
1.59k
  }
125
821
  else {
126
821
    CopyMem (Buffer, (void *) (((UINT64) PciCfg->PciBasicCfg.Device.Bar[1] << 32) | PciCfg->PciBasicCfg.Device.Bar[0] + Config->Offset + FieldOffset), FieldSize);
127
821
  }
128
129
2.41k
  return EFI_SUCCESS;
130
2.41k
}
131
132
STATIC
133
EFI_STATUS
134
EFIAPI
135
Virtio10GetDeviceFeatures (
136
  IN VIRTIO_DEVICE_PROTOCOL  *This,
137
  OUT UINT64                 *DeviceFeatures
138
  )
139
152
{
140
152
  VIRTIO_1_0_DEV  *Dev;
141
152
  UINT32          Selector;
142
152
  UINT32          Features32[2];
143
144
152
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
145
146
456
  for (Selector = 0; Selector < 2; ++Selector) {
147
304
    EFI_STATUS  Status;
148
149
    //
150
    // Select the low or high half of the features.
151
    //
152
304
    Status = Virtio10Transfer (
153
304
               Dev->PciIo,
154
304
               &Dev->CommonConfig,
155
304
               TRUE,
156
304
               OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeatureSelect),
157
304
               sizeof Selector,
158
304
               &Selector
159
304
               );
160
304
    if (EFI_ERROR (Status)) {
161
0
      return Status;
162
0
    }
163
164
    //
165
    // Fetch that half.
166
    //
167
304
    Status = Virtio10Transfer (
168
304
               Dev->PciIo,
169
304
               &Dev->CommonConfig,
170
304
               FALSE,
171
304
               OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeature),
172
304
               sizeof Features32[Selector],
173
304
               &Features32[Selector]
174
304
               );
175
304
    if (EFI_ERROR (Status)) {
176
0
      return Status;
177
0
    }
178
304
  }
179
180
152
  *DeviceFeatures = LShiftU64 (Features32[1], 32) | Features32[0];
181
152
  return EFI_SUCCESS;
182
152
}
183
184
STATIC
185
EFI_STATUS
186
EFIAPI
187
Virtio10SetGuestFeatures (
188
  IN VIRTIO_DEVICE_PROTOCOL  *This,
189
  IN UINT64                  Features
190
  )
191
71
{
192
71
  VIRTIO_1_0_DEV  *Dev;
193
71
  UINT32          Selector;
194
71
  UINT32          Features32[2];
195
196
71
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
197
198
71
  Features32[0] = (UINT32)Features;
199
71
  Features32[1] = (UINT32)RShiftU64 (Features, 32);
200
201
213
  for (Selector = 0; Selector < 2; ++Selector) {
202
142
    EFI_STATUS  Status;
203
204
    //
205
    // Select the low or high half of the features.
206
    //
207
142
    Status = Virtio10Transfer (
208
142
               Dev->PciIo,
209
142
               &Dev->CommonConfig,
210
142
               TRUE,
211
142
               OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeatureSelect),
212
142
               sizeof Selector,
213
142
               &Selector
214
142
               );
215
142
    if (EFI_ERROR (Status)) {
216
0
      return Status;
217
0
    }
218
219
    //
220
    // Write that half.
221
    //
222
142
    Status = Virtio10Transfer (
223
142
               Dev->PciIo,
224
142
               &Dev->CommonConfig,
225
142
               TRUE,
226
142
               OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeature),
227
142
               sizeof Features32[Selector],
228
142
               &Features32[Selector]
229
142
               );
230
231
142
    if (EFI_ERROR (Status)) {
232
0
      return Status;
233
0
    }
234
142
  }
235
236
71
  return EFI_SUCCESS;
237
71
}
238
239
STATIC
240
EFI_STATUS
241
EFIAPI
242
Virtio10SetQueueAddress (
243
  IN VIRTIO_DEVICE_PROTOCOL  *This,
244
  IN VRING                   *Ring,
245
  IN UINT64                  RingBaseShift
246
  )
247
64
{
248
64
  VIRTIO_1_0_DEV  *Dev;
249
64
  EFI_STATUS      Status;
250
64
  UINT64          Address;
251
64
  UINT16          Enable;
252
253
64
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
254
255
64
  Address  = (UINTN)Ring->Desc;
256
64
  Address += RingBaseShift;
257
64
  Status   = Virtio10Transfer (
258
64
               Dev->PciIo,
259
64
               &Dev->CommonConfig,
260
64
               TRUE,
261
64
               OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueDesc),
262
64
               sizeof Address,
263
64
               &Address
264
64
               );
265
64
  if (EFI_ERROR (Status)) {
266
0
    return Status;
267
0
  }
268
269
64
  Address  = (UINTN)Ring->Avail.Flags;
270
64
  Address += RingBaseShift;
271
64
  Status   = Virtio10Transfer (
272
64
               Dev->PciIo,
273
64
               &Dev->CommonConfig,
274
64
               TRUE,
275
64
               OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueAvail),
276
64
               sizeof Address,
277
64
               &Address
278
64
               );
279
64
  if (EFI_ERROR (Status)) {
280
0
    return Status;
281
0
  }
282
283
64
  Address  = (UINTN)Ring->Used.Flags;
284
64
  Address += RingBaseShift;
285
64
  Status   = Virtio10Transfer (
286
64
               Dev->PciIo,
287
64
               &Dev->CommonConfig,
288
64
               TRUE,
289
64
               OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueUsed),
290
64
               sizeof Address,
291
64
               &Address
292
64
               );
293
64
  if (EFI_ERROR (Status)) {
294
0
    return Status;
295
0
  }
296
297
64
  Enable = 1;
298
64
  Status = Virtio10Transfer (
299
64
             Dev->PciIo,
300
64
             &Dev->CommonConfig,
301
64
             TRUE,
302
64
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueEnable),
303
64
             sizeof Enable,
304
64
             &Enable
305
64
             );
306
64
  return Status;
307
64
}
308
309
STATIC
310
EFI_STATUS
311
EFIAPI
312
Virtio10SetQueueSel (
313
  IN VIRTIO_DEVICE_PROTOCOL  *This,
314
  IN UINT16                  Index
315
  )
316
71
{
317
71
  VIRTIO_1_0_DEV  *Dev;
318
71
  EFI_STATUS      Status;
319
320
71
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
321
322
71
  Status = Virtio10Transfer (
323
71
             Dev->PciIo,
324
71
             &Dev->CommonConfig,
325
71
             TRUE,
326
71
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
327
71
             sizeof Index,
328
71
             &Index
329
71
             );
330
71
  return Status;
331
71
}
332
333
STATIC
334
EFI_STATUS
335
EFIAPI
336
Virtio10SetQueueNotify (
337
  IN VIRTIO_DEVICE_PROTOCOL  *This,
338
  IN UINT16                  Index
339
  )
340
0
{
341
0
  VIRTIO_1_0_DEV  *Dev;
342
0
  EFI_STATUS      Status;
343
0
  UINT16          SavedQueueSelect;
344
0
  UINT16          NotifyOffset;
345
346
0
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
347
348
  //
349
  // Read NotifyOffset first. NotifyOffset is queue specific, so we have
350
  // to stash & restore the current queue selector around it.
351
  //
352
  // So, start with saving the current queue selector.
353
  //
354
0
  Status = Virtio10Transfer (
355
0
             Dev->PciIo,
356
0
             &Dev->CommonConfig,
357
0
             FALSE,
358
0
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
359
0
             sizeof SavedQueueSelect,
360
0
             &SavedQueueSelect
361
0
             );
362
0
  if (EFI_ERROR (Status)) {
363
0
    return Status;
364
0
  }
365
366
  //
367
  // Select the requested queue.
368
  //
369
0
  Status = Virtio10Transfer (
370
0
             Dev->PciIo,
371
0
             &Dev->CommonConfig,
372
0
             TRUE,
373
0
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
374
0
             sizeof Index,
375
0
             &Index
376
0
             );
377
0
  if (EFI_ERROR (Status)) {
378
0
    return Status;
379
0
  }
380
381
  //
382
  // Read the QueueNotifyOff field.
383
  //
384
0
  Status = Virtio10Transfer (
385
0
             Dev->PciIo,
386
0
             &Dev->CommonConfig,
387
0
             FALSE,
388
0
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueNotifyOff),
389
0
             sizeof NotifyOffset,
390
0
             &NotifyOffset
391
0
             );
392
0
  if (EFI_ERROR (Status)) {
393
0
    return Status;
394
0
  }
395
396
  //
397
  // Re-select the original queue.
398
  //
399
0
  Status = Virtio10Transfer (
400
0
             Dev->PciIo,
401
0
             &Dev->CommonConfig,
402
0
             TRUE,
403
0
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
404
0
             sizeof SavedQueueSelect,
405
0
             &SavedQueueSelect
406
0
             );
407
0
  if (EFI_ERROR (Status)) {
408
0
    return Status;
409
0
  }
410
411
  //
412
  // We can now kick the queue.
413
  //
414
0
  Status = Virtio10Transfer (
415
0
             Dev->PciIo,
416
0
             &Dev->NotifyConfig,
417
0
             TRUE,
418
0
             (UINTN)NotifyOffset * Dev->NotifyOffsetMultiplier,
419
0
             sizeof Index,
420
0
             &Index
421
0
             );
422
423
0
  return Status;
424
0
}
425
426
STATIC
427
EFI_STATUS
428
EFIAPI
429
Virtio10SetQueueAlign (
430
  IN VIRTIO_DEVICE_PROTOCOL  *This,
431
  IN UINT32                  Alignment
432
  )
433
64
{
434
64
  return (Alignment == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
435
64
}
436
437
STATIC
438
EFI_STATUS
439
EFIAPI
440
Virtio10SetPageSize (
441
  IN VIRTIO_DEVICE_PROTOCOL  *This,
442
  IN UINT32                  PageSize
443
  )
444
152
{
445
152
  return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
446
152
}
447
448
STATIC
449
EFI_STATUS
450
EFIAPI
451
Virtio10GetQueueNumMax (
452
  IN  VIRTIO_DEVICE_PROTOCOL  *This,
453
  OUT UINT16                  *QueueNumMax
454
  )
455
135
{
456
135
  VIRTIO_1_0_DEV  *Dev;
457
135
  EFI_STATUS      Status;
458
459
135
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
460
461
135
  Status = Virtio10Transfer (
462
135
             Dev->PciIo,
463
135
             &Dev->CommonConfig,
464
135
             FALSE,
465
135
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSize),
466
135
             sizeof *QueueNumMax,
467
135
             QueueNumMax
468
135
             );
469
470
135
  return Status;
471
135
}
472
473
STATIC
474
EFI_STATUS
475
EFIAPI
476
Virtio10SetQueueNum (
477
  IN VIRTIO_DEVICE_PROTOCOL  *This,
478
  IN UINT16                  QueueSize
479
  )
480
64
{
481
64
  EFI_STATUS  Status;
482
64
  UINT16      CurrentSize;
483
484
  //
485
  // This member function is required for VirtIo MMIO, and a no-op in
486
  // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
487
  // member to reduce memory consumption, but none of our drivers do. So
488
  // just check that they set the size that is already in effect.
489
  //
490
64
  Status = Virtio10GetQueueNumMax (This, &CurrentSize);
491
64
  if (EFI_ERROR (Status)) {
492
0
    return Status;
493
0
  }
494
495
64
  return (CurrentSize == QueueSize) ? EFI_SUCCESS : EFI_UNSUPPORTED;
496
64
}
497
498
STATIC
499
EFI_STATUS
500
EFIAPI
501
Virtio10GetDeviceStatus (
502
  IN  VIRTIO_DEVICE_PROTOCOL  *This,
503
  OUT UINT8                   *DeviceStatus
504
  )
505
71
{
506
71
  VIRTIO_1_0_DEV  *Dev;
507
71
  EFI_STATUS      Status;
508
  
509
71
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
510
  
511
71
  Status = Virtio10Transfer (
512
71
             Dev->PciIo,
513
71
             &Dev->CommonConfig,
514
71
             FALSE,
515
71
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
516
71
             sizeof *DeviceStatus,
517
71
             DeviceStatus
518
71
             );
519
71
  return Status;
520
71
}
521
522
STATIC
523
EFI_STATUS
524
EFIAPI
525
Virtio10SetDeviceStatus (
526
  IN VIRTIO_DEVICE_PROTOCOL  *This,
527
  IN UINT8                   DeviceStatus
528
  )
529
679
{
530
679
  VIRTIO_1_0_DEV  *Dev;
531
679
  EFI_STATUS      Status;
532
533
679
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
534
535
679
  Status = Virtio10Transfer (
536
679
             Dev->PciIo,
537
679
             &Dev->CommonConfig,
538
679
             TRUE,
539
679
             OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
540
679
             sizeof DeviceStatus,
541
679
             &DeviceStatus
542
679
             );
543
679
  return Status;
544
679
}
545
546
STATIC
547
EFI_STATUS
548
EFIAPI
549
Virtio10WriteDevice (
550
  IN VIRTIO_DEVICE_PROTOCOL  *This,
551
  IN UINTN                   FieldOffset,
552
  IN UINTN                   FieldSize,
553
  IN UINT64                  Value
554
  )
555
0
{
556
0
  VIRTIO_1_0_DEV  *Dev;
557
0
  EFI_STATUS      Status;
558
559
0
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
560
561
0
  Status = Virtio10Transfer (
562
0
             Dev->PciIo,
563
0
             &Dev->SpecificConfig,
564
0
             TRUE,
565
0
             FieldOffset,
566
0
             FieldSize,
567
0
             &Value
568
0
             );
569
0
  return Status;
570
0
}
571
572
STATIC
573
EFI_STATUS
574
EFIAPI
575
Virtio10ReadDevice (
576
  IN  VIRTIO_DEVICE_PROTOCOL  *This,
577
  IN  UINTN                   FieldOffset,
578
  IN  UINTN                   FieldSize,
579
  IN  UINTN                   BufferSize,
580
  OUT VOID                    *Buffer
581
  )
582
311
{
583
311
  VIRTIO_1_0_DEV  *Dev;
584
311
  EFI_STATUS      Status;
585
586
311
  if (FieldSize != BufferSize) {
587
0
    return EFI_INVALID_PARAMETER;
588
0
  }
589
590
311
  Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
591
592
311
  Status = Virtio10Transfer (
593
311
             Dev->PciIo,
594
311
             &Dev->SpecificConfig,
595
311
             FALSE,
596
311
             FieldOffset,
597
311
             FieldSize,
598
311
             Buffer
599
311
             );
600
311
  return Status;
601
311
}
602
603
STATIC
604
EFI_STATUS
605
EFIAPI
606
Virtio10AllocateSharedPages (
607
  IN     VIRTIO_DEVICE_PROTOCOL  *This,
608
  IN     UINTN                   Pages,
609
  IN OUT VOID                    **HostAddress
610
  )
611
64
{
612
64
  EFI_STATUS      Status = EFI_SUCCESS;
613
  
614
64
  *HostAddress = AllocatePages (Pages);
615
616
64
  if (*HostAddress == NULL) {
617
0
    Status = EFI_OUT_OF_RESOURCES;
618
0
  }
619
620
64
  return Status;
621
64
}
622
623
STATIC
624
VOID
625
EFIAPI
626
Virtio10FreeSharedPages (
627
  IN  VIRTIO_DEVICE_PROTOCOL  *This,
628
  IN  UINTN                   Pages,
629
  IN  VOID                    *HostAddress
630
  )
631
0
{
632
0
  FreePages(HostAddress, Pages);
633
0
}
634
635
STATIC
636
EFI_STATUS
637
EFIAPI
638
Virtio10MapSharedBuffer (
639
  IN     VIRTIO_DEVICE_PROTOCOL  *This,
640
  IN     VIRTIO_MAP_OPERATION    Operation,
641
  IN     VOID                    *HostAddress,
642
  IN OUT UINTN                   *NumberOfBytes,
643
  OUT    EFI_PHYSICAL_ADDRESS    *DeviceAddress,
644
  OUT    VOID                    **Mapping
645
  )
646
64
{
647
64
  return EFI_SUCCESS;
648
64
}
649
650
STATIC
651
EFI_STATUS
652
EFIAPI
653
Virtio10UnmapSharedBuffer (
654
  IN  VIRTIO_DEVICE_PROTOCOL  *This,
655
  IN  VOID                    *Mapping
656
  )
657
0
{
658
0
  return EFI_SUCCESS;
659
0
}
660
661
STATIC CONST VIRTIO_DEVICE_PROTOCOL  mVirtIoTemplate = {
662
  VIRTIO_SPEC_REVISION (1,     0, 0),
663
  0,                           // SubSystemDeviceId, filled in dynamically
664
  Virtio10GetDeviceFeatures,
665
  Virtio10SetGuestFeatures,
666
  Virtio10SetQueueAddress,
667
  Virtio10SetQueueSel,
668
  Virtio10SetQueueNotify,
669
  Virtio10SetQueueAlign,
670
  Virtio10SetPageSize,
671
  Virtio10GetQueueNumMax,
672
  Virtio10SetQueueNum,
673
  Virtio10GetDeviceStatus,
674
  Virtio10SetDeviceStatus,
675
  Virtio10WriteDevice,
676
  Virtio10ReadDevice,
677
  Virtio10AllocateSharedPages,
678
  Virtio10FreeSharedPages,
679
  Virtio10MapSharedBuffer,
680
  Virtio10UnmapSharedBuffer
681
};
682
683
EFI_STATUS
684
EFIAPI
685
FixPciCfg (
686
  IN OUT PCI_CFG_SPACE             *PciCfg,
687
  IN VIRTIO_PCI_CAP_COMMON_CONFIG  *PciCommonConfig
688
)
689
0
{ 
690
0
  PciCfg->PciBasicCfg.Device.Bar[0] = (UINT32) ((UINT64)PciCommonConfig);
691
 
692
0
  return EFI_SUCCESS;
693
0
}
694
695
STATIC
696
EFI_STATUS
697
ParseCapabilities (
698
  IN OUT VIRTIO_1_0_DEV *Device
699
  )
700
399
{
701
399
  EFI_STATUS   Status;
702
399
  PCI_CAP_DEV  *PciDevice;
703
399
  PCI_CAP_LIST *CapList;
704
399
  UINT16       VendorInstance;
705
399
  PCI_CAP      *VendorCap;
706
707
399
  Status = PciCapPciIoDeviceInit (Device->PciIo, &PciDevice);
708
399
  if (EFI_ERROR (Status)) {
709
0
    return Status;
710
0
  }
711
712
399
  Status = PciCapListInit (PciDevice, &CapList);
713
399
  if (EFI_ERROR (Status)) {
714
123
    goto UninitPciDevice;
715
123
  }
716
717
276
  for (VendorInstance = 0;
718
635
       !EFI_ERROR (PciCapListFindCap (CapList, PciCapNormal,
719
276
                     EFI_PCI_CAPABILITY_ID_VENDOR, VendorInstance,
720
276
                     &VendorCap));
721
405
       VendorInstance++) {
722
405
    UINT8             CapLen;
723
405
    VIRTIO_PCI_CAP    VirtIoCap;
724
405
    VIRTIO_1_0_CONFIG *ParsedConfig;
725
726
    //
727
    // Big enough to accommodate a VIRTIO_PCI_CAP structure?
728
    //
729
405
    Status = PciCapRead (PciDevice, VendorCap,
730
405
               OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length), &CapLen,
731
405
               sizeof CapLen);
732
405
    if (EFI_ERROR (Status)) {
733
0
      goto UninitCapList;
734
0
    }
735
405
    if (CapLen < sizeof VirtIoCap) {
736
      //
737
      // Too small, move to next.
738
      //
739
253
      continue;
740
253
    }
741
742
    //
743
    // Read interesting part of capability.
744
    //
745
152
    Status = PciCapRead (PciDevice, VendorCap, 0, &VirtIoCap, sizeof VirtIoCap);
746
152
    if (EFI_ERROR (Status)) {
747
31
      goto UninitCapList;
748
31
    }
749
750
121
    switch (VirtIoCap.ConfigType) {
751
35
    case VIRTIO_PCI_CAP_COMMON_CFG:
752
35
      ParsedConfig = &Device->CommonConfig;
753
35
      break;
754
38
    case VIRTIO_PCI_CAP_NOTIFY_CFG:
755
38
      ParsedConfig = &Device->NotifyConfig;
756
38
      break;
757
14
    case VIRTIO_PCI_CAP_DEVICE_CFG:
758
14
      ParsedConfig = &Device->SpecificConfig;
759
14
      break;
760
34
    default:
761
      //
762
      // Capability is not interesting.
763
      //
764
34
      continue;
765
121
    }
766
767
    //
768
    // Save the location of the register block into ParsedConfig.
769
    //
770
87
    Status = GetBarType (Device->PciIo, VirtIoCap.Bar, &ParsedConfig->BarType);
771
87
    if (EFI_ERROR (Status)) {
772
12
      goto UninitCapList;
773
12
    }
774
75
    ParsedConfig->Bar    = VirtIoCap.Bar;
775
75
    ParsedConfig->Offset = VirtIoCap.Offset;
776
75
    ParsedConfig->Length = VirtIoCap.Length;
777
778
75
    if (VirtIoCap.ConfigType == VIRTIO_PCI_CAP_NOTIFY_CFG) {
779
      //
780
      // This capability has an additional field called NotifyOffsetMultiplier;
781
      // parse it too.
782
      //
783
34
      if (CapLen < sizeof VirtIoCap + sizeof Device->NotifyOffsetMultiplier) {
784
        //
785
        // Too small, move to next.
786
        //
787
14
        continue;
788
14
      }
789
790
20
      Status = PciCapRead (PciDevice, VendorCap, sizeof VirtIoCap,
791
20
                 &Device->NotifyOffsetMultiplier,
792
20
                 sizeof Device->NotifyOffsetMultiplier);
793
20
      if (EFI_ERROR (Status)) {
794
3
        goto UninitCapList;
795
3
      }
796
20
    }
797
798
    //
799
    // Capability parsed successfully.
800
    //
801
58
    ParsedConfig->Exists = TRUE;
802
58
  }
803
804
230
  ASSERT_EFI_ERROR (Status);
805
806
276
UninitCapList:
807
276
  PciCapListUninit (CapList);
808
809
399
UninitPciDevice:
810
399
  PciCapPciIoDeviceUninit (PciDevice);
811
812
399
  return Status;
813
276
}
814
815
EFI_STATUS
816
EFIAPI
817
PciIoRead (
818
  IN EFI_PCI_IO_PROTOCOL       *PciIo,
819
  IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
820
  IN UINT32                    Offset,
821
  IN UINTN                     Count,
822
  IN OUT VOID                  *Buffer
823
21.2k
) {
824
21.2k
  UINT16 Len = 0;
825
826
21.2k
  switch (Width)
827
21.2k
  {
828
7.11k
  case EfiPciIoWidthUint32:
829
7.11k
    Len = Count * sizeof(UINT32);
830
7.11k
    break;
831
12.4k
  case EfiPciIoWidthUint16:
832
12.4k
    Len = Count * sizeof(UINT16);
833
12.4k
    break;
834
1.66k
  case EfiPciIoWidthUint8:
835
1.66k
    Len = Count * sizeof(UINT8);
836
1.66k
    break;
837
0
  default:
838
0
    break;
839
21.2k
  }
840
841
21.2k
  CopyMem (Buffer, (void *) ((UINT64) PciCfg + Offset), Len);
842
21.2k
  return EFI_SUCCESS;
843
21.2k
}
844
845
EFI_STATUS
846
EFIAPI
847
InitVirtioPciDevice (
848
  IN OUT  VIRTIO_1_0_DEV         *Device,
849
  IN      UINT8                  *TestBuffer,
850
  IN      UINTN                  BufferSize,
851
  IN      EFI_PCI_IO_PROTOCOL    *PciIo
852
) 
853
503
{
854
  // VOID  *ConfigRegion;
855
  
856
  // ConfigRegion = (VOID *) AllocateZeroPool (sizeof (PCI_CFG_SPACE));
857
503
  PciCfg = (PCI_CFG_SPACE *) TestBuffer; 
858
859
  // CopyMem (PciCfg, (void *) TestBuffer, sizeof (PCI_CFG_SPACE));
860
  
861
503
  PciIo->Pci.Read = &PciIoRead;
862
863
503
  if ((PciCfg->PciBasicCfg.Hdr.VendorId == VIRTIO_VENDOR_ID) &&
864
469
      (PciCfg->PciBasicCfg.Hdr.DeviceId >= 0x1040) &&
865
446
      (PciCfg->PciBasicCfg.Hdr.DeviceId <= 0x107F) &&
866
427
      (PciCfg->PciBasicCfg.Hdr.RevisionID >= 0x01) &&
867
420
      (PciCfg->PciBasicCfg.Device.SubsystemID >= 0x40) &&
868
404
      ((PciCfg->PciBasicCfg.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0))
869
399
  {
870
399
    if (!((PciCfg->PciBasicCfg.Hdr.DeviceId != 0x1050) || !(PciCfg->PciBasicCfg.Hdr.ClassCode == PciCfg))) {
871
0
      return EFI_OUT_OF_RESOURCES;
872
0
    }
873
399
  }
874
104
  else {
875
104
      return EFI_OUT_OF_RESOURCES;
876
104
  }
877
878
399
  ParseCapabilities (Device);
879
880
399
  return EFI_SUCCESS;
881
503
}
882
883
884
EFI_STATUS
885
EFIAPI
886
ParseBufferAndInitVirtioPciDev10 (
887
  IN      UINT8                   *TestBuffer,
888
  IN      UINTN                   BufferSize,
889
  IN      VOID                    *ConfigRegion,
890
  IN OUT  VIRTIO_1_0_DEV          *Device
891
) 
892
288
{
893
288
  EFI_STATUS                    Status;
894
288
  EFI_PCI_IO_PROTOCOL           *PciIo;
895
288
  VIRTIO_BLK_CONFIG             *BlkConfig;
896
288
  VIRTIO_PCI_CAP_COMMON_CONFIG  *PciCommonConfig;
897
288
  VOID                          *PciNotifyConfig;
898
  // VOID                          *ConfigRegion;
899
900
  // ConfigRegion = (VOID *) AllocatePool(sizeof (PCI_CFG_SPACE) + sizeof(VIRTIO_PCI_CAP_COMMON_CONFIG) + sizeof (VIRTIO_BLK_CONFIG) + 0x100);
901
288
  if (ConfigRegion == NULL) {
902
0
    return EFI_OUT_OF_RESOURCES;
903
0
  }
904
905
288
  if (BufferSize != sizeof (PCI_CFG_SPACE) + sizeof(VIRTIO_PCI_CAP_COMMON_CONFIG) + sizeof (VIRTIO_BLK_CONFIG)) {
906
66
    goto FreeDevice;
907
66
  }
908
909
222
  Device->Signature = VIRTIO_1_0_SIGNATURE;
910
222
  CopyMem (&Device->VirtIo, &mVirtIoTemplate, sizeof (VIRTIO_DEVICE_PROTOCOL));
911
912
222
  PciCfg = (PCI_CFG_SPACE *) ConfigRegion;
913
222
  PciCommonConfig = (VIRTIO_PCI_CAP_COMMON_CONFIG *) ((UINT64) ConfigRegion + sizeof (PCI_CFG_SPACE));
914
222
  BlkConfig = (VIRTIO_BLK_CONFIG *) ((UINT64) ConfigRegion + sizeof (PCI_CFG_SPACE) + sizeof(VIRTIO_PCI_CAP_COMMON_CONFIG));
915
222
  PciNotifyConfig = (VOID *) ((UINT64) ConfigRegion + sizeof (PCI_CFG_SPACE) + sizeof(VIRTIO_PCI_CAP_COMMON_CONFIG) + sizeof (VIRTIO_BLK_CONFIG));
916
917
222
  CopyMem (PciCfg, (void *) TestBuffer, sizeof (PCI_CFG_SPACE));
918
  
919
222
  CopyMem (PciCommonConfig, 
920
222
           (void *) ((UINT64)TestBuffer + sizeof (PCI_CFG_SPACE)), 
921
222
           sizeof (VIRTIO_PCI_CAP_COMMON_CONFIG));
922
923
222
  CopyMem (BlkConfig,
924
222
           (void *) ((UINT64)TestBuffer + sizeof (PCI_CFG_SPACE) + sizeof (VIRTIO_PCI_CAP_COMMON_CONFIG)), 
925
222
           sizeof (VIRTIO_BLK_CONFIG));
926
927
222
  if ((PciCfg->PciBasicCfg.Hdr.VendorId == VIRTIO_VENDOR_ID) &&
928
198
      (PciCfg->PciBasicCfg.Hdr.DeviceId >= 0x1040) &&
929
184
      (PciCfg->PciBasicCfg.Hdr.DeviceId <= 0x107F) &&
930
170
      (PciCfg->PciBasicCfg.Hdr.RevisionID >= 0x01) &&
931
168
      (PciCfg->PciBasicCfg.Device.SubsystemID >= 0x40) &&
932
161
      ((PciCfg->PciBasicCfg.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0))
933
160
  {
934
160
    if (!((PciCfg->PciBasicCfg.Hdr.DeviceId != 0x1050) || !(PciCfg->PciBasicCfg.Hdr.ClassCode == PciCfg))) {
935
0
      goto FreeDevice;
936
0
    }
937
160
  }
938
62
  else {
939
62
      goto FreeDevice;
940
62
  }
941
942
160
  PciCfg->PciBasicCfg.Device.Bar[0] = (UINT32) ((UINT64)PciCommonConfig);
943
160
  PciCfg->PciBasicCfg.Device.Bar[1] = (UINT32) ((UINT64)PciCommonConfig >> 32);
944
  
945
160
  Device->VirtIo.SubSystemDeviceId = PciCfg->PciBasicCfg.Hdr.DeviceId - 0x1040;
946
947
160
  Device->CommonConfig.Offset   = 0;
948
160
  Device->CommonConfig.Bar      = 0;
949
160
  Device->CommonConfig.Exists   = TRUE;
950
160
  Device->CommonConfig.Length   = sizeof(VIRTIO_PCI_CAP_COMMON_CONFIG);
951
  
952
160
  Device->NotifyConfig.Offset   = sizeof(VIRTIO_PCI_CAP_COMMON_CONFIG) + sizeof (VIRTIO_BLK_CONFIG);
953
160
  Device->NotifyConfig.Bar      = 0;
954
160
  Device->NotifyConfig.Exists   = TRUE;
955
160
  Device->NotifyConfig.Length   = 0x100;
956
957
160
  Device->SpecificConfig.Offset = sizeof(VIRTIO_PCI_CAP_COMMON_CONFIG);
958
160
  Device->SpecificConfig.Bar    = 0;
959
160
  Device->SpecificConfig.Exists = TRUE;
960
160
  Device->SpecificConfig.Length = sizeof (VIRTIO_BLK_CONFIG);
961
962
  // if (Device->NotifyConfig.Length < (Device->CommonConfig.Offset * Device->NotifyOffsetMultiplier + 4)) {
963
  //   goto FreeDevice;
964
  // }
965
966
160
  return EFI_SUCCESS;
967
968
128
FreeDevice:
969
  // FreePool (ConfigRegion);
970
971
128
  return EFI_OUT_OF_RESOURCES;
972
222
}