Added the apache license to all source files, accounting for authors. Also added a license.md containing the apache license + contributors.md listing all contributors.
300 lines
7.9 KiB
ObjectPascal
300 lines
7.9 KiB
ObjectPascal
// Copyright 2021 Aaron Hance
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
{ ************************************************
|
|
* Asuro
|
|
* Unit: Drivers/AHCI
|
|
* Description: AHCI SATA Driver
|
|
************************************************
|
|
* Author: Aaron Hance
|
|
* Contributors:
|
|
************************************************ }
|
|
|
|
unit AHCI;
|
|
|
|
interface
|
|
|
|
uses
|
|
util,
|
|
PCI,
|
|
drivertypes,
|
|
drivermanagement,
|
|
lmemorymanager,
|
|
console,
|
|
vmemorymanager;
|
|
|
|
type
|
|
|
|
//Struct hell
|
|
|
|
TFIS_Type = (
|
|
REG_H2D = $27,
|
|
REG_D2H = $34,
|
|
DMA_ACT = $39,
|
|
DMA_SETUP = $41,
|
|
DATA = $46,
|
|
BIST = $58,
|
|
PIO_SETUP = $5F,
|
|
DEV_BITS = $A0
|
|
);
|
|
|
|
PFIS_REG_H2D = ^TFIS_REG_H2D;
|
|
TFIS_REG_H2D = bitpacked record
|
|
fis_type : uint8;
|
|
port_mult : UBit4;
|
|
rsv0 : UBit3;
|
|
coc : boolean;
|
|
command : uint8;
|
|
feature_low : uint8;
|
|
lba0 : uint8;
|
|
lba1 : uint8;
|
|
lba2 : uint8;
|
|
device : uint8;
|
|
lba3 : uint8;
|
|
lba4 : uint8;
|
|
lba5 : uint8;
|
|
feature_high : uint8;
|
|
count_low : uint8;
|
|
count_high : uint8;
|
|
icc : uint8;
|
|
control : uint8;
|
|
rsvl : uint32;
|
|
end;
|
|
|
|
TFIS_REG_D2H = bitpacked record
|
|
fis_type : uint8;
|
|
port_mult : UBit4;
|
|
rsv0 : UBit2;
|
|
i : boolean;
|
|
rsvl : boolean;
|
|
status : uint8;
|
|
error : uint8;
|
|
lba0 : uint8;
|
|
lba1 : uint8;
|
|
lba2 : uint8;
|
|
device : uint8;
|
|
lba3 : uint8;
|
|
lba4 : uint8;
|
|
lba5 : uint8;
|
|
rsv2 : uint8;
|
|
count_low : uint8;
|
|
count_high : uint8;
|
|
rsv3 : uint16;
|
|
rsv4 : uint32;
|
|
end;
|
|
|
|
TFIS_Data = bitpacked record
|
|
fis_type : uint8;
|
|
port_mult : UBit4;
|
|
rsv0 : UBit4;
|
|
rsv1 : uint16;
|
|
data : ^uint32;
|
|
end;
|
|
|
|
TFIS_PIO_Setup = bitpacked record
|
|
fis_type : uint8;
|
|
pmport : UBit4;
|
|
rsv0 : boolean;
|
|
d : boolean;
|
|
i : boolean;
|
|
rsv1 : boolean;
|
|
status : uint8;
|
|
error : uint8;
|
|
lba0 : uint8;
|
|
lba1 : uint8;
|
|
lba2 : uint8;
|
|
device : uint8;
|
|
lba3 : uint8;
|
|
lba4 : uint8;
|
|
lba5 : uint8;
|
|
rsv2 : uint8;
|
|
countl : uint8;
|
|
counth : uint8;
|
|
rsv3 : uint8;
|
|
e_status : uint8;
|
|
tc : uint16;
|
|
rsv4 : uint16;
|
|
end;
|
|
|
|
// TFIS_DMA_Setup = bitpacked record
|
|
// end;
|
|
|
|
// THBA_Memory = bitpacked record
|
|
// end;
|
|
|
|
// THBA_Port = bitpacked record
|
|
// end;
|
|
|
|
// THBA_FIS = bitpacked record
|
|
// end;
|
|
|
|
PHBA_PORT = ^THBA_PORT;
|
|
THBA_PORT = bitpacked record
|
|
clb : uint32;
|
|
clbu : uint32;
|
|
fb : uint32;
|
|
fbu : uint32;
|
|
istat : uint32;
|
|
ie : uint32;
|
|
cmd : uint32;
|
|
rsv0 : uint32;
|
|
tfd : uint32;
|
|
sig : uint32;
|
|
ssts : uint32;
|
|
sctl : uint32;
|
|
serr : uint32;
|
|
sact : uint32;
|
|
ci : uint32;
|
|
sntf : uint32;
|
|
fbs : uint32;
|
|
rsv1 : array[0..11] of uint32;
|
|
vendor : array[0..4] of uint32;
|
|
end;
|
|
|
|
THBA_MEM = bitpacked record
|
|
cap : uint32; //0
|
|
global_host_control : uint32; //4
|
|
interrupt_status : uint32; //8
|
|
port_implemented : uint32; //c
|
|
version : uint32; //10
|
|
ccc_control : uint32; //14
|
|
ccc_ports : uint32; //18
|
|
em_location : uint32; //1c
|
|
em_Control : uint32; //20
|
|
hcap2 : uint32; //24
|
|
bohc : uint32; //28
|
|
rsv0 : array[0..210] of boolean;
|
|
ports : array[0..31] of THBA_Port;
|
|
end;
|
|
|
|
PHBA = ^THBA_MEM;
|
|
|
|
PCMDHeader = ^ TCommand_Header;
|
|
TCommand_Header = bitpacked record
|
|
cfl : ubit5;
|
|
a : boolean;
|
|
w : boolean;
|
|
p : boolean;
|
|
r : boolean;
|
|
b : boolean;
|
|
c : boolean;
|
|
rsv0 : boolean;
|
|
pmp : ubit4;
|
|
PRDTL : uint16;
|
|
PRDTBC : uint32;
|
|
CTBA : uint32;
|
|
CTBAU : uint32;
|
|
rsv1 : array[0..3] of uint32;
|
|
end;
|
|
|
|
TPRD_Entry = bitpacked record
|
|
data_base_address : uint32;
|
|
data_bade_address_U : uint32;
|
|
rsv0 : uint32;
|
|
data_byte_count : ubit22;
|
|
rsv1 : ubit9;
|
|
interrupt_oc : boolean;
|
|
end;
|
|
|
|
PCommand_Table = ^TCommand_Table;
|
|
TCommand_Table = bitpacked record
|
|
cfis : array[0..64] of uint8;
|
|
acmd : array[0..16] of uint8;
|
|
rsv : array[0..48] of uint8;
|
|
prdt : array[0..7] of TPRD_Entry;
|
|
end;
|
|
|
|
TSataDevice = record
|
|
controller : uint8;
|
|
port : uint8;
|
|
end;
|
|
|
|
var
|
|
//constants
|
|
//SATA_SIG_ATA := $101;
|
|
//SATA_SIG_ATAPI := $EB140101;
|
|
//STA_SIG_SEMB := $C33C0101;
|
|
//STAT_SIG_PM := $96690101;
|
|
AHCI_BASE: uint32 = $400000; //irrelivent
|
|
|
|
//other
|
|
ahciControllers : array[0.16] of PuInt32;
|
|
ahciControllerCount : uint8 = 0;
|
|
hba : array[0..16] of PHBA;
|
|
|
|
sataDevices : array[0..127] of TSataDevice;
|
|
sataDeviceCount : uint8;
|
|
|
|
|
|
|
|
procedure init();
|
|
procedure check_ports(controller : uint8);
|
|
procedure enable_cmd(port : uint8);
|
|
procedure disable_cmd(port : uint8);
|
|
procedure port_rebase(port : uint8);
|
|
function load(ptr:void): boolean;
|
|
function read(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean;
|
|
function write(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean;
|
|
function find_cmd_slot(port : uint8) : uint32;
|
|
|
|
implementation
|
|
|
|
procedure init();
|
|
var
|
|
devID : TDeviceIdentifier;
|
|
begin
|
|
console.writestringln('AHCI: Registering driver');
|
|
devID.bus:= biPCI;
|
|
devID.id0:= idANY;
|
|
devID.id1:= $00000001;
|
|
devID.id2:= $00000006;
|
|
devID.id3:= $00000001;
|
|
devID.id4:= idANY;
|
|
devID.ex:= nil;
|
|
drivermanagement.register_driver('AHCI Driver', @devID, @load);
|
|
end;
|
|
|
|
procedure load(ptr : void);
|
|
begin
|
|
console.writestringln('AHCI: initilizing a new controller');
|
|
ahciControllers[ahciControllerCount] := ptr;
|
|
hba[ahciControllerCount] := PPCI_Device(ptr)^.address5;
|
|
new_page_at_address(hba[ahciControllerCount]);
|
|
|
|
//here would be any controller setup needed
|
|
|
|
check_ports(ahciControllerCount);
|
|
ahciControllerCount += 1;
|
|
exit(true);
|
|
end;
|
|
|
|
procedure check_ports(controller : uint8);
|
|
var
|
|
d : uint32 = 1;
|
|
i : uint32;
|
|
begin
|
|
for i:=0 to 31 do begin
|
|
if (d > 0) and (hba[controller]^.port_implemented shr i) = 1 then begin
|
|
if (hba[controller]^.ports[i].ssts shr 8) <> 1 and (hba[controller]^.ports[i].ssts and $0F) <> 3 then begin
|
|
if hba[controller]^.ports[i].sig = 1 then begin
|
|
//device is sata
|
|
sataDevices[sataDeviceCount].controller := controller;
|
|
sataDevices[sataDeviceCount].port := i;
|
|
sataDeviceCount += 1;
|
|
end;
|
|
//TODO implement ATAPI
|
|
end;
|
|
end;
|
|
end;
|
|
end; |