summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/Library/SmbiosVersionLib/DetectSmbiosVersionLib.c
blob: 69c2d3640037fcf25477d8944a5eca66e9b246d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/** @file

  A hook-in library for MdeModulePkg/Universal/SmbiosDxe, in order to set
  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion (and possibly other PCDs)
  just before SmbiosDxe consumes them.

  Copyright (C) 2013, 2015, Red Hat, Inc.
  Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <IndustryStandard/SmBios.h>

#include <Base.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/QemuFwCfgLib.h>

typedef union {
  SMBIOS_TABLE_ENTRY_POINT        V2;
  SMBIOS_TABLE_3_0_ENTRY_POINT    V3;
} QEMU_SMBIOS_ANCHOR;

RETURN_STATUS
EFIAPI
DetectSmbiosVersion (
  VOID
  )
{
  FIRMWARE_CONFIG_ITEM  Anchor, Tables;
  UINTN                 AnchorSize, TablesSize;
  QEMU_SMBIOS_ANCHOR    QemuAnchor;
  UINT16                SmbiosVersion;
  RETURN_STATUS         PcdStatus;

  if (PcdGetBool (PcdQemuSmbiosValidated)) {
    //
    // Some other module, linked against this library, has already performed
    // the task at hand. This should never happen, but it's easy to handle;
    // just exit early.
    //
    return RETURN_SUCCESS;
  }

  if (RETURN_ERROR (
        QemuFwCfgFindFile (
          "etc/smbios/smbios-anchor",
          &Anchor,
          &AnchorSize
          )
        ) ||
      RETURN_ERROR (
        QemuFwCfgFindFile (
          "etc/smbios/smbios-tables",
          &Tables,
          &TablesSize
          )
        ) ||
      (TablesSize == 0))
  {
    return RETURN_SUCCESS;
  }

  QemuFwCfgSelectItem (Anchor);

  switch (AnchorSize) {
    case sizeof QemuAnchor.V2:
      QemuFwCfgReadBytes (AnchorSize, &QemuAnchor);

      if ((QemuAnchor.V2.MajorVersion != 2) ||
          (QemuAnchor.V2.TableLength != TablesSize) ||
          (CompareMem (QemuAnchor.V2.AnchorString, "_SM_", 4) != 0) ||
          (CompareMem (QemuAnchor.V2.IntermediateAnchorString, "_DMI_", 5) != 0))
      {
        return RETURN_SUCCESS;
      }

      SmbiosVersion = (UINT16)(QemuAnchor.V2.MajorVersion << 8 |
                               QemuAnchor.V2.MinorVersion);
      break;

    case sizeof QemuAnchor.V3:
      QemuFwCfgReadBytes (AnchorSize, &QemuAnchor);

      if ((QemuAnchor.V3.MajorVersion != 3) ||
          (QemuAnchor.V3.TableMaximumSize != TablesSize) ||
          (CompareMem (QemuAnchor.V3.AnchorString, "_SM3_", 5) != 0))
      {
        return RETURN_SUCCESS;
      }

      SmbiosVersion = (UINT16)(QemuAnchor.V3.MajorVersion << 8 |
                               QemuAnchor.V3.MinorVersion);

      DEBUG ((
        DEBUG_INFO,
        "%a: SMBIOS 3.x DocRev from QEMU: 0x%02x\n",
        __FUNCTION__,
        QemuAnchor.V3.DocRev
        ));
      PcdStatus = PcdSet8S (PcdSmbiosDocRev, QemuAnchor.V3.DocRev);
      ASSERT_RETURN_ERROR (PcdStatus);
      break;

    default:
      return RETURN_SUCCESS;
  }

  DEBUG ((
    DEBUG_INFO,
    "%a: SMBIOS version from QEMU: 0x%04x\n",
    __FUNCTION__,
    SmbiosVersion
    ));
  PcdStatus = PcdSet16S (PcdSmbiosVersion, SmbiosVersion);
  ASSERT_RETURN_ERROR (PcdStatus);

  //
  // SMBIOS platform drivers can now fetch and install
  // "etc/smbios/smbios-tables" from QEMU.
  //
  PcdStatus = PcdSetBoolS (PcdQemuSmbiosValidated, TRUE);
  ASSERT_RETURN_ERROR (PcdStatus);
  return RETURN_SUCCESS;
}