]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
OvmfPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / OvmfPkg / QemuFlashFvbServicesRuntimeDxe / QemuFlash.c
1 /** @file
2 OVMF support for QEMU system firmware flash device
3
4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <Library/BaseMemoryLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/PcdLib.h>
13
14 #include "QemuFlash.h"
15
16 #define WRITE_BYTE_CMD 0x10
17 #define BLOCK_ERASE_CMD 0x20
18 #define CLEAR_STATUS_CMD 0x50
19 #define READ_STATUS_CMD 0x70
20 #define READ_DEVID_CMD 0x90
21 #define BLOCK_ERASE_CONFIRM_CMD 0xd0
22 #define READ_ARRAY_CMD 0xff
23
24 #define CLEARED_ARRAY_STATUS 0x00
25
26
27 UINT8 *mFlashBase;
28
29 STATIC UINTN mFdBlockSize = 0;
30 STATIC UINTN mFdBlockCount = 0;
31
32 STATIC
33 volatile UINT8*
34 QemuFlashPtr (
35 IN EFI_LBA Lba,
36 IN UINTN Offset
37 )
38 {
39 return mFlashBase + ((UINTN)Lba * mFdBlockSize) + Offset;
40 }
41
42
43 /**
44 Determines if the QEMU flash memory device is present.
45
46 @retval FALSE The QEMU flash device is not present.
47 @retval TRUE The QEMU flash device is present.
48
49 **/
50 STATIC
51 BOOLEAN
52 QemuFlashDetected (
53 VOID
54 )
55 {
56 BOOLEAN FlashDetected;
57 volatile UINT8 *Ptr;
58
59 UINTN Offset;
60 UINT8 OriginalUint8;
61 UINT8 ProbeUint8;
62
63 FlashDetected = FALSE;
64 Ptr = QemuFlashPtr (0, 0);
65
66 for (Offset = 0; Offset < mFdBlockSize; Offset++) {
67 Ptr = QemuFlashPtr (0, Offset);
68 ProbeUint8 = *Ptr;
69 if (ProbeUint8 != CLEAR_STATUS_CMD &&
70 ProbeUint8 != READ_STATUS_CMD &&
71 ProbeUint8 != CLEARED_ARRAY_STATUS) {
72 break;
73 }
74 }
75
76 if (Offset >= mFdBlockSize) {
77 DEBUG ((EFI_D_INFO, "QEMU Flash: Failed to find probe location\n"));
78 return FALSE;
79 }
80
81 DEBUG ((EFI_D_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr));
82
83 OriginalUint8 = *Ptr;
84 *Ptr = CLEAR_STATUS_CMD;
85 ProbeUint8 = *Ptr;
86 if (OriginalUint8 != CLEAR_STATUS_CMD &&
87 ProbeUint8 == CLEAR_STATUS_CMD) {
88 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as RAM\n"));
89 *Ptr = OriginalUint8;
90 } else {
91 *Ptr = READ_STATUS_CMD;
92 ProbeUint8 = *Ptr;
93 if (ProbeUint8 == OriginalUint8) {
94 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as ROM\n"));
95 } else if (ProbeUint8 == READ_STATUS_CMD) {
96 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as RAM\n"));
97 *Ptr = OriginalUint8;
98 } else if (ProbeUint8 == CLEARED_ARRAY_STATUS) {
99 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as FLASH\n"));
100 FlashDetected = TRUE;
101 *Ptr = READ_ARRAY_CMD;
102 }
103 }
104
105 DEBUG ((EFI_D_INFO, "QemuFlashDetected => %a\n",
106 FlashDetected ? "Yes" : "No"));
107 return FlashDetected;
108 }
109
110
111 /**
112 Read from QEMU Flash
113
114 @param[in] Lba The starting logical block index to read from.
115 @param[in] Offset Offset into the block at which to begin reading.
116 @param[in] NumBytes On input, indicates the requested read size. On
117 output, indicates the actual number of bytes read
118 @param[in] Buffer Pointer to the buffer to read into.
119
120 **/
121 EFI_STATUS
122 QemuFlashRead (
123 IN EFI_LBA Lba,
124 IN UINTN Offset,
125 IN UINTN *NumBytes,
126 IN UINT8 *Buffer
127 )
128 {
129 UINT8 *Ptr;
130
131 //
132 // Only write to the first 64k. We don't bother saving the FTW Spare
133 // block into the flash memory.
134 //
135 if (Lba >= mFdBlockCount) {
136 return EFI_INVALID_PARAMETER;
137 }
138
139 //
140 // Get flash address
141 //
142 Ptr = (UINT8*) QemuFlashPtr (Lba, Offset);
143
144 CopyMem (Buffer, Ptr, *NumBytes);
145
146 return EFI_SUCCESS;
147 }
148
149
150 /**
151 Write to QEMU Flash
152
153 @param[in] Lba The starting logical block index to write to.
154 @param[in] Offset Offset into the block at which to begin writing.
155 @param[in] NumBytes On input, indicates the requested write size. On
156 output, indicates the actual number of bytes written
157 @param[in] Buffer Pointer to the data to write.
158
159 **/
160 EFI_STATUS
161 QemuFlashWrite (
162 IN EFI_LBA Lba,
163 IN UINTN Offset,
164 IN UINTN *NumBytes,
165 IN UINT8 *Buffer
166 )
167 {
168 volatile UINT8 *Ptr;
169 UINTN Loop;
170
171 //
172 // Only write to the first 64k. We don't bother saving the FTW Spare
173 // block into the flash memory.
174 //
175 if (Lba >= mFdBlockCount) {
176 return EFI_INVALID_PARAMETER;
177 }
178
179 //
180 // Program flash
181 //
182 Ptr = QemuFlashPtr (Lba, Offset);
183 for (Loop = 0; Loop < *NumBytes; Loop++) {
184 *Ptr = WRITE_BYTE_CMD;
185 *Ptr = Buffer[Loop];
186 Ptr++;
187 }
188
189 //
190 // Restore flash to read mode
191 //
192 if (*NumBytes > 0) {
193 *(Ptr - 1) = READ_ARRAY_CMD;
194 }
195
196 return EFI_SUCCESS;
197 }
198
199
200 /**
201 Erase a QEMU Flash block
202
203 @param Lba The logical block index to erase.
204
205 **/
206 EFI_STATUS
207 QemuFlashEraseBlock (
208 IN EFI_LBA Lba
209 )
210 {
211 volatile UINT8 *Ptr;
212
213 if (Lba >= mFdBlockCount) {
214 return EFI_INVALID_PARAMETER;
215 }
216
217 Ptr = QemuFlashPtr (Lba, 0);
218 *Ptr = BLOCK_ERASE_CMD;
219 *Ptr = BLOCK_ERASE_CONFIRM_CMD;
220 return EFI_SUCCESS;
221 }
222
223
224 /**
225 Initializes QEMU flash memory support
226
227 @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.
228 @retval EFI_SUCCESS The QEMU flash device is supported.
229
230 **/
231 EFI_STATUS
232 QemuFlashInitialize (
233 VOID
234 )
235 {
236 mFlashBase = (UINT8*)(UINTN) PcdGet32 (PcdOvmfFdBaseAddress);
237 mFdBlockSize = PcdGet32 (PcdOvmfFirmwareBlockSize);
238 ASSERT(PcdGet32 (PcdOvmfFirmwareFdSize) % mFdBlockSize == 0);
239 mFdBlockCount = PcdGet32 (PcdOvmfFirmwareFdSize) / mFdBlockSize;
240
241 //
242 // execute module specific hooks before probing the flash
243 //
244 QemuFlashBeforeProbe (
245 (EFI_PHYSICAL_ADDRESS)(UINTN) mFlashBase,
246 mFdBlockSize,
247 mFdBlockCount
248 );
249
250 if (!QemuFlashDetected ()) {
251 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
252 return EFI_WRITE_PROTECTED;
253 }
254
255 return EFI_SUCCESS;
256 }
257