summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/PlatformDxe/PlatformConfig.c
blob: 4058a324eb8cf61ebdfb3dee20951fb5f51ba21f (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
129
130
131
132
133
134
135
/** @file

  Utility functions for serializing (persistently storing) and deserializing
  OVMF's platform configuration.

  Copyright (C) 2014, Red Hat, Inc.

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

**/

#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Guid/OvmfPlatformConfig.h>

#include "PlatformConfig.h"

//
// Name of the UEFI variable that we use for persistent storage.
//
CHAR16  mVariableName[] = L"PlatformConfig";
CHAR16  mHiiFormName[]  = L"MainFormState";

/**
  Serialize and persistently save platform configuration.

  @param[in] PlatformConfig  The platform configuration to serialize and save.

  @return  Status codes returned by gRT->SetVariable().
**/
EFI_STATUS
EFIAPI
PlatformConfigSave (
  IN PLATFORM_CONFIG  *PlatformConfig
  )
{
  EFI_STATUS  Status;

  //
  // We could implement any kind of translation here, as part of serialization.
  // For example, we could expose the platform configuration in separate
  // variables with human-readable contents, allowing other tools to access
  // them more easily. For now, just save a binary dump.
  //
  Status = gRT->SetVariable (
                  mVariableName,
                  &gOvmfPlatformConfigGuid,
                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
                  EFI_VARIABLE_RUNTIME_ACCESS,
                  sizeof *PlatformConfig,
                  PlatformConfig
                  );
  return Status;
}

/**
  Load and deserialize platform configuration.

  When the function fails, output parameters are indeterminate.

  @param[out] PlatformConfig    The platform configuration to receive the
                                loaded data.

  @param[out] OptionalElements  This bitmap describes the presence of optional
                                configuration elements that have been loaded.
                                PLATFORM_CONFIG_F_DOWNGRADE means that some
                                unknown elements, present in the wire format,
                                have been ignored.

  @retval  EFI_SUCCESS         Loading & deserialization successful.
  @return                      Error codes returned by GetVariable2().
**/
EFI_STATUS
EFIAPI
PlatformConfigLoad (
  OUT PLATFORM_CONFIG  *PlatformConfig,
  OUT UINT64           *OptionalElements
  )
{
  VOID        *Data;
  UINTN       DataSize;
  EFI_STATUS  Status;

  //
  // Any translation done in PlatformConfigSave() would have to be mirrored
  // here. For now, just load the binary dump.
  //
  // Versioning of the binary wire format is implemented based on size
  // (only incremental changes, ie. new fields), and on GUID.
  // (Incompatible changes require a GUID change.)
  //
  Status = GetVariable2 (
             mVariableName,
             &gOvmfPlatformConfigGuid,
             &Data,
             &DataSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  *OptionalElements = 0;
  if (DataSize > sizeof *PlatformConfig) {
    //
    // Handle firmware downgrade -- keep only leading part.
    //
    CopyMem (PlatformConfig, Data, sizeof *PlatformConfig);
    *OptionalElements |= PLATFORM_CONFIG_F_DOWNGRADE;
  } else {
    CopyMem (PlatformConfig, Data, DataSize);

    //
    // Handle firmware upgrade -- zero out missing fields.
    //
    ZeroMem (
      (UINT8 *)PlatformConfig + DataSize,
      sizeof *PlatformConfig - DataSize
      );
  }

  //
  // Based on DataSize, report the optional features that we recognize.
  //
  if (DataSize >= (OFFSET_OF (PLATFORM_CONFIG, VerticalResolution) +
                   sizeof PlatformConfig->VerticalResolution))
  {
    *OptionalElements |= PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION;
  }

  FreePool (Data);
  return EFI_SUCCESS;
}