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