VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS-new/ahci.c@ 38997

Last change on this file since 38997 was 38997, checked in by vboxsync, 13 years ago

DMA recompiler bug workaround for floppy, too.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.9 KB
Line 
1/* $Id: ahci.c 38997 2011-10-14 13:48:03Z vboxsync $ */
2/** @file
3 * AHCI host adapter driver to boot from SATA disks.
4 */
5
6/*
7 * Copyright (C) 2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17/**
18 * Parts are based on the int13_harddisk code in rombios.c
19 */
20
21//@todo!!!! save/restore high bits of EAX/ECX and whatever else may be needed.
22
23#include <stdint.h>
24#include <string.h>
25#include "biosint.h"
26#include "ebda.h"
27#include "inlines.h"
28#include "pciutil.h"
29#include "vds.h"
30
31#define VBOX_AHCI_DEBUG 0
32#define VBOX_AHCI_INT13_DEBUG 0
33
34#if VBOX_AHCI_DEBUG
35# define VBOXAHCI_DEBUG(...) BX_INFO(__VA_ARGS__)
36#else
37# define VBOXAHCI_DEBUG(...)
38#endif
39
40#if VBOX_AHCI_INT13_DEBUG
41# define VBOXAHCI_INT13_DEBUG(...) BX_INFO(__VA_ARGS__)
42#else
43# define VBOXAHCI_INT13_DEBUG(...)
44#endif
45
46#define AHCI_MAX_STORAGE_DEVICES 4
47
48/* Number of S/G table entries in EDDS. */
49#define NUM_EDDS_SG 16
50
51
52/**
53 * AHCI device data.
54 */
55typedef struct
56{
57 uint8_t type; // Detected type of ata (ata/atapi/none/unknown/scsi)
58 uint8_t device; // Detected type of attached devices (hd/cd/none)
59 uint8_t removable; // Removable device flag
60 uint8_t lock; // Locks for removable devices
61 uint16_t blksize; // block size
62 chs_t lchs; // Logical CHS
63 chs_t pchs; // Physical CHS
64 uint32_t cSectors; // Total sectors count
65 uint8_t port; // Port this device is on.
66} ahci_device_t;
67
68/**
69 * AHCI PRDT structure.
70 */
71typedef struct
72{
73 uint32_t phys_addr;
74 uint32_t something;
75 uint32_t reserved;
76 uint32_t len;
77} ahci_prdt;
78
79/**
80 * AHCI controller data.
81 */
82typedef struct
83{
84 /** The AHCI command list as defined by chapter 4.2.2 of the Intel AHCI spec.
85 * Because the BIOS doesn't support NCQ only the first command header is defined
86 * to save memory. - Must be aligned on a 1K boundary.
87 */
88 uint32_t aCmdHdr[0x8];
89 /** Align the next structure on a 128 byte boundary. */
90 uint8_t abAlignment1[0x60];
91 /** The command table of one request as defined by chapter 4.2.3 of the Intel AHCI spec.
92 * Must be aligned on 128 byte boundary.
93 */
94 uint8_t abCmd[0x80];
95 /** Physical Region Descriptor Table (PRDT) array. In other
96 * words, a scatter/gather descriptor list.
97 */
98 ahci_prdt aPrdt[16];
99 /** Memory for the received command FIS area as specified by chapter 4.2.1
100 * of the Intel AHCI spec. This area is normally 256 bytes big but to save memory
101 * only the first 96 bytes are used because it is assumed that the controller
102 * never writes to the UFIS or reserved area. - Must be aligned on a 256byte boundary.
103 */
104 uint8_t abFisRecv[0x60];
105 /** Base I/O port for the index/data register pair. */
106 uint16_t iobase;
107 /** Current port which uses the memory to communicate with the controller. */
108 uint8_t port;
109 /** AHCI device information. */
110 ahci_device_t aDevices[AHCI_MAX_STORAGE_DEVICES];
111 /** Index of the next unoccupied device slot. */
112 uint8_t cDevices;
113 /** Map between (bios hd id - 0x80) and ahci devices. */
114 uint8_t cHardDisks;
115 uint8_t aHdIdMap[AHCI_MAX_STORAGE_DEVICES];
116 /** Map between (bios cd id - 0xE0) and ahci_devices. */
117 uint8_t cCdDrives;
118 uint8_t aCdIdMap[AHCI_MAX_STORAGE_DEVICES];
119 /** Number of harddisks detected before the AHCI driver started detection. */
120 uint8_t cHardDisksOld;
121 /** int13 handler to call if given device is not from AHCI. */
122 uint16_t pfnInt13Old;
123 /** VDS EDDS DMA buffer descriptor structure. */
124 vds_edds edds;
125 vds_sg edds_more_sg[NUM_EDDS_SG - 1];
126} ahci_t;
127
128#define AhciData ((ahci_t *) 0)
129
130/** PCI configuration fields. */
131#define PCI_CONFIG_CAP 0x34
132
133#define PCI_CAP_ID_SATACR 0x12
134#define VBOX_AHCI_NO_DEVICE 0xffff
135
136#define RT_BIT_32(bit) ((uint32_t)(1L << (bit)))
137
138/** Global register set. */
139#define AHCI_HBA_SIZE 0x100
140
141//@todo: what are the casts good for?
142#define AHCI_REG_CAP ((uint32_t)0x00)
143#define AHCI_REG_GHC ((uint32_t)0x04)
144# define AHCI_GHC_AE RT_BIT_32(31)
145# define AHCI_GHC_IR RT_BIT_32(1)
146# define AHCI_GHC_HR RT_BIT_32(0)
147#define AHCI_REG_IS ((uint32_t)0x08)
148#define AHCI_REG_PI ((uint32_t)0x0c)
149#define AHCI_REG_VS ((uint32_t)0x10)
150
151/** Per port register set. */
152#define AHCI_PORT_SIZE 0x80
153
154#define AHCI_REG_PORT_CLB 0x00
155#define AHCI_REG_PORT_CLBU 0x04
156#define AHCI_REG_PORT_FB 0x08
157#define AHCI_REG_PORT_FBU 0x0c
158#define AHCI_REG_PORT_IS 0x10
159# define AHCI_REG_PORT_IS_DHRS RT_BIT_32(0)
160#define AHCI_REG_PORT_IE 0x14
161#define AHCI_REG_PORT_CMD 0x18
162# define AHCI_REG_PORT_CMD_ST RT_BIT_32(0)
163# define AHCI_REG_PORT_CMD_FRE RT_BIT_32(4)
164# define AHCI_REG_PORT_CMD_FR RT_BIT_32(14)
165# define AHCI_REG_PORT_CMD_CR RT_BIT_32(15)
166#define AHCI_REG_PORT_TFD 0x20
167#define AHCI_REG_PORT_SIG 0x24
168#define AHCI_REG_PORT_SSTS 0x28
169#define AHCI_REG_PORT_SCTL 0x2c
170#define AHCI_REG_PORT_SERR 0x30
171#define AHCI_REG_PORT_SACT 0x34
172#define AHCI_REG_PORT_CI 0x38
173
174/** Returns the absolute register offset from a given port and port register. */
175#define AHCI_PORT_REG(port, reg) ((uint32_t)(AHCI_HBA_SIZE + (port) * AHCI_PORT_SIZE + (reg)))
176
177#define AHCI_REG_IDX 0
178#define AHCI_REG_DATA 4
179
180/** Writes the given value to a AHCI register. */
181#define AHCI_WRITE_REG(iobase, reg, val) \
182 outpd((iobase) + AHCI_REG_IDX, (uint32_t)(reg)); \
183 outpd((iobase) + AHCI_REG_DATA, (uint32_t)(val))
184
185/** Reads from a AHCI register. */
186#define AHCI_READ_REG(iobase, reg, val) \
187 outpd((iobase) + AHCI_REG_IDX, (uint32_t)(reg)); \
188 (val) = inpd((iobase) + AHCI_REG_DATA)
189
190/** Writes to the given port register. */
191#define VBOXAHCI_PORT_WRITE_REG(iobase, port, reg, val) \
192 AHCI_WRITE_REG((iobase), AHCI_PORT_REG((port), (reg)), val)
193
194/** Reads from the given port register. */
195#define VBOXAHCI_PORT_READ_REG(iobase, port, reg, val) \
196 AHCI_READ_REG((iobase), AHCI_PORT_REG((port), (reg)), val)
197
198#define ATA_CMD_IDENTIFY_DEVICE 0xEC
199#define AHCI_CMD_READ_DMA_EXT 0x25
200#define AHCI_CMD_WRITE_DMA_EXT 0x35
201
202
203/* Warning: Destroys high bits of EAX. */
204uint32_t inpd(uint16_t port);
205#pragma aux inpd = \
206 ".386" \
207 "in eax, dx" \
208 "mov dx, ax" \
209 "shr eax, 16" \
210 "xchg ax, dx" \
211 parm [dx] value [dx ax] modify nomemory;
212
213void outpd(uint16_t port, uint32_t val);
214#pragma aux outpd = \
215 ".386" \
216 "xchg ax, cx" \
217 "shl eax, 16" \
218 "mov ax, cx" \
219 "out dx, eax" \
220 parm [dx] [cx ax] modify nomemory;
221
222
223/**
224 * Sets a given set of bits in a register.
225 */
226static void ahci_ctrl_set_bits(uint16_t iobase, uint32_t reg, uint32_t mask)
227{
228 outpd(iobase + AHCI_REG_IDX, reg);
229 outpd(iobase + AHCI_REG_DATA, inpd(iobase + AHCI_REG_DATA) | mask);
230}
231
232/**
233 * Clears a given set of bits in a register.
234 */
235static void ahci_ctrl_clear_bits(uint16_t iobase, uint32_t reg, uint32_t mask)
236{
237 outpd(iobase + AHCI_REG_IDX, reg);
238 outpd(iobase + AHCI_REG_DATA, inpd(iobase + AHCI_REG_DATA) & ~mask);
239}
240
241/**
242 * Returns whether at least one of the bits in the given mask is set
243 * for a register.
244 */
245static uint8_t ahci_ctrl_is_bit_set(uint16_t iobase, uint32_t reg, uint32_t mask)
246{
247 outpd(iobase + AHCI_REG_IDX, reg);
248 return (inpd(iobase + AHCI_REG_DATA) & mask) != 0;
249}
250
251/**
252 * Extracts a range of bits from a register and shifts them
253 * to the right.
254 */
255static uint16_t ahci_ctrl_extract_bits(uint32_t val, uint32_t mask, uint8_t shift)
256{
257 return (val & mask) >> shift;
258}
259
260/**
261 * Converts a segment:offset pair into a 32bit physical address.
262 */
263static uint32_t ahci_addr_to_phys(void __far *ptr)
264{
265 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr);
266}
267
268/**
269 * Issues a command to the SATA controller and waits for completion.
270 */
271static void ahci_port_cmd_sync(uint16_t ahci_seg, uint16_t u16IoBase, bx_bool fWrite,
272 bx_bool fAtapi, uint8_t cFisDWords, uint16_t cbData)
273{
274 uint8_t u8Port;
275 ahci_t __far *ahci = ahci_seg :> 0;
276
277 u8Port = ahci->port;
278
279 if (u8Port != 0xff)
280 {
281 uint32_t u32Val;
282
283 /* Prepare the command header. */
284 u32Val = (1L << 16) | RT_BIT_32(7);
285 if (fWrite)
286 u32Val |= RT_BIT_32(6);
287
288 if (fAtapi)
289 u32Val |= RT_BIT_32(5);
290
291 u32Val |= cFisDWords;
292
293 ahci->aCmdHdr[0] = u32Val;
294 ahci->aCmdHdr[1] = cbData;
295 ahci->aCmdHdr[2] = ahci_addr_to_phys(&ahci->abCmd[0]);
296
297 /* Enable Command and FIS receive engine. */
298 ahci_ctrl_set_bits(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
299 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST);
300
301 /* Queue command. */
302 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CI, 0x1);
303
304 /* Wait for a D2H FIS. */
305 VBOXAHCI_DEBUG("AHCI: Waiting for D2H FIS\n");
306 while (ahci_ctrl_is_bit_set(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_IS),
307 AHCI_REG_PORT_IS_DHRS) == 0)
308 {
309 // This is where we'd need some kind of a yield functionality...
310 }
311
312 ahci_ctrl_set_bits(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_IS),
313 AHCI_REG_PORT_IS_DHRS); /* Acknowledge received D2H FIS. */
314
315 /* Disable command engine. */
316 ahci_ctrl_clear_bits(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
317 AHCI_REG_PORT_CMD_ST);
318
319 /** @todo: Examine status. */
320 }
321 else
322 VBOXAHCI_DEBUG("AHCI: Invalid port given\n");
323}
324
325/**
326 * Issue command to device.
327 */
328//@todo: don't chop up arguments into bytes?!
329static void ahci_cmd_data(uint16_t ahci_seg, uint16_t u16IoBase, uint8_t u8Cmd, uint8_t u8Feat, uint8_t u8Device, uint8_t u8CylHigh, uint8_t u8CylLow, uint8_t u8Sect,
330 uint8_t u8FeatExp, uint8_t u8CylHighExp, uint8_t u8CylLowExp, uint8_t u8SectExp, uint8_t u8SectCount, uint8_t u8SectCountExp,
331 void __far *buf, uint16_t cbData, bx_bool fWrite)
332{
333 ahci_t __far *ahci = ahci_seg :> 0;
334
335 _fmemset(&ahci->abCmd[0], 0, sizeof(ahci->abCmd));
336
337 /* Prepare the FIS. */
338 ahci->abCmd[0] = 0x27; /* FIS type H2D. */
339 ahci->abCmd[1] = 1 << 7; /* Command update. */
340 ahci->abCmd[2] = u8Cmd;
341 ahci->abCmd[3] = u8Feat;
342
343 ahci->abCmd[4] = u8Sect;
344 ahci->abCmd[5] = u8CylLow;
345 ahci->abCmd[6] = u8CylHigh;
346 ahci->abCmd[7] = u8Device;
347
348 ahci->abCmd[8] = u8SectExp;
349 ahci->abCmd[9] = u8CylLowExp;
350 ahci->abCmd[10] = u8CylHighExp;
351 ahci->abCmd[11] = u8FeatExp;
352
353 ahci->abCmd[12] = u8SectCount;
354 ahci->abCmd[13] = u8SectCountExp;
355
356 /* Lock memory needed for DMA. */
357 ahci->edds.num_avail = NUM_EDDS_SG;
358 vds_build_sg_list( &ahci->edds, buf, cbData );
359
360 /* Set up the PRDT. */
361 ahci->aPrdt[0].phys_addr = ahci->edds.u.sg[0].phys_addr;
362 ahci->aPrdt[0].len = ahci->edds.u.sg[0].size - 1;
363
364 ahci_port_cmd_sync(ahci_seg, u16IoBase, fWrite, 0, 5, cbData);
365
366 /* Unlock the buffer again. */
367 vds_free_sg_list( &ahci->edds );
368}
369
370/**
371 * Deinits the curent active port.
372 */
373static void ahci_port_deinit_current(uint16_t ahci_seg, uint16_t u16IoBase)
374{
375 uint8_t u8Port;
376 ahci_t __far *ahci = ahci_seg :> 0;
377
378 u8Port = ahci->port;
379
380 if (u8Port != 0xff)
381 {
382 /* Put the port into an idle state. */
383 ahci_ctrl_clear_bits(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
384 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST);
385
386 while (ahci_ctrl_is_bit_set(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
387 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST | AHCI_REG_PORT_CMD_FR | AHCI_REG_PORT_CMD_CR) == 1)
388 {
389 VBOXAHCI_DEBUG("AHCI: Waiting for the port to idle\n");
390 }
391
392 /*
393 * Port idles, set up memory for commands and received FIS and program the
394 * address registers.
395 */
396 //@todo: merge memsets?
397 _fmemset(&ahci->aCmdHdr[0], 0, sizeof(ahci->aCmdHdr));
398 _fmemset(&ahci->abCmd[0], 0, sizeof(ahci->abCmd));
399 _fmemset(&ahci->abFisRecv[0], 0, sizeof(ahci->abFisRecv));
400
401 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FB, 0);
402 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FBU, 0);
403
404 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLB, 0);
405 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLBU, 0);
406
407 /* Disable all interrupts. */
408 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_IE, 0);
409
410 ahci->port = 0xff;
411 }
412}
413
414/**
415 * Brings a port into a minimal state to make device detection possible
416 * or to queue requests.
417 */
418static void ahci_port_init(uint16_t ahci_seg, uint16_t u16IoBase, uint8_t u8Port)
419{
420 uint32_t u32PhysAddr;
421 ahci_t __far *ahci = ahci_seg :> 0;
422
423 /* Deinit any other port first. */
424 ahci_port_deinit_current(ahci_seg, u16IoBase);
425
426 /* Put the port into an idle state. */
427 ahci_ctrl_clear_bits(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
428 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST);
429
430 while (ahci_ctrl_is_bit_set(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
431 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST | AHCI_REG_PORT_CMD_FR | AHCI_REG_PORT_CMD_CR) == 1)
432 {
433 VBOXAHCI_DEBUG("AHCI: Waiting for the port to idle\n");
434 }
435
436 /*
437 * Port idles, set up memory for commands and received FIS and program the
438 * address registers.
439 */
440 //@todo: just one memset?
441 _fmemset(&ahci->aCmdHdr[0], 0, sizeof(ahci->aCmdHdr));
442 _fmemset(&ahci->abCmd[0], 0, sizeof(ahci->abCmd));
443 _fmemset(&ahci->abFisRecv[0], 0, sizeof(ahci->abFisRecv));
444
445 u32PhysAddr = ahci_addr_to_phys(&ahci->abFisRecv);
446 VBOXAHCI_DEBUG("AHCI: FIS receive area %lx from %x:%x\n", u32PhysAddr, ahci_seg, &AhciData->abFisRecv);
447 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FB, u32PhysAddr);
448 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FBU, 0);
449
450 u32PhysAddr = ahci_addr_to_phys(&ahci->aCmdHdr);
451 VBOXAHCI_DEBUG("AHCI: CMD list area %lx\n", u32PhysAddr);
452 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLB, u32PhysAddr);
453 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLBU, 0);
454
455 /* Disable all interrupts. */
456 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_IE, 0);
457 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_IS, 0xffffffff);
458 /* Clear all errors. */
459 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_SERR, 0xffffffff);
460
461 ahci->port = u8Port;
462}
463
464/**
465 * Write data to the device.
466 */
467static void ahci_cmd_data_out(uint16_t ahci_seg, uint16_t u16IoBase, uint8_t u8Port, uint8_t u8Cmd, uint32_t u32Lba, uint16_t u16Sectors, uint16_t SegData, uint16_t OffData)
468{
469 uint8_t u8CylLow, u8CylHigh, u8Device, u8Sect, u8CylHighExp, u8CylLowExp, u8SectExp, u8SectCount, u8SectCountExp;
470
471 u8SectCount = (uint8_t)(u16Sectors & 0xff);
472 u8SectCountExp = (uint8_t)((u16Sectors >> 8) & 0xff);;
473 u8Sect = (uint8_t)(u32Lba & 0xff);
474 u8SectExp = (uint8_t)((u32Lba >> 24) & 0xff);
475 u8CylLow = (uint8_t)((u32Lba >> 8) & 0xff);
476 u8CylLowExp = 0;
477 u8CylHigh = (uint8_t)((u32Lba >> 16) & 0xff);
478 u8CylHighExp = 0;
479 u8Device = (1 << 6); /* LBA access */
480
481 ahci_port_init(ahci_seg, u16IoBase, u8Port);
482 ahci_cmd_data(ahci_seg, u16IoBase, u8Cmd, 0, u8Device, u8CylHigh, u8CylLow,
483 u8Sect,0, u8CylHighExp, u8CylLowExp, u8SectExp, u8SectCount,
484 u8SectCountExp, SegData :> OffData, u16Sectors * 512, 1);
485}
486
487
488/**
489 * Read data from the device.
490 */
491static void ahci_cmd_data_in(uint16_t ahci_seg, uint16_t u16IoBase, uint8_t u8Port, uint8_t u8Cmd,
492 uint32_t u32Lba, uint16_t u16Sectors, uint16_t SegData, uint16_t OffData)
493{
494 uint8_t u8CylLow, u8CylHigh, u8Device, u8Sect, u8CylHighExp, u8CylLowExp, u8SectExp, u8SectCount, u8SectCountExp;
495
496 u8SectCount = (uint8_t)(u16Sectors & 0xff);
497 u8SectCountExp = (uint8_t)((u16Sectors >> 8) & 0xff);;
498 u8Sect = (uint8_t)(u32Lba & 0xff);
499 u8SectExp = (uint8_t)((u32Lba >> 24) & 0xff);
500 u8CylLow = (uint8_t)((u32Lba >> 8) & 0xff);
501 u8CylLowExp = 0;
502 u8CylHigh = (uint8_t)((u32Lba >> 16) & 0xff);
503 u8CylHighExp = 0;
504
505 u8Device = (1 << 6); /* LBA access */
506
507 ahci_port_init(ahci_seg, u16IoBase, u8Port);
508 ahci_cmd_data(ahci_seg, u16IoBase, u8Cmd, 0, u8Device, u8CylHigh, u8CylLow,
509 u8Sect, 0, u8CylHighExp, u8CylLowExp, u8SectExp, u8SectCount,
510 u8SectCountExp, SegData :> OffData, u16Sectors * 512, 0);
511#ifdef DMA_WORKAROUND
512 rep_movsw(SegData :> OffData, SegData :> OffData, u16Sectors * 512 / 2);
513#endif
514}
515
516static void ahci_port_detect_device(uint16_t ahci_seg, uint16_t u16IoBase, uint8_t u8Port)
517{
518 uint32_t val;
519
520 ahci_port_init(ahci_seg, u16IoBase, u8Port);
521
522 /* Reset connection. */
523 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_SCTL, 0x01);
524 /*
525 * According to the spec we should wait at least 1msec until the reset
526 * is cleared but this is a virtual controller so we don't have to.
527 */
528 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_SCTL, 0);
529
530 /* Check if there is a device on the port. */
531 VBOXAHCI_PORT_READ_REG(u16IoBase, u8Port, AHCI_REG_PORT_SSTS, val);
532 if (ahci_ctrl_extract_bits(val, 0xfL, 0) == 0x3L)
533 {
534 uint8_t idxDevice;
535
536 idxDevice = read_byte(ahci_seg, (uint16_t)&AhciData->cDevices);
537 VBOXAHCI_DEBUG("AHCI: Device detected on port %d\n", u8Port);
538
539 if (idxDevice < AHCI_MAX_STORAGE_DEVICES)
540 {
541 /* Device detected, enable FIS receive. */
542 ahci_ctrl_set_bits(u16IoBase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
543 AHCI_REG_PORT_CMD_FRE);
544
545 /* Check signature to determine device type. */
546 VBOXAHCI_PORT_READ_REG(u16IoBase, u8Port, AHCI_REG_PORT_SIG, val);
547 if (val == 0x101L)
548 {
549 uint8_t idxHdCurr;
550 uint32_t cSectors;
551 uint8_t abBuffer[0x0200];
552 uint8_t fRemovable;
553 uint16_t cCylinders, cHeads, cSectorsPerTrack;
554 uint8_t cHardDisksOld;
555 uint8_t idxCmosChsBase;
556
557 idxHdCurr = read_byte(ahci_seg, (uint16_t)&AhciData->cHardDisks);
558 VBOXAHCI_DEBUG("AHCI: Detected hard disk\n");
559
560 /* Identify device. */
561 ahci_cmd_data(ahci_seg, u16IoBase, ATA_CMD_IDENTIFY_DEVICE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &abBuffer, sizeof(abBuffer), 0);
562
563 write_byte(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].port, u8Port);
564
565 fRemovable = *(abBuffer+0) & 0x80 ? 1 : 0;
566 cCylinders = *(uint16_t *)(abBuffer+(1*2)); // word 1
567 cHeads = *(uint16_t *)(abBuffer+(3*2)); // word 3
568 cSectorsPerTrack = *(uint16_t *)(abBuffer+(6*2)); // word 6
569 cSectors = *(uint32_t *)(abBuffer+(60*2)); // word 60 and word 61
570
571 /** @todo update sectors to be a 64 bit number (also lba...). */
572 if (cSectors == 268435455)
573 cSectors = *(uint16_t *)(abBuffer+(100*2)); // words 100 to 103 (someday)
574
575 VBOXAHCI_DEBUG("AHCI: %ld sectors\n", cSectors);
576
577 write_byte(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].device,ATA_DEVICE_HD);
578 write_byte(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].removable, fRemovable);
579 write_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].blksize, 512);
580 write_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].pchs.heads, cHeads);
581 write_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].pchs.cylinders, cCylinders);
582 write_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].pchs.spt, cSectorsPerTrack);
583 write_dword(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].cSectors, cSectors);
584
585 /* Get logical CHS geometry. */
586 switch (idxDevice)
587 {
588 case 0:
589 idxCmosChsBase = 0x40;
590 break;
591 case 1:
592 idxCmosChsBase = 0x48;
593 break;
594 case 2:
595 idxCmosChsBase = 0x50;
596 break;
597 case 3:
598 idxCmosChsBase = 0x58;
599 break;
600 default:
601 idxCmosChsBase = 0;
602 }
603 if (idxCmosChsBase != 0)
604 {
605 cCylinders = inb_cmos(idxCmosChsBase) + (inb_cmos(idxCmosChsBase+1) << 8);
606 cHeads = inb_cmos(idxCmosChsBase+2);
607 cSectorsPerTrack = inb_cmos(idxCmosChsBase+7);
608 }
609 else
610 {
611 cCylinders = 0;
612 cHeads = 0;
613 cSectorsPerTrack = 0;
614 }
615 VBOXAHCI_DEBUG("AHCI: Dev %d LCHS=%d/%d/%d\n",
616 idxDevice, cCylinders, cHeads, cSectorsPerTrack);
617 write_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.heads, cHeads);
618 write_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.cylinders, cCylinders);
619 write_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.spt, cSectorsPerTrack);
620
621 write_byte(ahci_seg, (uint16_t)&AhciData->aHdIdMap[idxHdCurr], idxDevice);
622 idxHdCurr++;
623 write_byte(ahci_seg, (uint16_t)&AhciData->cHardDisks, idxHdCurr);
624
625 /* Update hdcount in the BDA. */
626 cHardDisksOld = read_byte(0x40, 0x75);
627 cHardDisksOld++;
628 write_byte(0x40, 0x75, cHardDisksOld);
629 }
630 else if (val == 0xeb140101)
631 {
632 VBOXAHCI_DEBUG("AHCI: Detected ATAPI device\n");
633 }
634 else
635 VBOXAHCI_DEBUG("AHCI: Ignoring unknown device\n");
636
637 idxDevice++;
638 write_byte(ahci_seg, (uint16_t)&AhciData->cDevices, idxDevice);
639 }
640 else
641 VBOXAHCI_DEBUG("AHCI: Reached maximum device count, skipping\n");
642 }
643}
644
645#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
646
647/**
648 * Int 13 handler.
649 */
650void BIOSCALL ahci_int13(volatile uint16_t RET, volatile uint16_t ES, volatile uint16_t DS, volatile uint16_t DI,
651 volatile uint16_t SI, volatile uint16_t BP, volatile uint16_t SP, volatile uint16_t BX,
652 volatile uint16_t DX, volatile uint16_t CX, volatile uint16_t AX, volatile uint16_t IPIRET,
653 volatile uint16_t CSIRET, volatile uint16_t FLAGSIRET, volatile uint16_t IP,
654 volatile uint16_t CS, volatile uint16_t FLAGS)
655{
656 uint16_t ebda_seg;
657 uint16_t ahci_seg, u16IoBase;
658 uint8_t idxDevice;
659 uint8_t old_disks;
660 uint8_t u8Port;
661
662 uint32_t lba;
663 uint16_t cylinder, head, sector;
664 uint16_t segment, offset;
665 uint16_t npc, nph, npspt, nlc, nlh, nlspt;
666 uint16_t count;
667// uint16_t size;
668 uint8_t status;
669
670 VBOXAHCI_INT13_DEBUG("ahci_int13 AX=%x CX=%x DX=%x BX=%x ES=%x SP=%x BP=%x SI=%x DI=%x IP=%x CS=%x FLAGS=%x\n",
671 AX, CX, DX, BX, ES, SP, BP, SI, DI, IP, CS, FLAGS);
672
673 ebda_seg = read_word(0x0040, 0x000E);
674 ahci_seg = read_word(ebda_seg, (uint16_t)&EbdaData->ahci_seg);
675 u16IoBase = read_word(ahci_seg, (uint16_t)&AhciData->iobase);
676 old_disks = read_byte(ahci_seg, (uint16_t)&AhciData->cHardDisksOld);
677 VBOXAHCI_INT13_DEBUG("ahci_int13: ahci_seg=%x u16IoBase=%x old_disks=%d\n", ahci_seg, u16IoBase, old_disks);
678
679 /* Check if the device is controlled by us first. */
680 if ( (GET_DL() < 0x80)
681 || (GET_DL() < 0x80 + old_disks)
682 || ((GET_DL() & 0xe0) != 0x80) /* No CD-ROM drives supported for now */)
683 {
684 VBOXAHCI_INT13_DEBUG("ahci_int13: device not controlled by us, forwarding to old handler (%d)\n", old_disks);
685 /* Fill the iret frame to jump to the old handler. */
686 IPIRET = read_word(ahci_seg, (uint16_t)&AhciData->pfnInt13Old);
687 CSIRET = 0xf000;
688 FLAGSIRET = FLAGS;
689 RET = 1;
690 return;
691 }
692
693 //@todo: pre-init aHdIdMap!
694 idxDevice = read_byte(ahci_seg, (uint16_t)&AhciData->aHdIdMap[GET_DL() - 0x80 - old_disks]);
695
696 if (idxDevice >= AHCI_MAX_STORAGE_DEVICES)
697 {
698 VBOXAHCI_INT13_DEBUG("ahci_int13: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_DL());
699 goto ahci_int13_fail;
700 }
701
702 u8Port = read_byte(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].port);
703
704 switch (GET_AH())
705 {
706 case 0x00: /* disk controller reset */
707 {
708 /** @todo: not really important I think. */
709 goto ahci_int13_success;
710 break;
711 }
712 case 0x01: /* read disk status */
713 {
714 status = read_byte(0x0040, 0x0074);
715 SET_AH(status);
716 SET_DISK_RET_STATUS(0);
717 /* set CF if error status read */
718 if (status)
719 goto ahci_int13_fail_nostatus;
720 else
721 goto ahci_int13_success_noah;
722 break;
723 }
724 case 0x02: // read disk sectors
725 case 0x03: // write disk sectors
726 case 0x04: // verify disk sectors
727 {
728 count = GET_AL();
729 cylinder = GET_CH();
730 cylinder |= ( ((uint16_t) GET_CL()) << 2) & 0x300;
731 sector = (GET_CL() & 0x3f);
732 head = GET_DH();
733
734 segment = ES;
735 offset = BX;
736
737 if ((count > 128) || (count == 0))
738 {
739 BX_INFO("ahci_int13: function %02x, count out of range!\n",GET_AH());
740 goto ahci_int13_fail;
741 }
742
743 nlc = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.cylinders);
744 nlh = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.heads);
745 nlspt = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.spt);
746
747 // sanity check on cyl heads, sec
748 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt ))
749 {
750 BX_INFO("ahci_int13: function %02x, disk %02x, idx %02x, parameters out of range %04x/%04x/%04x!\n",
751 GET_AH(), GET_DL(), idxDevice, cylinder, head, sector);
752 goto ahci_int13_fail;
753 }
754
755 // FIXME verify
756 if ( GET_AH() == 0x04 )
757 goto ahci_int13_success;
758
759 lba = ((((uint32_t)cylinder * (uint32_t)nlh) + (uint32_t)head) * (uint32_t)nlspt) + (uint32_t)sector - 1;
760
761 status = 0;
762 if ( GET_AH() == 0x02 )
763 ahci_cmd_data_in(ahci_seg, u16IoBase, u8Port, AHCI_CMD_READ_DMA_EXT, lba, count, segment, offset);
764 else
765 ahci_cmd_data_out(ahci_seg, u16IoBase, u8Port, AHCI_CMD_WRITE_DMA_EXT, lba, count, segment, offset);
766
767 // Set nb of sector transferred
768 SET_AL(read_word(ebda_seg, (uint16_t)&EbdaData->ata.trsfsectors));
769
770 if (status != 0)
771 {
772 BX_INFO("ahci_int13: function %02x, error %02x !\n",GET_AH(),status);
773 SET_AH(0x0c);
774 goto ahci_int13_fail_noah;
775 }
776
777 goto ahci_int13_success;
778 break;
779 }
780 case 0x05: /* format disk track */
781 BX_INFO("format disk track called\n");
782 goto ahci_int13_success;
783 break;
784 case 0x08: /* read disk drive parameters */
785 {
786 // Get logical geometry from table
787 nlc = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.cylinders);
788 nlh = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.heads);
789 nlspt = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].lchs.spt);
790
791 count = read_byte(ahci_seg, (uint16_t)&AhciData->cHardDisks); /** @todo correct? */
792 /* Maximum cylinder number is just one less than the number of cylinders. */
793 nlc = nlc - 1; /* 0 based , last sector not used */
794 SET_AL(0);
795 SET_CH(nlc & 0xff);
796 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
797 SET_DH(nlh - 1);
798 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
799 // FIXME should set ES & DI
800 goto ahci_int13_success;
801 break;
802 }
803 case 0x10: /* check drive ready */
804 {
805 /** @todo */
806 goto ahci_int13_success;
807 break;
808 }
809 case 0x15: /* read disk drive size */
810 {
811 // Get physical geometry from table
812 npc = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].pchs.cylinders);
813 nph = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].pchs.heads);
814 npspt = read_word(ahci_seg, (uint16_t)&AhciData->aDevices[idxDevice].pchs.spt);
815
816 // Compute sector count seen by int13
817 lba = (uint32_t)npc * (uint32_t)nph * (uint32_t)npspt;
818 CX = lba >> 16;
819 DX = lba & 0xffff;
820
821 SET_AH(3); // hard disk accessible
822 goto ahci_int13_success_noah;
823 break;
824 }
825#if 0
826 case 0x41: // IBM/MS installation check
827 {
828 BX=0xaa55; // install check
829 SET_AH(0x30); // EDD 3.0
830 CX=0x0007; // ext disk access and edd, removable supported
831 goto ahci_int13_success_noah;
832 break;
833 }
834 case 0x42: // IBM/MS extended read
835 case 0x43: // IBM/MS extended write
836 case 0x44: // IBM/MS verify
837 case 0x47: // IBM/MS extended seek
838 {
839 count=read_word(DS, SI+(uint16_t)&Int13Ext->count);
840 segment=read_word(DS, SI+(uint16_t)&Int13Ext->segment);
841 offset=read_word(DS, SI+(uint16_t)&Int13Ext->offset);
842
843 // Can't use 64 bits lba
844 lba=read_dword(DS, SI+(uint16_t)&Int13Ext->lba2);
845 if (lba != 0L)
846 {
847 BX_PANIC("ahci_int13: function %02x. Can't use 64bits lba\n",GET_AH());
848 goto ahci_int13_fail;
849 }
850
851 // Get 32 bits lba and check
852 lba=read_dword(DS, SI+(uint16_t)&Int13Ext->lba1);
853
854 if (lba >= read_word(ahci_seg, &AhciData->aDevices[idxDevice].cSectors) )
855 {
856 BX_INFO("ahci_int13: function %02x. LBA out of range\n",GET_AH());
857 goto ahci_int13_fail;
858 }
859
860 // If verify or seek
861 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
862 goto ahci_int13_success;
863
864 // Execute the command
865 if ( GET_AH() == 0x42 )
866 {
867 if (lba + count >= 268435456)
868 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
869 else
870 {
871 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
872 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, 0, 0, 0, lba, segment, offset);
873 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
874 }
875 }
876 else
877 {
878 if (lba + count >= 268435456)
879 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
880 else
881 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
882 }
883
884 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
885 write_word(DS, SI+(uint16_t)&Int13Ext->count, count);
886
887 if (status != 0)
888 {
889 BX_INFO("ahci_int13: function %02x, error %02x !\n",GET_AH(),status);
890 SET_AH(0x0c);
891 goto ahci_int13_fail_noah;
892 }
893 goto ahci_int13_success;
894 break;
895 }
896 case 0x45: // IBM/MS lock/unlock drive
897 case 0x49: // IBM/MS extended media change
898 goto ahci_int13_success; // Always success for HD
899 break;
900 case 0x46: // IBM/MS eject media
901 SET_AH(0xb2); // Volume Not Removable
902 goto ahci_int13_fail_noah; // Always fail for HD
903 break;
904
905 case 0x48: // IBM/MS get drive parameters
906 size=read_word(DS,SI+(uint16_t)&Int13DPT->size);
907
908 // Buffer is too small
909 if(size < 0x1a)
910 goto ahci_int13_fail;
911
912 // EDD 1.x
913 if(size >= 0x1a)
914 {
915 uint16_t blksize;
916
917 npc = read_word(ahci_seg, &AhciData->aDevices[idxDevice].pchs.cylinders);
918 nph = read_word(ahci_seg, &AhciData->aDevices[idxDevice].pchs.heads);
919 npspt = read_word(ahci_seg, &AhciData->aDevices[idxDevice].pchs.spt);
920 lba = read_dword(ahci_seg, &AhciData->aDevices[idxDevice].cSectors);
921 blksize = read_word(ahci_seg, &AhciData->aDevices[idxDevice].blksize);
922
923 write_word(DS, SI+(uint16_t)&Int13DPT->size, 0x1a);
924 write_word(DS, SI+(uint16_t)&Int13DPT->infos, 0x02); // geometry is valid
925 write_dword(DS, SI+(uint16_t)&Int13DPT->cylinders, (uint32_t)npc);
926 write_dword(DS, SI+(uint16_t)&Int13DPT->heads, (uint32_t)nph);
927 write_dword(DS, SI+(uint16_t)&Int13DPT->spt, (uint32_t)npspt);
928 write_dword(DS, SI+(uint16_t)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
929 write_dword(DS, SI+(uint16_t)&Int13DPT->sector_count2, 0L);
930 write_word(DS, SI+(uint16_t)&Int13DPT->blksize, blksize);
931 }
932
933#if 0 /* Disable EDD 2.X and 3.x for now, don't know if it is required by any OS loader yet */
934 // EDD 2.x
935 if(size >= 0x1e)
936 {
937 uint8_t channel, dev, irq, mode, checksum, i, translation;
938 uint16_t iobase1, iobase2, options;
939
940 translation = ATA_TRANSLATION_LBA;
941
942 write_word(DS, SI+(uint16_t)&Int13DPT->size, 0x1e);
943
944 write_word(DS, SI+(uint16_t)&Int13DPT->dpte_segment, ebda_seg);
945 write_word(DS, SI+(uint16_t)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
946
947 // Fill in dpte
948 channel = device / 2;
949 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
950 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
951 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
952 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
953 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
954
955 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
956 options |= (1<<4); // lba translation
957 options |= (mode==ATA_MODE_PIO32?1:0<<7);
958 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
959 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
960
961 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
962 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
963 //write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | /*(device % 2))<<4*/ );
964 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
965 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
966 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
967 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
968 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
969 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
970 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
971 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
972
973 checksum=0;
974 for (i=0; i<15; i++)
975 checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
976
977 checksum = -checksum;
978 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
979 }
980
981 // EDD 3.x
982 if(size >= 0x42)
983 {
984 uint8_t channel, iface, checksum, i;
985 uint16_t iobase1;
986
987 channel = device / 2;
988 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
989 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
990
991 write_word(DS, SI+(uint16_t)&Int13DPT->size, 0x42);
992 write_word(DS, SI+(uint16_t)&Int13DPT->key, 0xbedd);
993 write_byte(DS, SI+(uint16_t)&Int13DPT->dpi_length, 0x24);
994 write_byte(DS, SI+(uint16_t)&Int13DPT->reserved1, 0);
995 write_word(DS, SI+(uint16_t)&Int13DPT->reserved2, 0);
996
997 if (iface==ATA_IFACE_ISA) {
998 write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[0], 'I');
999 write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[1], 'S');
1000 write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[2], 'A');
1001 write_byte(DS, SI+(uint16_t)&Int13DPT->host_bus[3], 0);
1002 }
1003 else {
1004 // FIXME PCI
1005 }
1006 write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[0], 'A');
1007 write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[1], 'T');
1008 write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[2], 'A');
1009 write_byte(DS, SI+(uint16_t)&Int13DPT->iface_type[3], 0);
1010
1011 if (iface==ATA_IFACE_ISA) {
1012 write_word(DS, SI+(uint16_t)&Int13DPT->iface_path[0], iobase1);
1013 write_word(DS, SI+(uint16_t)&Int13DPT->iface_path[2], 0);
1014 write_dword(DS, SI+(uint16_t)&Int13DPT->iface_path[4], 0L);
1015 }
1016 else {
1017 // FIXME PCI
1018 }
1019 //write_byte(DS, SI+(uint16_t)&Int13DPT->device_path[0], device%2);
1020 write_byte(DS, SI+(uint16_t)&Int13DPT->device_path[1], 0);
1021 write_word(DS, SI+(uint16_t)&Int13DPT->device_path[2], 0);
1022 write_dword(DS, SI+(uint16_t)&Int13DPT->device_path[4], 0L);
1023
1024 checksum=0;
1025 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
1026 checksum = -checksum;
1027 write_byte(DS, SI+(uint16_t)&Int13DPT->checksum, checksum);
1028 }
1029#endif
1030 goto ahci_int13_success;
1031 break;
1032 case 0x4e: // // IBM/MS set hardware configuration
1033 // DMA, prefetch, PIO maximum not supported
1034 switch (GET_AL())
1035 {
1036 case 0x01:
1037 case 0x03:
1038 case 0x04:
1039 case 0x06:
1040 goto ahci_int13_success;
1041 break;
1042 default :
1043 goto ahci_int13_fail;
1044 }
1045 break;
1046#endif
1047 case 0x09: /* initialize drive parameters */
1048 case 0x0c: /* seek to specified cylinder */
1049 case 0x0d: /* alternate disk reset */
1050 case 0x11: /* recalibrate */
1051 case 0x14: /* controller internal diagnostic */
1052 BX_INFO("ahci_int13: function %02xh unimplemented, returns success\n", GET_AH());
1053 goto ahci_int13_success;
1054 break;
1055
1056 case 0x0a: /* read disk sectors with ECC */
1057 case 0x0b: /* write disk sectors with ECC */
1058 case 0x18: // set media type for format
1059 case 0x50: // IBM/MS send packet command
1060 default:
1061 BX_INFO("ahci_int13: function %02xh unsupported, returns fail\n", GET_AH());
1062 goto ahci_int13_fail;
1063 break;
1064 }
1065
1066 //@todo: this is really badly written, reuse the code more!
1067ahci_int13_fail:
1068 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
1069ahci_int13_fail_noah:
1070 SET_DISK_RET_STATUS(GET_AH());
1071ahci_int13_fail_nostatus:
1072 VBOXAHCI_INT13_DEBUG("ahci_int13: done, AH=%02x\n", GET_AH());
1073 SET_CF(); // error occurred
1074 return;
1075
1076ahci_int13_success:
1077 SET_AH(0x00); // no error
1078ahci_int13_success_noah:
1079 SET_DISK_RET_STATUS(0x00);
1080 VBOXAHCI_INT13_DEBUG("ahci_int13: done, AH=%02x\n", GET_AH());
1081 CLEAR_CF(); // no error
1082 return;
1083}
1084
1085#undef SET_DISK_RET_STATUS
1086
1087/* Defined in assembler code. */
1088extern void ahci_int13_handler(void);
1089#pragma aux ahci_int13_handler "*";
1090
1091/**
1092 * Install the in13 interrupt handler
1093 * preserving the previous one.
1094 */
1095static void ahci_install_int_handler(uint16_t ahci_seg)
1096{
1097
1098 uint16_t pfnInt13Old;
1099
1100 VBOXAHCI_DEBUG("AHCI: Hooking int 13h vector\n");
1101
1102 /* Read the old interrupt handler. */
1103 pfnInt13Old = read_word(0x0000, 0x0013*4);
1104 write_word(ahci_seg, (uint16_t)&AhciData->pfnInt13Old, pfnInt13Old);
1105
1106 /* Set our own */
1107 write_word(0x0000, 0x0013*4, (uint16_t)ahci_int13_handler);
1108}
1109
1110/**
1111 * Allocates 1K from the base memory.
1112 */
1113static uint16_t ahci_mem_alloc(void)
1114{
1115 uint16_t base_mem_kb;
1116 uint16_t ahci_seg;
1117
1118 base_mem_kb = read_word(0x00, 0x0413);
1119
1120 VBOXAHCI_DEBUG("AHCI: %dK of base mem\n", base_mem_kb);
1121
1122 if (base_mem_kb == 0)
1123 return 0;
1124
1125 base_mem_kb--; /* Allocate one block. */
1126 ahci_seg = (((uint32_t)base_mem_kb * 1024) >> 4); /* Calculate start segment. */
1127
1128 write_word(0x00, 0x0413, base_mem_kb);
1129
1130 return ahci_seg;
1131}
1132
1133/**
1134 * Initializes the AHCI HBA and detects attached devices.
1135 */
1136static int ahci_hba_init(uint16_t u16IoBase)
1137{
1138 uint8_t i, cPorts;
1139 uint32_t val;
1140 uint16_t ebda_seg;
1141 uint16_t ahci_seg;
1142
1143 ebda_seg = read_word(0x0040, 0x000E);
1144
1145 AHCI_READ_REG(u16IoBase, AHCI_REG_VS, val);
1146 VBOXAHCI_DEBUG("AHCI: Controller has version: 0x%x (major) 0x%x (minor)\n",
1147 ahci_ctrl_extract_bits(val, 0xffff0000, 16),
1148 ahci_ctrl_extract_bits(val, 0x0000ffff, 0));
1149
1150 /* Allocate 1K of base memory. */
1151 ahci_seg = ahci_mem_alloc();
1152 if (ahci_seg == 0)
1153 {
1154 VBOXAHCI_DEBUG("AHCI: Could not allocate 1K of memory, can't boot from controller\n");
1155 return 0;
1156 }
1157 VBOXAHCI_DEBUG("AHCI: ahci_seg=%04x, size=%04x, pointer at EBDA:%04x (EBDA size=%04x)\n",
1158 ahci_seg, sizeof(ahci_t), (uint16_t)&EbdaData->ahci_seg, sizeof(ebda_data_t));
1159
1160 write_word(ebda_seg, (uint16_t)&EbdaData->ahci_seg, ahci_seg);
1161 write_byte(ahci_seg, (uint16_t)&AhciData->port, 0xff);
1162 write_word(ahci_seg, (uint16_t)&AhciData->iobase, u16IoBase);
1163 write_byte(ahci_seg, (uint16_t)&AhciData->cHardDisksOld, read_byte(0x40, 0x75));
1164
1165 /* Reset the controller. */
1166 ahci_ctrl_set_bits(u16IoBase, AHCI_REG_GHC, AHCI_GHC_HR);
1167 do
1168 {
1169 AHCI_READ_REG(u16IoBase, AHCI_REG_GHC, val);
1170 } while (val & AHCI_GHC_HR != 0);
1171
1172 AHCI_READ_REG(u16IoBase, AHCI_REG_CAP, val);
1173 cPorts = ahci_ctrl_extract_bits(val, 0x1f, 0) + 1; /* Extract number of ports.*/
1174
1175 VBOXAHCI_DEBUG("AHCI: HBA has %u ports\n", cPorts);
1176
1177 /* Go through the ports. */
1178 i = 0;
1179 while (i < 32)
1180 {
1181 if (ahci_ctrl_is_bit_set(u16IoBase, AHCI_REG_PI, RT_BIT_32(i)) != 0)
1182 {
1183 VBOXAHCI_DEBUG("AHCI: Port %u is present\n", i);
1184 ahci_port_detect_device(ahci_seg, u16IoBase, i);
1185 cPorts--;
1186 if (cPorts == 0)
1187 break;
1188 }
1189 i++;
1190 }
1191
1192 if (read_byte(ahci_seg, (uint16_t)&AhciData->cDevices) > 0)
1193 {
1194 /*
1195 * Init completed and there is at least one device present.
1196 * Install our int13 handler.
1197 */
1198 ahci_install_int_handler(ahci_seg);
1199 }
1200
1201 return 0;
1202}
1203
1204/**
1205 * Init the AHCI driver and detect attached disks.
1206 */
1207void BIOSCALL ahci_init(void)
1208{
1209 uint16_t busdevfn;
1210
1211 busdevfn = pci_find_classcode(0x00010601);
1212 if (busdevfn != VBOX_AHCI_NO_DEVICE)
1213 {
1214 uint8_t u8Bus, u8DevFn;
1215 uint8_t u8PciCapOff;
1216
1217 u8Bus = (busdevfn & 0xff00) >> 8;
1218 u8DevFn = busdevfn & 0x00ff;
1219
1220 VBOXAHCI_DEBUG("AHCI HBA at Bus %u DevFn 0x%x (raw 0x%x)\n", u8Bus, u8DevFn, busdevfn);
1221
1222 /* Examine the capability list and search for the Serial ATA Capability Register. */
1223 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, PCI_CONFIG_CAP);
1224
1225 while (u8PciCapOff != 0)
1226 {
1227 uint8_t u8PciCapId = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
1228
1229 VBOXAHCI_DEBUG("Capability ID 0x%x at 0x%x\n", u8PciCapId, u8PciCapOff);
1230
1231 if (u8PciCapId == PCI_CAP_ID_SATACR)
1232 break;
1233
1234 /* Go on to the next capability. */
1235 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1);
1236 }
1237
1238 if (u8PciCapOff != 0)
1239 {
1240 uint8_t u8Rev;
1241
1242 VBOXAHCI_DEBUG("AHCI HBA with SATA Capability register at 0x%x\n", u8PciCapOff);
1243
1244 /* Advance to the stuff behind the id and next capability pointer. */
1245 u8PciCapOff += 2;
1246
1247 u8Rev = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
1248 if (u8Rev == 0x10)
1249 {
1250 /* Read the SATACR1 register and get the bar and offset of the index/data pair register. */
1251 uint8_t u8Bar = 0x00;
1252 uint16_t u16Off = 0x00;
1253 uint16_t u16BarOff = pci_read_config_word(u8Bus, u8DevFn, u8PciCapOff + 2);
1254
1255 VBOXAHCI_DEBUG("SATACR1: 0x%x\n", u16BarOff);
1256
1257 switch (u16BarOff & 0xf)
1258 {
1259 case 0x04:
1260 u8Bar = 0x10;
1261 break;
1262 case 0x05:
1263 u8Bar = 0x14;
1264 break;
1265 case 0x06:
1266 u8Bar = 0x18;
1267 break;
1268 case 0x07:
1269 u8Bar = 0x1c;
1270 break;
1271 case 0x08:
1272 u8Bar = 0x20;
1273 break;
1274 case 0x09:
1275 u8Bar = 0x24;
1276 break;
1277 case 0x0f:
1278 default:
1279 /* Reserved or unsupported. */
1280 VBOXAHCI_DEBUG("BAR 0x%x unsupported\n", u16BarOff & 0xf);
1281 }
1282
1283 /* Get the offset inside the BAR from bits 4:15. */
1284 u16Off = (u16BarOff >> 4) * 4;
1285
1286 if (u8Bar != 0x00)
1287 {
1288 uint32_t u32Bar = pci_read_config_dword(u8Bus, u8DevFn, u8Bar);
1289
1290 VBOXAHCI_DEBUG("BAR at 0x%x : 0x%x\n", u8Bar, u32Bar);
1291
1292 if ((u32Bar & 0x01) != 0)
1293 {
1294 int rc;
1295 uint16_t u16AhciIoBase = (u32Bar & 0xfff0) + u16Off;
1296
1297 VBOXAHCI_DEBUG("I/O base: 0x%x\n", u16AhciIoBase);
1298 rc = ahci_hba_init(u16AhciIoBase);
1299 }
1300 else
1301 VBOXAHCI_DEBUG("BAR is MMIO\n");
1302 }
1303 }
1304 else
1305 VBOXAHCI_DEBUG("Invalid revision 0x%x\n", u8Rev);
1306 }
1307 else
1308 VBOXAHCI_DEBUG("AHCI HBA with no usable Index/Data register pair!\n");
1309 }
1310 else
1311 VBOXAHCI_DEBUG("No AHCI HBA!\n");
1312}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette