7 Commits

Author SHA1 Message Date
569b2f0bca More cleanup 2025-03-23 10:20:55 +00:00
ed0f8d9c08 volume manager begginings 2025-03-22 18:22:22 +00:00
a2f6d7e76d Cleanup 2025-03-22 10:20:26 +00:00
babe4290e4 ahci reading 2025-03-20 22:12:42 +00:00
05eab23956 starting to work 2025-03-19 22:15:32 +00:00
f04f8aa411 there you go ki-ear-ron 2025-03-16 21:39:47 +00:00
6a3ebf1387 ahci progress 2025-03-15 20:13:33 +00:00
21 changed files with 2654 additions and 1845 deletions

View File

@ -4,4 +4,4 @@ echo "======================="
echo " " echo " "
echo "Compiling FPC Sources..." echo "Compiling FPC Sources..."
echo " " echo " "
fpc -Aelf -gw -n -va -O3 -Op3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas fpc -Aelf -gw -n -O3 -Op3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/storage/* -Fusrc/driver/storage/AHCI/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas

View File

@ -91,6 +91,7 @@ function getDeviceInfo(class_code : uint8; subclass_code : uint8; prog_if : uint
procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8); procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8);
procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32); procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32);
procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean); procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean);
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
implementation implementation
@ -442,4 +443,34 @@ begin
pop_trace; pop_trace;
end; end;
//Enable device inturrupts and set bus master
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
var
addr : uint32;
cmd : uint32;
begin
push_trace('PCI.enableDevice');
addr := ($1 shl 31);
addr := addr or (bus shl 16);
addr := addr or ((slot) shl 11);
addr := addr or ((func) shl 8);
addr := addr or ($04 and $FC);
outl(PCI_CONFIG_ADDRESS_PORT, addr);
cmd := inl(PCI_CONFIG_DATA_PORT);
cmd := cmd or PCI_COMMAND_MEM_SPACE;
cmd := cmd or PCI_COMMAND_BUS_MASTER;
cmd := cmd or (3 shl 1);
//enable interrupts, remove disable interrupt bit maybe
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
// cmd := cmd and not (1 shl 9);
outl(PCI_CONFIG_ADDRESS_PORT, addr);
outl(PCI_CONFIG_DATA_PORT, cmd);
pop_trace;
end;
end. end.

View File

@ -21,6 +21,29 @@ unit drivertypes;
interface interface
const
PCI_CONFIG_ADDRESS_PORT = $0CF8;
PCI_CONFIG_DATA_PORT = $0CFC;
PCI_COMMAND_IO_SPACE = $0001;
PCI_COMMAND_MEM_SPACE = $0002;
PCI_COMMAND_BUS_MASTER = $0004;
PCI_COMMAND_SPECIAL_CYC = $0008;
PCI_COMMAND_MEM_WRITE = $0010;
PCI_COMMAND_VGA_PALETTE = $0020;
PCI_COMMAND_PARITY = $0040;
PCI_COMMAND_WAIT = $0080;
PCI_COMMAND_SERR = $0100;
PCI_COMMAND_FAST_BACK = $0200;
PCI_COMMAND_INT_DISABLE = $0400;
PCI_COMMAND_SERR_ENABLE = $8000;
PCI_CAP_ID_MSI = $05;
// Bits in the MSI Control register (16-bit):
MSI_CONTROL_ENABLE = 1 shl 0; // Bit 0
MSI_CONTROL_64BIT = 1 shl 7; // Bit 7
MSI_CONTROL_PVMASK = 1 shl 8; // Bit 8 (optional: per-vector masking)
type type
PPCI_Device = ^TPCI_Device; PPCI_Device = ^TPCI_Device;
@ -44,6 +67,7 @@ type
address1 : uint32; address1 : uint32;
address2 : uint32; address2 : uint32;
address3 : uint32; address3 : uint32;
address4 : uint32; address4 : uint32;
address5 : uint32; address5 : uint32;
CIS_pointer : uint32; CIS_pointer : uint32;

View File

@ -1,296 +0,0 @@
// 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.
{
Drivers->Storage->AHCI - AHCI SATA Driver.
@author(Aaron Hance <ah@aaronhance.me>)
}
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;

View File

@ -23,21 +23,33 @@ unit AHCI;
interface interface
uses uses
util,
PCI,
drivertypes,
drivermanagement,
lmemorymanager,
console,
vmemorymanager,
AHCITypes, AHCITypes,
lists; console,
drivermanagement,
drivertypes,
idetypes,
isrmanager,
lists,
lmemorymanager,
PCI,
util,
vmemorymanager;
var var
ahciControllers : PDLList; ahciControllers : PDList;
page_base : puint32;
procedure init(); procedure init();
procedure load(); function load(ptr : void) : boolean;
procedure check_ports(controller : PAHCI_Controller);
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean);
procedure ahci_isr();
function find_cmd_slot(device : PAHCI_Device) : uint32;
function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
// function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
implementation implementation
@ -57,19 +69,388 @@ begin
//TODO check IDE devices in ide for sata devices //TODO check IDE devices in ide for sata devices
end; end;
procedure stop_port(port : PHBA_Port);
begin
port^.cmd := port^.cmd and not $1;
port^.cmd := port^.cmd and not $100;
while ((port^.cmd and $4000) or (port^.cmd and $8000)) <> 0 do begin
//wait for the port to stop
end;
end;
procedure start_port(port : PHBA_Port);
begin
while (port^.cmd and $8000) <> 0 do begin
//wait for port to not be busy
end;
port^.cmd := port^.cmd or $100;
port^.cmd := port^.cmd or $1;
end;
procedure reset_port(port : PHBA_Port);
var
ssts, serr, timeout : uint32;
begin
console.writestringln('AHCI: Performing a full port reset.');
port^.cmd := port^.cmd and not $1;
// Wait until CR (bit 15) is cleared.
timeout := 0;
while (port^.cmd and $8000) <> 0 do begin
timeout := timeout + 1;
if timeout > 1000000 then begin
console.writestringln('AHCI: Port reset timeout.');
break;
end;
end;
port^.sata_ctrl := port^.sata_ctrl or $FFFF0000;
while (port^.sata_status and $F) <> 3 do begin
//wait for the port to be ready
end;
// Clear the SERR register by writing 1s to it.
port^.sata_error := $FFFFFFFF;
start_port(port);
end;
// procedure reset_port(port : PHBA_Port);
// var
// ssts, serr, timeout : uint32;
// begin
// console.writestringln('AHCI: Performing a full port reset.');
// port^.cmd := port^.cmd and not $1;
// // Wait until CR (bit 15) is cleared.
// timeout := 0;
// while (port^.cmd and $8000) <> 0 do begin
// timeout := timeout + 1;
// if timeout > 1000000 then begin
// console.writestringln('AHCI: Port reset timeout.');
// break;
// end;
// end;
// port^.sata_ctrl := port^.sata_ctrl and $FFFF0000;
// port^.sata_ctrl := port^.sata_ctrl or $1;
// psleep(10);
// port^.sata_ctrl := port^.sata_ctrl and $FFFF0000;
// while (port^.sata_status and $F) <> $3 do begin
// //wait for the port to be ready
// end;
// // Clear the SERR register by writing 1s to it.
// port^.sata_error := $FFFFFFFF;
// // start_port(port);
// end;
{
Check the ports on the controller and setup the command list, FIS, and command table
}
procedure check_ports(controller : PAHCI_Controller); procedure check_ports(controller : PAHCI_Controller);
var var
i : uint32; i : uint32;
ii : uint32;
port : PHBA_Port; port : PHBA_Port;
device : PAHCI_Device;
cmd_list_base : puint32;
fis_base : puint32;
cmd_table_base : puint32;
command_header : PHBA_CMD_HEADER;
begin begin
console.writestring('AHCI: active ports: ');
console.writehexln(controller^.mio^.ports_implimented);
for i:=0 to 31 do begin
port := @controller^.mio^.ports[i];
console.writehex(port^.signature);
console.writestring(' ');
end;
for i:=0 to 31 do begin
if ((controller^.mio^.ports_implimented shr i) and 1) = 1 then begin
port := @controller^.mio^.ports[i];
console.writestring('AHCI: Port ');
console.writeint(i);
console.writestring(' implemented on controller ');
console.writehexln(uint32(controller^.pci_device^.address5));
device := PAHCI_Device(@controller^.devices[i]);
device^.port := port;
//check if the port is active TODO
console.writestring('AHCI: signature: ');
console.writehexln(port^.signature);
//check device type
case port^.signature of
SATA_SIG_ATA: begin
console.writestringln('AHCI: Device is SATA');
device^.device_type := SATA;
end;
SATA_SIG_ATAPI: begin
console.writestringln('AHCI: Device is ATAPI');
device^.device_type := ATAPI;
end;
SATA_SIG_SEMB: begin
console.writestringln('AHCI: Device is SEMB');
device^.device_type := SEMB;
end;
SATA_SIG_PM: begin
console.writestringln('AHCI: Device is PM');
device^.device_type := PM;
end;
end;
//NEEED TO STOP the port before doing anything
stop_port(port);
console.writestringln('AHCI: Port stopped');
//allocate memory for the command list and ensure it is aligned to 1024 bytes
cmd_list_base := kalloc(sizeof(THBA_CMD_HEADER) * 64);
cmd_list_base := puint32((uint32(cmd_list_base) + 1023) and $FFFFFC00);
memset(uint32(cmd_list_base), 0, sizeof(THBA_CMD_HEADER) * 32);
//set the command list base address
port^.cmdl_basel := vtop(uint32(cmd_list_base)); //todo set virtual address in device
port^.cmdl_baseu := 0;
device^.command_list := PHBA_CMD_HEADER(cmd_list_base);
//print the command list base address
console.writestring('AHCI: Command list base address: ');
console.writehexln(uint32(cmd_list_base));
//allocate memory for the FIS and ensure it is aligned to 256 bytes
fis_base := kalloc(sizeof(THBA_FIS) * 8);
fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00);
//set the FIS base address
port^.fis_basel := vtop(uint32(fis_base));
port^.fis_baseu := 0;
memset(uint32(fis_base), 0, sizeof(THBA_FIS));
device^.fis := PHBA_FIS(fis_base);
//todo check how many simultaneous commands are supported
//allocate memory for the command table and ensure it is aligned to 128 bytes
cmd_table_base := kalloc(sizeof(THBA_CMD_TABLE) * 64);
cmd_table_base := puint32((uint32(cmd_table_base) + 127) and $FFFFFF80);
memset(uint32(cmd_table_base), 0, sizeof(THBA_CMD_TABLE) * 32);
device^.command_table := PHBA_CMD_TABLE(cmd_table_base);
//set the command table base address and setup command table
for ii:=0 to 31 do begin
//set command header locations
command_header := PHBA_CMD_HEADER(uint32(cmd_list_base) + (ii * sizeof(THBA_CMD_HEADER)));
command_header^.prdtl := 32;
command_header^.cmd_table_base := vtop(uint32(cmd_table_base)) + (ii * sizeof(THBA_CMD_TABLE));
command_header^.cmd_table_baseu := 0;
end;
//reset the port
reset_port(port);
//print sata status
console.writestring('AHCI: sata status: ');
console.writehexln(port^.sata_status);
// //pass devices count as second param
if (device^.device_type = SATA) then begin
identify_device(controller, i, false);
end else if (device^.device_type = ATAPI) then begin
identify_device(controller, i, true);
end else begin
console.writestringln('AHCI: Unsupported device type');
end;
controller^.mio^.int_status := $FFFFFFFF;
end;
end;
end; end;
procedure load(ptr : void); procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean);
var
fis : PHBA_FIS_REG_H2D;
cmd_header : PHBA_CMD_HEADER;
cmd_table : PHBA_CMD_TABLE;
cmd : uint32;
i, timeout : uint32;
buffer : puint32;
device : PAHCI_Device;
tfd : uint32;
sec_count : uint32;
b8 : puint16;
begin
console.writestring('AHCI: Identifying device ');
console.writeintln(portIndex);
device := PAHCI_Device(@controller^.devices[portIndex]);
// (Optional) Print the device type if you store it:
console.writestring('AHCI: Device type: ');
// For example: if device^.device_type = SATA then ...
console.writestring('AHCI: sata status: ');
console.writehexln(device^.port^.sata_status);
console.writestring('AHCI: signature: ');
console.writehexln(device^.port^.signature);
console.writestring('AHCI: device type: ');
console.writeintln(uint32(device^.device_type));
//clear any pending interrupts
device^.port^.int_status := $FFFFFFFF;
device^.port^.int_enable := $0;
// Allocate a 512-byte DMA buffer for the IDENTIFY data
buffer := kalloc(512);
memset(uint32(buffer), 0, 512);
// Use command slot 0 for the IDENTIFY command.
cmd_header := device^.command_list; // Assuming slot 0 is at the beginning.
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
cmd_header^.wrt := 0;
cmd_header^.prdtl := 1;
cmd_header^.clear_busy := 1;
if isATAPI then begin
cmd_header^.atapi := 1;
end;
// Setup the command table (using slot 0)
cmd_table := device^.command_table;
cmd_table^.prdt[0].dba := vtop(uint32(buffer));
cmd_table^.prdt[0].dbc := 511; // 512 bytes (0-based count)
cmd_table^.prdt[0].int := 1; // Interrupt on completion
// if isATAPI then begin
// // ATAPI Identify Device command
// buffer[0] := $A1; // ATAPI Identify Device
// end;
// Construct the Command FIS in the command table's CFIS area
fis := PHBA_FIS_REG_H2D(@device^.command_table^.cmd_fis);
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
fis^.c := $1;
if isATAPI then begin
fis^.command := ATA_CMD_IDENTIFY_PACKET;
end else begin
fis^.command := ATA_CMD_IDENTIFY;
end;
fis^.device := $A0; // LBA mode 40?
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
while (device^.port^.tfd and $88) <> 0 do begin
// console.writestring('AHCI: tfd: ');
// console.writehexln(device^.port^.tfd);
end;
// Issue the command by setting bit 0 in the port's Command Issue register.
cmd := device^.port^.cmd_issue;
cmd := cmd or $1;
device^.port^.cmd_issue := cmd;
console.writestringln('AHCI: Sent identify command');
// Wait for command completion with a timeout.
timeout := 0;
repeat
cmd := device^.port^.cmd_issue; // Command Issue register
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
device^.port^.int_status := $FFFFFFFF; // Clear any pending interrupts
timeout := timeout + 10;
if timeout > 100000 then begin
console.writestringln('AHCI: IDENTIFY command timeout');
break;
end;
// check for bit 30 in the tfd register
if (tfd and $40000000) <> 0 then begin
console.writestringln('AHCI: error');
break;
end;
until ((device^.port^.cmd_issue and $1) = 0); // Wait until slot 0 is cleared
console.writestringln('AHCI: Command complete');
// Check for an error flag in the command register (bit 1)
if (cmd and $2) <> 0 then begin
console.writestringln('AHCI: Error sending identify command');
// Check the error register for more information
console.writestring('AHCI: Error register: ');
console.writehexln(device^.port^.sata_error);
end;
// Dump the 512-byte IDENTIFY data for debugging (display 64 DWORDs)
for i := 0 to 63 do begin
console.writehex(uint32(buffer[i]));
console.writestring(' ');
end;
console.writestringln('');
b8 := puint16(buffer);
sec_count := (b8[61] shl 16) or b8[60];
console.writestring('AHCI: Sector count: ');
console.writeintln(sec_count);
console.writestring('AHCI: Device size: ');
console.writeint(sec_count * 512 div 1024 div 1024);
console.writestringln(' MB');
console.writestringln('');
buffer := puint32(kalloc(2048));
memset(uint32(buffer), 0, 2048);
//send a read DMA command to the device
if isATAPI then begin
read_atapi(device, 0, 2048, buffer);
end else begin
memset(uint32(buffer), $77, 2048);
send_write_dma(device, 22, 512, buffer);
memset(uint32(buffer), 0, 2048);
send_read_dma(device, 22, 512, buffer);
end;
//print the buffer
for i:=0 to 63 do begin
console.writehex(puInt8(buffer)[i]);
console.writestring(' ');
end;
console.writestringln('');
end;
function load(ptr : void) : boolean;
var var
device : PPCI_Device; device : PPCI_Device;
controller : PAHCI_Controller; controller : PAHCI_Controller;
i : uint32; i : uint32;
base : PHBA_Memory; base : PHBA_Memory;
cmd_list_base : puint32;
fis_base : puint32;
cmd_table_base : puint32;
int_no : uInt8;
timeout : uint32;
bohc : uint32;
begin begin
console.writestringln('AHCI: initilizing a new controller'); console.writestringln('AHCI: initilizing a new controller');
@ -80,33 +461,439 @@ begin
device := PPCI_Device(ptr); device := PPCI_Device(ptr);
controller := DL_Add(ahciControllers); pci.enableDevice(device^.bus, device^.slot, device^.func);
controller^.device := device; psleep(5);
int_no := device^.interrupt_line + 32;
base: PHBA_Memory(kpalloc(device^.address5)); // get the base address of the controller
//print interrupt number
console.writestring('AHCI: Interrupt number: ');
console.writehexln(int_no);
controller := PAHCI_Controller(DL_Add(ahciControllers));
controller^.pci_device := PPCI_Device(device);
// Perform BIOS/OS handoff (if the bit in the extended capabilities is set)
// Reset controller
//get the base address of the controller
page_base := kpalloc(device^.address5); // TODO MEM memory manager need to be improved
base := PHBA_Memory(device^.address5);
controller^.mio := base; controller^.mio := base;
if (controller^.mio^.capabilites2 and $28) <> 0 then begin
console.writestringln('AHCI: Controller needs to be handed off to the OS');
end;
console.writestring('AHCI: Controller at: ');
console.writehexln(device^.address5);
console.writehexln(uint32(page_base));
bohc := controller^.mio^.bohc;
if (bohc and $1) <> 0 or (bohc and not (1 shl 1)) then begin
console.writestringln('AHCI: BIOS Owned Semaphore is set, initiating handoff.');
// Set the OS Owned Semaphore (typically bit 1).
bohc := bohc or (1 shl 1);
controller^.mio^.bohc := bohc;
// Wait until the BIOS Owned Semaphore (bit 0) is cleared.
timeout := 0;
while ((controller^.mio^.bohc and $1) <> 0) and (timeout < 1000000) do begin
timeout := timeout + 1;
end;
if timeout = 1000000 then begin
console.writestringln('AHCI: BIOS/OS handoff timed out.');
end else begin
console.writestringln('AHCI: BIOS/OS handoff successful.');
end;
end else begin
console.writestringln('AHCI: BIOS not holding controller or handoff already complete.');
end;
base^.global_ctrl := base^.global_ctrl or 1;
while (base^.global_ctrl and 1) <> 0 do begin
end;
registerISR(int_no, @ahci_isr);
//enable AHCI mode, TODO check if is not already in AHCI mode and enable it, also perhaps remove if loaded as IDE //enable AHCI mode, TODO check if is not already in AHCI mode and enable it, also perhaps remove if loaded as IDE
base^.ghc := base^.ghc or AHCI_CONTROLLER_MODE; base^.global_ctrl := base^.global_ctrl or AHCI_CONTROLLER_MODE;
// base^.global_ctrl := base^.global_ctrl or $2; //enable interrupts
//disable interrupts
base^.global_ctrl := base^.global_ctrl or $2;
//clear any pending interrupts //clear any pending interrupts
base^.int_status := $FFFFFFFF; base^.int_status := $FFFFFFFF;
check_ports(controller);
end;
procedure ahci_isr();
begin
console.writestringln('AHCI: ISR');
console.redrawWindows();
//welp there is no way to know what port caused the interrupt or even if it was the controller
//so we will just have to check all ports, and figure the operation that caused the interrupt
end;
function find_cmd_slot(device : PAHCI_Device) : uint32;
var
i : uint32;
begin
// for i:=0 to 31 do begin
// if (device^.port^.cmd_issue[i] and $80000000) = 0 then begin
// exit(i);
// end;
// end;
exit(0);
end;
function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
var
fis : PHBA_FIS_REG_H2D;
cmd_header : PHBA_CMD_HEADER;
cmd_table : PHBA_CMD_TABLE;
cmd : uint32;
i, timeout : uint32;
tfd : uint32;
sec_count : uint32;
prdt_count : uint32;
b8 : puint16;
slot : uint32;
begin
console.writestringln('AHCI: Sending read DMA command');
reset_port(device^.port);
//prdt count is 22 bits
prdt_count := (count div 4194304) + 1;
if prdt_count > 32 then begin
send_read_dma := false;
exit;
end;
// Use command slot 0 for the IDENTIFY command.
slot := find_cmd_slot(device);
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
cmd_header^.wrt := 0;
cmd_header^.prdtl := prdt_count;
cmd_header^.clear_busy := 1;
// Setup the command table (using slot 0)
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
for i:=0 to prdt_count - 1 do begin
cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304));
if i = prdt_count - 1 then begin
cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count)
end else begin
cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count)
end;
cmd_table^.prdt[i].int := 1; // Interrupt on completion
end;
// Construct the Command FIS in the command table's CFIS area
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
fis^.c := $1;
fis^.command := ATA_CMD_READ_DMA_EXT;
fis^.device := $40; // LBA mode 48?
fis^.lba0 := lba and $FF;
fis^.lba1 := (lba shr 8) and $FF;
fis^.lba2 := (lba shr 16) and $FF;
fis^.lba3 := (lba shr 24) and $FF;
fis^.lba4 := (lba shr 32) and $FF;
fis^.countl := count and $FF;
fis^.counth := (count shr 8) and $FF;
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
while (device^.port^.tfd and $88) <> 0 do begin
// console.writestring('AHCI: tfd: ');
// console.writehexln(device^.port^.tfd);
end;
// Issue the command by setting bit 0 in the port's Command Issue register.
cmd := device^.port^.cmd_issue;
cmd := cmd or (1 shl slot);
device^.port^.cmd_issue := cmd;
console.writestringln('AHCI: Sent read DMA command');
// Wait for command completion with a timeout.
timeout := 0;
repeat
cmd := device^.port^.cmd_issue; // Command Issue register
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
timeout := timeout + 10;
if timeout > 100000 then begin
console.writestringln('AHCI: Read DMA command timeout');
break;
end;
// check for bit 30 in the tfd register
if (tfd and $40000000) <> 0 then begin
console.writestringln('AHCI: error');
break;
end;
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
console.writestringln('AHCI: Command complete');
// Check for an error flag in the command register (bit 1)
if (cmd and (1 shl slot)) <> 0 then begin
console.writestringln('AHCI: Error sending read DMA command');
// Check the error register for more information
console.writestring('AHCI: Error register: ');
console.writehexln(device^.port^.sata_error);
end;
send_read_dma := true;
end;
function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
var
fis : PHBA_FIS_REG_H2D;
cmd_header : PHBA_CMD_HEADER;
cmd_table : PHBA_CMD_TABLE;
cmd : uint32;
i, timeout : uint32;
tfd : uint32;
sec_count : uint32;
prdt_count : uint32;
b8 : puint16;
slot : uint32;
begin
console.writestringln('AHCI: Sending write DMA command');
reset_port(device^.port);
//prdt count is 22 bits
prdt_count := (count div 4194304) + 1;
if prdt_count > 32 then begin
send_write_dma := false;
exit;
end;
// Use command slot 0 for the IDENTIFY command.
slot := find_cmd_slot(device);
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
cmd_header^.wrt := 1;
cmd_header^.prdtl := prdt_count;
cmd_header^.clear_busy := 1;
// Setup the command table (using slot 0)
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
for i:=0 to prdt_count - 1 do begin
cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304));
if i = prdt_count - 1 then begin
cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count)
end else begin
cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count)
end;
cmd_table^.prdt[i].int := 1; // Interrupt on completion
end;
// Construct the Command FIS in the command table's CFIS area
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
fis^.c := $1;
fis^.command := ATA_CMD_WRITE_DMA_EXT;
fis^.device := $40; // LBA mode 48?
count:= count div 512;
fis^.lba0 := lba and $FF;
fis^.lba1 := (
lba shr 8) and $FF;
fis^.lba2 := (
lba shr 16) and $FF;
fis^.lba3 := (
lba shr 24) and $FF;
fis^.lba4 := (
lba shr 32) and $FF;
fis^.countl := count and $FF;
fis^.counth := (
count shr 8) and $FF;
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
while (device^.port^.tfd and $88) <> 0 do begin
// console.writestring('AHCI: tfd: ');
// console.writehexln(device^.port^.tfd);
end;
// Issue the command by setting bit 0 in the port's Command Issue register.
cmd := device^.port^.cmd_issue;
cmd := cmd or (1 shl slot);
device^.port^.cmd_issue := cmd;
console.writestringln('AHCI: Sent write DMA command');
// Wait for command completion with a timeout.
timeout := 0;
repeat
cmd := device^.port^.cmd_issue; // Command Issue register
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
timeout := timeout + 10;
if timeout > 100000 then begin
console.writestringln('AHCI: Write DMA command timeout');
break;
end;
// check for bit 30 in the tfd register
if (tfd and $40000000) <> 0 then begin
console.writestringln('AHCI: error');
break;
end;
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
console.writestringln('AHCI: Command complete');
// Check for an error flag in the command register (bit 1)
if (cmd and (1 shl slot)) <> 0 then begin
console.writestringln('AHCI: Error sending write DMA command');
// Check the error register for more information
console.writestring('AHCI: Error register: ');
console.writehexln(device^.port^.sata_error);
end;
send_write_dma := true;
end;
//read atapi
function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
var
fis : PHBA_FIS_REG_H2D;
cmd_header : PHBA_CMD_HEADER;
cmd_table : PHBA_CMD_TABLE;
cmd : uint32;
i, timeout : uint32;
tfd : uint32;
sec_count : uint32;
prdt_count : uint32;
b8 : puint16;
slot : uint32;
begin
console.writestringln('AHCI: Sending read ATAPI command');
reset_port(device^.port);
//prdt count is 22 bits
prdt_count := (count div 4194304) + 1;
if prdt_count > 32 then begin
read_atapi := false;
exit;
end;
// Use command slot 0 for the IDENTIFY command.
slot := find_cmd_slot(device);
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
cmd_header^.wrt := 0;
cmd_header^.prdtl := 1;
cmd_header^.atapi := 1;
cmd_header^.clear_busy := 1;
// Setup the command table (using slot 0)
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
cmd_table^.prdt[0].dba := vtop(uint32(buffer));
cmd_table^.prdt[0].dbc := 2048 - 1; // 512 bytes (0-based count
cmd_table^.prdt[0].int := 1; // Interrupt on completion
// Construct the Command FIS in the command table's CFIS area
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
fis^.c := $1;
fis^.command := ATA_CMD_PACKET;
fis^.device := $A0;
fis^.featurel := fis^.featurel or 1; //setting both of these might not work on real hardware
fis^.featurel := fis^.featurel or (1 shl 2);
cmd_table^.acmd[0] := $A8; //ATAPI command
cmd_table^.acmd[1] := $0; //ATAPI command
cmd_table^.acmd[2] := uInt8((lba shr 24) and $FF);
cmd_table^.acmd[3] := uInt8((lba shr 16) and $FF);
cmd_table^.acmd[4] := uInt8((lba shr 8) and $FF);
cmd_table^.acmd[5] := uInt8(lba and $FF);
cmd_table^.acmd[9] := uInt8((1) and $FF);
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
while (device^.port^.tfd and $88) <> 0 do begin
// console.writestring('AHCI: tfd: ');
// console.writehexln(device^.port^.tfd);
end;
// Issue the command by setting bit 0 in the port's Command Issue register.
cmd := device^.port^.cmd_issue;
cmd := cmd or (1 shl slot);
device^.port^.cmd_issue := cmd;
// console.writestringln('AHCI: initilizing a new controller'); console.writestringln('AHCI: Sent read ATAPI command');
// ahciControllers[ahciControllerCount] := ptr;
// hba[ahciControllerCount] := PPCI_Device(ptr)^.address5;
// new_page_at_address(hba[ahciControllerCount]);
// //here would be any controller setup needed // Wait for command completion with a timeout.
timeout := 0;
repeat
cmd := device^.port^.cmd_issue; // Command Issue register
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
timeout := timeout + 10;
if timeout > 100000 then begin
console.writestringln('AHCI: Read ATAPI command timeout');
break;
end;
// check for bit 30 in the tfd register
if (tfd and $40000000) <> 0 then begin
console.writestringln('AHCI: error');
break;
end;
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
console.writestringln('AHCI: Command complete');
// Check for an error flag in the command register (bit 1)
if (cmd and (1 shl slot)) <> 0 then begin
console.writestringln('AHCI: Error sending read ATAPI command');
// Check the error register for more information
console.writestring('AHCI: Error register: ');
console.writehexln(device^.port^.sata_error);
end;
read_atapi := true;
// check_ports(ahciControllerCount);
// ahciControllerCount += 1;
// exit(true);
end; end;
end. end.

View File

@ -26,11 +26,18 @@ uses
drivermanagement, drivermanagement,
lmemorymanager, lmemorymanager,
console, console,
vmemorymanager; vmemorymanager,
idetypes,
lists;
const const
AHCI_CONTROLLER_MODE = $80000000; AHCI_CONTROLLER_MODE = $80000000;
CMD_LIST_ALIGN = 1024;
CMD_TBL_ALIGN = 128;
NUM_CMD_ENTRIES = 32;
//device type signatures //device type signatures
SATA_SIG_ATA = $00000101; SATA_SIG_ATA = $00000101;
SATA_SIG_ATAPI = $EB140101; SATA_SIG_ATAPI = $EB140101;
@ -65,7 +72,7 @@ type
rsv0: uint32; // Reserved rsv0: uint32; // Reserved
tfd: uint32; // Task File Data tfd: uint32; // Task File Data
signature: uint32; // Signature signature: uint32; // Signature
sata_stat: uint32; // SATA Status (SCR0:SStatus) sata_status: uint32; // SATA Status (SCR0:SStatus)
sata_ctrl: uint32; // SATA Control (SCR2:SControl) sata_ctrl: uint32; // SATA Control (SCR2:SControl)
sata_error: uint32; // SATA Error (SCR1:SError) sata_error: uint32; // SATA Error (SCR1:SError)
sata_active: uint32; // SATA Active sata_active: uint32; // SATA Active
@ -73,19 +80,22 @@ type
sata_noti: uint32; // SATA Notification sata_noti: uint32; // SATA Notification
fis_switch_ctrl: uint32;// FIS-based Switch Control fis_switch_ctrl: uint32;// FIS-based Switch Control
rsv1: array[0..10] of uint32; rsv1: array[0..10] of uint32;
vendor: array[0..3] of uint32;
end; end;
PHBA_Port = ^THBA_Port;
{ {
AHCI Host Bus Adapter (HBA) Memory-Mapped Register Interface AHCI Host Bus Adapter (HBA) Memory-Mapped Register Interface
This structure is used to access the AHCI HBA's memory-mapped registers. This structure is used to access the AHCI's memory-mapped registers.
The AHCI HBA's memory-mapped registers are used to configure the HBA and The AHCI's memory-mapped registers are used to configure the HBA and to
to issue commands to the SATA devices connected to the HBA. issue commands to the SATA devices connected to the HBA.
} }
THBA_Memory = bitpacked record THBA_Memory = bitpacked record
capabilites: uint32; // Host Capabilities capabilites: uint32; // Host Capabilities
global_ctrl: uint32; // Global Host Control global_ctrl: uint32; // Global Host Control
int_status: uint32; // Interrupt Status int_status: uint32; // Interrupt Status
ports_implemented: uint32; // Ports Implemented ports_implimented: uint32;// Ports Implemented
version: uint32; // Version version: uint32; // Version
ccc_control: uint32; // Command Completion Coalescing Control ccc_control: uint32; // Command Completion Coalescing Control
ccc_ports: uint32; // Command Completion Coalescing Ports ccc_ports: uint32; // Command Completion Coalescing Ports
@ -93,8 +103,16 @@ type
em_control: uint32; // Enclosure Management Control em_control: uint32; // Enclosure Management Control
capabilites2: uint32; // Host Capabilities Extended capabilites2: uint32; // Host Capabilities Extended
bohc: uint32; // BIOS/OS Handoff Control and Status bohc: uint32; // BIOS/OS Handoff Control and Status
rsv0: array[0..0x210] of boolean;
//0x2c to 0x9f reserved
rsv0: array[0..115] of uint8;
//vendor specific
vendor: array[0..95] of uint8;
//port registers
ports: array[0..31] of THBA_Port; ports: array[0..31] of THBA_Port;
end; end;
PHBA_Memory = ^THBA_Memory; PHBA_Memory = ^THBA_Memory;
@ -102,93 +120,119 @@ type
{ {
AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface
This structure is used to access the AHCI HBA's FIS (Frame Information Structure) This structure is used to access the AHCI HBA's FIS (Frame Information Structure)
memory-mapped registers. The AHCI HBA's FIS memory-mapped registers are used to memory-mapped registers. RX
configure the HBA and to issue commands to the SATA devices connected to the HBA.
} }
THBA_FIS = bitpacked record THBA_FIS = bitpacked record
dsfis: array[0..0x1F] of uint32; // DMA Setup FIS dsfis: array[0..$1F] of uint32; // DMA Setup FIS
rsv0: array[0..0x1F] of uint32; rsv0: array[0..$1F] of uint32;
psfis: array[0..0x1F] of uint32; // PIO Setup FIS psfis: array[0..$1F] of uint32; // PIO Setup FIS
rsv1: array[0..0x1F] of uint32; rsv1: array[0..$1F] of uint32;
rfis: array[0..0x1F] of uint32; // D2H Register FIS rfis: array[0..$1F] of uint32; // D2H Register FIS
rsv2: array[0..0x1F] of uint32; rsv2: array[0..$1F] of uint32;
sdbfis: array[0..0xF] of uint32; // Set Device Bits FIS sdbfis: array[0..$F] of uint32; // Set Device Bits FIS
ufis: array[0..0x1F] of uint32; // Unknown FIS ufis: array[0..$1F] of uint32; // Unknown FIS
rsv3: array[0..0x67] of uint32; rsv3: array[0..$67] of uint32;
end; end;
PHBA_FIS = ^THBA_FIS;
//enum fis type
TFISType = (
FIS_TYPE_REG_H2D = $27, // Register FIS - Host to Device
FIS_TYPE_REG_D2H = $34, // Register FIS - Device to Host
FIS_TYPE_DMA_ACT = $39, // DMA Activate FIS - Device to Host
FIS_TYPE_DMA_SETUP = $41, // DMA Setup FIS - Bidirectional
FIS_TYPE_DATA = $46, // Data FIS - Bidirectional
FIS_TYPE_BIST = $58, // BIST Activate FIS - Bidirectional
FIS_TYPE_PIO_SETUP = $5F, // PIO Setup FIS - Device to Host
FIS_TYPE_DEV_BITS = $A1 // Set Device Bits FIS - Device to Host
);
{
AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface
This structure is used to access the AHCI HBA's FIS (Frame Information Structure)
}
THBA_FIS_REG_H2D = bitpacked record
fis_type: uint8; // FIS Type
// pmport: uint8; // Port Multiplier Port is pmport:4 and rsv0:3 and i:1
pmport: ubit4; // Port Multiplier Port
rsv: ubit3; // Reserved
c: ubit1; // command or control
command: uint8; // Command
featurel: uint8; // Feature Lower 8-bits
lba0: uint8; // LBA0
lba1: uint8; // LBA1
lba2: uint8; // LBA2
device: uint8; // Device
lba3: uint8; // LBA3
lba4: uint8; // LBA4
lba5: uint8; // LBA5
featureh: uint8; // Feature Upper 8-bits
countl: uint8; // Count Lower 8-bits
counth: uint8; // Count Upper 8-bits
icc: uint8; // Isochronous Command Completion
control: uint8; // Control
rsv0: array[0..3] of uint8;
end;
PHBA_FIS_REG_H2D = ^THBA_FIS_REG_H2D;
{ {
AHCI Host Bus Adapter (HBA) Command Header Interface AHCI Host Bus Adapter (HBA) Command Header Interface
This structure is used to access the AHCI HBA's Command Header memory-mapped
registers. The AHCI HBA's Command Header memory-mapped registers are used to
configure the HBA and to issue commands to the SATA devices connected to the HBA.
} }
THBA_CMD_HEADER = bitpacked record THBA_CMD_HEADER = bitpacked record
cmd_fis_length: uint8; // Command FIS Length cmd_fis_length: UBit5; // Command FIS Length
atapi: uint8; // ATAPI atapi: UBit1; // ATAPI
write: uint8; // Write wrt: UBit1; // Write
prefetchable: uint8; // Prefetchable prefetchable: UBit1; // Prefetchable
reset: uint8; // Reset
bist: uint8; // BIST reset: UBit1; // Reset
clear_busy: uint8; // Clear Busy bist: UBit1; // BIST
reserved0: uint8; // Reserved clear_busy: UBit1; // Clear Busy
reserved0: UBit1; // Reserved
port_multiplier: UBit4; // Port Multiplier Port
prdtl: uint16; // Physical Region Descriptor Table Length prdtl: uint16; // Physical Region Descriptor Table Length
prdbc: uint32; // Physical Region Descriptor Byte Count prdbc: uint32; // Physical Region Descriptor Byte Count
cmd_table_base: uint32; // Command Table Base Address cmd_table_base: uint32; // Command Table Base Address
cmd_table_baseu: uint32; // Command Table Base Address Upper 32-bits cmd_table_baseu: uint32; // Command Table Base Address Upper 32-bits
rsv0: array[0..4] of uint32; rsv0: array[0..3] of uint32;
end; end;
PHBA_CMD_HEADER = ^THBA_CMD_HEADER;
{ {
AHCI Host Bus Adapter (HBA) Command Table Interface AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped
registers. The AHCI HBA's Command Table memory-mapped registers are used to
configure the HBA and to issue commands to the SATA devices connected to the HBA.
}
THBA_CMD_TABLE = bitpacked record
cmd_fis: THBA_FIS; // Command FIS
acmd: array[0..0x1F] of uint8; // ATAPI Command
rsv0: array[0..0x30] of uint8;
end;
{
AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped
registers. The AHCI HBA's Command Table memory-mapped registers are used to
configure the HBA and to issue commands to the SATA devices connected to the HBA.
} }
THBA_PRD = bitpacked record THBA_PRD = bitpacked record
dba: uint32; // Data Base Address dba: uint32; // Data Base Address
dbau: uint32; // Data Base Address Upper 32-bits dbau: uint32; // Data Base Address Upper 32-bits
rsv0: uint32; // Reserved rsv0: uint32; // Reserved
dbc: uint32; // Data Byte Count dbc: ubit22; // Data Byte Count
rsv1: uint32; // Reserved reserved: ubit9; // Reserved
int: ubit1; // Interrupt
// dbc: uint32; // Data Byte Count, bit 1 is Interrupt, then 22 bits of Byte Count, then 9 bits of Reserved
end; end;
TPRDT = array[0..31] of THBA_PRD;
PPRDT = ^TPRDT;
{ {
AHCI Host Bus Adapter (HBA) Command Table Interface AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped
registers. The AHCI HBA's Command Table memory-mapped registers are used to
configure the HBA and to issue commands to the SATA devices connected to the HBA.
} }
THBA_CMD = bitpacked record THBA_CMD_TABLE = bitpacked record
header: THBA_CMD_HEADER; // Command Header cmd_fis: array[0..63] of uint8; // Command FIS
table: THBA_CMD_TABLE; // Command Table acmd: array[0..15] of uint8; // ATAPI Command
prd: array[0..0x7] of THBA_PRD; // Physical Region Descriptor Table rsv0: array[0..47] of uint8;
prdt: array[0..31] of THBA_PRD; // Physical Region Descriptor Table
end; end;
{ PHBA_CMD_TABLE = ^THBA_CMD_TABLE;
AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped
registers. The AHCI HBA's Command Table memory-mapped registers are used to
configure the HBA and to issue commands to the SATA devices connected to the HBA.
}
THBA = bitpacked record
memory: THBA_Memory; // HBA Memory
cmd: array[0..0x7FF] of THBA_CMD; // Command List
end;
PHBA = ^THBA; TCMD_LIST = array[0..255] of THBA_CMD_HEADER;
PCMD_LIST = ^TCMD_LIST;
////////////////////////////////////////// //////////////////////////////////////////
//////////// Asuro AHCI types //////////// //////////// Asuro AHCI types ////////////
@ -198,26 +242,41 @@ type
Device type enum Device type enum
} }
TDeviceType = ( TDeviceType = (
SATA, SATA = 1,
ATAPI, ATAPI = 2,
SEMB, SEMB,
PM PM
); );
{
AHCI device reference
}
TAHCI_Device = bitpacked record
port : PHBA_Port;
device_type : TDeviceType;
ata_info : TIdentResponse;
command_list : PHBA_CMD_HEADER;
fis : PHBA_FIS;
command_table : PHBA_CMD_TABLE;
end;
PAHCI_Device = ^TAHCI_Device;
{ {
controller reference controller reference
} }
TAHCI_Controller = bitpacked record TAHCI_Controller = bitpacked record
pci_device : PPCI_Device; pci_device : PPCI_Device;
mio: PHBA_Memory; mio: PHBA_Memory;
devices : array[0..31] of uint8; //TODO type for devices ata_info : TIdentResponse;
devices : array[0..31] of TAHCI_Device;
end; end;
PAHCI_Controller = ^TAHCI_Controller; PAHCI_Controller = ^TAHCI_Controller;
function get_device_type(sig : uint32) : TDeviceType; function get_device_type(sig : uint32) : TDeviceType;
function get_device_type_string(deive_type : TDeviceType) : string; // function get_device_type_string(deive_type : TDeviceType) : string;
implementation implementation
@ -239,23 +298,23 @@ begin
end; end;
end; end;
function get_device_type_string(deive_type : TDeviceType) : string; // function get_device_type_string(deive_type : TDeviceType) : string;
begin // begin
case deive_type of // case deive_type of
SATA: begin // SATA: begin
get_device_type_string := 'SATA'; // get_device_type_string := 'SATA';
end; // end;
ATAPI: begin // ATAPI: begin
get_device_type_string := 'ATAPI'; // get_device_type_string := 'ATAPI';
end; // end;
SEMB: begin // SEMB: begin
get_device_type_string := 'SEMB'; // get_device_type_string := 'SEMB';
end; // end;
PM: begin // PM: begin
get_device_type_string := 'PM'; // get_device_type_string := 'PM';
end; // end;
end; // end;
end; // end;
end. end.

View File

@ -1,85 +0,0 @@
// 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.
{
Drivers->Storage->ATA_ISR - Primary ATA IRQ.
@author(Aaron Hance <ah@aaronhance.me>)
}
unit ATA_ISR;
interface
uses
util,
console,
isr_types,
isrmanager,
IDT;
procedure register();
procedure hook(hook_method : uint32);
procedure unhook(hook_method : uint32);
implementation
var
Hooks : Array[1..MAX_HOOKS] of pp_hook_method;
procedure Main(); interrupt;
var
i : integer;
begin
CLI;
for i:=0 to MAX_HOOKS-1 do begin
if uint32(Hooks[i]) <> 0 then Hooks[i](void($00000000));
end;
console.writestringln('Disk Operation Complete');
end;
procedure register();
begin
memset(uint32(@Hooks[0]), 0, sizeof(pp_hook_method)*MAX_HOOKS);
//isrmanager.registerISR(76, @Main);
//IDT.set_gate(76, uint32(@Main), $08, ISR_RING_0);
end;
procedure hook(hook_method : uint32);
var
i : uint32;
begin
for i:=0 to MAX_HOOKS-1 do begin
if uint32(Hooks[i]) = hook_method then exit;
end;
for i:=0 to MAX_HOOKS-1 do begin
if uint32(Hooks[i]) = 0 then begin
Hooks[i]:= pp_hook_method(hook_method);
exit;
end;
end;
end;
procedure unhook(hook_method : uint32);
var
i : uint32;
begin
for i:=0 to MAX_HOOKS-1 do begin
If uint32(Hooks[i]) = hook_method then Hooks[i]:= nil;
exit;
end;
end;
end.

View File

@ -15,6 +15,8 @@
{ {
Drivers->Storage->ide - IDE Driver. Drivers->Storage->ide - IDE Driver.
NOT FINSIHED NEEDS WORK
@author(Aaron Hance <ah@aaronhance.me>) @author(Aaron Hance <ah@aaronhance.me>)
} }
unit ide; unit ide;
@ -24,20 +26,18 @@ interface
uses uses
ata, ata,
atapi, atapi,
util,
drivertypes,
console, console,
terminal,
drivermanagement, drivermanagement,
vmemorymanager, drivertypes,
lmemorymanager,
storagemanagement,
strings,
tracer,
drivemanager,
storagetypes,
idetypes, idetypes,
isrmanager; isrmanager,
lmemorymanager,
storagetypes,
strings,
terminal,
tracer,
util,
vmemorymanager;
var var
@ -440,8 +440,8 @@ begin
// end; // end;
end; end;
//register the device //register the device TODO
drivemanager.register_device(storageDevice); // drivemanager.register_device(storageDevice);
end else begin end else begin
console.writestringln('[IDE] (load_device) Device is not present'); console.writestringln('[IDE] (load_device) Device is not present');

View File

@ -0,0 +1,429 @@
// 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.
{
Driver->Storage->VolumeManager Drive volume manager
@author(Aaron Hance ah@aaronhance.me)
}
unit volumemanager;
interface
uses
util,
console,
terminal,
strings,
lists,
tracer,
lmemorymanager,
vfs,
MBR,
storagetypes;
type
TDirectory_Entry_Type = (directoryEntry, fileEntry, mountEntry);
PDirectory_Entry = ^TDirectory_Entry;
PFilesystem = ^TFilesystem;
PStorage_Volume = ^TStorage_Volume;
PPWriteHook = procedure(volume : PStorage_volume; directory : pchar; entry : PDirectory_Entry; byteCount : uint32; buffer : puint32; statusOut : puint32);
PPReadHook = function(volume : PStorage_Volume; directory : pchar; fileName : pchar; fileExtension : pchar; buffer : puint32; bytecount : puint32) : uint32;
PPHIOHook = procedure(volume : PStorage_device; addr : uint32; sectors : uint32; buffer : puint32);
PPCreateHook = procedure(volume : PStorage_volume; start : uint32; size : uint32; config : puint32);
PPDetectHook = procedure(disk : PStorage_Device);
PPCreateDirHook = procedure(volume : PStorage_volume; directory : pchar; dirname : pchar; attributes : uint32; status : puint32);
PPReadDirHook = function(volume : PStorage_volume; directory : pchar; status : puint32) : PLinkedListBase; //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error
PPHIOHook_ = procedure;
TFilesystem = record
sName : pchar;
system_id : uint8;
writeCallback : PPWriteHook;
readCallback : PPReadHook;
createCallback : PPCreateHook; //create volume
detectCallback : PPDetectHook; //detect volume
createDirCallback : PPCreateDirHook;
readDirCallback : PPReadDirHook;
end;
TStorage_Volume = record
volumeHandle : uint32;
device : PStorage_device;
sectorStart : uint32;
sectorSize : uint32;
sectorCount : uint32;
freeSectors : uint32;
filesystem : PFilesystem;
{ True if this drive contains the loaded OS }
isBootDrive : boolean;
end;
{ Generic directory entry }
TDirectory_Entry = record
{ Contains filename and optionally file extension, seperated by the last period.}
fileName : pchar;
entryType : TDirectory_Entry_Type;
// creationT : TDateTime;
// modifiedT : TDateTime;
end;
TFilehandleEntry = record
volume : PStorage_Volume;
fileName : pchar;
fileHandle : uint32;
openMode : TOpenMode;
writeMode : TWriteMode;
lock : Boolean;
closed : Boolean;
end;
PFilehandleEntry = ^TFilehandleEntry;
var
storageVolumes : PLinkedListBase;
filesystems : PlinkedListBase;
fileHandles : PLinkedListBase;
{ Returns the number of volumes }
procedure init();
procedure register_filesystem(filesystem : PFilesystem);
procedure check_for_volumes(drive : PStorage_device);
procedure create_volume(disk : PStorage_device; filesystem : PChar; sectorStart : uint32; sectorCount : uint32);
//IO functions
implementation
procedure format_volume_command(params : PParamList);
var
volume : PStorage_Volume;
filesystem : PFilesystem;
config : puint32;
begin
push_trace('VolumeManager.format_volume_command');
console.writestringlnWND('Not implimented, use disk format', getTerminalHWND());
exit;
if paramCount(params) < 3 then begin
console.writestringlnWND('Invalid arguments', getTerminalHWND());
end;
push_trace('VolumeManager.format_volume_command.1');
volume := PStorage_volume(LL_get(storageVolumes, stringToInt(getParam(1, params))));
filesystem := PFilesystem(LL_get(filesystems, stringToInt(getParam(2, params))));
push_trace('VolumeManager.format_volume_command.2');
config := PuInt32(kalloc(sizeof(uInt32)));
config^ := 4;
push_trace('VolumeManager.format_volume_command.3');
//TODO check things exsist
console.writestringlnWND('Staring volume formatting...', getTerminalHWND());
// filesystem^.formatVolumeCallback(volume^.device, volume^.sectorSize, volume^.sectorStart, config);
console.writestringlnWND('Volume format finished.', getTerminalHWND());
end;
procedure list_filesystems_command();
var
i : uint32;
filesystem : PFilesystem;
begin
push_trace('VolumeManager.list_filesystems_command');
if LL_Size(filesystems) < 1 then begin
console.writestringlnWnd('ERROR: no filesystems found!', getTerminalHWND());
exit;
end;
console.writestringlnWnd('Filesystems: ', getTerminalHWND());
for i:=0 to LL_Size(filesystems) - 1 do begin
filesystem := PFilesystem(LL_Get(filesystems, i));
console.writestringWnd(' ', getTerminalHWND());
console.writestringWnd(filesystem^.sName, getTerminalHWND());
console.writestringWnd(' - ', getTerminalHWND());
console.writehexlnWND(filesystem^.system_id, getTerminalHWND());
end;
end;
procedure list_volume_command();
var
i : uint32;
volume : PStorage_Volume;
begin
push_trace('VolumeManager.list_volume_command');
if LL_Size(storageVolumes) < 1 then begin
console.writestringlnWnd('No volumes found.', getTerminalHWND());
exit;
end;
console.writestringlnWnd('Volumes: ', getTerminalHWND());
for i:=0 to LL_Size(storageVolumes) - 1 do begin
volume := PStorage_Volume(LL_Get(storageVolumes, i));
console.writestringWnd(' ', getTerminalHWND());
console.writeintWnd(i, getTerminalHWND());
console.writestringWnd(' - Capacity: ', getTerminalHWND());
console.writeintWnd(uint32((volume^.sectorSize * volume^.sectorCount) DIV 1024 DIV 1024), getTerminalHWND());
console.writestringWnd('MB, Filesystem: ', getTerminalHWND());
if volume^.filesystem <> nil then begin
console.writestringlnWnd(volume^.filesystem^.sName, getTerminalHWND());
end else begin
console.writestringlnWnd('None', getTerminalHWND());
end;
end;
end;
procedure volume_command(params : PParamList);
var
i : uint16;
subcmd : pchar;
begin
push_trace('VolumeManager.volume_command');
subcmd:= getParam(0, params);
if ((paramCount(params) = 0)) then begin
console.writestringlnWnd('Please provide valid arguments.', getTerminalHWND());
console.writestringlnWnd(' ls - for listing all volumes', getTerminalHWND());
console.writestringlnWnd(' lsfs - for listing all filesystems', getTerminalHWND());
console.writestringlnWnd(' info [volume] - display formation for specified volume', getTerminalHWND());
console.writestringlnWnd(' format [volume] [filesystem] - destructive, formats a volume with a specified filesystem', getTerminalHWND());
exit;
end;
if( stringEquals(subcmd, 'ls') ) then begin
list_volume_command();
exit;
end;
if( stringEquals(subcmd, 'lsfs') ) then begin
list_filesystems_command();
exit;
end;
if( stringEquals(subcmd, 'format') ) then begin
format_volume_command(params);
exit;
end;
end;
{ Initialise volume manager }
procedure init();
begin
push_trace('VolumeManager.init');
{ setup lists }
storageVolumes:= ll_New(sizeof(TFilesystem));
filesystems:= ll_New(sizeof(TFilesystem));
fileHandles:= ll_New(sizeof(TFilehandleEntry));
{ register commands }
terminal.registerCommand('volume', @volume_command, 'Volume utility');
end;
{ register a new type of filesystem }
procedure register_filesystem(filesystem : PFilesystem); //TODO on init create null filesystem for empty partition
var
elm : void;
begin
//add filesystem
elm := LL_add(filesystems);
memcpy(uint32(filesystem), uInt32(elm), SizeOf(TFilesystem));
//check drives for volumes of new type
end;
{ Check for volumes on a physical device }
procedure check_for_volumes(drive : PStorage_device);
var
bootrecord : PMaster_Boot_Record;
storageVolume : TStorage_Volume;
i : uint32 = 0;
elm : void;
begin
push_trace('VolumeManager.check_for_volumes');
bootrecord := PMaster_Boot_Record(kalloc(SizeOf(TMaster_Boot_Record)));
drive^.readCallback(drive, 0, 1, puint32(bootrecord)); //TODO multiple drives
//TODO multipe partition entries
if bootrecord^.partition[0].LBA_start <> 0 then
begin
//set volume information
storageVolume.device := drive;
storageVolume.sectorStart := bootrecord^.partition[0].LBA_start;
storageVolume.sectorCount := bootrecord^.partition[0].sector_count;
storageVolume.sectorSize := drive^.sectorSize;
storageVolume.freeSectors := 0; //TODO impliment
storageVolume.filesystem := nil;
if LL_Size(filesystems) < 1 then begin
console.writestringln('Failed to initalise storage system, no filesystems found, stopping!');
exit;
end;
//check for filesystem type
for i:=0 to LL_Size(filesystems) - 1 do begin
if bootrecord^.partition[0].system_id = PFilesystem(LL_Get(filesystems, i))^.system_id then
begin
storageVolume.filesystem := PFilesystem(LL_Get(filesystems, i));
end;
end;
push_trace('VolumeManager.init3');
//add volume to list
elm := LL_Add(storageVolumes);
memcpy(uint32(@storageVolume), uint32(elm), SizeOf(TStorage_Volume));
push_trace('VolumeManager.init4');
elm := LL_Add(drive^.volumes);
memcpy(uint32(@storageVolume), uint32(elm), SizeOf(TStorage_Volume));
end;
end;
procedure remove_volume(list : PLinkedListBase; volume : PStorage_Volume);
var
i : uint32;
elm : void;
begin
for i:=0 to LL_Size(list) - 1 do begin
elm := LL_Get(list, i);
if (PStorage_Volume(elm)^.device = volume^.device)
and (PStorage_Volume(elm)^.sectorStart = volume^.sectorStart) then begin
LL_Delete(list, i);
break;
end;
end;
end;
procedure create_volume(disk : PStorage_device; filesystem : PChar; sectorStart : uint32; sectorCount : uint32);
var
volume : PStorage_Volume;
elm : void;
i : uint16;
config : PuInt32;
begin
push_trace('VolumeManager.create_volume');
volume := PStorage_Volume(kalloc(SizeOf(TStorage_Volume)));
volume^.device := disk;
volume^.sectorStart := sectorStart;
volume^.sectorCount := sectorCount - 10;
volume^.sectorSize := disk^.sectorSize;
volume^.freeSectors := 0; //setup by filesystem
//find filesystem
for i:=0 to LL_Size(filesystems) - 1 do begin
if stringEquals(filesystem, PFilesystem(LL_Get(filesystems, i))^.sName) then begin
volume^.filesystem := PFilesystem(LL_Get(filesystems, i));
end;
end;
//TODO CHECK FILESYSTEM EXSISTS
//format volume
volume^.filesystem^.createCallback(volume, sectorCount, sectorStart, config);
push_trace('VolumeManager.create_volume.2');
//remove volume from list of volumes
remove_volume(storageVolumes, volume);
//add volume to list
elm := LL_Add(storageVolumes);
memcpy(uint32(volume), uint32(elm), SizeOf(TStorage_Volume));
push_trace('VolumeManager.create_volume.3');
//remove volume from list of volumes on device
remove_volume(disk^.volumes, volume);
//add volume to device
elm := LL_Add(disk^.volumes);
memcpy(uint32(volume), uint32(elm), SizeOf(TStorage_Volume));
//free memory
kfree(puint32(volume));
end;
procedure register_volume(device : PStorage_Device; volume : PStorage_Volume);
var
elm : void;
begin
push_trace('storagemanagement.register_volume');
elm := LL_Add(device^.volumes);
PStorage_volume(elm)^:= volume^;
// if rootVolume = PStorage_Volume(0) then rootVolume:= volume;
end;
procedure openFile(Handle : uint32; Filename : PChar; OpenMode : TOpenMode; WriteMode : TWriteMode; lock : boolean; Error : PError);
var
fileHandleEntree : PFilehandleEntry;
fileHandle : uInt32;
i : uint32;
elm : void;
begin
push_trace('VolumeManager.openFile');
//check if file is already open and if it is locked, if openmode is not read only
if OpenMode <> omReadOnly then begin
for i:=0 to LL_Size(fileHandles) - 1 do begin
elm := LL_Get(fileHandles, i);
if stringEquals(PFilehandleEntry(elm)^.filename, Filename) then begin
if PFilehandleEntry(elm)^.lock and (not PFilehandleEntry(elm)^.closed) then begin
Error^ := eFileInUse;
exit;
end;
end;
end;
end;
//create filehandleentry
fileHandleEntree := PFilehandleEntry(kalloc(SizeOf(TFilehandleEntry)));
fileHandleEntree^.fileName := Filename;
fileHandleEntree^.openMode := OpenMode;
fileHandleEntree^.writeMode := WriteMode;
fileHandleEntree^.lock := lock;
fileHandleEntree^.closed := false;
//create filehandle
fileHandle := LL_Size(fileHandles);
end;
end.

View File

@ -22,19 +22,17 @@ unit ata;
interface interface
uses uses
util,
drivertypes,
console, console,
terminal,
drivermanagement, drivermanagement,
vmemorymanager, drivertypes,
idetypes,
lmemorymanager, lmemorymanager,
storagemanagement,
strings,
tracer,
drivemanager,
storagetypes, storagetypes,
idetypes; strings,
terminal,
tracer,
util,
vmemorymanager;
var var

View File

@ -1,21 +1,43 @@
// 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.
{
Drivers->Storage->ATAPI - ATAPI Driver.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!! CURRENTLY NOT FUNCTIONAL !!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@author(Aaron Hance <ah@aaronhance.me>)
}
unit atapi; unit atapi;
interface interface
uses uses
util,
drivertypes,
console, console,
terminal,
drivermanagement, drivermanagement,
vmemorymanager, drivertypes,
idetypes,
lmemorymanager, lmemorymanager,
storagemanagement,
strings,
tracer,
drivemanager,
storagetypes, storagetypes,
idetypes; strings,
terminal,
tracer,
util,
vmemorymanager;
var var
@ -30,7 +52,8 @@ var
implementation implementation
uses uses
ide, ata; ata,
ide;
procedure ide_irq(); procedure ide_irq();

View File

@ -1,504 +0,0 @@
{ ************************************************
* Asuro
* Unit: Drivers/storage/IDE
* Description: IDE ATA Driver
*
************************************************
* Author: Aaron Hance
* Contributors:
************************************************ }
unit IDE;
interface
uses
util,
drivertypes,
console,
terminal,
drivermanagement,
vmemorymanager,
lmemorymanager,
storagemanagement,
strings,
tracer,
drivemanager,
storagetypes;
type
TPortMode = (P_READ, P_WRITE);
TIdentResponse = array[0..255] of uint16;
TIDE_Channel_Registers = record
base : uint16;
ctrl : uint16;
bmide : uint16;
noInter : uint8
end;
TIDE_Device = record
exists : boolean;
isPrimary : boolean;
isMaster : boolean;
isATAPI : boolean;
info : TIdentResponse;
end;
TIDE_Status = bitpacked record
Busy : Boolean;
Ready : Boolean;
Fault : Boolean;
Seek : Boolean;
DRQ : Boolean;
CORR : Boolean;
IDDEX : Boolean;
ERROR : Boolean;
end;
PIDE_Status = ^TIDE_Status;
const
ATA_SR_BUSY = $80; //BUSY
ATA_SR_DRDY = $40; //DRIVE READY
ATA_SR_DF = $20; //DRIVE WRITE FAULT
ATA_SR_DSC = $10; //DRIVE SEEK COMPLETE
ATA_SR_DRQ = $08; //DATA REQUEST READY
ATA_SR_CORR = $04; //CORRECTED DATA
ATA_SR_IDX = $02; //INLEX
ATA_SR_ERR = $01; //ERROR
ATA_ER_BBK = $80; //BAD SECTOR
ATA_ER_UNC = $40; //UNCORRECTABLE DATA
ATA_ER_MC = $20; //NO MEDIA
ATA_ER_IDNF = $10; //ID MARK NOT FOUND
ATA_ER_MCR = $08; //NO MEDIA
ATA_ER_ABRT = $04; //COMMAND ABORTED
ATA_ER_TK0NF = $02; //TRACK 0 NOT FOUND
ATA_ER_AMNF = $01; //NO ADDRESS MARK
ATA_CMD_READ_PIO = $20;
ATA_CMD_READ_PIO_EXT = $24;
ATA_CMD_READ_DMA = $C8;
ATA_CMD_READ_DMA_EXT = $25;
ATA_CMD_WRITE_PIO = $30;
ATA_CMD_WRITE_PIO_EXT = $34;
ATA_CMD_WRITE_DMA = $CA;
ATA_CMD_WRITE_DMA_EXT = $35;
ATA_CMD_CACHE_FLUSH = $E7;
ATA_CMD_CACHE_FLUSH_EXT = $EA;
ATA_CMD_PACKET = $A0;
ATA_CMD_IDENTIFY_PACKET = $A1;
ATA_CMD_IDENTIFY = $EC;
ATAPI_CMD_READ = $A8;
ATAPI_CMD_EJECT = $1B;
ATA_IDENT_DEVICETYPE = $0;
ATA_IDENT_CYLINDERS = $2;
ATA_IDENT_HEADS = $6;
ATA_IDENT_SECOTRS = $12;
ATA_IDENT_SERIAL = $20;
ATA_IDENT_MODEL = $54;
ATA_IDENT_CAPABILITIES = $98;
ATA_IDENT_FIELDVALID = $106;
ATA_IDENT_MAX_LBA = $120;
ATA_IDENT_COMMANDSETS = $164;
ATA_IDENT_MAX_LBA_EXT = $200;
ATA_REG_DATA = $00;
ATA_REG_ERROR = $01;
ATA_REG_FEATURES = $01;
ATA_REG_SECCOUNT = $02;
ATA_REG_LBA0 = $03;
ATA_REG_LBA1 = $04;
ATA_REG_LBA2 = $05;
ATA_REG_HDDEVSEL = $06;
ATA_REG_COMMAND = $07;
ATA_REG_STATUS = $07;
ATA_REG_SECCOUNT1 = $08;
ATA_REG_LBA3 = $09;
ATA_REG_LBA4 = $0A;
ATA_REG_LBA5 = $0B;
ATA_REG_CONTROL = $0C;
ATA_REG_ALTSTATUS = $0C;
ATA_REG_DEVADDRESS = $0D;
ATA_DEVICE_MASTER = $A0;
ATA_DEVICE_SLAVE = $B0;
ATA_PRIMARY_BASE = $1F0;
var
controller : PPCI_Device;
bar0 : uint32;
bar1 : uint32;
bar4 : uint32;
IDEDevices : array[0..3] of TIDE_Device;
buffer : Puint32;
procedure init();
function load(ptr : void) : boolean;
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
// procedure flush();
procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8);
procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8);
//read/write must be capable of reading/writting any amknt of data upto disk size
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
implementation
function port_read(register : uint8) : uint8;
begin
port_read:= inb(ATA_PRIMARY_BASE + register);
end;
procedure port_write(register : uint8; data : uint8);
var
i : uint8;
begin
outb(ATA_PRIMARY_BASE + register, data);
util.psleep(1);
if register = ATA_REG_COMMAND then begin
for i:= 0 to 5 do begin
port_read(ATA_REG_STATUS);
end;
end;
end;
procedure no_interrupt(device : uint8);
begin
outb($3F6, inb($3f6) or (1 shl 1));
end;
procedure device_select(device : uint8);
begin
outb($1F6, device); //TODO clean
end;
function is_ready() : boolean;
var
status : uint8;
i : uint32;
begin
//wait for drive to be ready
while true do begin
status := port_read(ATA_REG_COMMAND);
if(status and ATA_SR_ERR) = ATA_SR_ERR then begin
console.writestringln('[IDE] (IDENTIFY_DEVICE) DRIVE ERROR!');
console.redrawWindows();
is_ready := false;
break;
end;
if (status and ATA_SR_BUSY) <> ATA_SR_BUSY then begin
is_ready := true;
break;
end;
end;
end;
function validate_28bit_address(addr : uint32) : boolean;
begin
validate_28bit_address := (addr and $F0000000) = 0;
end;
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
var
status : uint8;
identResponse : TIdentResponse;
i : uint8;
begin
push_trace('IDE.Identify_Device');
device_select(device);
no_interrupt(device);
port_write(ATA_REG_CONTROL, 0);
console.writestringln('[IDE] (IDENTIFY_DEVICE) CHECK FLOATING BUS');
//check if bus is floating
status := port_read(ATA_REG_COMMAND);
if status = $FF then exit;
port_write(ATA_REG_SECCOUNT, 0);
port_write(ATA_REG_LBA0, 0);
port_write(ATA_REG_LBA1, 0);
port_write(ATA_REG_LBA2, 0);
console.writestringln('[IDE] (IDENTIFY_DEVICE) SEND IDENTIFY COMMAND');
port_write(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
console.writestringln('[IDE] (IDENTIFY_DEVICE) WAIT FOR DRIVE TO BE READY');
//check if drive is present
status := port_read(ATA_REG_COMMAND);
if status = $00 then exit;
console.writestringln('[IDE] (IDENTIFY_DEVICE) WAIT FOR DRIVE TO BE READY');
if not is_ready() then exit;
console.writestringln('[IDE] (IDENTIFY_DEVICE) READ IDENTIFY RESPONSE');
for i:=0 to 255 do begin
console.writeint(i);
identResponse[i] := inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
end;
console.writestringln('[IDE] (IDENTIFY_DEVICE) IDENTIFY RESPONSE RECEIVED');
identify_device := identResponse;
end;
procedure init();
var
devID : TDeviceIdentifier;
begin
push_trace('ide.init');
console.writestringln('[IDE] (INIT) BEGIN');
devID.bus:= biPCI;
devID.id0:= idANY;
devID.id1:= $00000001;
devID.id2:= $00000001;
devID.id3:= idANY;
devID.id4:= idANY;
devID.ex:= nil;
drivermanagement.register_driver('IDE ATA Driver', @devID, @load);
console.writestringln('[IDE] (INIT) END');
end;
function load(ptr : void) : boolean;
var
controller : PPCI_Device;
masterDevice : TStorage_Device;
slaveDevice : TStorage_Device;
buffer : puint8;
i : uint8;
test : PStorage_device;
tbuf : puint8;
begin
push_trace('ide.load');
console.writestringln('[IDE] (LOAD) BEGIN');
controller := PPCI_Device(ptr);
console.writestringln('[IDE] (INIT) CHECK FLOATING BUS');
//check if bus is floating and identify device
if inb($1F7) <> $FF then begin
//outb($3F6, inb($3f6) or (1 shl 1)); // disable interrupts
IDEDevices[0].isMaster:= true;
IDEDevices[0].info := identify_device(0, ATA_DEVICE_MASTER);
e
mastrDevice.controller := ControllerIDE;
masterDevice.controllerId0:= 0;
masterDevice.maxSectorCount:= (IDEDevices[0].info[60] or (IDEDevices[0].info[61] shl 16) ); //LBA28 SATA
if IDEDevices[0].info[1] = 0 then begin
console.writestringln('[IDE] (INIT) ERROR: DEVICE IDENT FAILED!');
exit;
end;
// masterDevice.hpc:= uint32(IDEDevices[0].info[3] DIV IDEDevices[0].info[1]); //TODO wtf is hpc
masterDevice.sectorSize:= 512;
if masterDevice.maxSectorCount <> 0 then begin
IDEDevices[0].exists:= true;
masterDevice.readCallback:= @dread;
masterDevice.writeCallback:= @dwrite;
// storagemanagement.register_device(@masterDevice);
drivemanager.register_device(@masterDevice);
end;
end;
// buffer:= puint8(kalloc(512));
// buffer[0] := 1;
// buffer[1] := 2;
// buffer[2] := 3;
// buffer[3] := 4;
// buffer[4] := 5;
// buffer[5] := 6;
// writePIO28(0, 3, buffer);
// writePIO28(0, 3, buffer);
// writePIO28(0, 3, buffer);
// writePIO28(0, 4, buffer);
// writePIO28(0, 5, buffer);
// writePIO28(0, 5, buffer);
// writePIO28(0, 5, buffer);
// psleep(1000);
// writePIO28(0, 5, buffer);
// writePIO28(0, 5, buffer);
// writePIO28(0, 5, buffer);
// kfree(puint32(buffer));
console.writestringln('[IDE] (LOAD) END');
//read first 16 bytes of disk
tbuf:= puint8(kalloc(512));
//set buffer to 1F1F repeating
for i:=0 to 200 do begin
tbuf[i] := 31;
end;
//write buffer to disk
writePIO28(0, 0, tbuf);
memset(uint32(tbuf), 0, 512);
readPIO28(0, 0, puint8(tbuf));
console.writestringln('[IDE] (INIT) READ FIRST 4 BYTES OF DISK');
console.writehexln(tbuf[0]);
console.writehexln(tbuf[1]);
console.writehexln(tbuf[2]);
console.writehexln(tbuf[3]);
kfree(puint32(tbuf));
end;
procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8);
var
status : uint8;
i: uint16;
device: uint8;
data: uint16;
begin
push_trace('IDE.readPIO28');
if not validate_28bit_address(LBA) then begin
console.writestringln('IDE (writePIO28) ERROR: Invalid LBA!');
end;
// push_trace('IDE.readPIO28.2');
//Add last 4 bits of LBA to device port
if IDEDevices[drive].isMaster then begin
device:= ATA_DEVICE_MASTER;
device_select($E0 or ((LBA and $0F000000) shr 24)); //LBA primary master
end
else begin
device:= ATA_DEVICE_SLAVE;
device_select($F0 or ((LBA and $0F000000) shr 24)); //LBA primary slave
end;
// push_trace('IDE.readPIO28.3');
no_interrupt(device);
port_write(ATA_REG_ERROR, 0);
//Write sector count and LBA
port_write(ATA_REG_SECCOUNT, 1);
port_write(ATA_REG_LBA0, (LBA and $000000FF));
port_write(ATA_REG_LBA1, (LBA and $0000FF00) shr 8);
port_write(ATA_REG_LBA2, (LBA and $00FF0000) shr 16);
// push_trace('IDE.readPIO28.4');
//send read command
port_write(ATA_REG_COMMAND, ATA_CMD_READ_PIO);
if not is_ready() then exit;
i:=0;
while i < 512 do begin
// if not is_ready() then exit;
data:= inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
buffer[i+1] := uint8($00ff and (data shr 8));
buffer[i] := uint8($00ff and data);
i:= i + 2;
if not is_ready() then exit;
end;
// push_trace('IDE.readPIO28.5');
end;
procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8);
var
status : uint8;
i: uint16;
device: uint8;
begin
push_trace('IDE.WritePIO28');
if not validate_28bit_address(LBA) then begin
console.writestringln('IDE (writePIO28) ERROR: Invalid LBA!');
end;
console.writeintln(uint32(drive));
console.writeintln(LBA);
//Add last 4 bits of LBA to device port
if IDEDevices[drive].isMaster then begin
device:= ATA_DEVICE_MASTER;
device_select($E0 or ((LBA and $0F000000) shr 24)); //LBA primary master
end
else begin
device:= ATA_DEVICE_SLAVE;
device_select($F0 or ((LBA and $0F000000) shr 24)); //LBA primary slave
end;
// no_interrupt(device);
port_write(ATA_REG_ERROR, 0);
port_write(ATA_REG_CONTROL, 0);
// check if bus is floating
status := port_read(ATA_REG_COMMAND);
if status = $FF then exit;
//Write sector count and LBA
port_write(ATA_REG_SECCOUNT, 1);
port_write(ATA_REG_LBA0, (LBA and $000000FF));
port_write(ATA_REG_LBA1, (LBA and $0000FF00) shr 8);
port_write(ATA_REG_LBA2, (LBA and $00FF0000) shr 16);
//send write command
port_write(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
//write data
i:=0;
while i < 512 do begin
outw(ATA_PRIMARY_BASE + ATA_REG_DATA, uint16(buffer[i] or (buffer[i+1] shl 8)));
i:= i + 2;
end;
//flush drive cache
psleep(1);
port_write(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
psleep(1);
if not is_ready() then exit;
end;
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : Puint32);
var
i : uint16;
begin
push_trace('IDE.dread');
for i:=0 to sectorCount-1 do begin
readPIO28(device^.controllerId0, LBA + i, puint8(@buffer[512*i]));
psleep(100)
end;
end;
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : Puint32);
var
i : uint16;
begin
for i:=0 to sectorCount-1 do begin
writePIO28(device^.controllerId0, LBA + i, puint8(@buffer[512*i]));
psleep(100)
end;
// writePIO28(device^.controllerId0, LBA, puint8(buffer));
end;
end.

View File

@ -26,8 +26,26 @@ uses
type type
TControllerType = (ControllerATA, ControllerATAPI, ControllerUSB, ControllerAHCI, TControllerType = (
ControllerNET, ControllerRAM, rsvctr1, rsvctr2, rsvctr3); ControllerATA,
ControllerATAPI,
ControllerUSB,
ControllerAHCI,
ControllerAHCI_ATAPI,
ControllerNVMe,
ControllerNET,
ControllerRAM,
ControllerSCSI
);
TFileSystemType = (
FileSystemFAT32,
FileSystemExFAT,
FileSystemEXT,
FileSystemEXT2,
FileSystemCDFS,
FileSystemOther
);
PStorage_device = ^TStorage_Device; PStorage_device = ^TStorage_Device;
PDrive_Error = ^TDrive_Error; PDrive_Error = ^TDrive_Error;
@ -44,13 +62,26 @@ type
controller : TControllerType; controller : TControllerType;
controllerId0 : uint32; controllerId0 : uint32;
writable : boolean; writable : boolean;
volumes : PLinkedListBase; volumes : PDList;
writeCallback : PPHIOHook; writeCallback : PPHIOHook;
readCallback : PPHIOHook; readCallback : PPHIOHook;
maxSectorCount : uint32; maxSectorCount : uint32;
sectorSize : uint32; sectorSize : uint32; //in bytes
start : uint32; //start of device in sectors
end; end;
{ Generic storage volume }
TStorage_Volume = record
id : uint32;
device : PStorage_device;
name : pchar;
fileSystem : TFileSystemType;
size : uint32; //size of volume in sectors
start : uint32; //start of volume in sectors
end;
PStorage_Volume = ^TStorage_Volume;
TDrive_Error = record TDrive_Error = record
code : uint16; code : uint16;
description : pchar; description : pchar;

View File

@ -13,417 +13,96 @@
// limitations under the License. // limitations under the License.
{ {
Driver->Storage->VolumeManager Drive volume manager Driver->Storage->VolumeManager - Volume manager for storage devices.
@author(Aaron Hance ah@aaronhance.me) @author(Aaron Hance ah@aaronhance.me)
} }
unit volumemanager; unit volumemanager;
interface interface
uses uses
util,
console, console,
terminal, drivermanagement,
strings, drivertypes,
lists, lists,
tracer,
lmemorymanager, lmemorymanager,
vfs,
MBR, MBR,
storagetypes; rtc,
serial,
type storagetypes,
strings,
TDirectory_Entry_Type = (directoryEntry, fileEntry, mountEntry); terminal,
tracer,
PDirectory_Entry = ^TDirectory_Entry; util;
PFilesystem = ^TFilesystem;
PStorage_Volume = ^TStorage_Volume;
PPWriteHook = procedure(volume : PStorage_volume; directory : pchar; entry : PDirectory_Entry; byteCount : uint32; buffer : puint32; statusOut : puint32);
PPReadHook = function(volume : PStorage_Volume; directory : pchar; fileName : pchar; fileExtension : pchar; buffer : puint32; bytecount : puint32) : uint32;
PPHIOHook = procedure(volume : PStorage_device; addr : uint32; sectors : uint32; buffer : puint32);
PPCreateHook = procedure(volume : PStorage_volume; start : uint32; size : uint32; config : puint32);
PPDetectHook = procedure(disk : PStorage_Device);
PPCreateDirHook = procedure(volume : PStorage_volume; directory : pchar; dirname : pchar; attributes : uint32; status : puint32);
PPReadDirHook = function(volume : PStorage_volume; directory : pchar; status : puint32) : PLinkedListBase; //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error
PPHIOHook_ = procedure;
TFilesystem = record
sName : pchar;
system_id : uint8;
writeCallback : PPWriteHook;
readCallback : PPReadHook;
createCallback : PPCreateHook; //create volume
detectCallback : PPDetectHook; //detect volume
createDirCallback : PPCreateDirHook;
readDirCallback : PPReadDirHook;
end;
TStorage_Volume = record
volumeHandle : uint32;
device : PStorage_device;
sectorStart : uint32;
sectorSize : uint32;
sectorCount : uint32;
freeSectors : uint32;
filesystem : PFilesystem;
{ True if this drive contains the loaded OS }
isBootDrive : boolean;
end;
{ Generic directory entry }
TDirectory_Entry = record
{ Contains filename and optionally file extension, seperated by the last period.}
fileName : pchar;
entryType : TDirectory_Entry_Type;
// creationT : TDateTime;
// modifiedT : TDateTime;
end;
TFilehandleEntry = record
volume : PStorage_Volume;
fileName : pchar;
fileHandle : uint32;
openMode : TOpenMode;
writeMode : TWriteMode;
lock : Boolean;
closed : Boolean;
end;
PFilehandleEntry = ^TFilehandleEntry;
var var
storageDevices : PDList; //index in this array is global drive id
storageVolumes : PLinkedListBase; volumes : PDList;
filesystems : PlinkedListBase;
fileHandles : PLinkedListBase;
{ Returns the number of volumes }
procedure init(); procedure init();
procedure register_device(device : PStorage_Device);
function discover_volumes(device : PStorage_device) : PDList;
procedure register_filesystem(filesystem : PFilesystem); function get_volume_list() : PDList;
procedure check_for_volumes(drive : PStorage_device);
procedure create_volume(disk : PStorage_device; filesystem : PChar; sectorStart : uint32; sectorCount : uint32);
//IO functions
implementation implementation
procedure format_volume_command(params : PParamList);
var
volume : PStorage_Volume;
filesystem : PFilesystem;
config : puint32;
begin
push_trace('VolumeManager.format_volume_command');
console.writestringlnWND('Not implimented, use disk format', getTerminalHWND());
exit;
if paramCount(params) < 3 then begin
console.writestringlnWND('Invalid arguments', getTerminalHWND());
end;
push_trace('VolumeManager.format_volume_command.1');
volume := PStorage_volume(LL_get(storageVolumes, stringToInt(getParam(1, params))));
filesystem := PFilesystem(LL_get(filesystems, stringToInt(getParam(2, params))));
push_trace('VolumeManager.format_volume_command.2');
config := PuInt32(kalloc(sizeof(uInt32)));
config^ := 4;
push_trace('VolumeManager.format_volume_command.3');
//TODO check things exsist
console.writestringlnWND('Staring volume formatting...', getTerminalHWND());
// filesystem^.formatVolumeCallback(volume^.device, volume^.sectorSize, volume^.sectorStart, config);
console.writestringlnWND('Volume format finished.', getTerminalHWND());
end;
procedure list_filesystems_command();
var
i : uint32;
filesystem : PFilesystem;
begin
push_trace('VolumeManager.list_filesystems_command');
if LL_Size(filesystems) < 1 then begin
console.writestringlnWnd('ERROR: no filesystems found!', getTerminalHWND());
exit;
end;
console.writestringlnWnd('Filesystems: ', getTerminalHWND());
for i:=0 to LL_Size(filesystems) - 1 do begin
filesystem := PFilesystem(LL_Get(filesystems, i));
console.writestringWnd(' ', getTerminalHWND());
console.writestringWnd(filesystem^.sName, getTerminalHWND());
console.writestringWnd(' - ', getTerminalHWND());
console.writehexlnWND(filesystem^.system_id, getTerminalHWND());
end;
end;
procedure list_volume_command();
var
i : uint32;
volume : PStorage_Volume;
begin
push_trace('VolumeManager.list_volume_command');
if LL_Size(storageVolumes) < 1 then begin
console.writestringlnWnd('No volumes found.', getTerminalHWND());
exit;
end;
console.writestringlnWnd('Volumes: ', getTerminalHWND());
for i:=0 to LL_Size(storageVolumes) - 1 do begin
volume := PStorage_Volume(LL_Get(storageVolumes, i));
console.writestringWnd(' ', getTerminalHWND());
console.writeintWnd(i, getTerminalHWND());
console.writestringWnd(' - Capacity: ', getTerminalHWND());
console.writeintWnd(uint32((volume^.sectorSize * volume^.sectorCount) DIV 1024 DIV 1024), getTerminalHWND());
console.writestringWnd('MB, Filesystem: ', getTerminalHWND());
if volume^.filesystem <> nil then begin
console.writestringlnWnd(volume^.filesystem^.sName, getTerminalHWND());
end else begin
console.writestringlnWnd('None', getTerminalHWND());
end;
end;
end;
procedure volume_command(params : PParamList);
var
i : uint16;
subcmd : pchar;
begin
push_trace('VolumeManager.volume_command');
subcmd:= getParam(0, params);
if ((paramCount(params) = 0)) then begin
console.writestringlnWnd('Please provide valid arguments.', getTerminalHWND());
console.writestringlnWnd(' ls - for listing all volumes', getTerminalHWND());
console.writestringlnWnd(' lsfs - for listing all filesystems', getTerminalHWND());
console.writestringlnWnd(' info [volume] - display formation for specified volume', getTerminalHWND());
console.writestringlnWnd(' format [volume] [filesystem] - destructive, formats a volume with a specified filesystem', getTerminalHWND());
exit;
end;
if( stringEquals(subcmd, 'ls') ) then begin
list_volume_command();
exit;
end;
if( stringEquals(subcmd, 'lsfs') ) then begin
list_filesystems_command();
exit;
end;
if( stringEquals(subcmd, 'format') ) then begin
format_volume_command(params);
exit;
end;
end;
{ Initialise volume manager }
procedure init(); procedure init();
begin begin
push_trace('VolumeManager.init'); push_trace('VolumeManager.init');
{ setup lists } storageDevices := DL_New(sizeof(PStorage_Device));
storageVolumes:= ll_New(sizeof(TFilesystem)); volumes := DL_New(sizeof(PStorage_Volume));
filesystems:= ll_New(sizeof(TFilesystem));
fileHandles:= ll_New(sizeof(TFilehandleEntry));
{ register commands } //TODO register commnads
pop_trace();
terminal.registerCommand('volume', @volume_command, 'Volume utility');
end; end;
{ register a new type of filesystem } procedure register_device(device : PStorage_Device);
procedure register_filesystem(filesystem : PFilesystem); //TODO on init create null filesystem for empty partition
var var
elm : void; diskVolumes : PDList;
begin begin
//add filesystem push_trace('VolumeManager.register_device');
elm := LL_add(filesystems);
memcpy(uint32(filesystem), uInt32(elm), SizeOf(TFilesystem));
//check drives for volumes of new type DL_Add(storageDevices);
DL_Set(storageDevices, DL_Size(storageDevices) - 1, puint32(device));
diskVolumes := discover_volumes(device);
if volumes <> nil then begin
volumes := DL_Concat(volumes, diskVolumes);
end;
pop_trace();
end; end;
{ Check for volumes on a physical device } function discover_volumes(device : PStorage_device) : PDList;
procedure check_for_volumes(drive : PStorage_device);
var
bootrecord : PMaster_Boot_Record;
storageVolume : TStorage_Volume;
i : uint32 = 0;
elm : void;
begin begin
push_trace('VolumeManager.check_for_volumes'); push_trace('VolumeManager.discover_volumes');
bootrecord := PMaster_Boot_Record(kalloc(SizeOf(TMaster_Boot_Record))); discover_volumes := nil;
drive^.readCallback(drive, 0, 1, puint32(bootrecord)); //TODO multiple drives //TODO implement
//TODO multipe partition entries
if bootrecord^.partition[0].LBA_start <> 0 then
begin
//set volume information
storageVolume.device := drive;
storageVolume.sectorStart := bootrecord^.partition[0].LBA_start;
storageVolume.sectorCount := bootrecord^.partition[0].sector_count;
storageVolume.sectorSize := drive^.sectorSize;
storageVolume.freeSectors := 0; //TODO impliment
storageVolume.filesystem := nil;
if LL_Size(filesystems) < 1 then begin
console.writestringln('Failed to initalise storage system, no filesystems found, stopping!');
exit;
end;
//check for filesystem type
for i:=0 to LL_Size(filesystems) - 1 do begin
if bootrecord^.partition[0].system_id = PFilesystem(LL_Get(filesystems, i))^.system_id then
begin
storageVolume.filesystem := PFilesystem(LL_Get(filesystems, i));
end;
end;
push_trace('VolumeManager.init3');
//add volume to list
elm := LL_Add(storageVolumes);
memcpy(uint32(@storageVolume), uint32(elm), SizeOf(TStorage_Volume));
push_trace('VolumeManager.init4');
elm := LL_Add(drive^.volumes);
memcpy(uint32(@storageVolume), uint32(elm), SizeOf(TStorage_Volume));
end;
pop_trace();
end; end;
procedure remove_volume(list : PLinkedListBase; volume : PStorage_Volume); function get_volume_list() : PDList;
var var
newList : PDList;
i : uint32; i : uint32;
elm : void;
begin begin
push_trace('VolumeManager.get_volume_list');
for i:=0 to LL_Size(list) - 1 do begin //get copy of volume list
elm := LL_Get(list, i); newList := DL_New(sizeof(PStorage_Volume)); //TODO need to add DL_Copy function
if (PStorage_Volume(elm)^.device = volume^.device)
and (PStorage_Volume(elm)^.sectorStart = volume^.sectorStart) then begin for i := 0 to DL_Size(volumes) - 1 do begin
LL_Delete(list, i); DL_Add(newList);
break; DL_Set(newList, i, DL_Get(volumes, i));
end;
end; end;
end; end;
procedure create_volume(disk : PStorage_device; filesystem : PChar; sectorStart : uint32; sectorCount : uint32);
var
volume : PStorage_Volume;
elm : void;
i : uint16;
config : PuInt32;
begin
push_trace('VolumeManager.create_volume');
volume := PStorage_Volume(kalloc(SizeOf(TStorage_Volume)));
volume^.device := disk;
volume^.sectorStart := sectorStart;
volume^.sectorCount := sectorCount - 10;
volume^.sectorSize := disk^.sectorSize;
volume^.freeSectors := 0; //setup by filesystem
//find filesystem
for i:=0 to LL_Size(filesystems) - 1 do begin
if stringEquals(filesystem, PFilesystem(LL_Get(filesystems, i))^.sName) then begin
volume^.filesystem := PFilesystem(LL_Get(filesystems, i));
end;
end;
//TODO CHECK FILESYSTEM EXSISTS
//format volume
volume^.filesystem^.createCallback(volume, sectorCount, sectorStart, config);
push_trace('VolumeManager.create_volume.2');
//remove volume from list of volumes
remove_volume(storageVolumes, volume);
//add volume to list
elm := LL_Add(storageVolumes);
memcpy(uint32(volume), uint32(elm), SizeOf(TStorage_Volume));
push_trace('VolumeManager.create_volume.3');
//remove volume from list of volumes on device
remove_volume(disk^.volumes, volume);
//add volume to device
elm := LL_Add(disk^.volumes);
memcpy(uint32(volume), uint32(elm), SizeOf(TStorage_Volume));
//free memory
kfree(puint32(volume));
end;
procedure register_volume(device : PStorage_Device; volume : PStorage_Volume);
var
elm : void;
begin
push_trace('storagemanagement.register_volume');
elm := LL_Add(device^.volumes);
PStorage_volume(elm)^:= volume^;
// if rootVolume = PStorage_Volume(0) then rootVolume:= volume;
end;
procedure openFile(Handle : uint32; Filename : PChar; OpenMode : TOpenMode; WriteMode : TWriteMode; lock : boolean; Error : PError);
var
fileHandleEntree : PFilehandleEntry;
fileHandle : uInt32;
i : uint32;
elm : void;
begin
push_trace('VolumeManager.openFile');
//check if file is already open and if it is locked, if openmode is not read only
if OpenMode <> omReadOnly then begin
for i:=0 to LL_Size(fileHandles) - 1 do begin
elm := LL_Get(fileHandles, i);
if stringEquals(PFilehandleEntry(elm)^.filename, Filename) then begin
if PFilehandleEntry(elm)^.lock and (not PFilehandleEntry(elm)^.closed) then begin
Error^ := eFileInUse;
exit;
end;
end;
end;
end;
//create filehandleentry
fileHandleEntree := PFilehandleEntry(kalloc(SizeOf(TFilehandleEntry)));
fileHandleEntree^.fileName := Filename;
fileHandleEntree^.openMode := OpenMode;
fileHandleEntree^.writeMode := WriteMode;
fileHandleEntree^.lock := lock;
fileHandleEntree^.closed := false;
//create filehandle
fileHandle := LL_Size(fileHandles);
end;
end. end.

File diff suppressed because it is too large Load Diff

View File

@ -40,13 +40,13 @@ uses
testdriver, testdriver,
E1000, E1000,
IDE, IDE,
storagemanagement, // storagemanagement,
drivemanager, // drivemanager,
volumemanager, volumemanager,
lists, lists,
net, net,
fat32, // fat32,
flatfs, // flatfs,
isrmanager, isrmanager,
faults, faults,
fonts, fonts,
@ -57,7 +57,8 @@ uses
base64, base64,
rand, rand,
terminal, terminal,
hashmap, vfs; hashmap, vfs,
AHCI;
procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall; procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall;
@ -209,8 +210,8 @@ begin
drivermanagement.init(); drivermanagement.init();
tracer.push_trace('kmain.STRMGMT'); tracer.push_trace('kmain.STRMGMT');
// storagemanagement.init(); // storagemanagement.init();
drivemanager.init(); // drivemanager.init();
volumemanager.init(); // volumemanager.init();
{ Hook Timer for Ticks } { Hook Timer for Ticks }
tracer.push_trace('kmain.TMR'); tracer.push_trace('kmain.TMR');
@ -218,8 +219,8 @@ begin
TMR_0_ISR.hook(uint32(@bios_data_area.tick_update)); TMR_0_ISR.hook(uint32(@bios_data_area.tick_update));
{ Filsystems } { Filsystems }
fat32.init(); // fat32.init();
flatfs.init(); // flatfs.init();
{ Device Drivers } { Device Drivers }
tracer.push_trace('kmain.DEVDRV'); tracer.push_trace('kmain.DEVDRV');
@ -228,7 +229,8 @@ begin
mouse.init(); mouse.init();
testdriver.init(); testdriver.init();
E1000.init(); E1000.init();
IDE.init(); // IDE.init();
AHCI.init();
console.outputln('KERNEL', 'DEVICE DRIVERS: INIT END.'); console.outputln('KERNEL', 'DEVICE DRIVERS: INIT END.');
{ Bus Drivers } { Bus Drivers }

View File

@ -57,6 +57,7 @@ var
procedure init; procedure init;
function kalloc(size : uint32) : void; function kalloc(size : uint32) : void;
function kalloc(size : uint32; isPersistent : boolean) : void;
function klalloc(size : uint32) : void; function klalloc(size : uint32) : void;
procedure klfree(size : uint32); //Todo ??? Profit? procedure klfree(size : uint32); //Todo ??? Profit?
function kpalloc(address : uint32) : void; function kpalloc(address : uint32) : void;
@ -217,6 +218,11 @@ begin
//pop_trace; //pop_trace;
end; end;
function kalloc(size : uint32; isPersistent : boolean) : void;
begin
kalloc:= kalloc(size);
end;
procedure kfree(area : void); procedure kfree(area : void);
var var
hp : PHeapPage; hp : PHeapPage;

View File

@ -22,7 +22,15 @@ unit edit;
interface interface
uses uses
console, terminal, keyboard, shell, strings, tracer, storagemanagement, lmemorymanager, util; console,
keyboard,
lmemorymanager,
shell,
storagemanagement,
strings,
terminal,
tracer,
util;
procedure init(); procedure init();

View File

@ -25,7 +25,7 @@ uses
tracer, console, tracer, console,
//progs //progs
base64_prog, md5sum, shell, terminal, base64_prog, md5sum, shell, terminal,
edit, netlog, themer, netlog, themer,
memview, udpcat, dhclient, vbeinfo; memview, udpcat, dhclient, vbeinfo;
{ Initialize all baked-in programs } { Initialize all baked-in programs }
@ -43,8 +43,8 @@ begin
themer.init(); themer.init();
tracer.push_trace('progmanager.netlog.init'); tracer.push_trace('progmanager.netlog.init');
netlog.init(); netlog.init();
tracer.push_trace('progmanager.edit.init'); // tracer.push_trace('progmanager.edit.init');
edit.init(); // edit.init();
tracer.push_trace('progmanager.udpcat.init'); tracer.push_trace('progmanager.udpcat.init');
udpcat.init(); udpcat.init();
tracer.push_trace('progmanager.md5sum.init'); tracer.push_trace('progmanager.md5sum.init');