Compare commits

..

No commits in common. "837d69a44bfa1310e713a5a96c3f8eaec97daff4" and "07e90955826268c4cf5f6889599f64700b2729db" have entirely different histories.

14 changed files with 426 additions and 1250 deletions

1
.gitignore vendored
View File

@ -10,4 +10,3 @@
/*.sh~
/*.img
src/include/asuro.pas
localenv.json

2
.vscode/launch.json vendored
View File

@ -6,7 +6,7 @@
"type": "PowerShell",
"preLaunchTask": "Build",
"script": "${workspaceFolder}/virtualbox-wrapper.ps1",
"args": ["-Command", "up"],
"args": ["-MachineName", "7d395c96-891c-4139-b77d-9b6b144b0b93"],
"cwd": "${workspaceFolder}",
}
]

26
.vscode/tasks.json vendored
View File

@ -9,18 +9,14 @@
"command": "docker-compose",
"args": [
"run",
"builder",
"builder"
],
"type": "shell",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
},
"dependsOn": [
"Close VirtualBox",
"Clean"
]
}
},
{
"label": "Build (Builder)",
@ -30,24 +26,6 @@
"builder"
],
"type": "shell"
},
{
"label": "Clean",
"command": "docker-compose",
"args": [
"down",
"--remove-orphans"
],
"type": "shell"
},
{
"label": "Close VirtualBox",
"command": "./virtualbox-wrapper.ps1",
"args": [
"-Command",
"down"
],
"type": "shell"
}
]
}

View File

@ -1,3 +1,4 @@
version: "3.9"
services:
builder:
build: .

View File

@ -50,26 +50,23 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f
```xml
<Machine uuid="{7d395c96-891c-4139-b77d-9b6b144b0b93}" name="Asuro" OSType="Linux" snapshotFolder="Snapshots" lastStateChange="2021-06-20T20:33:07Z">
```
Copy the uuid, in our case `7d395c96-891c-4139-b77d-9b6b144b0b93` & create a `localenv.json` file in the project root with the following content:
Copy the uuid, in our case `7d395c96-891c-4139-b77d-9b6b144b0b93` and replace the uuid found in `.vscode\launch.json` under `args`, so that it looks something like this:
```json
{
"VirtualBox":{
"MachineName":"<YOUR_UUID_OR_MACHINE_NAME>"
"configurations": [
{
"name":"Run",
"request": "launch",
"type": "PowerShell",
"preLaunchTask": "Build",
"script": "${workspaceFolder}/virtualbox-wrapper.ps1",
"args": ["-MachineName", "7d395c96-891c-4139-b77d-9b6b144b0b93"],
"cwd": "${workspaceFolder}",
}
]
}
```
This will allow VSCode to automatically launch VirtualBox once Asuro has been compiled.
You can also enable the serial adapter "COM1" in mode "Raw File", give it a path, and provide this path in the `localenv.json` as follows:
```json
{
"VirtualBox" : {
"MachineName": "<YOUR_UUID_OR_MACHINE_NAME>",
"LogLocation": "Fully\\Qualified\\Path\\To\\Your\\Log\\File"
}
}
```
This will allow you to see the console output from Asuro in your host terminal.
13. Open your project folder in VSCode, use CTRL+SHIFT+B to build & F5 to build + run in VBox.
14. Congratulations! You can now play with Asuro!

View File

@ -1,9 +1,17 @@
unit ide;
{ ************************************************
* Asuro
* Unit: Drivers/storage/IDE
* Description: IDE ATA Driver
*
************************************************
* Author: Aaron Hance
* Contributors:
************************************************ }
unit IDE;
interface
uses
ata,
util,
drivertypes,
console,
@ -15,324 +23,226 @@ uses
strings,
tracer,
drivemanager,
storagetypes,
idetypes;
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
primaryDevices: array[0..1] of TIDE_Device = (
(exists: false; isPrimary: true; isMaster: true; isATAPI: false;
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
base: ATA_PRIMARY_BASE; info: nil),
controller : PPCI_Device;
(exists: false; isPrimary: true; isMaster: false; isATAPI: false;
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
base: ATA_PRIMARY_BASE; info: nil)
);
bar0 : uint32;
bar1 : uint32;
bar4 : uint32;
secondaryDevices: array[0..1] of TIDE_Device = (
(exists: false; isPrimary: false; isMaster: true; isATAPI: false;
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
base: ATA_SECONDARY_BASE; info: nil),
IDEDevices : array[0..3] of TIDE_Device;
(exists: false; isPrimary: false; isMaster: false; isATAPI: false;
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
base: ATA_SECONDARY_BASE; info: nil)
);
buffer : Puint32;
procedure init();
function load(ptr : void) : boolean;
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
function load(ptr: void) : boolean;
procedure init();
function get_status(var device : TIDE_Device) : TIDE_Status;
function wait_for_device(device : TIDE_Device) : boolean;
procedure no_interrupt(isPrimary : boolean);
procedure select_device(device : TIDE_Device);
// 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
{
Disable interrupts on the IDE bus
@param(isPrimary The bus to disable interrupts on)
}
procedure no_interrupt(isPrimary : boolean);
function port_read(register : uint8) : uint8;
begin
if isPrimary then begin
outb(ATA_INTERRUPT_PRIMARY, inb(ATA_INTERRUPT_PRIMARY) or (1 shl 1));
end else begin
outb(ATA_INTERRUPT_SECONDARY, inb(ATA_INTERRUPT_SECONDARY) or (1 shl 1));
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;
{
Wait for the device to be ready on the IDE bus
procedure no_interrupt(device : uint8);
begin
outb($3F6, inb($3f6) or (1 shl 1));
end;
@param(device The device to wait for)
@returns(@True if the device is ready, @False otherwise)
}
function wait_for_device(device : TIDE_Device) : boolean;
procedure device_select(device : uint8);
begin
outb($1F6, device); //TODO clean
end;
function is_ready() : boolean;
var
status : TIDE_Status;
status : uint8;
i : uint32;
begin
push_trace('ide.wait_for_device()');
//wait for drive to be ready
while true do begin
status := port_read(ATA_REG_COMMAND);
i := 0;
while (i < 10000) do begin
status := get_status(device);
if (status.BUSY = false) then begin //todo test
wait_for_device := true;
pop_trace();
exit;
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;
i := i + 1;
if (status and ATA_SR_BUSY) <> ATA_SR_BUSY then begin
is_ready := true;
break;
end;
end;
wait_for_device := false;
pop_trace();
end;
{
Select the active device on the IDE bus
@param(device The device to select)
Function can set the device to either master or slave,
one device per bus/channel can be active at a time.
}
procedure select_device(device : TIDE_Device);
var
dev : uint8;
function validate_28bit_address(addr : uint32) : boolean;
begin
push_trace('ide.select_device()');
dev := ATA_DEVICE_SLAVE;
if device.isMaster then begin
dev := ATA_DEVICE_MASTER;
end;
outb(device.base + ATA_REG_HDDEVSEL, dev);
pop_trace();
validate_28bit_address := (addr and $F0000000) = 0;
end;
{
Get the status of the device on the IDE bus
@param(device The device to get the status of)
@returns(@TIDE_Device The status of the device on the IDE bus)
}
function get_status(var device : TIDE_Device) : TIDE_Status;
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
var
status : TIDE_Status;
begin
push_trace('ide.get_status()');
select_device(device);
status := TIDE_Status(inb(device.base + ATA_REG_STATUS));
device.status := status;
pop_trace();
get_status := status;
end;
{
Check if the device is present on the IDE bus
@param(device The device to check)
@returns(@True if the device is present, @False otherwise)
}
function is_device_present(var device : TIDE_Device) : boolean;
begin
push_trace('ide.is_device_present()');
get_status(device);
if (uInt8(device.status) = $FF) then begin //TODO make this more robust
is_device_present := false;
end else begin
is_device_present := true;
end;
end;
{
Check if the device is an ATAPI device
@param(device The device to check)
@returns(@True if the device is an ATAPI device, @False otherwise)
}
function check_device_type(var device : TIDE_Device) : boolean;
var
sec, lba0, lba1, lba2 : uint8;
begin
push_trace('ide.check_device_type()');
select_device(device);
//TODO make sure dvice signture is set at this time, else reset it
//read all bytes of LBA address
sec := inb(device.base + ATA_REG_SECCOUNT);
lba0 := inb(device.base + ATA_REG_LBA0);
lba1 := inb(device.base + ATA_REG_LBA1);
lba2 := inb(device.base + ATA_REG_LBA2);
//check if the device is an ATAPI device (01, 01, 14, EB)
if (lba1 = $14) and (lba2 = $EB) then begin
check_device_type := true;
end else begin
check_device_type := false;
end;
device.isATAPI := check_device_type;
end;
{
Load the device on the IDE bus
@param(device The device to load)
@returns(@True if the device is loaded, @False otherwise)
}
procedure load_device(var device : TIDE_Device);
var
i : uint8;
buffer : puint8;
storageDevice : PStorage_device;
success : boolean;
begin
push_trace('ide.load_device()');
if (is_device_present(device)) then begin
console.writestringln('[IDE] (load_device) Device is present');
if (check_device_type(device)) then begin
console.writestringln('[IDE] (load_device) Device is ATAPI');
//todo load device info
end else begin
console.writestringln('[IDE] (load_device) Device is ATA');
success:= ata.identify_device(device);
end;
if not success then begin
console.writestringln('[IDE] (load_device) Error identifying device'); //todo
device.exists := false;
exit;
end;
device.exists := true;
storageDevice := PStorage_Device(kalloc(sizeof(TStorage_Device)));
memset(uint32(storageDevice), 0, sizeof(TStorage_Device));
if (device.isATAPI) then begin
storageDevice^.controller := TControllerType.ControllerATAPI;
storageDevice^.writable := false; //TODO atapi
end else begin
storageDevice^.controller := TControllerType.ControllerATA;
storageDevice^.writable := true;
storageDevice^.maxSectorCount := (device.info^[61] shl 16) or device.info^[60];
storageDevice^.sectorSize := 512; //todo
if (device.isMaster) then begin
storageDevice^.controllerId0 := 0;
end else begin
storageDevice^.controllerId0 := 1;
end;
//if secotorcount is 0, then the device is not present
if (storageDevice^.maxSectorCount = 0) then begin
device.exists := false;
exit;
end;
//wrtie test, 1F2F1F2F repeated
buffer := puint8(kalloc(512));
memset(uint32(buffer), 0, 512);
for i:=0 to 200 do begin
if (i mod 4 = 0) then begin
buffer[i] := $1F;
end else begin
buffer[i] := $2F;
end;
end;
//write to the first sector
ata.write_pio28(device, 0, 1, puint16(buffer));
//read the first sector
memset(uint32(buffer), 0, 512);
ata.read_pio28(device, 0, 1, puint16(buffer));
//check if the data is the same
for i:=0 to 200 do begin
console.writehexln(buffer[i]);
end;
end;
//register the device
drivemanager.register_device(storageDevice);
end else begin
console.writestringln('[IDE] (load_device) Device is not present');
device.exists := false;
end;
pop_trace();
end;
function load(ptr: void) : boolean;
var
pciDevice : PPCI_Device;
buffer : puint8;
status : uint8;
identResponse : TIdentResponse;
i : uint8;
begin
push_trace('ide.load()');
console.writestringln('[IDE] (load) Loading IDE Devices');
push_trace('IDE.Identify_Device');
device_select(device);
no_interrupt(device);
port_write(ATA_REG_CONTROL, 0);
pciDevice := PPCI_Device(ptr);
//check if bus is floating
status := port_read(ATA_REG_COMMAND);
if status = $FF then exit;
load_device(primaryDevices[0]);
load_device(primaryDevices[1]);
load_device(secondaryDevices[0]);
load_device(secondaryDevices[1]);
port_write(ATA_REG_SECCOUNT, 0);
port_write(ATA_REG_LBA0, 0);
port_write(ATA_REG_LBA1, 0);
port_write(ATA_REG_LBA2, 0);
pop_trace();
load := true;
port_write(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
console.writestringln('[IDE] (load) IDE Device Loading Finished');
//check if drive is present
status := port_read(ATA_REG_COMMAND);
if status = $00 then exit;
i := 0;
if not is_ready() then exit;
if (primaryDevices[0].exists) then begin
console.writestringln('[IDE] (load) FOUND Primary Master Device 0');
i := i + 1;
for i:=0 to 255 do begin
identResponse[i] := inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
end;
if (primaryDevices[1].exists) then begin
console.writestringln('[IDE] (load) FOUND Primary Slave Device 1');
i := i + 1;
end;
if (secondaryDevices[0].exists) then begin
console.writestringln('[IDE] (load) FOUND Secondary Master Device 2');
i := i + 1;
end;
if (secondaryDevices[1].exists) then begin
console.writestringln('[IDE] (load) FOUND Secondary Slave Device 3');
i := i + 1;
end;
// console.writestringln('[IDE] (load) Found ' + i + ' IDE Devices');
identify_device := identResponse;
end;
procedure init();
@ -348,8 +258,208 @@ begin
devID.id3:= idANY;
devID.id4:= idANY;
devID.ex:= nil;
drivermanagement.register_driver('IDE ATA/ATAPI Driver', @devID, @load);
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;
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);
masterDevice.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');
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;
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

@ -1,221 +0,0 @@
unit ata;
interface
uses
util,
drivertypes,
console,
terminal,
drivermanagement,
vmemorymanager,
lmemorymanager,
storagemanagement,
strings,
tracer,
drivemanager,
storagetypes,
idetypes;
var
test : uint32;
function identify_device(var device : TIDE_Device) : Boolean;
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
implementation
uses
ide;
{
ensure the address is a valid 28 bit address
@param(addr The address to validate)
@returns(@True if the address is valid, @False otherwise)
}
function validate_28bit_address(addr : uint32) : boolean;
begin
validate_28bit_address := (addr and $F0000000) = 0;
end;
{
Identify the device on the IDE bus
@param(device The device to identify)
@returns(@True if the device is identified, @False otherwise)
}
function identify_device(var device : TIDE_Device) : Boolean;
var
i : uint8;
status : TIDE_Status;
buffer : TIdentResponse;
ready : boolean;
begin
select_device(device);
no_interrupt(device.isPrimary);
status := get_status(device);
outb(device.base + ATA_REG_SECCOUNT, 0);
outb(device.base + ATA_REG_LBA0, 0);
outb(device.base + ATA_REG_LBA1, 0);
outb(device.base + ATA_REG_LBA2, 0);
outb(device.base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
status := get_status(device);
if status.ERROR then begin
console.writestringln('Error identifying device, maybe'); //todo
end;
ready := wait_for_device(device);
if not ready then begin
console.writestringln('Device not ready in time!');
//teapot time
// BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR IDENT');
exit(false);
end;
for i:=0 to 255 do begin
buffer[i] := inw(device.base + ATA_REG_DATA);
end;
device.info := @buffer;
identify_device := true;
end;
procedure set_lba_mode(device : TIDE_Device; lba : uint32);
begin
// if device.isPrimary then begin
if device.isMaster then begin
outb(device.base + ATA_REG_HDDEVSEL, $E0 or ((lba and $0F000000) shr 24));
end else begin
outb(device.base + ATA_REG_HDDEVSEL, $F0 or ((lba and $0F000000) shr 24));
end;
// end else begin //TODO
// if device.isMaster then begin
// outb(device.base + ATA_REG_HDDEVSEL, $A0);
// end else begin
// outb(device.base + ATA_REG_HDDEVSEL, $B0);
// end;
// end;
end;
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
var
i : uint16;
ii : uint16;
status : TIDE_Status;
ready : boolean;
begin
push_trace('ata.read_pio28()');
if not validate_28bit_address(lba) then begin
console.writestringln('Invalid address for 28 bit read');
read_pio28 := false;
exit;
end;
select_device(device);
no_interrupt(device.isPrimary);
set_lba_mode(device, lba);
outb(device.base + ATA_REG_SECCOUNT, count);
outb(device.base + ATA_REG_LBA0, (lba and $000000FF));
outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8);
outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16);
outb(device.base + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
ready := wait_for_device(device);
if not ready then begin
console.writestringln('Device not ready in time!');
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR READ COMMAND');
end;
for i:=0 to count-1 do begin
for ii:=0 to 511 do begin //TODO needs to read sector size
buffer[i] := inw(device.base + ATA_REG_DATA);
ready := wait_for_device(device);
if not ready then begin
console.writestringln('Device not ready in time!');
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR READ');
end;
end;
end;
read_pio28 := true;
pop_trace();
end;
function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
var
i : uint16;
ii : uint16;
status : TIDE_Status;
ready : boolean;
begin
push_trace('ata.write_pio28()');
if not validate_28bit_address(lba) then begin
console.writestringln('Invalid address for 28 bit write');
write_pio28 := false;
exit;
end;
select_device(device);
no_interrupt(device.isPrimary); //maybe not?
set_lba_mode(device, lba);
outb(device.base + ATA_REG_SECCOUNT, count);
outb(device.base + ATA_REG_LBA0, (lba and $000000FF));
outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8);
outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16);
outb(device.base + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
ready := wait_for_device(device);
if not ready then begin
console.writestringln('Device not ready in time!');
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR WRITE COMMAND');
end;
for i:=0 to count-1 do begin
for ii:=0 to 511 do begin //TODO needs to read sector size
outw(device.base + ATA_REG_DATA, uint16(buffer[i]));
ready := wait_for_device(device);
if not ready then begin
console.writestringln('Device not ready in time!');
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR WRITE');
end;
end;
end;
psleep(50); //todo check
outb(device.base + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
ready := wait_for_device(device);
// if not ready then begin
// console.writestringln('Device not ready in time!');
// BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR CACHE FLUSH');
// end;
write_pio28 := true;
pop_trace();
end;
end.

View File

@ -271,7 +271,7 @@ begin
PStorage_device(elm)^.volumes := LL_New(sizeof(TStorage_Volume));
//TODO register with volume manager
//volumemanager.check_for_volumes(PStorage_Device(elm));
volumemanager.check_for_volumes(PStorage_Device(elm));
end;
{ Get the drive list }
@ -290,8 +290,7 @@ begin
//return string of controller type
case controllerType of
ControllerATA : controller_type_2_string:= 'ATA';
ControllerATAPI : controller_type_2_string:= 'ATAPI';
ControllerIDE : controller_type_2_string:= 'IDE';
ControllerUSB : controller_type_2_string:= 'USB';
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
ControllerNET : controller_type_2_string:= 'Net';

View File

@ -1,140 +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.
{
Driver->Storage->IDE->idetypes - IDE device types and constants.
@author(Aaron Hance <ah@aaronhance.me>)
}
unit idetypes;
interface
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;
ATA_PRIMARY_BASE1 = $3F6;
ATA_SECONDARY_BASE = $170; //todo check this
ATA_SECONDARY_BASE1 = $376; //todo check this
ATA_INTERRUPT_PRIMARY = $3F6;
ATA_INTERRUPT_SECONDARY = $376;
type
TPortMode = (P_READ, P_WRITE);
TIdentResponse = array[0..255] of uint16;
PIdentResponse = ^TIdentResponse;
TIDE_Channel_Registers = record
base : uint16;
ctrl : uint16;
bmide : uint16;
noInter : uint8
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;
TIDE_Device = record
exists : boolean;
isPrimary : boolean;
isMaster : boolean;
isATAPI : boolean;
status : TIDE_Status;
base : uint16;
info : PIdentResponse;
end;
implementation
end.

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

@ -82,8 +82,7 @@ implementation
function controller_type_2_string(controllerType : TControllerType) : pchar;
begin
case controllerType of
ControllerATA : controller_type_2_string:= 'ATA';
ControllerATAPI : controller_type_2_string:= 'ATAPI';
ControllerIDE : controller_type_2_string:= 'IDE';
ControllerUSB : controller_type_2_string:= 'USB';
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
ControllerNET : controller_type_2_string:= 'Net';

View File

@ -26,7 +26,7 @@ uses
type
TControllerType = (ControllerATA, ControllerATAPI, ControllerUSB, ControllerAHCI,
TControllerType = (ControllerIDE, ControllerUSB, ControllerAHCI,
ControllerNET, ControllerRAM, rsvctr1, rsvctr2, rsvctr3);
PStorage_device = ^TStorage_Device;

View File

@ -1,58 +1,16 @@
<#
You need a local git-ignored localenv.json file with the following content:
{
"virtualbox": {
"MachineName": "your-machine-name or guid"
}
}
#>
param (
[Parameter(Mandatory=$true)]
[ValidateSet('up', 'down')]
[String]$Command
$MachineName
)
$Config = Get-Content .\localenv.json | ConvertFrom-Json
$MachineName = $Config.virtualbox.MachineName
$LogLocation = $Config.virtualbox.LogLocation
$LogOutputEnabled = $LogLocation -ne $null
VBoxManage.exe startvm $MachineName
if ($Command -eq 'up') {
if($LogOutputEnabled) {
Clear-Content $LogLocation
}
$MonitorJob = Start-Job -ArgumentList $MachineName -ScriptBlock {
param($MachineName)
Write-Output "Starting $MachineName"
VBoxManage.exe startvm $MachineName
$running=$true
while($running) {
$running=$true
while($running) {
Start-Sleep -Seconds 1
$status=(VBoxManage.exe list runningvms)
if($status) {
$running=$status.contains($MachineName)
} else {
$running=$false
}
}
}
if($LogOutputEnabled) {
$LogJob = Start-Job -ArgumentList $LogLocation -ScriptBlock {
param($LogLocation)
Get-Content -Path $LogLocation -Wait
}
}
while($MonitorJob.State -eq 'Running') {
if($LogOutputEnabled) {
Receive-Job $LogJob
}
Receive-Job $MonitorJob
}
} elseif ($Command -eq 'down') {
Write-Output "Stopping $MachineName"
VBoxManage.exe controlvm $MachineName poweroff
}