VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/ahci.c@ 89364

Last change on this file since 89364 was 89364, checked in by vboxsync, 4 years ago

Devices/PC/BIOS: Remove the skip_b,skip_a mechanism as it is unused now making the device drivers lss complex, bugref:4841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 KB
Line 
1/* $Id: ahci.c 89364 2021-05-28 15:44:38Z vboxsync $ */
2/** @file
3 * AHCI host adapter driver to boot from SATA disks.
4 */
5
6/*
7 * Copyright (C) 2011-2020 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#include <stdint.h>
19#include <string.h>
20#include "biosint.h"
21#include "ebda.h"
22#include "inlines.h"
23#include "pciutil.h"
24#include "vds.h"
25
26#if DEBUG_AHCI
27# define DBG_AHCI(...) BX_INFO(__VA_ARGS__)
28#else
29# define DBG_AHCI(...)
30#endif
31
32/* Number of S/G table entries in EDDS. */
33#define NUM_EDDS_SG 16
34
35
36/**
37 * AHCI PRDT structure.
38 */
39typedef struct
40{
41 uint32_t phys_addr;
42 uint32_t something;
43 uint32_t reserved;
44 uint32_t len;
45} ahci_prdt;
46
47/**
48 * SATA D2H FIS (Device to Host Frame Information Structure).
49 */
50typedef struct {
51 uint8_t fis_type; /* 34h */
52 uint8_t intr; /* Bit 6 indicates interrupt status. */
53 uint8_t status; /* Status register. */
54 uint8_t error; /* Error register. */
55 uint8_t sec_no; /* Sector number register. */
56 uint8_t cyl_lo; /* Cylinder low register. */
57 uint8_t cyl_hi; /* Cylinder high register. */
58 uint8_t dev_hd; /* Device/head register. */
59 uint8_t sec_no_exp; /* Expanded sector number register. */
60 uint8_t cyl_lo_exp; /* Expanded cylinder low register. */
61 uint8_t cyl_hi_exp; /* Expanded cylinder high register. */
62 uint8_t resvd0;
63 uint8_t sec_cn; /* Sector count register. */
64 uint8_t sec_cn_exp; /* Expanded sector count register. */
65 uint16_t resvd1;
66 uint32_t resvd2;
67} fis_d2h;
68
69ct_assert(sizeof(fis_d2h) == 20);
70
71/**
72 * AHCI controller data.
73 */
74typedef struct
75{
76 /** The AHCI command list as defined by chapter 4.2.2 of the Intel AHCI spec.
77 * Because the BIOS doesn't support NCQ only the first command header is defined
78 * to save memory. - Must be aligned on a 1K boundary.
79 */
80 uint32_t aCmdHdr[0x8];
81 /** Align the next structure on a 128 byte boundary. */
82 uint8_t abAlignment1[0x60];
83 /** The command table of one request as defined by chapter 4.2.3 of the Intel AHCI spec.
84 * Must be aligned on 128 byte boundary.
85 */
86 uint8_t abCmd[0x40];
87 /** The ATAPI command region.
88 * Located 40h bytes after the beginning of the CFIS (Command FIS).
89 */
90 uint8_t abAcmd[0x20];
91 /** Align the PRDT structure on a 128 byte boundary. */
92 uint8_t abAlignment2[0x20];
93 /** Physical Region Descriptor Table (PRDT) array. In other
94 * words, a scatter/gather descriptor list.
95 */
96 ahci_prdt aPrdt[16];
97 /** Memory for the received command FIS area as specified by chapter 4.2.1
98 * of the Intel AHCI spec. This area is normally 256 bytes big but to save memory
99 * only the first 96 bytes are used because it is assumed that the controller
100 * never writes to the UFIS or reserved area. - Must be aligned on a 256byte boundary.
101 */
102 uint8_t abFisRecv[0x60];
103 /** Base I/O port for the index/data register pair. */
104 uint16_t iobase;
105 /** Current port which uses the memory to communicate with the controller. */
106 uint8_t cur_port;
107 /** Current PRD index (for pre/post skip). */
108 uint8_t cur_prd;
109 /** Saved high bits of EAX. */
110 uint16_t saved_eax_hi;
111 /** VDS EDDS DMA buffer descriptor structure. */
112 vds_edds edds;
113 vds_sg edds_more_sg[NUM_EDDS_SG - 1];
114} ahci_t;
115
116/* The AHCI specific data must fit into 1KB (statically allocated). */
117ct_assert(sizeof(ahci_t) <= 1024);
118
119/** PCI configuration fields. */
120#define PCI_CONFIG_CAP 0x34
121
122#define PCI_CAP_ID_SATACR 0x12
123#define VBOX_AHCI_NO_DEVICE 0xffff
124
125#define RT_BIT_32(bit) ((uint32_t)(1L << (bit)))
126
127/** Global register set. */
128#define AHCI_HBA_SIZE 0x100
129
130/// @todo what are the casts good for?
131#define AHCI_REG_CAP ((uint32_t)0x00)
132#define AHCI_REG_GHC ((uint32_t)0x04)
133# define AHCI_GHC_AE RT_BIT_32(31)
134# define AHCI_GHC_IR RT_BIT_32(1)
135# define AHCI_GHC_HR RT_BIT_32(0)
136#define AHCI_REG_IS ((uint32_t)0x08)
137#define AHCI_REG_PI ((uint32_t)0x0c)
138#define AHCI_REG_VS ((uint32_t)0x10)
139
140/** Per port register set. */
141#define AHCI_PORT_SIZE 0x80
142
143#define AHCI_REG_PORT_CLB 0x00
144#define AHCI_REG_PORT_CLBU 0x04
145#define AHCI_REG_PORT_FB 0x08
146#define AHCI_REG_PORT_FBU 0x0c
147#define AHCI_REG_PORT_IS 0x10
148# define AHCI_REG_PORT_IS_DHRS RT_BIT_32(0)
149# define AHCI_REG_PORT_IS_TFES RT_BIT_32(30)
150#define AHCI_REG_PORT_IE 0x14
151#define AHCI_REG_PORT_CMD 0x18
152# define AHCI_REG_PORT_CMD_ST RT_BIT_32(0)
153# define AHCI_REG_PORT_CMD_FRE RT_BIT_32(4)
154# define AHCI_REG_PORT_CMD_FR RT_BIT_32(14)
155# define AHCI_REG_PORT_CMD_CR RT_BIT_32(15)
156#define AHCI_REG_PORT_TFD 0x20
157#define AHCI_REG_PORT_SIG 0x24
158#define AHCI_REG_PORT_SSTS 0x28
159#define AHCI_REG_PORT_SCTL 0x2c
160#define AHCI_REG_PORT_SERR 0x30
161#define AHCI_REG_PORT_SACT 0x34
162#define AHCI_REG_PORT_CI 0x38
163
164/** Returns the absolute register offset from a given port and port register. */
165#define AHCI_PORT_REG(port, reg) (AHCI_HBA_SIZE + (port) * AHCI_PORT_SIZE + (reg))
166
167#define AHCI_REG_IDX 0
168#define AHCI_REG_DATA 4
169
170/** Writes the given value to a AHCI register. */
171#define AHCI_WRITE_REG(iobase, reg, val) \
172 outpd((iobase) + AHCI_REG_IDX, reg); \
173 outpd((iobase) + AHCI_REG_DATA, val)
174
175/** Reads from a AHCI register. */
176#define AHCI_READ_REG(iobase, reg, val) \
177 outpd((iobase) + AHCI_REG_IDX, reg); \
178 (val) = inpd((iobase) + AHCI_REG_DATA)
179
180/** Writes to the given port register. */
181#define VBOXAHCI_PORT_WRITE_REG(iobase, port, reg, val) \
182 AHCI_WRITE_REG((iobase), AHCI_PORT_REG((port), (reg)), val)
183
184/** Reads from the given port register. */
185#define VBOXAHCI_PORT_READ_REG(iobase, port, reg, val) \
186 AHCI_READ_REG((iobase), AHCI_PORT_REG((port), (reg)), val)
187
188#define ATA_CMD_IDENTIFY_DEVICE 0xEC
189#define ATA_CMD_IDENTIFY_PACKET 0xA1
190#define ATA_CMD_PACKET 0xA0
191#define AHCI_CMD_READ_DMA_EXT 0x25
192#define AHCI_CMD_WRITE_DMA_EXT 0x35
193
194
195/* Warning: Destroys high bits of EAX. */
196uint32_t inpd(uint16_t port);
197#pragma aux inpd = \
198 ".386" \
199 "in eax, dx" \
200 "mov dx, ax" \
201 "shr eax, 16" \
202 "xchg ax, dx" \
203 parm [dx] value [dx ax] modify nomemory;
204
205/* Warning: Destroys high bits of EAX. */
206void outpd(uint16_t port, uint32_t val);
207#pragma aux outpd = \
208 ".386" \
209 "xchg ax, cx" \
210 "shl eax, 16" \
211 "mov ax, cx" \
212 "out dx, eax" \
213 parm [dx] [cx ax] modify nomemory;
214
215
216/* Machinery to save/restore high bits of EAX. 32-bit port I/O needs to use
217 * EAX, but saving/restoring EAX around each port access would be inefficient.
218 * Instead, each externally callable routine must save the high bits before
219 * modifying them and restore the high bits before exiting.
220 */
221
222/* Note: Reading high EAX bits destroys them - *must* be restored later. */
223uint16_t eax_hi_rd(void);
224#pragma aux eax_hi_rd = \
225 ".386" \
226 "shr eax, 16" \
227 value [ax] modify nomemory;
228
229void eax_hi_wr(uint16_t);
230#pragma aux eax_hi_wr = \
231 ".386" \
232 "shl eax, 16" \
233 parm [ax] modify nomemory;
234
235void inline high_bits_save(ahci_t __far *ahci)
236{
237 ahci->saved_eax_hi = eax_hi_rd();
238}
239
240void inline high_bits_restore(ahci_t __far *ahci)
241{
242 eax_hi_wr(ahci->saved_eax_hi);
243}
244
245/**
246 * Sets a given set of bits in a register.
247 */
248static void inline ahci_ctrl_set_bits(uint16_t iobase, uint16_t reg, uint32_t mask)
249{
250 outpd(iobase + AHCI_REG_IDX, reg);
251 outpd(iobase + AHCI_REG_DATA, inpd(iobase + AHCI_REG_DATA) | mask);
252}
253
254/**
255 * Clears a given set of bits in a register.
256 */
257static void inline ahci_ctrl_clear_bits(uint16_t iobase, uint16_t reg, uint32_t mask)
258{
259 outpd(iobase + AHCI_REG_IDX, reg);
260 outpd(iobase + AHCI_REG_DATA, inpd(iobase + AHCI_REG_DATA) & ~mask);
261}
262
263/**
264 * Returns whether at least one of the bits in the given mask is set
265 * for a register.
266 */
267static uint8_t inline ahci_ctrl_is_bit_set(uint16_t iobase, uint16_t reg, uint32_t mask)
268{
269 outpd(iobase + AHCI_REG_IDX, reg);
270 return (inpd(iobase + AHCI_REG_DATA) & mask) != 0;
271}
272
273/**
274 * Extracts a range of bits from a register and shifts them
275 * to the right.
276 */
277static uint16_t ahci_ctrl_extract_bits(uint32_t val, uint32_t mask, uint8_t shift)
278{
279 return (val & mask) >> shift;
280}
281
282/**
283 * Converts a segment:offset pair into a 32bit physical address.
284 */
285static uint32_t ahci_addr_to_phys(void __far *ptr)
286{
287 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr);
288}
289
290/**
291 * Issues a command to the SATA controller and waits for completion.
292 */
293static void ahci_port_cmd_sync(ahci_t __far *ahci, uint8_t val)
294{
295 uint16_t io_base;
296 uint8_t port;
297
298 port = ahci->cur_port;
299 io_base = ahci->iobase;
300
301 if (port != 0xff)
302 {
303 /* Prepare the command header. */
304 ahci->aCmdHdr[0] = ((uint32_t)ahci->cur_prd << 16) | RT_BIT_32(7) | val;
305 ahci->aCmdHdr[1] = 0;
306 ahci->aCmdHdr[2] = ahci_addr_to_phys(&ahci->abCmd[0]);
307
308 /* Enable Command and FIS receive engine. */
309 ahci_ctrl_set_bits(io_base, AHCI_PORT_REG(port, AHCI_REG_PORT_CMD),
310 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST);
311
312 /* Queue command. */
313 VBOXAHCI_PORT_WRITE_REG(io_base, port, AHCI_REG_PORT_CI, 0x1);
314
315 /* Wait for a D2H FIS. */
316 DBG_AHCI("AHCI: Waiting for D2H FIS\n");
317 while (ahci_ctrl_is_bit_set(io_base, AHCI_PORT_REG(port, AHCI_REG_PORT_IS),
318 AHCI_REG_PORT_IS_DHRS | AHCI_REG_PORT_IS_TFES) == 0)
319 {
320 // This is where we'd need some kind of a yield functionality...
321 }
322
323 ahci_ctrl_set_bits(io_base, AHCI_PORT_REG(port, AHCI_REG_PORT_IS),
324 AHCI_REG_PORT_IS_DHRS); /* Acknowledge received D2H FIS. */
325
326 /* Disable command engine. */
327 ahci_ctrl_clear_bits(io_base, AHCI_PORT_REG(port, AHCI_REG_PORT_CMD),
328 AHCI_REG_PORT_CMD_ST);
329 /* Caller must examine status. */
330 }
331 else
332 DBG_AHCI("AHCI: Invalid port given\n");
333}
334
335/**
336 * Issue command to device.
337 */
338static uint16_t ahci_cmd_data(bio_dsk_t __far *bios_dsk, uint8_t cmd)
339{
340 ahci_t __far *ahci = bios_dsk->ahci_seg :> 0;
341 uint16_t n_sect = bios_dsk->drqp.nsect;
342 uint16_t sectsz = bios_dsk->drqp.sect_sz;
343 fis_d2h __far *d2h;
344
345 _fmemset(&ahci->abCmd[0], 0, sizeof(ahci->abCmd));
346
347 /* Prepare the FIS. */
348 ahci->abCmd[0] = 0x27; /* FIS type H2D. */
349 ahci->abCmd[1] = 1 << 7; /* Command update. */
350 ahci->abCmd[2] = cmd;
351 ahci->abCmd[3] = 0;
352
353 ahci->abCmd[4] = bios_dsk->drqp.lba & 0xff;
354 ahci->abCmd[5] = (bios_dsk->drqp.lba >> 8) & 0xff;
355 ahci->abCmd[6] = (bios_dsk->drqp.lba >> 16) & 0xff;
356 ahci->abCmd[7] = RT_BIT_32(6); /* LBA access. */
357
358 ahci->abCmd[8] = (bios_dsk->drqp.lba >> 24) & 0xff;
359 ahci->abCmd[9] = (bios_dsk->drqp.lba >> 32) & 0xff;
360 ahci->abCmd[10] = (bios_dsk->drqp.lba >> 40) & 0xff;
361 ahci->abCmd[11] = 0;
362
363 ahci->abCmd[12] = (uint8_t)(n_sect & 0xff);
364 ahci->abCmd[13] = (uint8_t)((n_sect >> 8) & 0xff);
365
366 /* Lock memory needed for DMA. */
367 ahci->edds.num_avail = NUM_EDDS_SG;
368 DBG_AHCI("AHCI: S/G list for %lu bytes\n", (uint32_t)n_sect * sectsz);
369 vds_build_sg_list(&ahci->edds, bios_dsk->drqp.buffer, (uint32_t)n_sect * sectsz);
370
371 /* Set up the PRDT. */
372 ahci->aPrdt[ahci->cur_prd].len = ahci->edds.u.sg[0].size - 1;
373 ahci->aPrdt[ahci->cur_prd].phys_addr = ahci->edds.u.sg[0].phys_addr;
374 ++ahci->cur_prd;
375
376#if DEBUG_AHCI
377 {
378 uint16_t prdt_idx;
379
380 for (prdt_idx = 0; prdt_idx < ahci->cur_prd; ++prdt_idx) {
381 DBG_AHCI("S/G entry %u: %5lu bytes @ %08lX\n", prdt_idx,
382 ahci->aPrdt[prdt_idx].len + 1, ahci->aPrdt[prdt_idx].phys_addr);
383 }
384 }
385#endif
386
387 /* Build variable part of first command DWORD (reuses 'cmd'). */
388 if (cmd == AHCI_CMD_WRITE_DMA_EXT)
389 cmd = RT_BIT_32(6); /* Indicate a write to device. */
390 else if (cmd == ATA_CMD_PACKET) {
391 cmd |= RT_BIT_32(5); /* Indicate ATAPI command. */
392 ahci->abCmd[3] |= 1; /* DMA transfers. */
393 } else
394 cmd = 0;
395
396 cmd |= 5; /* Five DWORDs. */
397
398 ahci_port_cmd_sync(ahci, cmd);
399
400 /* Examine operation status. */
401 d2h = (void __far *)&ahci->abFisRecv[0x40];
402 DBG_AHCI("AHCI: ERR=%02x, STAT=%02x, SCNT=%02x\n", d2h->error, d2h->status, d2h->sec_cn);
403
404 /* Unlock the buffer again. */
405 vds_free_sg_list(&ahci->edds);
406 return d2h->error ? 4 : 0;
407}
408
409/**
410 * Deinits the curent active port.
411 */
412static void ahci_port_deinit_current(ahci_t __far *ahci)
413{
414 uint16_t io_base;
415 uint8_t port;
416
417 io_base = ahci->iobase;
418 port = ahci->cur_port;
419
420 if (port != 0xff)
421 {
422 /* Put the port into an idle state. */
423 ahci_ctrl_clear_bits(io_base, AHCI_PORT_REG(port, AHCI_REG_PORT_CMD),
424 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST);
425
426 while (ahci_ctrl_is_bit_set(io_base, AHCI_PORT_REG(port, AHCI_REG_PORT_CMD),
427 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST | AHCI_REG_PORT_CMD_FR | AHCI_REG_PORT_CMD_CR) == 1)
428 {
429 DBG_AHCI("AHCI: Waiting for the port to idle\n");
430 }
431
432 /*
433 * Port idles, set up memory for commands and received FIS and program the
434 * address registers.
435 */
436 /// @todo merge memsets?
437 _fmemset(&ahci->aCmdHdr[0], 0, sizeof(ahci->aCmdHdr));
438 _fmemset(&ahci->abCmd[0], 0, sizeof(ahci->abCmd));
439 _fmemset(&ahci->abFisRecv[0], 0, sizeof(ahci->abFisRecv));
440
441 VBOXAHCI_PORT_WRITE_REG(io_base, port, AHCI_REG_PORT_FB, 0);
442 VBOXAHCI_PORT_WRITE_REG(io_base, port, AHCI_REG_PORT_FBU, 0);
443
444 VBOXAHCI_PORT_WRITE_REG(io_base, port, AHCI_REG_PORT_CLB, 0);
445 VBOXAHCI_PORT_WRITE_REG(io_base, port, AHCI_REG_PORT_CLBU, 0);
446
447 /* Disable all interrupts. */
448 VBOXAHCI_PORT_WRITE_REG(io_base, port, AHCI_REG_PORT_IE, 0);
449
450 ahci->cur_port = 0xff;
451 }
452}
453
454/**
455 * Brings a port into a minimal state to make device detection possible
456 * or to queue requests.
457 */
458static void ahci_port_init(ahci_t __far *ahci, uint8_t u8Port)
459{
460 /* Deinit any other port first. */
461 ahci_port_deinit_current(ahci);
462
463 /* Put the port into an idle state. */
464 ahci_ctrl_clear_bits(ahci->iobase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
465 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST);
466
467 while (ahci_ctrl_is_bit_set(ahci->iobase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
468 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST | AHCI_REG_PORT_CMD_FR | AHCI_REG_PORT_CMD_CR) == 1)
469 {
470 DBG_AHCI("AHCI: Waiting for the port to idle\n");
471 }
472
473 /*
474 * Port idles, set up memory for commands and received FIS and program the
475 * address registers.
476 */
477 /// @todo just one memset?
478 _fmemset(&ahci->aCmdHdr[0], 0, sizeof(ahci->aCmdHdr));
479 _fmemset(&ahci->abCmd[0], 0, sizeof(ahci->abCmd));
480 _fmemset(&ahci->abFisRecv[0], 0, sizeof(ahci->abFisRecv));
481
482 DBG_AHCI("AHCI: FIS receive area %lx from %x:%x\n",
483 ahci_addr_to_phys(&ahci->abFisRecv), FP_SEG(ahci->abFisRecv), FP_OFF(ahci->abFisRecv));
484 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_FB, ahci_addr_to_phys(&ahci->abFisRecv));
485 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_FBU, 0);
486
487 DBG_AHCI("AHCI: CMD list area %lx\n", ahci_addr_to_phys(&ahci->aCmdHdr));
488 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_CLB, ahci_addr_to_phys(&ahci->aCmdHdr));
489 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_CLBU, 0);
490
491 /* Disable all interrupts. */
492 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_IE, 0);
493 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_IS, 0xffffffff);
494 /* Clear all errors. */
495 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_SERR, 0xffffffff);
496
497 ahci->cur_port = u8Port;
498 ahci->cur_prd = 0;
499}
500
501/**
502 * Read sectors from an attached AHCI device.
503 *
504 * @returns status code.
505 * @param bios_dsk Pointer to disk request packet (in the
506 * EBDA).
507 */
508int ahci_read_sectors(bio_dsk_t __far *bios_dsk)
509{
510 uint16_t device_id;
511 uint16_t rc;
512
513 device_id = VBOX_GET_AHCI_DEVICE(bios_dsk->drqp.dev_id);
514 if (device_id > BX_MAX_AHCI_DEVICES)
515 BX_PANIC("%s: device_id out of range %d\n", __func__, device_id);
516
517 DBG_AHCI("%s: %u sectors @ LBA 0x%llx, device %d, port %d\n", __func__,
518 bios_dsk->drqp.nsect, bios_dsk->drqp.lba,
519 device_id, bios_dsk->ahcidev[device_id].port);
520
521 high_bits_save(bios_dsk->ahci_seg :> 0);
522 ahci_port_init(bios_dsk->ahci_seg :> 0, bios_dsk->ahcidev[device_id].port);
523 rc = ahci_cmd_data(bios_dsk, AHCI_CMD_READ_DMA_EXT);
524 DBG_AHCI("%s: transferred %lu bytes\n", __func__, ((ahci_t __far *)(bios_dsk->ahci_seg :> 0))->aCmdHdr[1]);
525 bios_dsk->drqp.trsfsectors = bios_dsk->drqp.nsect;
526#ifdef DMA_WORKAROUND
527 rep_movsw(bios_dsk->drqp.buffer, bios_dsk->drqp.buffer, bios_dsk->drqp.nsect * 512 / 2);
528#endif
529 high_bits_restore(bios_dsk->ahci_seg :> 0);
530 return rc;
531}
532
533/**
534 * Write sectors to an attached AHCI device.
535 *
536 * @returns status code.
537 * @param bios_dsk Pointer to disk request packet (in the
538 * EBDA).
539 */
540int ahci_write_sectors(bio_dsk_t __far *bios_dsk)
541{
542 uint16_t device_id;
543 uint16_t rc;
544
545 device_id = VBOX_GET_AHCI_DEVICE(bios_dsk->drqp.dev_id);
546 if (device_id > BX_MAX_AHCI_DEVICES)
547 BX_PANIC("%s: device_id out of range %d\n", __func__, device_id);
548
549 DBG_AHCI("%s: %u sectors @ LBA 0x%llx, device %d, port %d\n", __func__,
550 bios_dsk->drqp.nsect, bios_dsk->drqp.lba, device_id,
551 bios_dsk->ahcidev[device_id].port);
552
553 high_bits_save(bios_dsk->ahci_seg :> 0);
554 ahci_port_init(bios_dsk->ahci_seg :> 0, bios_dsk->ahcidev[device_id].port);
555 rc = ahci_cmd_data(bios_dsk, AHCI_CMD_WRITE_DMA_EXT);
556 DBG_AHCI("%s: transferred %lu bytes\n", __func__, ((ahci_t __far *)(bios_dsk->ahci_seg :> 0))->aCmdHdr[1]);
557 bios_dsk->drqp.trsfsectors = bios_dsk->drqp.nsect;
558 high_bits_restore(bios_dsk->ahci_seg :> 0);
559 return rc;
560}
561
562/// @todo move
563#define ATA_DATA_NO 0x00
564#define ATA_DATA_IN 0x01
565#define ATA_DATA_OUT 0x02
566
567uint16_t ahci_cmd_packet(uint16_t device_id, uint8_t cmdlen, char __far *cmdbuf,
568 uint32_t length, uint8_t inout, char __far *buffer)
569{
570 bio_dsk_t __far *bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
571 ahci_t __far *ahci;
572
573 /* Data out is currently not supported. */
574 if (inout == ATA_DATA_OUT) {
575 BX_INFO("%s: DATA_OUT not supported yet\n", __func__);
576 return 1;
577 }
578
579 /* Convert to AHCI specific device number. */
580 device_id = VBOX_GET_AHCI_DEVICE(device_id);
581
582 DBG_AHCI("%s: reading %lu bytes, device %d, port %d\n", __func__,
583 length, device_id, bios_dsk->ahcidev[device_id].port);
584 DBG_AHCI("%s: reading %u %u-byte sectors\n", __func__,
585 bios_dsk->drqp.nsect, bios_dsk->drqp.sect_sz);
586
587 bios_dsk->drqp.lba = length << 8; /// @todo xfer length limit
588 bios_dsk->drqp.buffer = buffer;
589 bios_dsk->drqp.nsect = length / bios_dsk->drqp.sect_sz;
590// bios_dsk->drqp.sect_sz = 2048;
591
592 ahci = bios_dsk->ahci_seg :> 0;
593 high_bits_save(ahci);
594
595 ahci_port_init(bios_dsk->ahci_seg :> 0, bios_dsk->ahcidev[device_id].port);
596
597 /* Copy the ATAPI command where the HBA can fetch it. */
598 _fmemcpy(ahci->abAcmd, cmdbuf, cmdlen);
599
600 /* Reset transferred counts. */
601 /// @todo clear in calling code?
602 bios_dsk->drqp.trsfsectors = 0;
603 bios_dsk->drqp.trsfbytes = 0;
604
605 ahci_cmd_data(bios_dsk, ATA_CMD_PACKET);
606 DBG_AHCI("%s: transferred %lu bytes\n", __func__, ahci->aCmdHdr[1]);
607 bios_dsk->drqp.trsfbytes = ahci->aCmdHdr[1];
608#ifdef DMA_WORKAROUND
609 rep_movsw(bios_dsk->drqp.buffer, bios_dsk->drqp.buffer, bios_dsk->drqp.trsfbytes / 2);
610#endif
611 high_bits_restore(ahci);
612
613 return ahci->aCmdHdr[1] == 0 ? 4 : 0;
614}
615
616/* Wait for the specified number of BIOS timer ticks or data bytes. */
617void wait_ticks_device_init( unsigned wait_ticks, unsigned wait_bytes )
618{
619}
620
621void ahci_port_detect_device(ahci_t __far *ahci, uint8_t u8Port)
622{
623 uint32_t val;
624 bio_dsk_t __far *bios_dsk;
625 volatile uint32_t __far *ticks;
626 uint32_t end_tick;
627 int device_found = 0;
628
629 ahci_port_init(ahci, u8Port);
630
631 bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
632
633 /* Reset connection. */
634 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_SCTL, 0x01);
635 /*
636 * According to the spec we should wait at least 1msec until the reset
637 * is cleared but this is a virtual controller so we don't have to.
638 */
639 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_SCTL, 0);
640
641 /*
642 * We do however have to wait for the device to initialize (the port reset
643 * to complete). That can take up to 10ms according to the SATA spec (device
644 * must send COMINIT within 10ms of COMRESET). We should be generous with
645 * the wait because in the typical case there are no ports without a device
646 * attached.
647 */
648 ticks = MK_FP( 0x40, 0x6C );
649 end_tick = *ticks + 3; /* Wait up to five BIOS ticks, something in 150ms range. */
650
651 while( *ticks < end_tick )
652 {
653 /* If PxSSTS.DET is 3, everything went fine. */
654 VBOXAHCI_PORT_READ_REG(ahci->iobase, u8Port, AHCI_REG_PORT_SSTS, val);
655 if (ahci_ctrl_extract_bits(val, 0xfL, 0) == 3) {
656 device_found = 1;
657 break;
658 }
659 }
660
661 /* Timed out, no device detected. */
662 if (!device_found) {
663 DBG_AHCI("AHCI: Timed out, no device detected on port %d\n", u8Port);
664 return;
665 }
666
667 if (ahci_ctrl_extract_bits(val, 0xfL, 0) == 0x3)
668 {
669 uint8_t abBuffer[0x0200];
670 uint8_t hdcount, devcount_ahci, hd_index;
671 uint8_t cdcount;
672 uint8_t removable;
673
674 /* Clear all errors after the reset. */
675 VBOXAHCI_PORT_WRITE_REG(ahci->iobase, u8Port, AHCI_REG_PORT_SERR, 0xffffffff);
676
677 devcount_ahci = bios_dsk->ahci_devcnt;
678
679 DBG_AHCI("AHCI: Device detected on port %d\n", u8Port);
680
681 /// @todo Merge common HD/CDROM detection code
682 if (devcount_ahci < BX_MAX_AHCI_DEVICES)
683 {
684 /* Device detected, enable FIS receive. */
685 ahci_ctrl_set_bits(ahci->iobase, AHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
686 AHCI_REG_PORT_CMD_FRE);
687
688 /* Check signature to determine device type. */
689 VBOXAHCI_PORT_READ_REG(ahci->iobase, u8Port, AHCI_REG_PORT_SIG, val);
690 if (val == 0x101)
691 {
692 uint64_t sectors;
693 uint16_t cylinders, heads, spt;
694 chs_t lgeo;
695 uint8_t idxCmosChsBase;
696
697 DBG_AHCI("AHCI: Detected hard disk\n");
698
699 /* Identify device. */
700 bios_dsk->drqp.lba = 0;
701 bios_dsk->drqp.buffer = &abBuffer;
702 bios_dsk->drqp.nsect = 1;
703 bios_dsk->drqp.sect_sz = 512;
704 ahci_cmd_data(bios_dsk, ATA_CMD_IDENTIFY_DEVICE);
705
706 /* Calculate index into the generic device table. */
707 hd_index = devcount_ahci + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES;
708
709 removable = *(abBuffer+0) & 0x80 ? 1 : 0;
710 cylinders = *(uint16_t *)(abBuffer+(1*2)); // word 1
711 heads = *(uint16_t *)(abBuffer+(3*2)); // word 3
712 spt = *(uint16_t *)(abBuffer+(6*2)); // word 6
713 sectors = *(uint32_t *)(abBuffer+(60*2)); // word 60 and word 61
714
715 if (sectors == 0x0FFFFFFF) /* For disks bigger than ~128GB */
716 sectors = *(uint64_t *)(abBuffer+(100*2)); // words 100 to 103
717
718 DBG_AHCI("AHCI: 0x%llx sectors\n", sectors);
719
720 bios_dsk->ahcidev[devcount_ahci].port = u8Port;
721 bios_dsk->devices[hd_index].type = DSK_TYPE_AHCI;
722 bios_dsk->devices[hd_index].device = DSK_DEVICE_HD;
723 bios_dsk->devices[hd_index].removable = removable;
724 bios_dsk->devices[hd_index].lock = 0;
725 bios_dsk->devices[hd_index].blksize = 512;
726 bios_dsk->devices[hd_index].translation = GEO_TRANSLATION_LBA;
727 bios_dsk->devices[hd_index].sectors = sectors;
728
729 bios_dsk->devices[hd_index].pchs.heads = heads;
730 bios_dsk->devices[hd_index].pchs.cylinders = cylinders;
731 bios_dsk->devices[hd_index].pchs.spt = spt;
732
733 /* Get logical CHS geometry. */
734 switch (devcount_ahci)
735 {
736 case 0:
737 idxCmosChsBase = 0x40;
738 break;
739 case 1:
740 idxCmosChsBase = 0x48;
741 break;
742 case 2:
743 idxCmosChsBase = 0x50;
744 break;
745 case 3:
746 idxCmosChsBase = 0x58;
747 break;
748 default:
749 idxCmosChsBase = 0;
750 }
751 if (idxCmosChsBase && inb_cmos(idxCmosChsBase+7))
752 {
753 lgeo.cylinders = inb_cmos(idxCmosChsBase + 0) + (inb_cmos(idxCmosChsBase + 1) << 8);
754 lgeo.heads = inb_cmos(idxCmosChsBase + 2);
755 lgeo.spt = inb_cmos(idxCmosChsBase + 7);
756 }
757 else
758 set_geom_lba(&lgeo, sectors); /* Default EDD-style translated LBA geometry. */
759
760 BX_INFO("AHCI %d-P#%d: PCHS=%u/%u/%u LCHS=%u/%u/%u 0x%llx sectors\n", devcount_ahci,
761 u8Port, cylinders, heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt,
762 sectors);
763
764 bios_dsk->devices[hd_index].lchs = lgeo;
765
766 /* Store the ID of the disk in the BIOS hdidmap. */
767 hdcount = bios_dsk->hdcount;
768 bios_dsk->hdidmap[hdcount] = devcount_ahci + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES;
769 hdcount++;
770 bios_dsk->hdcount = hdcount;
771
772 /* Update hdcount in the BDA. */
773 hdcount = read_byte(0x40, 0x75);
774 hdcount++;
775 write_byte(0x40, 0x75, hdcount);
776 }
777 else if (val == 0xeb140101)
778 {
779 DBG_AHCI("AHCI: Detected ATAPI device\n");
780
781 /* Identify packet device. */
782 bios_dsk->drqp.lba = 0;
783 bios_dsk->drqp.buffer = &abBuffer;
784 bios_dsk->drqp.nsect = 1;
785 bios_dsk->drqp.sect_sz = 512;
786 ahci_cmd_data(bios_dsk, ATA_CMD_IDENTIFY_PACKET);
787
788 /* Calculate index into the generic device table. */
789 hd_index = devcount_ahci + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES;
790
791 removable = *(abBuffer+0) & 0x80 ? 1 : 0;
792
793 bios_dsk->ahcidev[devcount_ahci].port = u8Port;
794 bios_dsk->devices[hd_index].type = DSK_TYPE_AHCI;
795 bios_dsk->devices[hd_index].device = DSK_DEVICE_CDROM;
796 bios_dsk->devices[hd_index].removable = removable;
797 bios_dsk->devices[hd_index].blksize = 2048;
798 bios_dsk->devices[hd_index].translation = GEO_TRANSLATION_NONE;
799
800 /* Store the ID of the device in the BIOS cdidmap. */
801 cdcount = bios_dsk->cdcount;
802 bios_dsk->cdidmap[cdcount] = devcount_ahci + BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES;
803 cdcount++;
804 bios_dsk->cdcount = cdcount;
805 }
806 else
807 DBG_AHCI("AHCI: Ignoring unknown device\n");
808
809 devcount_ahci++;
810 bios_dsk->ahci_devcnt = devcount_ahci;
811 }
812 else
813 DBG_AHCI("AHCI: Reached maximum device count, skipping\n");
814 }
815}
816
817/**
818 * Allocates 1K of conventional memory.
819 */
820static uint16_t ahci_mem_alloc(void)
821{
822 uint16_t base_mem_kb;
823 uint16_t ahci_seg;
824
825 base_mem_kb = read_word(0x00, 0x0413);
826
827 DBG_AHCI("AHCI: %dK of base mem\n", base_mem_kb);
828
829 if (base_mem_kb == 0)
830 return 0;
831
832 base_mem_kb--; /* Allocate one block. */
833 ahci_seg = (((uint32_t)base_mem_kb * 1024) >> 4); /* Calculate start segment. */
834
835 write_word(0x00, 0x0413, base_mem_kb);
836
837 return ahci_seg;
838}
839
840/**
841 * Initializes the AHCI HBA and detects attached devices.
842 */
843static int ahci_hba_init(uint16_t io_base)
844{
845 uint8_t i, cPorts;
846 uint32_t val;
847 uint16_t ebda_seg;
848 uint16_t ahci_seg;
849 bio_dsk_t __far *bios_dsk;
850 ahci_t __far *ahci;
851
852
853 ebda_seg = read_word(0x0040, 0x000E);
854 bios_dsk = ebda_seg :> &EbdaData->bdisk;
855
856 AHCI_READ_REG(io_base, AHCI_REG_VS, val);
857 DBG_AHCI("AHCI: Controller version: 0x%x (major) 0x%x (minor)\n",
858 ahci_ctrl_extract_bits(val, 0xffff0000, 16),
859 ahci_ctrl_extract_bits(val, 0x0000ffff, 0));
860
861 /* Allocate 1K of base memory. */
862 ahci_seg = ahci_mem_alloc();
863 if (ahci_seg == 0)
864 {
865 DBG_AHCI("AHCI: Could not allocate 1K of memory, can't boot from controller\n");
866 return 0;
867 }
868 DBG_AHCI("AHCI: ahci_seg=%04x, size=%04x, pointer at EBDA:%04x (EBDA size=%04x)\n",
869 ahci_seg, sizeof(ahci_t), (uint16_t)&EbdaData->bdisk.ahci_seg, sizeof(ebda_data_t));
870
871 bios_dsk->ahci_seg = ahci_seg;
872 bios_dsk->ahci_devcnt = 0;
873
874 ahci = ahci_seg :> 0;
875 ahci->cur_port = 0xff;
876 ahci->iobase = io_base;
877
878 /* Reset the controller. */
879 ahci_ctrl_set_bits(io_base, AHCI_REG_GHC, AHCI_GHC_HR);
880 do
881 {
882 AHCI_READ_REG(io_base, AHCI_REG_GHC, val);
883 } while ((val & AHCI_GHC_HR) != 0);
884
885 AHCI_READ_REG(io_base, AHCI_REG_CAP, val);
886 cPorts = ahci_ctrl_extract_bits(val, 0x1f, 0) + 1; /* Extract number of ports.*/
887
888 DBG_AHCI("AHCI: HBA has %u ports\n", cPorts);
889
890 /* Go through the ports. */
891 i = 0;
892 while (i < 32)
893 {
894 if (ahci_ctrl_is_bit_set(io_base, AHCI_REG_PI, RT_BIT_32(i)) != 0)
895 {
896 DBG_AHCI("AHCI: Port %u is present\n", i);
897 ahci_port_detect_device(ahci_seg :> 0, i);
898 cPorts--;
899 if (cPorts == 0)
900 break;
901 }
902 i++;
903 }
904
905 return 0;
906}
907
908/**
909 * Init the AHCI driver and detect attached disks.
910 */
911void BIOSCALL ahci_init(void)
912{
913 uint16_t busdevfn;
914
915 busdevfn = pci_find_classcode(0x00010601);
916 if (busdevfn != VBOX_AHCI_NO_DEVICE)
917 {
918 uint8_t u8Bus, u8DevFn;
919 uint8_t u8PciCapOff;
920
921 u8Bus = (busdevfn & 0xff00) >> 8;
922 u8DevFn = busdevfn & 0x00ff;
923
924 DBG_AHCI("AHCI HBA at Bus %u DevFn 0x%x (raw 0x%x)\n", u8Bus, u8DevFn, busdevfn);
925
926 /* Examine the capability list and search for the Serial ATA Capability Register. */
927 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, PCI_CONFIG_CAP);
928
929 while (u8PciCapOff != 0)
930 {
931 uint8_t u8PciCapId = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
932
933 DBG_AHCI("Capability ID 0x%x at 0x%x\n", u8PciCapId, u8PciCapOff);
934
935 if (u8PciCapId == PCI_CAP_ID_SATACR)
936 break;
937
938 /* Go on to the next capability. */
939 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1);
940 }
941
942 if (u8PciCapOff != 0)
943 {
944 uint8_t u8Rev;
945
946 DBG_AHCI("AHCI HBA with SATA Capability register at 0x%x\n", u8PciCapOff);
947
948 /* Advance to the stuff behind the id and next capability pointer. */
949 u8PciCapOff += 2;
950
951 u8Rev = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
952 if (u8Rev == 0x10)
953 {
954 /* Read the SATACR1 register and get the bar and offset of the index/data pair register. */
955 uint8_t u8Bar = 0x00;
956 uint16_t u16Off = 0x00;
957 uint16_t u16BarOff = pci_read_config_word(u8Bus, u8DevFn, u8PciCapOff + 2);
958
959 DBG_AHCI("SATACR1: 0x%x\n", u16BarOff);
960
961 switch (u16BarOff & 0xf)
962 {
963 case 0x04:
964 u8Bar = 0x10;
965 break;
966 case 0x05:
967 u8Bar = 0x14;
968 break;
969 case 0x06:
970 u8Bar = 0x18;
971 break;
972 case 0x07:
973 u8Bar = 0x1c;
974 break;
975 case 0x08:
976 u8Bar = 0x20;
977 break;
978 case 0x09:
979 u8Bar = 0x24;
980 break;
981 case 0x0f:
982 default:
983 /* Reserved or unsupported. */
984 DBG_AHCI("BAR 0x%x unsupported\n", u16BarOff & 0xf);
985 }
986
987 /* Get the offset inside the BAR from bits 4:15. */
988 u16Off = (u16BarOff >> 4) * 4;
989
990 if (u8Bar != 0x00)
991 {
992 uint32_t u32Bar = pci_read_config_dword(u8Bus, u8DevFn, u8Bar);
993
994 DBG_AHCI("BAR at 0x%x : 0x%x\n", u8Bar, u32Bar);
995
996 if ((u32Bar & 0x01) != 0)
997 {
998 int rc;
999 uint16_t u16AhciIoBase = (u32Bar & 0xfff0) + u16Off;
1000
1001 /* Enable PCI memory, I/O, bus mastering access in command register. */
1002 pci_write_config_word(u8Bus, u8DevFn, 4, 0x7);
1003
1004 DBG_AHCI("I/O base: 0x%x\n", u16AhciIoBase);
1005 rc = ahci_hba_init(u16AhciIoBase);
1006 }
1007 else
1008 DBG_AHCI("BAR is MMIO\n");
1009 }
1010 }
1011 else
1012 DBG_AHCI("Invalid revision 0x%x\n", u8Rev);
1013 }
1014 else
1015 DBG_AHCI("AHCI HBA with no usable Index/Data register pair!\n");
1016 }
1017 else
1018 DBG_AHCI("No AHCI HBA!\n");
1019}
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