summaryrefslogtreecommitdiffstats
path: root/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c
blob: 55bce88bc8dd647788b92ab1121c7b0c52be3735 (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
136
/** @file

 Copyright (c) 2014-2018, Linaro Ltd. All rights reserved.<BR>

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

 **/

#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/VirtNorFlashPlatformLib.h>

#include <Protocol/FdtClient.h>

#define QEMU_NOR_BLOCK_SIZE  SIZE_256KB

#define MAX_FLASH_BANKS  4

EFI_STATUS
VirtNorFlashPlatformInitialization (
  VOID
  )
{
  return EFI_SUCCESS;
}

STATIC VIRT_NOR_FLASH_DESCRIPTION  mNorFlashDevices[MAX_FLASH_BANKS];

EFI_STATUS
VirtNorFlashPlatformGetDevices (
  OUT VIRT_NOR_FLASH_DESCRIPTION  **NorFlashDescriptions,
  OUT UINT32                      *Count
  )
{
  FDT_CLIENT_PROTOCOL  *FdtClient;
  INT32                Node;
  EFI_STATUS           Status;
  EFI_STATUS           FindNodeStatus;
  CONST UINT32         *Reg;
  UINT32               PropSize;
  UINT32               Num;
  UINT64               Base;
  UINT64               Size;

  Status = gBS->LocateProtocol (
                  &gFdtClientProtocolGuid,
                  NULL,
                  (VOID **)&FdtClient
                  );
  ASSERT_EFI_ERROR (Status);

  Num = 0;
  for (FindNodeStatus = FdtClient->FindCompatibleNode (
                                     FdtClient,
                                     "cfi-flash",
                                     &Node
                                     );
       !EFI_ERROR (FindNodeStatus) && Num < MAX_FLASH_BANKS;
       FindNodeStatus = FdtClient->FindNextCompatibleNode (
                                     FdtClient,
                                     "cfi-flash",
                                     Node,
                                     &Node
                                     ))
  {
    Status = FdtClient->GetNodeProperty (
                          FdtClient,
                          Node,
                          "reg",
                          (CONST VOID **)&Reg,
                          &PropSize
                          );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "%a: GetNodeProperty () failed (Status == %r)\n",
        __FUNCTION__,
        Status
        ));
      continue;
    }

    ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);

    while (PropSize >= (4 * sizeof (UINT32)) && Num < MAX_FLASH_BANKS) {
      Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
      Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
      Reg += 4;

      PropSize -= 4 * sizeof (UINT32);

      //
      // Disregard any flash devices that overlap with the primary FV.
      // The firmware is not updatable from inside the guest anyway.
      //
      if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
          ((Base + Size) > PcdGet64 (PcdFvBaseAddress)))
      {
        continue;
      }

      mNorFlashDevices[Num].DeviceBaseAddress = (UINTN)Base;
      mNorFlashDevices[Num].RegionBaseAddress = (UINTN)Base;
      mNorFlashDevices[Num].Size              = (UINTN)Size;
      mNorFlashDevices[Num].BlockSize         = QEMU_NOR_BLOCK_SIZE;
      Num++;
    }

    //
    // UEFI takes ownership of the NOR flash, and exposes its functionality
    // through the UEFI Runtime Services GetVariable, SetVariable, etc. This
    // means we need to disable it in the device tree to prevent the OS from
    // attaching its device driver as well.
    // Note that this also hides other flash banks, but the only other flash
    // bank we expect to encounter is the one that carries the UEFI executable
    // code, which is not intended to be guest updatable, and is usually backed
    // in a readonly manner by QEMU anyway.
    //
    Status = FdtClient->SetNodeProperty (
                          FdtClient,
                          Node,
                          "status",
                          "disabled",
                          sizeof ("disabled")
                          );
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_WARN, "Failed to set NOR flash status to 'disabled'\n"));
    }
  }

  *NorFlashDescriptions = mNorFlashDevices;
  *Count                = Num;

  return EFI_SUCCESS;
}