mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-06-07 08:14:48 +00:00
AHCI Identify, Added ST_FALSE_TRUE
This commit is contained in:
parent
e92c1ca443
commit
928f6d4671
Binary file not shown.
259
src/Home/ahci.CC
Normal file
259
src/Home/ahci.CC
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
//AHCI driver, by V0x3L. (AHCI spec 1.3.1)
|
||||||
|
|
||||||
|
I64 AHCILBA48CapacityGet(U16 *id_record)
|
||||||
|
{//Get capacity of drive, in LBA blocks.
|
||||||
|
return *&id_record[ATA_IDENT_LBA48_CAPACITY](U64 *) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
I64 AHCIPortCmdSlotGet(CAHCIPort *port)
|
||||||
|
{//Get next free command slot in port; if none, return -1.
|
||||||
|
I64 i;
|
||||||
|
U32 slots = port->sata_active | port->cmd_issue;
|
||||||
|
|
||||||
|
for (i = 0; i < blkdev.cmd_slot_count; i++)
|
||||||
|
{
|
||||||
|
if (!(slots & 1))
|
||||||
|
return i;
|
||||||
|
slots >>= 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool AHCIPortIsIdle(CAHCIPort *port)
|
||||||
|
{//Check if the command engine is running on port.
|
||||||
|
return !(port->command & (AHCI_PxCMDF_ST | AHCI_PxCMDF_CR | AHCI_PxCMDF_FR | AHCI_PxCMDF_FRE));
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 AHCIPortCmdStop(CAHCIPort *port)
|
||||||
|
{//Stop command engine on port.
|
||||||
|
Btr(&port->command, AHCI_PxCMDf_ST);
|
||||||
|
Btr(&port->command, AHCI_PxCMDf_FRE);
|
||||||
|
// while (port->command & (AHCI_PxCMDF_CR | AHCI_PxCMDF_FR));
|
||||||
|
while (Bt(&port->command, AHCI_PxCMDf_CR) || Bt(&port->command, AHCI_PxCMDf_FR));
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 AHCIPortCmdStart(CAHCIPort *port)
|
||||||
|
{//Start command engine on port.
|
||||||
|
while (Bt(&port->command, AHCI_PxCMDf_CR));
|
||||||
|
Bts(&port->command, AHCI_PxCMDf_FRE);
|
||||||
|
Bts(&port->command, AHCI_PxCMDf_ST);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool AHCIPortWait(CAHCIPort *port, F64 timeout)
|
||||||
|
{//Wait until DRQ & BSY are clear in port task file.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!(port->task_file_data & (ATAS_DRQ | ATAS_BSY)))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
while (timeout > tS);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 AHCIPortReset(CAHCIPort *port)
|
||||||
|
{//Software reset of port. Port command engine must be started after this.
|
||||||
|
//If port is not responsive we do a full reset.
|
||||||
|
AHCIPortCmdStop(port);
|
||||||
|
port->interrupt_status = port->interrupt_status; //Acknowledge all interrupt statuses.
|
||||||
|
|
||||||
|
if (!AHCIPortWait(port, tS + 1))
|
||||||
|
{//Perform 'more intrusive' HBA<->Port comm reset (sec. 10.4.2 of spec).
|
||||||
|
port->sata_ctrl = AHCI_PxSCTLF_DET_INIT;
|
||||||
|
Sleep(2); //Spec says 1 millisecond
|
||||||
|
port->sata_ctrl = 0;
|
||||||
|
}
|
||||||
|
while (port->sata_status & 0xF != AHCI_PxSSTSF_DET_PRESENT);
|
||||||
|
port->sata_error = ~0; //Write all 1s to sata error register.
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 AHCIPortIdentify(CBlkDev *bd)
|
||||||
|
{
|
||||||
|
CHBACmdHeader *cmd_header;
|
||||||
|
CHBACmdTable *cmd_table;
|
||||||
|
CFisH2D *cmd_fis;
|
||||||
|
U16 *dev_id_record;
|
||||||
|
CAHCIPort *port = bd->ahci_port;
|
||||||
|
I64 *slot = AHCIPortCmdSlotGet(port);
|
||||||
|
|
||||||
|
if (slot < 0)
|
||||||
|
{
|
||||||
|
ZenithErr("No empty command slots.");
|
||||||
|
throw('AHCI');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sticking with code heap for this alloc because we don't want to deal with 64 bit buffer address shit.
|
||||||
|
dev_id_record = CAlloc(512, Fs->code_heap);
|
||||||
|
|
||||||
|
port->interrupt_status = port->interrupt_status; //Ackowledge all interrupt statuses???? is this needed?
|
||||||
|
|
||||||
|
cmd_header = *&port->cmd_list_base(I64 *); //Read full 64-bit cmd_list_base value.
|
||||||
|
cmd_header += slot; //Move up pointer to the slot we have in the command list.
|
||||||
|
|
||||||
|
//Setting Command FIS Length, bits 4:0, takes size in U32s.
|
||||||
|
cmd_header->desc = (cmd_header->desc & ~0x1F) + sizeof(CFisH2D) / sizeof(U32);
|
||||||
|
Btr(&cmd_header->desc, AHCI_CH_DESCf_W); //Disable 'write' bit.
|
||||||
|
|
||||||
|
cmd_table = *&cmd_header->cmd_table_base(I64 *); //Read full 64-bit cmd_table_base value.
|
||||||
|
MemSet(cmd_table, 0, sizeof(CHBACmdTable));
|
||||||
|
cmd_table->prdt[0].data_base = dev_id_record;
|
||||||
|
cmd_table->prdt[0].data_base_upper = 0;
|
||||||
|
cmd_table->prdt[0].data_byte_count = 512 - 1;
|
||||||
|
cmd_header->prdt_len = 1; //1 PRD, descrived above, which contains the address to put the ID record.
|
||||||
|
|
||||||
|
cmd_fis = &cmd_table->command_fis;
|
||||||
|
MemSet(cmd_fis, 0, sizeof(CFisH2D));
|
||||||
|
cmd_fis->type = FISt_H2D;
|
||||||
|
cmd_fis->command = ATA_IDENTIFY;
|
||||||
|
cmd_fis->device = 0; //No bits need to be set in the device register.
|
||||||
|
Bts(&cmd_fis->desc, AHCI_CF_DESCf_C); //Set cmd_fis->c to 1 (Command bit).
|
||||||
|
|
||||||
|
if (!AHCIPortWait(port, tS + 2))
|
||||||
|
{
|
||||||
|
ZenithErr("AHCI: Port %d hung!\n", bd->port_num);
|
||||||
|
throw('AHCI');
|
||||||
|
}
|
||||||
|
|
||||||
|
Bts(&port->cmd_issue, slot);
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (!Bt(&port->cmd_issue, slot))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (Bt(&port->interrupt_status, AHCI_PxIf_TFE)) //tfe = task file error
|
||||||
|
{
|
||||||
|
oof:
|
||||||
|
ZenithErr("AHCI: Port %d: Identify command failed!\n", bd->port_num);
|
||||||
|
throw('AHCI');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Bt(&port->interrupt_status, AHCI_PxIf_TFE)) //Second safety check
|
||||||
|
goto oof;
|
||||||
|
|
||||||
|
bd->max_blk = AHCILBA48CapacityGet(dev_id_record);
|
||||||
|
"%X\n", bd->max_blk;
|
||||||
|
Free(bd->dev_id_record);
|
||||||
|
bd->dev_id_record = dev_id_record;
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 AHCIPortInit(CBlkDev *bd, CAHCIPort *port, I64 port_num)
|
||||||
|
{
|
||||||
|
CHBACmdHeader *cmd_header;
|
||||||
|
I64 i, addr = 0;
|
||||||
|
|
||||||
|
bd->ahci_port = port;
|
||||||
|
bd->port_num = port_num;
|
||||||
|
|
||||||
|
AHCIPortReset(port);
|
||||||
|
AHCIPortCmdStart(port);
|
||||||
|
|
||||||
|
//Spin up, power on device. If the capability isn't suppport the bits will be read-only and this won't do anything.
|
||||||
|
port->command |= AHCI_PxCMDF_POD | AHCI_PxCMDF_SUD;
|
||||||
|
Sleep(100);//Why?
|
||||||
|
AHCIPortCmdStop(port);
|
||||||
|
|
||||||
|
if (blkdev.ahci64)
|
||||||
|
{
|
||||||
|
//'1K-byte' align as per SATA spec.
|
||||||
|
addr = CAllocAligned(sizeof(CHBACmdHeader) * blkdev.cmd_slot_count, 1024);
|
||||||
|
port->cmd_list_base = addr.u32[0];
|
||||||
|
port->cmd_list_base_upper = addr.u32[1];
|
||||||
|
|
||||||
|
//Alloc where received FISes will be copied to. '256-byte' align as per spec.
|
||||||
|
addr = CAllocAligned(sizeof(CFisReceived), 256);
|
||||||
|
port->fis_base = addr.u32[0];
|
||||||
|
port->fis_base_upper = addr.u32[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{//Code Heap is always under 4 GB in address space, so we can use that instead.
|
||||||
|
port->cmd_list_base = CAllocAligned(sizeof(CHBACmdHeader) * blkdev.cmd_slot_count, 1024, Fs->code_heap);
|
||||||
|
port->cmd_list_base_upper = 0;
|
||||||
|
|
||||||
|
port->fis_base = CAllocAligned(sizeof(CFisReceived), 256, Fs->code_heap);
|
||||||
|
port->fis_base_upper = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < blkdev.cmd_slot_count; i++)
|
||||||
|
{
|
||||||
|
cmd_header = &port->cmd_list_base(CHBACmdHeader *)[i];
|
||||||
|
cmd_header->prdt_len = 8; //TODO: reason
|
||||||
|
|
||||||
|
if (blkdev.ahci64)
|
||||||
|
{
|
||||||
|
//'128-byte' align as per SATA spec, minus 1 since length is 1-based.
|
||||||
|
addr = CAllocAligned(sizeof(CHBACmdTable) + sizeof(CPrdtEntry) * (cmd_header->prdt_len - 1), 128);
|
||||||
|
cmd_header->cmd_table_base = addr.u32[0];
|
||||||
|
cmd_header->cmd_table_base_upper = addr.u32[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmd_header->cmd_table_base = CAllocAligned(sizeof(CHBACmdTable) + sizeof(CPrdtEntry) *
|
||||||
|
(cmd_header->prdt_len - 1), 128, Fs->code_heap);
|
||||||
|
cmd_header->cmd_table_base_upper = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AHCIPortCmdStart(port);
|
||||||
|
AHCIPortIdentify(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 AHCIInit()
|
||||||
|
{
|
||||||
|
CAHCIHba *hba;
|
||||||
|
CAHCIPort *port;
|
||||||
|
I64 i, bdf = PCIClassFind(PCIC_STORAGE << 16 | PCISC_AHCI << 8 + 1, 0); //0x010601, last byte prog_if, AHCI version 1.0
|
||||||
|
|
||||||
|
if (bdf == -1)
|
||||||
|
{
|
||||||
|
"No AHCI controller found.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hba = dev.uncached_alias + PCIReadU32(bdf.u8[2], bdf.u8[1], bdf.u8[0], PCIR_BASE5) & ~0x1F; //Last 4 bits not part of addr.
|
||||||
|
|
||||||
|
Bts(&hba->ghc, AHCI_GHCf_HBA_RESET);
|
||||||
|
while (Bt(&hba->ghc, AHCI_GHCf_HBA_RESET));
|
||||||
|
|
||||||
|
Bts(&hba->ghc, AHCI_GHCf_AHCI_ENABLE);
|
||||||
|
|
||||||
|
//Transferring ownership from BIOS if supported.
|
||||||
|
if (Bt(&hba->caps_ext, AHCI_CAPSEXTf_BOH))
|
||||||
|
{
|
||||||
|
Bt(&hba->bohc, AHCI_BOHCf_OOS);
|
||||||
|
while (Bt(&hba->bohc, AHCI_BOHCf_BOS));
|
||||||
|
Sleep(25);
|
||||||
|
if (Bt(&hba->bohc, AHCI_BOHCf_BB)) //if Bios Busy is still set after 25 mS, wait 2 seconds.
|
||||||
|
Sleep(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
blkdev.ahci64 = Bt(&hba->caps, AHCI_CAPSf_S64A);
|
||||||
|
blkdev.cmd_slot_count = (hba->caps & 0x1F00) >> 8;
|
||||||
|
blkdev.ahci_hba = hba;
|
||||||
|
// blkdev.ahci64 = 0;
|
||||||
|
|
||||||
|
"ahci64: %Z\n", blkdev.ahci64, "ST_FALSE_TRUE";
|
||||||
|
|
||||||
|
for (i = 0; i < AHCI_MAX_PORTS; i++)
|
||||||
|
{
|
||||||
|
if (Bt(&hba->ports_implemented, i))
|
||||||
|
{
|
||||||
|
port = &hba->ports[i];
|
||||||
|
if (port->signature == AHCI_PxSIG_ATA || port->signature == AHCI_PxSIG_ATAPI)
|
||||||
|
{
|
||||||
|
"Port on %d\n", i;
|
||||||
|
if (port->signature == AHCI_PxSIG_ATAPI)
|
||||||
|
Bts(&port->command, AHCI_PxCMDf_ATAPI);
|
||||||
|
|
||||||
|
if (!AHCIPortIsIdle(port))
|
||||||
|
{
|
||||||
|
"Port not idle\n";
|
||||||
|
AHCIPortCmdStop(port);
|
||||||
|
}
|
||||||
|
AHCIPortInit(BlkDevNextFreeSlot('G', BDT_ATA), port, i); //gay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AHCIInit;
|
@ -98,7 +98,11 @@ U0 SysDefinesLoad()
|
|||||||
{
|
{
|
||||||
DefineListLoad("ST_OFF_ON",
|
DefineListLoad("ST_OFF_ON",
|
||||||
"Off\0"
|
"Off\0"
|
||||||
"On\0");
|
"On");
|
||||||
|
|
||||||
|
DefineListLoad("ST_FALSE_TRUE",
|
||||||
|
"False\0"
|
||||||
|
"True");
|
||||||
|
|
||||||
DefineListLoad("ST_HTT_TYPES",
|
DefineListLoad("ST_HTT_TYPES",
|
||||||
"ExportSysSym\0"
|
"ExportSysSym\0"
|
||||||
|
@ -2763,6 +2763,16 @@ public class CATARep
|
|||||||
#define AHCI_PxSIG_SEMB 0xC33C0101 //Enclosure Management Bridge... rare to encounter in wild.
|
#define AHCI_PxSIG_SEMB 0xC33C0101 //Enclosure Management Bridge... rare to encounter in wild.
|
||||||
#define AHCI_PxSIG_PM 0x96690101 //Port multiplier... not relevant to PC-type systems.
|
#define AHCI_PxSIG_PM 0x96690101 //Port multiplier... not relevant to PC-type systems.
|
||||||
|
|
||||||
|
//Interrupt flags (same in PxIE and PxIS)
|
||||||
|
#define AHCI_PxIf_TFE 30 //Task File Error, see $LK,"ATAS_ERR",A="MN:ATAS_ERR"$.
|
||||||
|
|
||||||
|
//COMRESET flags
|
||||||
|
//SATA Control register flags
|
||||||
|
#define AHCI_PxSCTLf_DET_INIT 1
|
||||||
|
#define AHCI_PxSCTLF_DET_INIT (1 << AHCI_PxSCTLf_DET_INIT)
|
||||||
|
//SATA Status register flags
|
||||||
|
#define AHCI_PxSSTSF_DET_PRESENT 3
|
||||||
|
|
||||||
class CAHCIPort
|
class CAHCIPort
|
||||||
{//Port register layout
|
{//Port register layout
|
||||||
U32 cmd_list_base,
|
U32 cmd_list_base,
|
||||||
@ -2827,6 +2837,19 @@ class CFisH2D
|
|||||||
U32 reserved;
|
U32 reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CFisReceived
|
||||||
|
{
|
||||||
|
U8 dma_fis[28],
|
||||||
|
reserved[4],
|
||||||
|
pio_fis[20],
|
||||||
|
reserved[12],
|
||||||
|
r_fis[20],
|
||||||
|
reserved[4],
|
||||||
|
devbits_fis[8],
|
||||||
|
unknown_fis[64],
|
||||||
|
reserved[96];
|
||||||
|
};
|
||||||
|
|
||||||
class CPrdtEntry
|
class CPrdtEntry
|
||||||
{
|
{
|
||||||
U32 data_base,
|
U32 data_base,
|
||||||
@ -3243,7 +3266,7 @@ public class CBlkDev
|
|||||||
init_root_dir_blks,
|
init_root_dir_blks,
|
||||||
max_blk,
|
max_blk,
|
||||||
locked_flags,
|
locked_flags,
|
||||||
port_number;
|
port_num;
|
||||||
U16 *dev_id_record;
|
U16 *dev_id_record;
|
||||||
F64 last_time;
|
F64 last_time;
|
||||||
};
|
};
|
||||||
|
@ -136,8 +136,7 @@ public _extern _D3_DIST_SQR F64 D3DistSqr(CD3 *d1,CD3 *d2); //Distance Squared
|
|||||||
public _extern _D3_DIV CD3 *D3Div(CD3 *quot,CD3 *d,F64 s); //quot=d/s
|
public _extern _D3_DIV CD3 *D3Div(CD3 *quot,CD3 *d,F64 s); //quot=d/s
|
||||||
public _extern _D3_DIV_EQU CD3 *D3DivEqu(CD3 *quot,F64 s); //quot/=s
|
public _extern _D3_DIV_EQU CD3 *D3DivEqu(CD3 *quot,F64 s); //quot/=s
|
||||||
public _extern _D3_DOT F64 D3Dot(CD3 *d1,CD3 *d2); //d1 dot d2
|
public _extern _D3_DOT F64 D3Dot(CD3 *d1,CD3 *d2); //d1 dot d2
|
||||||
public _extern _D3_EQU CD3 *D3Equ(
|
public _extern _D3_EQU CD3 *D3Equ(CD3 *dst,F64 x=0,F64 y=0,F64 z=0); //dst=(x,y,z)
|
||||||
CD3 *dst,F64 x=0,F64 y=0,F64 z=0); //dst=(x,y,z)
|
|
||||||
public _extern _D3_MUL CD3 *D3Mul(CD3 *prod,F64 s,CD3 *d); //prod=s*d
|
public _extern _D3_MUL CD3 *D3Mul(CD3 *prod,F64 s,CD3 *d); //prod=s*d
|
||||||
public _extern _D3_MUL_EQU CD3 *D3MulEqu(CD3 *prod,F64 s); //prod*=s
|
public _extern _D3_MUL_EQU CD3 *D3MulEqu(CD3 *prod,F64 s); //prod*=s
|
||||||
public _extern _D3_NORM F64 D3Norm(CD3 *d); //Norm
|
public _extern _D3_NORM F64 D3Norm(CD3 *d); //Norm
|
||||||
@ -148,16 +147,11 @@ public _extern _D3_UNIT CD3 *D3Unit(CD3 *d); //To unit vect
|
|||||||
public _extern _D3_ZERO CD3 *D3Zero(CD3 *dst); //To zero
|
public _extern _D3_ZERO CD3 *D3Zero(CD3 *dst); //To zero
|
||||||
|
|
||||||
#help_index "Memory"
|
#help_index "Memory"
|
||||||
public _extern _MEMCOMPARE I64 MemCompare(
|
public _extern _MEMCOMPARE I64 MemCompare(U8 *ptr1,U8 *ptr2,I64 count); //Compare chunk of memory.
|
||||||
U8 *ptr1,U8 *ptr2,I64 count); //Compare chunk of memory.
|
public _extern _MEMCOPY U8 *MemCopy(U8 *dst,U8 *src,I64 count); //Copy chunk of memory. Only goes forward.
|
||||||
public _extern _MEMCOPY U8 *MemCopy(
|
public _extern _MEMSET U8 *MemSet(U8 *dst,I64 val,I64 count); //Set chunk of U8s to value.
|
||||||
U8 *dst,U8 *src,I64 count); //Copy chunk of memory. Only goes forward.
|
public _extern _MEMSET_I64 I64 *MemSetI64(I64 *dst,I64 val,I64 I64count); //Set chunk of I64s to value.
|
||||||
public _extern _MEMSET U8 *MemSet(
|
public _extern _MEMSET_U16 U16 *MemSetU16(U16 *dst,I64 val,I64 U16count); //Set chunk of U16s to value.
|
||||||
U8 *dst,I64 val,I64 count); //Set chunk of U8s to value.
|
|
||||||
public _extern _MEMSET_I64 I64 *MemSetI64(
|
|
||||||
I64 *dst,I64 val,I64 I64count); //Set chunk of I64s to value.
|
|
||||||
public _extern _MEMSET_U16 U16 *MemSetU16(
|
|
||||||
U16 *dst,I64 val,I64 U16count); //Set chunk of U16s to value.
|
|
||||||
public _extern _MEMSET_U32 U32 *MemSetU32(U32 *dst,I64 val,I64 U32count); //Set chunk of U32s to value.
|
public _extern _MEMSET_U32 U32 *MemSetU32(U32 *dst,I64 val,I64 U32count); //Set chunk of U32s to value.
|
||||||
_extern SYS_HEAP_DEBUG_FLAG U8 sys_heap_debug;
|
_extern SYS_HEAP_DEBUG_FLAG U8 sys_heap_debug;
|
||||||
_extern SYS_HEAP_INIT_FLAG U8 sys_heap_init_flag;
|
_extern SYS_HEAP_INIT_FLAG U8 sys_heap_init_flag;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user