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