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