OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
BiosDisk.c
Go to the documentation of this file.
1
7
8//
9// Int 13 BIOS Errors
10//
11#define BIOS_PASS 0x00
12#define BIOS_WRITE_PROTECTED 0x03
13#define BIOS_SECTOR_NOT_FOUND 0x04
14#define BIOS_RESET_FAILED 0x05
15#define BIOS_DISK_CHANGED 0x06
16#define BIOS_DRIVE_DOES_NOT_EXIST 0x07
17#define BIOS_DMA_ERROR 0x08
18#define BIOS_DATA_BOUNDRY_ERROR 0x09
19#define BIOS_BAD_SECTOR 0x0a
20#define BIOS_BAD_TRACK 0x0b
21#define BIOS_MEADIA_TYPE_NOT_FOUND 0x0c
22#define BIOS_INVALED_FORMAT 0x0d
23#define BIOS_ECC_ERROR 0x10
24#define BIOS_ECC_CORRECTED_ERROR 0x11
25#define BIOS_HARD_DRIVE_FAILURE 0x20
26#define BIOS_SEEK_FAILED 0x40
27#define BIOS_DRIVE_TIMEOUT 0x80
28#define BIOS_DRIVE_NOT_READY 0xaa
29#define BIOS_UNDEFINED_ERROR 0xbb
30#define BIOS_WRITE_FAULT 0xcc
31#define BIOS_SENSE_FAILED 0xff
32
33typedef struct {
34 UINT8 PacketSizeInBytes; // 0x10
35 UINT8 Zero;
36 UINT8 NumberOfBlocks; // Max 0x7f
37 UINT8 Zero2;
38 UINT32 SegOffset;
39 UINT64 Lba;
41
42#define BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT 4
43
44STATIC
45EFI_STATUS
47 IN THUNK_CONTEXT *ThunkContext,
48 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259,
49 IN UINT8 DriveNumber
50 )
51{
52 IA32_REGISTER_SET Regs;
53 UINTN CarryFlag;
54
55 ZeroMem (&Regs, sizeof (IA32_REGISTER_SET));
56
57 Regs.H.AH = 0x00;
58 Regs.H.DL = DriveNumber;
59 CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs);
60
61 if (CarryFlag != 0) {
62 DEBUG ((DEBUG_INFO, "OLB: Failed to reset BIOS disk %u, error 0x%X\n", DriveNumber, Regs.H.AL));
63 if (Regs.H.AL == BIOS_RESET_FAILED) {
64 Regs.H.AH = 0x00;
65 Regs.H.DL = DriveNumber;
66 CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs);
67 if (CarryFlag != 0) {
68 DEBUG ((DEBUG_INFO, "OLB: Failed to reset BIOS disk %u, error 0x%X\n", DriveNumber, Regs.H.AH));
69 return EFI_DEVICE_ERROR;
70 }
71 }
72 }
73
74 return EFI_SUCCESS;
75}
76
77STATIC
78EFI_STATUS
80 IN THUNK_CONTEXT *ThunkContext,
81 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259,
82 IN UINT8 DriveNumber
83 )
84{
85 INTN CarryFlag;
86 IA32_REGISTER_SET Regs;
87
88 ZeroMem (&Regs, sizeof (IA32_REGISTER_SET));
89
90 Regs.H.AH = 0x41;
91 Regs.X.BX = 0x55aa;
92 Regs.H.DL = DriveNumber;
93 CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs);
94
95 if ((CarryFlag != 0) || (Regs.X.BX != 0xaa55)) {
96 return EFI_UNSUPPORTED;
97 }
98
99 return EFI_SUCCESS;
100}
101
102STATIC
103EFI_STATUS
105 IN THUNK_CONTEXT *ThunkContext,
106 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259,
107 IN DEVICE_ADDRESS_PACKET *DeviceAddressPacket,
108 IN UINT8 DriveNumber,
109 IN UINT64 Lba,
110 IN UINT8 NumSectors,
111 IN OUT UINT8 *Buffer
112 )
113{
114 INTN CarryFlag;
115 IA32_REGISTER_SET Regs;
116
117 ZeroMem (&Regs, sizeof (IA32_REGISTER_SET));
118
119 DeviceAddressPacket->PacketSizeInBytes = sizeof (*DeviceAddressPacket);
120 DeviceAddressPacket->Zero = 0;
121 DeviceAddressPacket->NumberOfBlocks = NumSectors;
122 DeviceAddressPacket->Zero2 = 0;
123 DeviceAddressPacket->SegOffset = (UINT32)LShiftU64 (RShiftU64 ((UINTN)Buffer, 4), 16);
124 DeviceAddressPacket->Lba = Lba;
125
126 Regs.H.AH = 0x42;
127 Regs.H.DL = DriveNumber;
128 Regs.X.SI = EFI_OFFSET (DeviceAddressPacket);
129 Regs.E.DS = EFI_SEGMENT (DeviceAddressPacket);
130 CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs);
131
132 if (CarryFlag != 0) {
133 return EFI_DEVICE_ERROR;
134 }
135
136 return EFI_SUCCESS;
137}
138
139EFI_STATUS
141 IN THUNK_CONTEXT *ThunkContext,
142 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259,
143 IN EFI_HANDLE DiskHandle,
144 OUT UINT8 *DriveAddress
145 )
146{
147 EFI_STATUS Status;
148 OC_DISK_CONTEXT DiskContext;
149 UINT8 DriveAddr;
150 EFI_PHYSICAL_ADDRESS DeviceAddressPacketAddress;
151 DEVICE_ADDRESS_PACKET *DeviceAddressPacket;
152 UINT8 *BiosBuffer;
153 UINTN BiosBufferPages;
154 UINT32 BiosCrc32;
155 UINT8 *DiskBuffer;
156 UINTN DiskBufferSize;
157 UINT32 DiskCrc32;
158 BOOLEAN MatchedDisk;
159
160 //
161 // Read sectors from EFI disk device.
162 //
163 Status = OcDiskInitializeContext (&DiskContext, DiskHandle, TRUE);
164 if (EFI_ERROR (Status)) {
165 return Status;
166 }
167
168 DiskBufferSize = ALIGN_VALUE (BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT * MBR_SIZE, DiskContext.BlockSize);
169 DiskBuffer = AllocatePool (DiskBufferSize);
170 if (DiskBuffer == NULL) {
171 return EFI_OUT_OF_RESOURCES;
172 }
173
174 Status = OcDiskRead (
175 &DiskContext,
176 0,
177 DiskBufferSize,
178 DiskBuffer
179 );
180 if (EFI_ERROR (Status)) {
181 FreePool (DiskBuffer);
182 return Status;
183 }
184
185 gBS->CalculateCrc32 (
186 DiskBuffer,
188 &DiskCrc32
189 );
190 DEBUG ((DEBUG_INFO, "OLB: EFI disk CRC32: 0x%X\n", DiskCrc32));
191
192 //
193 // Allocate low memory buffer for disk reads.
194 //
195 DeviceAddressPacketAddress = (SIZE_1MB - 1);
196 BiosBufferPages = EFI_SIZE_TO_PAGES (sizeof (*DeviceAddressPacket) + (BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT * MBR_SIZE)) + 1;
197 Status = gBS->AllocatePages (
198 AllocateMaxAddress,
199 EfiBootServicesData,
200 BiosBufferPages,
201 &DeviceAddressPacketAddress
202 );
203 if (EFI_ERROR (Status)) {
204 DEBUG ((DEBUG_INFO, "OLB: Failure allocating low memory packet for BIOS disk read - %r\n", Status));
205 FreePool (DiskBuffer);
206 return Status;
207 }
208
209 DeviceAddressPacket = (DEVICE_ADDRESS_PACKET *)(UINTN)DeviceAddressPacketAddress;
210 BiosBuffer = (UINT8 *)(UINTN)DeviceAddressPacketAddress + 0x200;
211
212 //
213 // Read sectors from each BIOS disk.
214 // Compare against sectors from EFI disk to determine BIOS disk address.
215 //
216 MatchedDisk = FALSE;
217 for (DriveAddr = 0x80; DriveAddr < 0x88; DriveAddr++) {
218 DEBUG ((DEBUG_INFO, "OLB: Reading BIOS drive 0x%X\n", DriveAddr));
219
220 //
221 // Reset disk and verify INT13H extensions are supported.
222 //
223 Status = BiosDiskReset (ThunkContext, Legacy8259, DriveAddr);
224 if (EFI_ERROR (Status)) {
225 continue;
226 }
227
228 Status = BiosDiskExtensionsSupported (ThunkContext, Legacy8259, DriveAddr);
229 if (EFI_ERROR (Status)) {
230 continue;
231 }
232
233 //
234 // Read first 4 sectors from disk.
235 //
236 Status = BiosDiskReadExtSectors (
237 ThunkContext,
238 Legacy8259,
239 DeviceAddressPacket,
240 DriveAddr,
241 0,
243 BiosBuffer
244 );
245 if (EFI_ERROR (Status)) {
246 continue;
247 }
248
249 //
250 // Calculate CRC32 of BIOS disk sectors.
251 //
252 gBS->CalculateCrc32 (
253 BiosBuffer,
255 &BiosCrc32
256 );
257 DEBUG ((DEBUG_INFO, "OLB: BIOS disk CRC32: 0x%X\n", BiosCrc32));
258
259 if (BiosCrc32 == DiskCrc32) {
260 DEBUG ((DEBUG_INFO, "OLB: Matched BIOS disk address 0x%X\n", DriveAddr));
261
262 MatchedDisk = TRUE;
263 *DriveAddress = DriveAddr;
264 break;
265 }
266 }
267
268 FreePool (DiskBuffer);
269 gBS->FreePages (
270 DeviceAddressPacketAddress,
271 BiosBufferPages
272 );
273
274 return MatchedDisk ? EFI_SUCCESS : EFI_NOT_FOUND;
275}
#define BIOS_RESET_FAILED
Definition BiosDisk.c:14
#define BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT
Definition BiosDisk.c:42
STATIC EFI_STATUS BiosDiskExtensionsSupported(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN UINT8 DriveNumber)
Definition BiosDisk.c:79
STATIC EFI_STATUS BiosDiskReadExtSectors(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN DEVICE_ADDRESS_PACKET *DeviceAddressPacket, IN UINT8 DriveNumber, IN UINT64 Lba, IN UINT8 NumSectors, IN OUT UINT8 *Buffer)
Definition BiosDisk.c:104
EFI_STATUS InternalGetBiosDiskAddress(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN EFI_HANDLE DiskHandle, OUT UINT8 *DriveAddress)
Definition BiosDisk.c:140
STATIC EFI_STATUS BiosDiskReset(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN UINT8 DriveNumber)
Definition BiosDisk.c:46
EFI_BOOT_SERVICES * gBS
EFI_STATUS OcDiskRead(IN OC_DISK_CONTEXT *Context, IN UINT64 Lba, IN UINTN BufferSize, OUT VOID *Buffer)
Definition DiskMisc.c:116
EFI_STATUS OcDiskInitializeContext(OUT OC_DISK_CONTEXT *Context, IN EFI_HANDLE DiskHandle, IN BOOLEAN UseBlockIo2)
Definition DiskMisc.c:46
#define EFI_OFFSET(_Adr)
BOOLEAN EFIAPI OcLegacyThunkBiosInt86(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN UINT8 BiosInt, IN IA32_REGISTER_SET *Regs)
#define EFI_SEGMENT(_Adr)
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition UserMath.c:86
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition UserMath.c:76