]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenPvBlkDxe/BlockIo.c
OvmfPkg/Csm/LegacyBiosDxe: Fix Legacy16GetTableAddress call for E820 data
[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
51
52 /**
53 Read/Write BufferSize bytes from Lba into Buffer.
54
55 This function is commun to XenPvBlkDxeBlockIoReadBlocks and
56 XenPvBlkDxeBlockIoWriteBlocks.
57
58 @param This Indicates a pointer to the calling context.
59 @param MediaId Id of the media, changes every time the media is replaced.
60 @param Lba The starting Logical Block Address to read from/write to.
61 @param BufferSize Size of Buffer, must be a multiple of device block size.
62 @param Buffer A pointer to the destination/source buffer for the data.
63 @param IsWrite Indicate if the operation is write or read.
64
65 @return See description of XenPvBlkDxeBlockIoReadBlocks and
66 XenPvBlkDxeBlockIoWriteBlocks.
67 **/
68 STATIC
69 EFI_STATUS
70 XenPvBlkDxeBlockIoReadWriteBlocks (
71 IN EFI_BLOCK_IO_PROTOCOL *This,
72 IN UINT32 MediaId,
73 IN EFI_LBA Lba,
74 IN UINTN BufferSize,
75 IN OUT VOID *Buffer,
76 IN BOOLEAN IsWrite
77 )
78 {
79 XEN_BLOCK_FRONT_IO IoData;
80 EFI_BLOCK_IO_MEDIA *Media = This->Media;
81 UINTN Sector;
82 EFI_STATUS Status;
83
84 if (Buffer == NULL) {
85 return EFI_INVALID_PARAMETER;
86 }
87 if (BufferSize == 0) {
88 return EFI_SUCCESS;
89 }
90
91 if (BufferSize % Media->BlockSize != 0) {
92 DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: Bad buffer size: 0x%Lx\n",
93 (UINT64)BufferSize));
94 return EFI_BAD_BUFFER_SIZE;
95 }
96
97 if (Lba > Media->LastBlock ||
98 (BufferSize / Media->BlockSize) - 1 > Media->LastBlock - Lba) {
99 DEBUG ((EFI_D_ERROR,
100 "XenPvBlkDxe: %a with invalid LBA: 0x%Lx, size: 0x%Lx\n",
101 IsWrite ? "Write" : "Read", Lba, (UINT64)BufferSize));
102 return EFI_INVALID_PARAMETER;
103 }
104
105 if (IsWrite && Media->ReadOnly) {
106 return EFI_WRITE_PROTECTED;
107 }
108
109 if ((Media->IoAlign > 1) && (UINTN)Buffer & (Media->IoAlign - 1)) {
110 //
111 // Grub2 does not appear to respect IoAlign of 512, so reallocate the
112 // buffer here.
113 //
114 VOID *NewBuffer;
115
116 //
117 // Try again with a properly aligned buffer.
118 //
119 NewBuffer = AllocateAlignedPages((BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE,
120 Media->IoAlign);
121 if (!IsWrite) {
122 Status = XenPvBlkDxeBlockIoReadBlocks (This, MediaId,
123 Lba, BufferSize, NewBuffer);
124 CopyMem (Buffer, NewBuffer, BufferSize);
125 } else {
126 CopyMem (NewBuffer, Buffer, BufferSize);
127 Status = XenPvBlkDxeBlockIoWriteBlocks (This, MediaId,
128 Lba, BufferSize, NewBuffer);
129 }
130 FreeAlignedPages (NewBuffer, (BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE);
131 return Status;
132 }
133
134 IoData.Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (This);
135 Sector = (UINTN)MultU64x32 (Lba, Media->BlockSize / 512);
136
137 while (BufferSize > 0) {
138 if (((UINTN)Buffer & EFI_PAGE_MASK) == 0) {
139 IoData.Size = MIN (BLKIF_MAX_SEGMENTS_PER_REQUEST * EFI_PAGE_SIZE,
140 BufferSize);
141 } else {
142 IoData.Size = MIN ((BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * EFI_PAGE_SIZE,
143 BufferSize);
144 }
145
146 IoData.Buffer = Buffer;
147 IoData.Sector = Sector;
148 BufferSize -= IoData.Size;
149 Buffer = (VOID*) ((UINTN) Buffer + IoData.Size);
150 Sector += IoData.Size / 512;
151 Status = XenPvBlockIo (&IoData, IsWrite);
152 if (EFI_ERROR (Status)) {
153 DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: Error during %a operation.\n",
154 IsWrite ? "write" : "read"));
155 return Status;
156 }
157 }
158 return EFI_SUCCESS;
159 }
160
161
162 /**
163 Read BufferSize bytes from Lba into Buffer.
164
165 @param This Indicates a pointer to the calling context.
166 @param MediaId Id of the media, changes every time the media is replaced.
167 @param Lba The starting Logical Block Address to read from
168 @param BufferSize Size of Buffer, must be a multiple of device block size.
169 @param Buffer A pointer to the destination buffer for the data. The caller is
170 responsible for either having implicit or explicit ownership of the buffer.
171
172 @retval EFI_SUCCESS The data was read correctly from the device.
173 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
174 @retval EFI_NO_MEDIA There is no media in the device.
175 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
176 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
177 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
178 or the buffer is not on proper alignment.
179
180 **/
181 EFI_STATUS
182 EFIAPI
183 XenPvBlkDxeBlockIoReadBlocks (
184 IN EFI_BLOCK_IO_PROTOCOL *This,
185 IN UINT32 MediaId,
186 IN EFI_LBA Lba,
187 IN UINTN BufferSize,
188 OUT VOID *Buffer
189 )
190 {
191 return XenPvBlkDxeBlockIoReadWriteBlocks (This,
192 MediaId, Lba, BufferSize, Buffer, FALSE);
193 }
194
195 /**
196 Write BufferSize bytes from Lba into Buffer.
197
198 @param This Indicates a pointer to the calling context.
199 @param MediaId The media ID that the write request is for.
200 @param Lba The starting logical block address to be written. The caller is
201 responsible for writing to only legitimate locations.
202 @param BufferSize Size of Buffer, must be a multiple of device block size.
203 @param Buffer A pointer to the source buffer for the data.
204
205 @retval EFI_SUCCESS The data was written correctly to the device.
206 @retval EFI_WRITE_PROTECTED The device can not be written to.
207 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
208 @retval EFI_NO_MEDIA There is no media in the device.
209 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
210 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
211 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
212 or the buffer is not on proper alignment.
213
214 **/
215 EFI_STATUS
216 EFIAPI
217 XenPvBlkDxeBlockIoWriteBlocks (
218 IN EFI_BLOCK_IO_PROTOCOL *This,
219 IN UINT32 MediaId,
220 IN EFI_LBA Lba,
221 IN UINTN BufferSize,
222 IN VOID *Buffer
223 )
224 {
225 return XenPvBlkDxeBlockIoReadWriteBlocks (This,
226 MediaId, Lba, BufferSize, Buffer, TRUE);
227 }
228
229 /**
230 Flush the Block Device.
231
232 @param This Indicates a pointer to the calling context.
233
234 @retval EFI_SUCCESS All outstanding data was written to the device
235 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
236 @retval EFI_NO_MEDIA There is no media in the device.
237
238 **/
239 EFI_STATUS
240 EFIAPI
241 XenPvBlkDxeBlockIoFlushBlocks (
242 IN EFI_BLOCK_IO_PROTOCOL *This
243 )
244 {
245 XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This));
246 return EFI_SUCCESS;
247 }
248
249 /**
250 Reset the block device hardware.
251
252 @param[in] This Indicates a pointer to the calling context.
253 @param[in] ExtendedVerification Not used.
254
255 @retval EFI_SUCCESS The device was reset.
256
257 **/
258 EFI_STATUS
259 EFIAPI
260 XenPvBlkDxeBlockIoReset (
261 IN EFI_BLOCK_IO_PROTOCOL *This,
262 IN BOOLEAN ExtendedVerification
263 )
264 {
265 //
266 // Since the initialization of the devices is done, then the device is
267 // working correctly.
268 //
269 return EFI_SUCCESS;
270 }