]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenPvBlkDxe/BlockIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / XenPvBlkDxe / BlockIo.c
CommitLineData
5de8a35c
AP
1/** @file\r
2 BlockIo implementation for Xen PV Block driver.\r
3\r
4 This file is implementing the interface between the actual driver in\r
5 BlockFront.c to the BlockIo protocol.\r
6\r
7 Copyright (C) 2014, Citrix Ltd.\r
8\r
b26f0cf9 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
5de8a35c
AP
10\r
11**/\r
12\r
13#include "XenPvBlkDxe.h"\r
14\r
15#include "BlockFront.h"\r
16\r
17///\r
18/// Block I/O Media structure\r
19///\r
20GLOBAL_REMOVE_IF_UNREFERENCED\r
21EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia = {\r
22 0, // MediaId\r
23 FALSE, // RemovableMedia\r
24 FALSE, // MediaPresent\r
25 FALSE, // LogicalPartition\r
26 TRUE, // ReadOnly\r
27 FALSE, // WriteCaching\r
28 512, // BlockSize\r
29 512, // IoAlign, BlockFront does not support less than 512 bits-aligned.\r
30 0, // LastBlock\r
31 0, // LowestAlignedLba\r
32 0, // LogicalBlocksPerPhysicalBlock\r
33 0 // OptimalTransferLengthGranularity\r
34};\r
35\r
36///\r
37/// Block I/O Protocol instance\r
38///\r
39GLOBAL_REMOVE_IF_UNREFERENCED\r
40EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo = {\r
41 EFI_BLOCK_IO_PROTOCOL_REVISION3, // Revision\r
42 &gXenPvBlkDxeBlockIoMedia, // Media\r
43 XenPvBlkDxeBlockIoReset, // Reset\r
44 XenPvBlkDxeBlockIoReadBlocks, // ReadBlocks\r
45 XenPvBlkDxeBlockIoWriteBlocks, // WriteBlocks\r
46 XenPvBlkDxeBlockIoFlushBlocks // FlushBlocks\r
47};\r
48\r
5de8a35c
AP
49/**\r
50 Read/Write BufferSize bytes from Lba into Buffer.\r
51\r
493dde94 52 This function is common to XenPvBlkDxeBlockIoReadBlocks and\r
5de8a35c
AP
53 XenPvBlkDxeBlockIoWriteBlocks.\r
54\r
55 @param This Indicates a pointer to the calling context.\r
56 @param MediaId Id of the media, changes every time the media is replaced.\r
57 @param Lba The starting Logical Block Address to read from/write to.\r
58 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
59 @param Buffer A pointer to the destination/source buffer for the data.\r
60 @param IsWrite Indicate if the operation is write or read.\r
61\r
62 @return See description of XenPvBlkDxeBlockIoReadBlocks and\r
63 XenPvBlkDxeBlockIoWriteBlocks.\r
64**/\r
65STATIC\r
66EFI_STATUS\r
67XenPvBlkDxeBlockIoReadWriteBlocks (\r
68 IN EFI_BLOCK_IO_PROTOCOL *This,\r
69 IN UINT32 MediaId,\r
70 IN EFI_LBA Lba,\r
71 IN UINTN BufferSize,\r
72 IN OUT VOID *Buffer,\r
73 IN BOOLEAN IsWrite\r
74 )\r
75{\r
ac0a286f
MK
76 XEN_BLOCK_FRONT_IO IoData;\r
77 EFI_BLOCK_IO_MEDIA *Media = This->Media;\r
78 UINTN Sector;\r
79 EFI_STATUS Status;\r
5de8a35c
AP
80\r
81 if (Buffer == NULL) {\r
82 return EFI_INVALID_PARAMETER;\r
83 }\r
ac0a286f 84\r
5de8a35c
AP
85 if (BufferSize == 0) {\r
86 return EFI_SUCCESS;\r
87 }\r
88\r
89 if (BufferSize % Media->BlockSize != 0) {\r
ac0a286f
MK
90 DEBUG ((\r
91 DEBUG_ERROR,\r
92 "XenPvBlkDxe: Bad buffer size: 0x%Lx\n",\r
93 (UINT64)BufferSize\r
94 ));\r
5de8a35c
AP
95 return EFI_BAD_BUFFER_SIZE;\r
96 }\r
97\r
ac0a286f
MK
98 if ((Lba > Media->LastBlock) ||\r
99 ((BufferSize / Media->BlockSize) - 1 > Media->LastBlock - Lba))\r
100 {\r
101 DEBUG ((\r
102 DEBUG_ERROR,\r
6394c35a 103 "XenPvBlkDxe: %a with invalid LBA: 0x%Lx, size: 0x%Lx\n",\r
ac0a286f
MK
104 IsWrite ? "Write" : "Read",\r
105 Lba,\r
106 (UINT64)BufferSize\r
107 ));\r
5de8a35c
AP
108 return EFI_INVALID_PARAMETER;\r
109 }\r
110\r
111 if (IsWrite && Media->ReadOnly) {\r
112 return EFI_WRITE_PROTECTED;\r
113 }\r
114\r
115 if ((Media->IoAlign > 1) && (UINTN)Buffer & (Media->IoAlign - 1)) {\r
116 //\r
117 // Grub2 does not appear to respect IoAlign of 512, so reallocate the\r
118 // buffer here.\r
119 //\r
ac0a286f 120 VOID *NewBuffer;\r
5de8a35c
AP
121\r
122 //\r
123 // Try again with a properly aligned buffer.\r
124 //\r
ac0a286f
MK
125 NewBuffer = AllocateAlignedPages (\r
126 (BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE,\r
127 Media->IoAlign\r
128 );\r
5de8a35c 129 if (!IsWrite) {\r
ac0a286f
MK
130 Status = XenPvBlkDxeBlockIoReadBlocks (\r
131 This,\r
132 MediaId,\r
133 Lba,\r
134 BufferSize,\r
135 NewBuffer\r
136 );\r
5de8a35c
AP
137 CopyMem (Buffer, NewBuffer, BufferSize);\r
138 } else {\r
139 CopyMem (NewBuffer, Buffer, BufferSize);\r
ac0a286f
MK
140 Status = XenPvBlkDxeBlockIoWriteBlocks (\r
141 This,\r
142 MediaId,\r
143 Lba,\r
144 BufferSize,\r
145 NewBuffer\r
146 );\r
5de8a35c 147 }\r
ac0a286f 148\r
5de8a35c
AP
149 FreeAlignedPages (NewBuffer, (BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE);\r
150 return Status;\r
151 }\r
152\r
153 IoData.Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (This);\r
ac0a286f 154 Sector = (UINTN)MultU64x32 (Lba, Media->BlockSize / 512);\r
5de8a35c
AP
155\r
156 while (BufferSize > 0) {\r
157 if (((UINTN)Buffer & EFI_PAGE_MASK) == 0) {\r
ac0a286f
MK
158 IoData.Size = MIN (\r
159 BLKIF_MAX_SEGMENTS_PER_REQUEST * EFI_PAGE_SIZE,\r
160 BufferSize\r
161 );\r
5de8a35c 162 } else {\r
ac0a286f
MK
163 IoData.Size = MIN (\r
164 (BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * EFI_PAGE_SIZE,\r
165 BufferSize\r
166 );\r
5de8a35c
AP
167 }\r
168\r
169 IoData.Buffer = Buffer;\r
170 IoData.Sector = Sector;\r
ac0a286f
MK
171 BufferSize -= IoData.Size;\r
172 Buffer = (VOID *)((UINTN)Buffer + IoData.Size);\r
173 Sector += IoData.Size / 512;\r
174 Status = XenPvBlockIo (&IoData, IsWrite);\r
5de8a35c 175 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
176 DEBUG ((\r
177 DEBUG_ERROR,\r
178 "XenPvBlkDxe: Error during %a operation.\n",\r
179 IsWrite ? "write" : "read"\r
180 ));\r
5de8a35c
AP
181 return Status;\r
182 }\r
183 }\r
ac0a286f 184\r
5de8a35c
AP
185 return EFI_SUCCESS;\r
186}\r
187\r
5de8a35c
AP
188/**\r
189 Read BufferSize bytes from Lba into Buffer.\r
190\r
191 @param This Indicates a pointer to the calling context.\r
192 @param MediaId Id of the media, changes every time the media is replaced.\r
193 @param Lba The starting Logical Block Address to read from\r
194 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
195 @param Buffer A pointer to the destination buffer for the data. The caller is\r
196 responsible for either having implicit or explicit ownership of the buffer.\r
197\r
198 @retval EFI_SUCCESS The data was read correctly from the device.\r
199 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
200 @retval EFI_NO_MEDIA There is no media in the device.\r
493dde94 201 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
5de8a35c
AP
202 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
203 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
204 or the buffer is not on proper alignment.\r
205\r
206**/\r
207EFI_STATUS\r
208EFIAPI\r
209XenPvBlkDxeBlockIoReadBlocks (\r
ac0a286f
MK
210 IN EFI_BLOCK_IO_PROTOCOL *This,\r
211 IN UINT32 MediaId,\r
212 IN EFI_LBA Lba,\r
213 IN UINTN BufferSize,\r
214 OUT VOID *Buffer\r
5de8a35c
AP
215 )\r
216{\r
ac0a286f
MK
217 return XenPvBlkDxeBlockIoReadWriteBlocks (\r
218 This,\r
219 MediaId,\r
220 Lba,\r
221 BufferSize,\r
222 Buffer,\r
223 FALSE\r
224 );\r
5de8a35c
AP
225}\r
226\r
227/**\r
228 Write BufferSize bytes from Lba into Buffer.\r
229\r
230 @param This Indicates a pointer to the calling context.\r
231 @param MediaId The media ID that the write request is for.\r
232 @param Lba The starting logical block address to be written. The caller is\r
233 responsible for writing to only legitimate locations.\r
234 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
235 @param Buffer A pointer to the source buffer for the data.\r
236\r
237 @retval EFI_SUCCESS The data was written correctly to the device.\r
238 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
239 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
240 @retval EFI_NO_MEDIA There is no media in the device.\r
493dde94 241 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
5de8a35c
AP
242 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
243 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
244 or the buffer is not on proper alignment.\r
245\r
246**/\r
247EFI_STATUS\r
248EFIAPI\r
249XenPvBlkDxeBlockIoWriteBlocks (\r
ac0a286f
MK
250 IN EFI_BLOCK_IO_PROTOCOL *This,\r
251 IN UINT32 MediaId,\r
252 IN EFI_LBA Lba,\r
253 IN UINTN BufferSize,\r
254 IN VOID *Buffer\r
5de8a35c
AP
255 )\r
256{\r
ac0a286f
MK
257 return XenPvBlkDxeBlockIoReadWriteBlocks (\r
258 This,\r
259 MediaId,\r
260 Lba,\r
261 BufferSize,\r
262 Buffer,\r
263 TRUE\r
264 );\r
5de8a35c
AP
265}\r
266\r
267/**\r
268 Flush the Block Device.\r
269\r
270 @param This Indicates a pointer to the calling context.\r
271\r
272 @retval EFI_SUCCESS All outstanding data was written to the device\r
493dde94 273 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
5de8a35c
AP
274 @retval EFI_NO_MEDIA There is no media in the device.\r
275\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279XenPvBlkDxeBlockIoFlushBlocks (\r
280 IN EFI_BLOCK_IO_PROTOCOL *This\r
281 )\r
282{\r
283 XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This));\r
284 return EFI_SUCCESS;\r
285}\r
286\r
287/**\r
288 Reset the block device hardware.\r
289\r
290 @param[in] This Indicates a pointer to the calling context.\r
291 @param[in] ExtendedVerification Not used.\r
292\r
293 @retval EFI_SUCCESS The device was reset.\r
294\r
295**/\r
296EFI_STATUS\r
297EFIAPI\r
298XenPvBlkDxeBlockIoReset (\r
ac0a286f
MK
299 IN EFI_BLOCK_IO_PROTOCOL *This,\r
300 IN BOOLEAN ExtendedVerification\r
5de8a35c
AP
301 )\r
302{\r
303 //\r
304 // Since the initialization of the devices is done, then the device is\r
305 // working correctly.\r
306 //\r
307 return EFI_SUCCESS;\r
308}\r