34 Commits

Author SHA1 Message Date
837d69a44b ide rework again 2025-03-09 13:50:11 +00:00
f0d5eb21f1 DevOps Workflow Improvements
- `VirtualBox-Wrapper.ps1` now takes 'up' or 'down' as opposed to a machine name. This allows start/stop of a virtualmachine.
- `VirtualBox-Wrapper.ps1` now relies on a gitignored `localenv.json` to work.
- `VirtualBox-Wrapper.ps1` can also optionally monitor the log file generated from the serial adapter in VirtualBox.
- `readme.md` updated to provide instructions on how to populate the `localenv.json` file.
- `tasks.json` updated to have a "Clean" task to --remove-orphans, the Build task depends on this.
- `tasks.json` updated to have a "Close VirtualBox" task, this runs the `virtualbox-wrapper.ps1` in 'down' mode. The Build task depends on this.
- `launch.json` updated to run the `VirtualBox-Wrapper.ps1` with the "-Command up" argument, instead of machine name.
- .gitignore updated to ignore any instances of `localenv.json`.

# Conflicts:
#	.gitignore
2025-03-09 13:49:53 +00:00
07e9095582 VirtualBox 7 Compatability Changes
- Created a PowerShell script `virtualbox-wrapper.ps1` to wrap calls to vboxmanage and only exit once the virtual machine has been terminated.
- Updated launch.json to use the PowerShell launch type to launch `virtualbox-wrapper.ps1` with the machine name supplied as an argument.
- Updated `readme.md` to reflect these changes.

# Conflicts:
#	.vscode/launch.json
2025-03-08 21:09:13 +00:00
72769fbef7 fix 2022-09-28 16:15:45 +01:00
95599c0e7c fix 2022-09-28 16:14:06 +01:00
fcaafa0d12 Started aadding file handle stuff to volume manager 2022-09-28 16:04:51 +01:00
e490b95f1d comments 2022-09-27 17:23:42 +01:00
b601080960 Added delete files and directory functions to flatfs 2022-02-03 02:21:51 +00:00
27177979a2 Flatfs reading and writing files and directories done 2022-02-03 01:21:37 +00:00
f88a282893 Progress on flatfs 2022-02-02 23:19:30 +00:00
ff4c597ff3 Work on storage and flat file system 2022-02-01 05:07:52 +00:00
24c371cab1 Added new String functions 2022-01-31 00:34:38 +00:00
7588a4c9cb Revert "Updated Strings unit with new functions"
This reverts commit 5cb415c76b.
2022-01-31 00:31:01 +00:00
5cb415c76b Updated Strings unit with new functions 2022-01-31 00:27:02 +00:00
118d8b0c03 Merge branch 'feature/storage-system' of https://gitlab.spexeah.com/spexeah/asuro into feature/storage-system
# Conflicts:
#	src/driver/storage/drivemanager.pas
#	src/driver/storage/storagemanagement.pas
2022-01-30 00:42:37 +00:00
28caca3bcc commiting before rebase 2022-01-30 00:34:52 +00:00
6476a774dc More progress and fixes 2022-01-30 00:34:52 +00:00
e791edb02a Progress 2022-01-30 00:34:51 +00:00
da36f6fabb Continued new volume management stuff. 2022-01-30 00:34:51 +00:00
97e1a18253 Restructuring and expanding storage system. 2022-01-30 00:34:51 +00:00
88a850e8fc More progress and fixes 2022-01-29 22:21:10 +00:00
10c9194c5f Progress 2022-01-29 20:05:11 +00:00
346dc4e4c9 Merge branch 'feature/readme-update-1' into 'develop'
Update readme.md

See merge request spexeah/asuro!29
2022-01-29 12:47:56 +00:00
b2eee58df4 Update readme.md 2022-01-29 12:46:35 +00:00
170b93dd69 Merge branch 'feature/pipeline-docs-fix' into 'develop'
Docgen changes

See merge request spexeah/asuro!27
2021-07-06 19:42:57 +00:00
34d6873a6a Docgen changes
Changed docgen job to create doc folder, not public for now.
2021-07-06 20:35:26 +01:00
e69d06ea4f Merge branch 'joe/ci-suggestions' into 'develop'
3 time the charm

See merge request spexeah/asuro!26
2021-07-06 19:18:24 +00:00
2939afa729 3 time the charm 2021-07-06 19:18:23 +00:00
ad8e80913a Merge branch 'feature/documentation' into 'develop'
Changed comments in Asuro.pas when generated

Changed the Asuro.pas comment to be the standard format in terms of Directory->File (no .pas) for PasDoc gen.

See merge request spexeah/asuro!23
2021-07-05 18:23:11 +00:00
33cb042b8c Changed comments in Asuro.pas when generated
Changed the Asuro.pas comment to be the standard format in terms of Directory->File (no .pas) for PasDoc gen.
2021-07-05 19:18:32 +01:00
4d25ceef77 Merge branch 'feature/documentation' into 'develop'
Tidied up comments for docgen.

Added some documentation to Asuro.pas, ProgManager, AHCI, asfs & ATA_ISR to fix some of the pasdoc/docgen issues.

See merge request spexeah/asuro!22
2021-07-05 18:09:51 +00:00
439d4ef8ac Tidied out comments for docgen.
Added some documentation to Asuro.pas & ProgManager.
2021-07-05 19:07:33 +01:00
94b477d8f7 Continued new volume management stuff. 2021-06-25 01:48:20 +01:00
ba38f4fd19 Restructuring and expanding storage system. 2021-06-23 21:22:06 +01:00
21 changed files with 3087 additions and 519 deletions

3
.gitignore vendored
View File

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

13
.vscode/launch.json vendored
View File

@ -3,18 +3,11 @@
{ {
"name":"Run", "name":"Run",
"request": "launch", "request": "launch",
"type": "coreclr", "type": "PowerShell",
"preLaunchTask": "Build", "preLaunchTask": "Build",
"program": "VBoxSDL", "script": "${workspaceFolder}/virtualbox-wrapper.ps1",
"args": [ "args": ["-Command", "up"],
"--comment",
"Asuro",
"--startvm",
"7d395c96-891c-4139-b77d-9b6b144b0b93"
],
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"console": "internalConsole",
"internalConsoleOptions": "neverOpen"
} }
] ]
} }

26
.vscode/tasks.json vendored
View File

@ -9,14 +9,18 @@
"command": "docker-compose", "command": "docker-compose",
"args": [ "args": [
"run", "run",
"builder" "builder",
], ],
"type": "shell", "type": "shell",
"problemMatcher": [], "problemMatcher": [],
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
} },
"dependsOn": [
"Close VirtualBox",
"Clean"
]
}, },
{ {
"label": "Build (Builder)", "label": "Build (Builder)",
@ -26,6 +30,24 @@
"builder" "builder"
], ],
"type": "shell" "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"
} }
] ]
} }

32
doc/flatfs.md Normal file
View File

@ -0,0 +1,32 @@
#Flat filesystem
A super simple filesystem for asuro. Folders are emulated in filenames.
Starts with disk info sector, sector 0 of volume
---
#### disk info
jmp2boot : ubit24;
OEMName : array[0..7] of char;
version : uint16 // numerical version of filesystem
sectorCount : uint16;
fileCount : uint16
signature : uint32 = 0x0B00B1E5
the Rest of the sector is reserved
---
Starting from sector 1 is the file table. Table size is determined by entry size (64) * fileCount
---
####File entry
name : array[0..59] of char //file name max 60 chars
fileStart : 16bit // start sector of data
fileSize : 16bit // data size in sectors
---

View File

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

View File

@ -13,8 +13,8 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f
I don't think this needs an explaination. I don't think this needs an explaination.
* [VSCode (Optional, but highly recommended)](https://code.visualstudio.com/) * [VSCode (Optional, but highly recommended)](https://code.visualstudio.com/)
Visual Studio code is our IDE of choice, and we have a number of recommended plugins. Visual Studio code is our IDE of choice, and we have a number of recommended plugins.
* [C# Plugin by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) * [PowerShell Plugin by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-vscode.powershell)
This plugin gives you the ability to use the 'coreclr' task type, allowing the automatic launching of virtualbox with the resulting image generated during compilation of Asuro. This plugin gives you the ability to use the 'PowerShell' task type, allowing the automatic launching of virtualbox with the resulting image generated during compilation of Asuro.
* [VirtualBox](https://www.virtualbox.org/) * [VirtualBox](https://www.virtualbox.org/)
Virtualbox is our Virtualisation environment of choice, don't ask why, it just is. Virtualbox is our Virtualisation environment of choice, don't ask why, it just is.
@ -27,15 +27,15 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f
3. Install Docker for Windows. 3. Install Docker for Windows.
4. Install Git for Windows. 4. Install Git for Windows.
5. Install VSCode & the listed plugins. 5. Install VSCode & the listed plugins.
6. Install VirtualBox. 6. Install VirtualBox (v7+).
7. Clone this repository. 7. Clone this repository.
8. Run the following command in the root of the repo to build the docker image: 8. Run the following command in the root of the repo to build the docker image:
```powershell ```powershell
docker-compose build builder docker compose build builder
``` ```
9. Run the following command to compile Asuro: 9. Run the following command to compile Asuro:
```powershell ```powershell
docker-compose run builder docker compose run builder
``` ```
10. Create a new virtual machine in Virtualbox and mount the `Asuro.iso` generated in step 9 as a boot image. 10. Create a new virtual machine in Virtualbox and mount the `Asuro.iso` generated in step 9 as a boot image.
11. Add the virtualbox installation directory to your `%PATH%` environment variable, usually: 11. Add the virtualbox installation directory to your `%PATH%` environment variable, usually:
@ -50,32 +50,29 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f
```xml ```xml
<Machine uuid="{7d395c96-891c-4139-b77d-9b6b144b0b93}" name="Asuro" OSType="Linux" snapshotFolder="Snapshots" lastStateChange="2021-06-20T20:33:07Z"> <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` and replace the uuid found in `.vscode\launch.json` under `args`, so that it looks something like this: Copy the uuid, in our case `7d395c96-891c-4139-b77d-9b6b144b0b93` & create a `localenv.json` file in the project root with the following content:
```json ```json
{ {
"configurations": [ "VirtualBox":{
{ "MachineName":"<YOUR_UUID_OR_MACHINE_NAME>"
"name":"Run", }
"request": "launch",
"type": "coreclr",
"preLaunchTask": "Build",
"program": "VBoxSDL",
"args": [
"--comment",
"Asuro",
"--startvm",
"<YOUR UUID HERE>"
],
"cwd": "${workspaceFolder}",
"console": "internalConsole",
"internalConsoleOptions": "neverOpen"
}
]
} }
``` ```
This will allow VSCode to automatically launch VirtualBox once Asuro has been compiled. 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. 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! 14. Congratulations! You can now play with Asuro!
### Gotchas ### Notes & Gotchas
- It was noted that Windows builds above `20H2` seem to have issues installing WSL2. We may have to wait for a patch from Microsoft to fix this. Our devs are currently using build `20H2`. - The above process has been updated to be compatible with VirtualBox 7+, in which VBoxSDL was removed and vboxmanage should be used in its place. A small wrapper powershell script is used to achieve this.
- It was noted that Windows builds above `20H2` seem to have issues installing WSL2. We may have to wait for a patch from Microsoft to fix this. Our devs are currently using build `20H2`.

View File

@ -1,17 +1,9 @@
{ ************************************************ unit ide;
* Asuro
* Unit: Drivers/storage/IDE
* Description: IDE ATA Driver
*
************************************************
* Author: Aaron Hance
* Contributors:
************************************************ }
unit IDE;
interface interface
uses uses
ata,
util, util,
drivertypes, drivertypes,
console, console,
@ -21,226 +13,326 @@ uses
lmemorymanager, lmemorymanager,
storagemanagement, storagemanagement,
strings, strings,
tracer; tracer,
drivemanager,
type storagetypes,
TPortMode = (P_READ, P_WRITE); idetypes;
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 var
controller : PPCI_Device; 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),
bar0 : uint32; (exists: false; isPrimary: true; isMaster: false; isATAPI: false;
bar1 : uint32; status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
bar4 : uint32; base: ATA_PRIMARY_BASE; info: nil)
);
IDEDevices : array[0..3] of TIDE_Device; 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),
buffer : Puint32; (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)
);
procedure init();
function load(ptr : void) : boolean;
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
// procedure flush(); function load(ptr: void) : boolean;
procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8); procedure init();
procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8); function get_status(var device : TIDE_Device) : TIDE_Status;
//read/write must be capable of reading/writting any amknt of data upto disk size function wait_for_device(device : TIDE_Device) : boolean;
procedure no_interrupt(isPrimary : boolean);
procedure select_device(device : TIDE_Device);
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32); implementation
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
implementation {
Disable interrupts on the IDE bus
function port_read(register : uint8) : uint8; @param(isPrimary The bus to disable interrupts on)
}
procedure no_interrupt(isPrimary : boolean);
begin begin
port_read:= inb(ATA_PRIMARY_BASE + register); if isPrimary then begin
end; outb(ATA_INTERRUPT_PRIMARY, inb(ATA_INTERRUPT_PRIMARY) or (1 shl 1));
end else begin
procedure port_write(register : uint8; data : uint8); outb(ATA_INTERRUPT_SECONDARY, inb(ATA_INTERRUPT_SECONDARY) or (1 shl 1));
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;
end; end;
procedure no_interrupt(device : uint8); {
begin Wait for the device to be ready on the IDE bus
outb($3F6, inb($3f6) or (1 shl 1));
end;
procedure device_select(device : uint8); @param(device The device to wait for)
begin @returns(@True if the device is ready, @False otherwise)
outb($1F6, device); //TODO clean }
end; function wait_for_device(device : TIDE_Device) : boolean;
var
function is_ready() : boolean; status : TIDE_Status;
var
status : uint8;
i : uint32; i : uint32;
begin begin
//wait for drive to be ready push_trace('ide.wait_for_device()');
while true do begin
status := port_read(ATA_REG_COMMAND);
if(status and ATA_SR_ERR) = ATA_SR_ERR then begin i := 0;
console.writestringln('[IDE] (IDENTIFY_DEVICE) DRIVE ERROR!');
console.redrawWindows(); while (i < 10000) do begin
is_ready := false; status := get_status(device);
break;
if (status.BUSY = false) then begin //todo test
wait_for_device := true;
pop_trace();
exit;
end; end;
if (status and ATA_SR_BUSY) <> ATA_SR_BUSY then begin i := i + 1;
is_ready := true;
break;
end;
end; end;
wait_for_device := false;
pop_trace();
end; end;
function validate_28bit_address(addr : uint32) : boolean; {
begin Select the active device on the IDE bus
validate_28bit_address := (addr and $F0000000) = 0; @param(device The device to select)
end;
function identify_device(bus : uint8; device : uint8) : TIdentResponse; 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 var
status : uint8; dev : uint8;
identResponse : TIdentResponse; begin
i : uint8; push_trace('ide.select_device()');
begin
push_trace('IDE.Identify_Device');
device_select(device);
no_interrupt(device);
port_write(ATA_REG_CONTROL, 0);
//check if bus is floating dev := ATA_DEVICE_SLAVE;
status := port_read(ATA_REG_COMMAND);
if status = $FF then exit;
port_write(ATA_REG_SECCOUNT, 0); if device.isMaster then begin
port_write(ATA_REG_LBA0, 0); dev := ATA_DEVICE_MASTER;
port_write(ATA_REG_LBA1, 0);
port_write(ATA_REG_LBA2, 0);
port_write(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
//check if drive is present
status := port_read(ATA_REG_COMMAND);
if status = $00 then exit;
if not is_ready() then exit;
for i:=0 to 255 do begin
identResponse[i] := inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
end; end;
identify_device := identResponse; outb(device.base + ATA_REG_HDDEVSEL, dev);
pop_trace();
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;
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;
i : uint8;
begin
push_trace('ide.load()');
console.writestringln('[IDE] (load) Loading IDE Devices');
pciDevice := PPCI_Device(ptr);
load_device(primaryDevices[0]);
load_device(primaryDevices[1]);
load_device(secondaryDevices[0]);
load_device(secondaryDevices[1]);
pop_trace();
load := true;
console.writestringln('[IDE] (load) IDE Device Loading Finished');
i := 0;
if (primaryDevices[0].exists) then begin
console.writestringln('[IDE] (load) FOUND Primary Master Device 0');
i := i + 1;
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');
end; end;
procedure init(); procedure init();
@ -256,193 +348,8 @@ begin
devID.id3:= idANY; devID.id3:= idANY;
devID.id4:= idANY; devID.id4:= idANY;
devID.ex:= nil; devID.ex:= nil;
drivermanagement.register_driver('IDE ATA Driver', @devID, @load); drivermanagement.register_driver('IDE ATA/ATAPI Driver', @devID, @load);
console.writestringln('[IDE] (INIT) END'); console.writestringln('[IDE] (INIT) END');
end; end;
function load(ptr : void) : boolean;
var
controller : PPCI_Device;
masterDevice : TStorage_Device;
slaveDevice : TStorage_Device;
buffer : puint8;
i : uint8;
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]);
masterDevice.sectorSize:= 512;
if masterDevice.maxSectorCount <> 0 then begin
IDEDevices[0].exists:= true;
masterDevice.readCallback:= @dread;
masterDevice.writeCallback:= @dwrite;
storagemanagement.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
if not validate_28bit_address(LBA) then begin
console.writestringln('IDE (writePIO28) ERROR: Invalid LBA!');
end;
//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);
//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 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;
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
for i:=0 to sectorCount-1 do begin
readPIO28(device^.controllerId0, LBA, puint8(@buffer[512*i]));
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, puint8(@buffer[512*i]));
end;
// writePIO28(device^.controllerId0, LBA, puint8(buffer));
end;
end. end.

View File

@ -0,0 +1,81 @@
{
Driver->Storage->MBR Master boot record
@author(Aaron Hance ah@aaronhance.me)
}
unit mbr;
interface
uses
tracer;
type
PMaster_Boot_Record = ^TMaster_Boot_Record;
PPartition_table = ^TPartition_table;
TPartition_table = bitpacked record
attributes : uint8;
CHS_start : array[0..2] of uint8;
system_id : uint8;
CHS_end : array[0..2] of uint8;
LBA_start : uInt32;
sector_count : uInt32;
end;
TMaster_Boot_Record = bitpacked record
bootstrap : array[0..439] of uint8;
signature : uint32;
rsv : uint16;
partition : array[0..3] of TPartition_table;
boot_sector : uint16;
end;
T24bit = array[0..2] of uint8;
function get_bootable(partition_table : PPartition_table) : boolean;
procedure set_bootable(partition_table : PPartition_table);
procedure setup_partition(partition_table : PPartition_table; address : uint32; sectorSize : uint32);
implementation
{ convert LBA address to CHS address}
function LBA_2_CHS(lba : uint32) : T24bit;
var
dat : T24bit;
begin
//TODO impliment procedure
LBA_2_CHS := dat;
end;
{ Set a partition struct to be bootable}
procedure set_bootable(partition_table : PPartition_table);
begin
push_trace('MBR.set_bootable');
//set the bootble bit in attributes
partition_table^.attributes := (partition_table^.attributes and $80);
end;
{ Check a partitions bootable bit }
function get_bootable(partition_table : PPartition_table) : boolean;
begin
push_trace('MBR.get_bootable');
//get the bootble bit in attributes
get_bootable := (partition_table^.attributes and $80) = $80;
end;
{ Setup a partition table struct }
procedure setup_partition(partition_table : PPartition_table; address : uint32; sectorSize : uint32);
begin
push_trace('MBR.setup_partition');
//set values in both LBA and CHS addressing schemes
partition_table^.LBA_start := address;
partition_table^.sector_count := sectorSize;
partition_table^.CHS_start := LBA_2_CHS(address);
partition_table^.CHS_start := LBA_2_CHS(address + sectorSize);
push_trace('MBR.setup_partition.end');
end;
end.

221
src/driver/storage/ata.pas Normal file
View File

@ -0,0 +1,221 @@
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

View File

@ -0,0 +1,306 @@
// 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->DriveManager Physical storage device manager
@author(Aaron Hance ah@aaronhance.me)
}
unit drivemanager;
interface
uses
util,
drivertypes,
console,
terminal,
drivermanagement,
lmemorymanager,
strings,
lists,
tracer,
rtc,
MBR,
serial,
volumemanager,
storagetypes;
var
storageDevices : PLinkedListBase; //index in this array is global drive id
procedure init();
procedure register_device(device : PStorage_Device);
function get_drive_list() : PLinkedListBase;
function controller_type_2_string(controllerType : TControllerType) : pchar;
implementation
procedure list_drive_command();
var
i : uint32 = 0;
begin
push_trace('DriverManager.list_drive_command');
//if no storage device print none found
if LL_Size(storageDevices) < 1 then begin
console.writestringlnWnd('No storage devices found.', getTerminalHWND());
exit;
end;
//print number of storage devices
console.writeintwnd(LL_Size(storageDevices), getTerminalHWND());
console.writestringlnWnd(' devices found', getTerminalHWND());
for i:=0 to LL_Size(storageDevices)-1 do begin
//print device id and type
console.writeintwnd(i, getTerminalHWND());
console.writestringwnd(' - Device type: ', getTerminalHWND());
console.writestringwnd(controller_type_2_string(PStorage_Device(LL_Get(storageDevices, i))^.controller), getTerminalHWND());
console.writestringwnd(', ', getTerminalHWND());
//print device capcity
console.writestringwnd(' Capacity: ', getTerminalHWND());
console.writeintwnd((( PStorage_Device(LL_Get(storageDevices, i))^.maxSectorCount * PStorage_Device(LL_Get(storageDevices, i))^.sectorSize) DIV 1024) DIV 1024, getTerminalHWND());
console.writestringlnWnd('MB', getTerminalHWND());
end;
end;
{ Disk subcommand for formatting drives }
procedure format_command(params : PParamList);
var
driveIndex : uint16;
drive : PStorage_Device;
filesystemString : pchar;
spc : puint32;
sectorCount : uint32;
volumeId : uint8;
mb : PMaster_Boot_Record;
i : uint32 = 0;
begin
push_trace('DriverManager.format_command');
//format <DRIVE_ID> <FILESYSTEM> <size>
spc:= puint32(kalloc(4));
spc^:= 1;
push_trace('DriverManager.format_command.0');
//get drive from index/id
driveIndex:= stringToInt( getParam(1, params) );
drive:= PStorage_Device(LL_Get(storageDevices, driveIndex));
filesystemString := getParam(2, params);
sectorCount := stringToInt( getParam(3, params) );
// if sector count is 0, use full drive
if sectorCount = 0 then begin
sectorCount := drive^.maxSectorCount - 10;
end;
//create MBR if none, and partition table
mb := PMaster_Boot_Record(kalloc(sizeof(TMaster_Boot_Record)*2));
memset(uint32(mb), 0, sizeof(TMaster_Boot_Record));
drive^.readCallback(drive, 0, 1, PuInt32(mb));
//check if MBR exists
if (mb^.boot_sector <> $55AA)then begin
writestringlnWND('Creating MBR', getTerminalHWND());
//create MBR
mb^.signature := $A570 + drive^.id;
mb^.boot_sector := $55AA;
//create partition table
mbr.setup_partition(@mb^.partition[0], 2, sectorCount);
//write MBR
drive^.writeCallback(drive, 0, 1, puint32(mb));
end else begin
writestringlnWND('MBR already exists', getTerminalHWND());
//write first partiton sectorStart and sectorCount
writeintlnWND(mb^.partition[0].LBA_start, getTerminalHWND());
writeintlnWND(mb^.partition[0].sector_count, getTerminalHWND());
//create partition table
mbr.setup_partition(@mb^.partition[0], 2, sectorCount);
//write MBR
drive^.writeCallback(drive, 0, 1, puint32(mb));
end;
kfree(puint32(mb));
//setup volume
volumemanager.create_volume(drive, filesystemString, 2, sectorCount);
writestringWnd('Drive ', getTerminalHWND);
writeintWnd(driveIndex, getTerminalHWND);
writestringlnWnd(' formatted.', getTerminalHWND);
end;
{ initalise a drive with a MBR - TODO needs to be expanded for partitioning }
procedure init_drive_command(driveIndex : uint32);
var
bootrecord : PMaster_Boot_Record;
partition : PPartition_table;
drive : PStorage_device;
begin
push_trace('DriverManager.init_drive_command');
//setup MBR and partition table
bootrecord := PMaster_Boot_record(kalloc(SizeOf(TMaster_boot_record)));
partition := PPartition_table(kalloc(SizeOf(TPartition_table)));
drive := PStorage_device(LL_Get(storageDevices, driveIndex));
MBR.setup_partition(partition, 100, drive^.maxSectorCount-300);
bootrecord^.partition[0] := partition^;
//write MBR and partition table to disk
drive^.writeCallback(drive, 0, 1, puint32(bootrecord));
//volume_manager reload partition
//TODO
end;
procedure drive_command(params : PParamList);
var
i : uint16;
drive : uint16;
subcmd : pchar;
begin
push_trace('DriverManager.drive_command');
subcmd:= getParam(0, params);
push_trace('DriverManager.drive_command.0');
if ((paramCount(params) = 0)) then begin
console.writestringlnWnd('Please provide valid arguments.', getTerminalHWND());
console.writestringlnWnd(' ls - for listing all drives', getTerminalHWND());
console.writestringlnWnd(' info [drive] - display formation for specified drive', getTerminalHWND());
console.writestringlnWnd(' init [drive] - destructive, formats a drive with a blank partition', getTerminalHWND());
console.writestringlnWnd(' format [drive] [filesystem] [size (0 for max)] - destructive, formats a drive with MBR and volume', getTerminalHWND());
exit;
end;
push_trace('DriverManager.drive_command.1');
if( stringEquals(subcmd, 'ls') ) then begin
list_drive_command();
exit;
end;
push_trace('DriverManager.drive_command.2');
if( stringEquals(subcmd, 'info') ) then begin
console.writestringWnd('Disk: ', getTerminalHWND());
console.writeintlnWND(1, getTerminalHWND());
console.writestringWnd('Capacity: ', getTerminalHWND());
console.writeintlnWND(1, getTerminalHWND());
//TODO impliment
exit;
end;
if( stringEquals(subcmd, 'init') ) then begin
init_drive_command(stringToInt(getParam(1, params) ) );
exit;
end;
push_trace('DriverManager.drive_command.3');
if( stringEquals(subcmd, 'format') ) then begin
format_command(params);
exit;
end;
push_trace('DriverManager.drive_command.4');
end;
{ Initialise the drive manager }
procedure init();
begin
push_trace('DriveManager.init');
//setup drive manager
setworkingdirectory('.');
storageDevices:= ll_new(sizeof(TStorage_Device));
//register DISK command
terminal.registerCommand('DISK', @drive_command, 'Disk utility');
end;
{ Register a new drive with the drive manager }
procedure register_device(device : PStorage_device);
var
i : uint8;
elm : void;
begin
push_trace('DriveManager.register_device');
//add the drive to the list of storage devices.
elm:= LL_Add(storageDevices);
//PStorage_device(elm)^ := device^; //TODO memcopy
memcpy(uint32(device), uint32(elm), SizeOf(TStorage_Device));
//set drive id in struct
PStorage_device(elm)^.id := LL_Size(storageDevices) - 1;
//create empty volume list for drive
PStorage_device(elm)^.volumes := LL_New(sizeof(TStorage_Volume));
//TODO register with volume manager
//volumemanager.check_for_volumes(PStorage_Device(elm));
end;
{ Get the drive list }
function get_drive_list() : PLinkedListBase;
begin
push_trace('DriverManager.get_drive_list');
//return the device list
get_drive_list:= storageDevices;
end;
{ Get string name for controller type }
function controller_type_2_string(controllerType : TControllerType) : pchar;
begin
push_trace('DriverManager.controller_type_2_string');
//return string of controller type
case controllerType of
ControllerATA : controller_type_2_string:= 'ATA';
ControllerATAPI : controller_type_2_string:= 'ATAPI';
ControllerUSB : controller_type_2_string:= 'USB';
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
ControllerNET : controller_type_2_string:= 'Net';
end;
end;
function write_2_drive(drive : uint32; address : uint32; byteSize : uint32; buffer : puint32) : PDrive_Error;
begin
end;
end.

View File

@ -10,14 +10,16 @@ interface
uses uses
console, console,
storagemanagement, util,
util, terminal, terminal,
lmemorymanager, lmemorymanager,
strings, strings,
lists, lists,
tracer, tracer,
serial, serial,
rtc; rtc,
volumemanager,
storagetypes;
type type
@ -89,7 +91,7 @@ var
filesystem : TFilesystem; filesystem : TFilesystem;
procedure init; procedure init;
procedure create_volume(disk : PStorage_Device; sectors : uint32; start : uint32; config : puint32); procedure create_volume(volume : PStorage_Volume; sectors : uint32; start : uint32; config : puint32);
procedure detect_volumes(disk : PStorage_Device); procedure detect_volumes(disk : PStorage_Device);
//function writeDirectory(volume : PStorage_volume; directory : pchar; attributes : uint32) : uint8; // need to handle parent table cluster overflow, need to take attributes //function writeDirectory(volume : PStorage_volume; directory : pchar; attributes : uint32) : uint8; // need to handle parent table cluster overflow, need to take attributes
//function readDirectory(volume : PStorage_volume; directory : pchar; listPtr : PLinkedListBase) : uint8; //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error //function readDirectory(volume : PStorage_volume; directory : pchar; listPtr : PLinkedListBase) : uint8; //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error
@ -751,7 +753,7 @@ end;
//TODO check directory commands for errors with a clean disk //TODO check directory commands for errors with a clean disk
procedure create_volume(disk : PStorage_Device; sectors : uint32; start : uint32; config : puint32); procedure create_volume(volume : PStorage_Volume; sectors : uint32; start : uint32; config : puint32);
var var
buffer : puint32; buffer : puint32;
bt: puint32; bt: puint32;
@ -772,9 +774,18 @@ var
programFileArray : byteArray8 = ('P','R','O','G','R','A','M','S'); programFileArray : byteArray8 = ('P','R','O','G','R','A','M','S');
rootCluster : uint32 = 1; rootCluster : uint32 = 1;
sysArray : byteArray8 = ('S','Y','S','T','E','M',' ',' ');
progArray : byteArray8 = ('P','R','O','G','R','A','M','S');
userArray : byteArray8 = ('U','S','E','R',' ',' ',' ',' ');
status : puint32;
disk : PStorage_device;
begin //maybe increase buffer size by one? begin //maybe increase buffer size by one?
push_trace('fat32.create_volume()'); push_trace('fat32.create_volume()');
disk := volume^.device;
// zeroBuffer:= puint32(kalloc( disk^.sectorSize * 4 )); // zeroBuffer:= puint32(kalloc( disk^.sectorSize * 4 ));
// memset(uint32(zeroBuffer), 0, disk^.sectorSize * 4); // memset(uint32(zeroBuffer), 0, disk^.sectorSize * 4);
@ -811,7 +822,7 @@ begin //maybe increase buffer size by one?
bootRecord^.jmp2boot := $0; //TODO impliment boot jump bootRecord^.jmp2boot := $0; //TODO impliment boot jump
bootRecord^.OEMName := asuroArray; bootRecord^.OEMName := asuroArray;
bootRecord^.sectorSize := disk^.sectorsize; bootRecord^.sectorSize := disk^.sectorsize;
bootRecord^.spc := config^; bootRecord^.spc := 1;
bootRecord^.rsvSectors := 32; //32 is standard bootRecord^.rsvSectors := 32; //32 is standard
bootRecord^.numFats := 1; bootRecord^.numFats := 1;
bootRecord^.mediaDescp := $F8; bootRecord^.mediaDescp := $F8;
@ -873,8 +884,16 @@ begin //maybe increase buffer size by one?
disk^.writecallback(disk, dataStart + (config^ * rootCluster), 1, buffer); disk^.writecallback(disk, dataStart + (config^ * rootCluster), 1, buffer);
memset(uint32(buffer), 0, disk^.sectorsize);
status := puint32(kalloc(sizeof(uint32)));
writeDirectory(volume, '', sysArray, $10, status, '');
kfree(buffer); kfree(buffer);
end; end;
procedure detect_volumes(disk : PStorage_Device); procedure detect_volumes(disk : PStorage_Device);
@ -903,11 +922,11 @@ begin
if (puint32(buffer)[127] = $55AA) and (PBootRecord(buffer)^.bsignature = $29) then begin //TODO partition table if (puint32(buffer)[127] = $55AA) and (PBootRecord(buffer)^.bsignature = $29) then begin //TODO partition table
console.writestringln('FAT32: volume found!'); console.writestringln('FAT32: volume found!');
volume^.device:= disk; volume^.device:= disk;
volume^.sectorStart:= 1; volume^.sectorStart:= 1; //THIS MAKE SURE IF NOT FUCKY, cos im getting info from 2
volume^.sectorSize:= PBootRecord(buffer)^.sectorSize; volume^.sectorSize:= PBootRecord(buffer)^.sectorSize;
volume^.freeSectors:= 1000000; //TODO implement get free sectors need FSINFO implemented first volume^.freeSectors:= 1000000; //TODO implement get free sectors need FSINFO implemented first
volume^.filesystem := @filesystem; volume^.filesystem := @filesystem;
storagemanagement.register_volume(disk, volume); // storagemanagement.register_volume(disk, volume); TODO repalce with new thing
end; end;
kfree(buffer); kfree(buffer);
@ -917,6 +936,7 @@ procedure init();
begin begin
push_trace('fat32.init()'); push_trace('fat32.init()');
filesystem.sName:= 'FAT32'; filesystem.sName:= 'FAT32';
filesystem.system_id:= $01;
filesystem.readDirCallback:= @readDirectoryGen; filesystem.readDirCallback:= @readDirectoryGen;
filesystem.createDirCallback:= @writeDirectoryGen; filesystem.createDirCallback:= @writeDirectoryGen;
filesystem.createcallback:= @create_volume; filesystem.createcallback:= @create_volume;
@ -924,7 +944,7 @@ begin
filesystem.writecallback:= @writeFile; filesystem.writecallback:= @writeFile;
filesystem.readcallback := @readFile; filesystem.readcallback := @readFile;
storagemanagement.register_filesystem(@filesystem); volumemanager.register_filesystem(@filesystem);
end; end;
end. end.

View File

@ -0,0 +1,725 @@
// 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->flatfs super simple flat filesystem
@author(Aaron Hance ah@aaronhance.me)
}
unit flatfs;
interface
uses
tracer,
strings,
volumemanager,
lists,
console,
terminal,
storagetypes,
lmemorymanager,
util;
type
TDisk_Info = bitpacked record
jmp2boot: ubit24;
OEMName: array[0..7] of char;
version: uint16;
sectorCount : uint16;
fileCount : uint16;
signature : uint32;
end;
PDisk_Info = ^TDisk_Info;
TFile_Entry = bitpacked record
attribues : uint8; // 0x00 = does not exsist, 0x01 = file, 0x02 = hidden, 0x04 = system/read only, 0x10 = directory, 0x20 = archive
name: array[0..53] of char; //max file name length is 54
rsv : uint8;
size: uint32;
start : uint32;
end;
PFile_Entry = ^TFile_Entry;
var
filesystem : TFilesystem;
procedure init;
procedure create_volume(volume : PStorage_Volume; sectors : uint32; start : uint32; config : puint32);
procedure detect_volumes(disk : PStorage_Device);
function read_directory(volume : PStorage_Volume; directory : pchar; status : PuInt32) : PLinkedListBase;
procedure write_directory(volume : PStorage_Volume; directory : pchar; status : PuInt32);
procedure write_file(volume : PStorage_Volume; fileName : pchar; data : PuInt32; size : uint32; status : PuInt32);
procedure read_file(volume : PStorage_Volume; fileName : pchar; data : PuInt32; status : PuInt32);
implementation
procedure create_volume(volume : PStorage_Volume; sectors : uint32; start : uint32; config : puint32);
var
info : PDisk_Info;
entryTable : PFile_Entry;
i : uint32;
directories : PLinkedListBase;
status : PuInt32;
data : pchar;
const
asuroArray : array[0..7] of char = 'ASURO';
systemArray : array[0..6] of char = '/system';
programsArray : array[0..8] of char = '/programs';
userArray : array[0..4] of char = '/user';
testArray : array[0..23] of char = 'ASURO TEST DATA ARRAY';
begin
info := PDisk_Info(Kalloc(512));
memset(uint32(info), 0, 512);
info^.jmp2boot := $0;
info^.OEMName := asuroArray;
info^.version := 1;
info^.sectorCount := sectors;
info^.fileCount := 1000;
info^.signature := $0B00B1E5;
if config^ <> 0 then begin
info^.fileCount := config^;
end;
volume^.device^.writeCallback(volume^.device, start, 1, PuInt32(info));// what happens if buffer is smaller than 512?
// create file table
entryTable := PFile_Entry(Kalloc(126 * 512));
memset(uint32(entryTable), 0, 126 * 512);
//create system folders
entryTable[0].attribues := $10;
memcpy(uint32(@systemArray), uint32(@entryTable[0].name), 7);
entryTable[0].size := 0;
entryTable[0].start := 0;
entryTable[1].attribues := $10;
memcpy(uint32(@programsArray), uint32(@entryTable[1].name), 9);
entryTable[1].size := 0;
entryTable[1].start := 0;
entryTable[2].attribues := $10;
memcpy(uint32(@userArray), uint32(@entryTable[2].name), 5);
entryTable[2].size := 0;
entryTable[2].start := 0;
//write file table
volume^.device^.writeCallback(volume^.device, start + 1, ((sizeof(TFile_Entry) * info^.fileCount) div 512), puint32(entryTable));
//volume^.device^.writeCallback(volume^.device, start + 1, 1, puint32(entryTable));
//temp read
status := PuInt32(Kalloc(sizeof(uint32)));
// directories := read_directory(volume, '/', status);
data := stringNew(1024);
memset(uint32(data), 0, 513);
memcpy(uint32(@testArray), uint32(data), 23);
write_directory(volume, '/logs', status);
write_directory(volume, '/logs/test', status);
write_file(volume, '/logs/log.txt', PuInt32(data), 1, status);
write_file(volume, '/logs/log2.txt', PuInt32(data), 1, status);
write_file(volume, '/logs/log3.txt', PuInt32(data), 1, status);
read_directory(volume, '/logs', status);
kfree(puint32(data));
read_file(volume, '/logs/log.txt', PuInt32(data), status);
writestringlnWND(pchar(data), getterminalhwnd());
end;
procedure write_directory(volume : PStorage_Volume; directory : pchar; status : PuInt32);
var
directories : PLinkedListBase;
i : uint32;
fileEntries : PFile_Entry;
fileEntry : PFile_Entry;
buffer : PuInt32;
position : uint32;
offset : uint32;
const
fileCount : uint32 = 1000;
begin
status^ := 0;
//directories := read_directory(volume, directory, status);
fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount + 512);
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1, (sizeof(TFile_Entry) * fileCount) div 512, PuInt32(fileEntries));
if status^ = 0 then begin
for i := 0 to fileCount - 1 do begin
push_trace('write_directory_2');
//fileEntry := PFile_Entry(STRLL_Get(directories, i));
fileEntry := @fileEntries[i];
if fileEntry^.attribues = 0 then begin
fileEntry^.attribues := $10;
fileEntry^.size := 0;
fileEntry^.start := 0;
memcpy(uint32(directory), uint32(@fileEntry^.name), stringSize(directory));
push_trace('write_directory_3');
//write file table
buffer := PuInt32(Kalloc(513));
memset(uint32(buffer), 0, 512);
push_trace('write_directory.b4_read');
//read file table cointaining entry of interest
position := (i * sizeof(TFile_Entry)) div 512;
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1 + position, 1, buffer);
push_trace('write_directory.after_read');
//calculate entry offset into sector
offset := (i * sizeof(TFile_Entry)) mod 512;
offset := offset div sizeof(TFile_Entry);
//set entry in buffer
PFile_Entry(buffer)[offset] := fileEntry^;
//write updated file table sector
volume^.device^.writeCallback(volume^.device, volume^.sectorStart + 1 + position, 1, buffer);
Kfree(buffer);
push_trace('write_directory.after_write');
break;
end;
end;
end;
if fileEntry^.attribues = 0 then begin
status^ := 1;
end;
end;
function read_directory(volume : PStorage_Volume; directory : pchar; status : PuInt32) : PLinkedListBase;
var
directories : PLinkedListBase;
fileEntrys : PFile_Entry;
i : uint32;
compString : PChar;
afterString : PChar;
slash : PChar;
compStringLength : uint32;
fileCount : uint32 = 1000;
slashArray : array[0..1] of char = '/';
begin
compString := pchar(kalloc(60));
memset(uint32(compString), 0, 60);
afterString := pchar(kalloc(60));
memset(uint32(afterString), 0, 60);
slash := stringNew(2);
memcpy(uint32(@slashArray), uint32(slash), 1);
directories := STRLL_New();
fileEntrys := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntrys));
for i := 0 to fileCount - 1 do begin
if uint32(fileEntrys[i].name[0]) = 0 then begin
break;
end;
compString := stringSub(fileEntrys[i].name, 0, stringSize(directory));
afterString := stringSub(fileEntrys[i].name, stringSize(directory), stringSize(fileEntrys[i].name)-1);
writestringlnWND(afterString, getterminalhwnd());
push_trace('read_directory_2');
if stringEquals(compString, directory) and
(not stringContains(afterString, slash)) then begin
writestringlnWND(fileEntrys[i].name, getterminalhwnd());
STRLL_Add(directories, afterString);
end;
end;
push_trace('read_directory_3');
Kfree(puint32(fileEntrys));
read_directory := directories;
end;
procedure quicksort_start(list : PFile_Entry; begining : uint32; stop : uint32);
var
pivot : uint32;
i : uint32;
j : uint32;
temp : PLinkedListBase;
tempFileEntry : PFile_Entry;
begin
tempFileEntry := PFile_Entry(Kalloc(sizeof(TFile_Entry)));
memset(uint32(tempFileEntry), 0, sizeof(TFile_Entry));
i:=begining;
j:=stop;
pivot := list[(begining + stop) div 2].start;
while i <= j do begin
while list[i].start < pivot do begin
i := i + 1;
end;
while list[j].start > pivot do begin
j := j - 1;
end;
if i <= j then begin
tempFileEntry^ := list[i];
list[i] := list[j];
list[j] := tempFileEntry^;
i := i + 1;
j := j - 1;
end;
end;
if begining < j then begin
quicksort_start(list, begining, j);
end;
if i < stop then begin
quicksort_start(list, i, stop);
end;
Kfree(puint32(tempFileEntry));
end;
function find_free_space(volume : PStorage_Volume; size : uint32; status : PuInt32) : uint32;
var
fileEntrys : PFile_Entry;
confirmedFileEntrys : PFile_Entry;
confirmedFileEntrysCount : uint32 = 0;
fileEntry : PFile_Entry;
i : uint32;
fileCount : uint32 = 1000;
baseAddress : uint32;
begin
fileEntrys := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
confirmedFileEntrys := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
memset(uint32(fileEntrys), 0, sizeof(TFile_Entry) * fileCount + 512);
memset(uint32(confirmedFileEntrys), 0, sizeof(TFile_Entry) * fileCount + 512);
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntrys));
baseAddress := volume^.sectorStart + 2 + ( (fileCount * sizeof(TFile_Entry)) div 512);
for i := 0 to fileCount - 1 do begin
if fileEntrys[i].attribues <> 0 then begin
confirmedFileEntrys[confirmedFileEntrysCount] := fileEntrys[i];
confirmedFileEntrysCount := confirmedFileEntrysCount + 1;
end;
end;
//sort file table by start address using quicksort
quicksort_start(confirmedFileEntrys, 0, confirmedFileEntrysCount - 1);
//find free space big enough to fit size //TODO: make this work
for i := 0 to confirmedFileEntrysCount - 1 do begin
if confirmedFileEntrys[i+1].attribues = 0 then begin
if confirmedFileEntrys[i].size = 0 then begin
find_free_space := baseAddress;
break;
end else begin
find_free_space := confirmedFileEntrys[i].start + confirmedFileEntrys[i].size;
break;
end;
break;
end;
if confirmedFileEntrys[i].size <> 0 then begin
if confirmedFileEntrys[i+1].start - (confirmedFileEntrys[i].start + confirmedFileEntrys[i].size) > size+1 then begin
find_free_space := confirmedFileEntrys[i].start + confirmedFileEntrys[i].size;
status^ := 0;
break;
end;
end;
end;
Kfree(puint32(fileEntrys));
Kfree(puint32(confirmedFileEntrys));
end;
procedure write_file(volume : PStorage_Volume; fileName : pchar; data : PuInt32; size : uint32; status : PuInt32);
var
directories : PLinkedListBase;
i : uint32;
p : uint32;
fileEntries : PFile_Entry;
fileEntry : PFile_Entry;
buffer : PuInt32;
position : uint32;
offset : uint32;
fileCount : uint32 = 1000;
exsists : boolean;
elm : puint32;
begin
push_trace('flatfs.write_file');
//load file table
fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount);
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries));
//check if file exists else find free entry
for i := 0 to fileCount - 1 do begin
if stringEquals(fileEntries[i].name, fileName) then begin
exsists := true;
p:= i;
break;
end;
if fileEntries[i].attribues = 0 then begin
exsists := false;
p:= i;
break;
end;
end;
//if entry is directory then exit
if fileEntries[p].attribues and $10 = $10 then begin
status^ := 1;
exit;
end;
// //read file table cointaining entry of interest
position := (p * sizeof(TFile_Entry)) div 512;
//if file exists update entry else create new entry
if exsists then begin
//check if size is greater than current size
if size > fileEntries[p].size then begin
//find free space
fileEntries[p].start := find_free_space(volume, size, status);
fileEntries[p].size := size;
end else begin
//update size
fileEntries[p].size := size;
end;
end else begin
//find free space
fileEntries[p].start := find_free_space(volume, size, status);
fileEntries[p].size := size;
fileEntries[p].attribues := $01;
//add file name
memcpy(uint32(fileName), uint32(@fileEntries[p].name), 14);
end;
//write file table
volume^.device^.writeCallback(volume^.device, volume^.sectorStart + 1 , 1, puint32(@fileEntries[position]));
//write file
volume^.device^.writeCallback(volume^.device, fileEntries[p].start, size, data);
//free buffer
Kfree(puint32(fileEntries));
end;
procedure read_file(volume : PStorage_Volume; fileName : pchar; data : PuInt32; status : PuInt32);
var
directories : PLinkedListBase;
i : uint32;
p : uint32;
fileEntries : PFile_Entry;
fileEntry : PFile_Entry;
fileCount : uint32 = 1000;
exsists : boolean = false;
size : uint32;
begin
//load file table
fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount);
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries));
//check if file exists else exit
for i := 0 to fileCount - 1 do begin
if stringEquals(fileEntries[i].name, fileName) then begin
exsists := true;
p:= i;
break;
end;
end;
//if entry is directory then exit
if fileEntries[p].attribues and $10 = $10 then begin
status^ := 1;
exit;
end;
//if entry is not found exit
if fileEntries[i].attribues = 0 then begin
exsists := false;
p:= i;
exit;
end;
//file size rounded up to nearest 512
size := (fileEntries[p].size + 511) and -512;
//read file
data := Kalloc(size);
volume^.device^.readCallback(volume^.device, fileEntries[p].start, size, data);
//free buffer
Kfree(puint32(fileEntries));
status^ := 0;
end;
procedure detect_volumes(disk : PStorage_Device);
var
buffer : puint32;
volume : PStorage_volume;
begin
push_trace('flatfs.detectVolumes()');
volume:= PStorage_volume(kalloc(sizeof(TStorage_Volume)));
//check first address for MBR
//if found then add volume and use info to see if there is another volume
buffer := puint32(kalloc(512));
memset(uint32(buffer), 0, 512);
disk^.readcallback(disk, 2, 1, buffer);
if (PDisk_Info(buffer)^.signature = $0B00B1E5) then begin
console.writestringln('FlatFS: volume found!');
volume^.device:= disk;
volume^.sectorStart:= 2;
volume^.sectorSize:= 512;
volume^.sectorCount:= PDisk_Info(buffer)^.sectorCount;
volume^.freeSectors:= 1000000; //TODO implement get free sectors need FSINFO implemented first
volume^.filesystem := @filesystem;
volume^.isBootDrive := false;
// storagemanagement.register_volume(disk, volume); TODO repalce with new thing
end;
kfree(buffer);
end;
procedure delete_file(volume : PStorage_Volume; fileName : pchar; status : PuInt32);
var
directories : PLinkedListBase;
i : uint32;
p : uint32;
fileEntries : PFile_Entry;
fileEntry : PFile_Entry;
zeroBuffer : PuInt32;
position : uint32;
offset : uint32;
fileCount : uint32 = 1000;
exsists : boolean;
begin
//load file table
fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount);
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries));
//check if file exists else exit
for i := 0 to fileCount - 1 do begin
if stringEquals(fileEntries[i].name, fileName) then begin
exsists := true;
p:= i;
break;
end;
end;
//set position of entry
position := (p * sizeof(TFile_Entry)) div 512;
//if entry is directory then exit
if fileEntries[p].attribues and $10 = $10 then begin
status^ := 1;
exit;
end;
//if entry is not found exit
if fileEntries[i].attribues = 0 then begin
exsists := false;
p:= i;
exit;
end;
//zero out file
zeroBuffer := Kalloc(fileEntries[p].size);
memset(uint32(zeroBuffer), 0, fileEntries[p].size);
//write file
volume^.device^.writeCallback(volume^.device, fileEntries[p].start, fileEntries[p].size, zeroBuffer);
//free buffer
Kfree(puint32(zeroBuffer));
//zero out file table
memset(uint32(@fileEntries[p]), 0, sizeof(TFile_Entry));
//write file table
volume^.device^.writeCallback(volume^.device, volume^.sectorStart + 1 , 1, puint32(@fileEntries[position]));
//free buffer
Kfree(puint32(fileEntries));
status^ := 0;
end;
procedure delete_directory(volume : PStorage_Volume; directoryName : pchar; status : PuInt32);
var
directories : PLinkedListBase;
i : uint32;
p : uint32;
fileEntries : PFile_Entry;
fileEntry : PFile_Entry;
zeroBuffer : PuInt32;
position : uint32;
offset : uint32;
fileCount : uint32 = 1000;
exsists : boolean;
begin
//load file table
fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512));
memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount);
volume^.device^.readCallback(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries));
//check if file exists else exit
for i := 0 to fileCount - 1 do begin
if stringEquals(fileEntries[i].name, directoryName) then begin
exsists := true;
p:= i;
break;
end;
end;
//if entry is not directory then exit
if fileEntries[i].attribues and $10 <> $10 then begin
status^ := 1;
exit;
end;
//calculate position of directory in file table
position := (p * sizeof(TFile_Entry)) div 512;
//zero file table
memset(uint32(@fileEntries[p]), 0, sizeof(TFile_Entry));
//write file table
volume^.device^.writeCallback(volume^.device, volume^.sectorStart + 1 , 1, puint32(@fileEntries[position]));
//free buffer
Kfree(puint32(fileEntries));
status^ := 0;
end;
procedure init();
begin
push_trace('flatfs.init()');
filesystem.sName:= 'flatfs';
filesystem.system_id:= $02;
filesystem.readDirCallback:= @read_directory;
// filesystem.createDirCallback:= @writeDirectoryGen;
filesystem.createcallback:= @create_volume;
filesystem.detectcallback:= @detect_volumes;
// filesystem.writecallback:= @writeFile;
// filesystem.readcallback := @readFile;
// filesystem.formatVolumeCallback := @create_volume;
volumemanager.register_filesystem(@filesystem);
end;
end.

View File

@ -0,0 +1,140 @@
// 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

@ -0,0 +1,504 @@
{ ************************************************
* 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

@ -15,6 +15,8 @@
{ {
Driver->Storage->StorageManagment Storage Managment System Driver->Storage->StorageManagment Storage Managment System
DEPRECATED unit
@author(Aaron Hance ah@aaronhance.me) @author(Aaron Hance ah@aaronhance.me)
} }
unit storagemanagement; unit storagemanagement;
@ -31,14 +33,14 @@ uses
strings, strings,
lists, lists,
tracer, tracer,
rtc; rtc,
MBR,
volumemanager,
storagetypes;
type type
TControllerType = (ControllerIDE, ControllerUSB, ControllerAHCI, ControllerNET, ControllerRAM, rsvctr1, rsvctr2, rsvctr3);
TDirectory_Entry_Type = (directoryEntry, fileEntry, mountEntry); TDirectory_Entry_Type = (directoryEntry, fileEntry, mountEntry);
PStorage_volume = ^TStorage_Volume;
PStorage_device = ^TStorage_Device;
APStorage_Volume = array[0..10] of PStorage_volume; APStorage_Volume = array[0..10] of PStorage_volume;
byteArray8 = array[0..7] of char; byteArray8 = array[0..7] of char;
PByteArray8 = ^byteArray8; PByteArray8 = ^byteArray8;
@ -54,41 +56,6 @@ type
PPHIOHook_ = procedure; PPHIOHook_ = procedure;
TFilesystem = record
sName : pchar;
writeCallback : PPWriteHook;
readCallback : PPReadHook;
createCallback : PPCreateHook;
detectCallback : PPDetectHook;
createDirCallback : PPCreateDirHook;
readDirCallback : PPReadDirHook;
end;
PFileSystem = ^TFilesystem;
TStorage_Volume = record
device : PStorage_device;
sectorStart : uint32;
sectorSize : uint32;
freeSectors : uint32;
filesystem : PFilesystem;
{ True if this drive contains the loaded OS }
isBootDrive : boolean;
end;
{ Generic storage device }
TStorage_Device = record
idx : uint8;
controller : TControllerType;
controllerId0 : uint32;
maxSectorCount : uint32;
sectorSize : uint32;
writable : boolean;
volumes : PLinkedListBase;
writeCallback : PPHIOHook;
readCallback : PPHIOHook;
hpc : uint16;
spt : uint16;
end;
APStorage_Device = array[0..255] of PStorage_device; APStorage_Device = array[0..255] of PStorage_device;
{ Generic directory entry } { Generic directory entry }
@ -110,20 +77,13 @@ procedure init();
procedure register_device(device : PStorage_Device); procedure register_device(device : PStorage_Device);
function get_device_list() : PLinkedListBase; function get_device_list() : PLinkedListBase;
procedure register_filesystem(filesystem : PFilesystem);
procedure register_volume(device : PStorage_Device; volume : PStorage_Volume);
//function writeNewFile(fileName : pchar; extension : pchar; buffer : puint32; size : uint32) : uint32;
//function readFile(fileName : pchar; extension : pchar; buffer : puint32; byteCount : puint32) : puint32;
//TODO write partition table
implementation implementation
function controller_type_2_string(controllerType : TControllerType) : pchar; function controller_type_2_string(controllerType : TControllerType) : pchar;
begin begin
case controllerType of case controllerType of
ControllerIDE : controller_type_2_string:= 'IDE'; ControllerATA : controller_type_2_string:= 'ATA';
ControllerATAPI : controller_type_2_string:= 'ATAPI';
ControllerUSB : controller_type_2_string:= 'USB'; ControllerUSB : controller_type_2_string:= 'USB';
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)'; ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
ControllerNET : controller_type_2_string:= 'Net'; ControllerNET : controller_type_2_string:= 'Net';
@ -169,18 +129,57 @@ var
drive : PStorage_Device; drive : PStorage_Device;
filesystemString : pchar; filesystemString : pchar;
filesystem : PFileSystem;
spc : puint32; spc : puint32;
sectorCount : uint32;
volumeId : uint8;
mb : PMaster_Boot_Record;
i : uint32 = 0;
begin begin
//format <DRIVE_ID> <FILESYSTEM> <size>
spc:= puint32(kalloc(4)); spc:= puint32(kalloc(4));
spc^:= 4; spc^:= 1;
driveIndex:= stringToInt( getParam(1, params) ); driveIndex:= stringToInt( getParam(1, params) );
drive:= PStorage_Device(LL_Get(storageDevices, driveIndex)); drive:= PStorage_Device(LL_Get(storageDevices, driveIndex));
//todo change b4 adding in aniother filesytem filesystemString := getParam(2, params);
PFilesystem(LL_Get(filesystems, 0))^.createCallback(drive, drive^.maxSectorCount-1, 1, spc);
sectorCount := stringToInt( getParam(4, params) );
// if sector count is 0, use full drive
if sectorCount = 0 then begin
sectorCount := drive^.maxSectorCount - 10;
end;
//create MBR if none, and partition table
mb := PMaster_Boot_Record(kalloc(sizeof(TMaster_Boot_Record)));
drive^.readCallback(drive, 0, 1, PuInt32(mb));
//check if MBR exists
if not mb^.boot_sector = $55AA then begin
//create MBR
mb^.signature := $A570 + drive^.id;
mb^.boot_sector := $55AA;
//create partition table
mbr.setup_partition(@mb^.partition[0], 2, sectorCount);
//write MBR
drive^.writeCallback(drive, 0, 1, puint32(mb));
end;
kfree(puint32(mb));
//setup volume
volumemanager.create_volume(drive, filesystemString, 2, sectorCount);
writestringWnd('Drive ', getTerminalHWND); writestringWnd('Drive ', getTerminalHWND);
writeintWnd(driveIndex, getTerminalHWND); writeintWnd(driveIndex, getTerminalHWND);
@ -217,10 +216,6 @@ begin
format_command(params); format_command(params);
end; end;
//lsfs command for listing filesystems
if stringEquals(subcmd, 'lsfs') then begin
end;
pop_trace(); pop_trace();
end; end;
@ -231,10 +226,8 @@ begin
setworkingdirectory('.'); setworkingdirectory('.');
storageDevices:= ll_new(sizeof(TStorage_Device)); storageDevices:= ll_new(sizeof(TStorage_Device));
fileSystems:= ll_New(sizeof(TFilesystem));
terminal.registerCommand('DISK', @disk_command, 'Disk utility'); terminal.registerCommand('DISK', @disk_command, 'Disk utility');
pop_trace();
end; end;
{ Register a new drive with the storage manager } { Register a new drive with the storage manager }
@ -253,9 +246,7 @@ begin
PStorage_Device(LL_Get(storageDevices, LL_Size(storageDevices) - 1))^.volumes := LL_New(sizeof(TStorage_Volume)); PStorage_Device(LL_Get(storageDevices, LL_Size(storageDevices) - 1))^.volumes := LL_New(sizeof(TStorage_Volume));
//check for volumes //check for volumes
for i:=0 to ll_size(filesystems) - 1 do begin
PFileSystem(LL_Get(filesystems, i))^.detectCallback(PStorage_Device(LL_Get(storageDevices, LL_Size(storageDevices) - 1)));
end;
pop_trace(); pop_trace();
end; end;
@ -265,23 +256,4 @@ begin
get_device_list:= storageDevices; get_device_list:= storageDevices;
end; end;
procedure register_filesystem(filesystem : PFilesystem);
var
elm : void;
begin
elm:= LL_Add(fileSystems);
PFileSystem(elm)^ := filesystem^;
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;
end. end.

View File

@ -0,0 +1,64 @@
// 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->Include->storagetypes - Structs & Data Shared Across Storage Drivers.
@author(Aaron Hance <ah@aaronhance.me>)
}
unit storagetypes;
interface
uses
lists;
type
TControllerType = (ControllerATA, ControllerATAPI, ControllerUSB, ControllerAHCI,
ControllerNET, ControllerRAM, rsvctr1, rsvctr2, rsvctr3);
PStorage_device = ^TStorage_Device;
PDrive_Error = ^TDrive_Error;
PPHIOHook = procedure(drive : PStorage_device; addr : uint32; sectors : uint32; buffer : puint32);
PPHIOHook_ = procedure;
byteArray8 = array[0..7] of char;
PByteArray8 = ^byteArray8;
{ Generic storage device }
TStorage_Device = record
id : uint8;
controller : TControllerType;
controllerId0 : uint32;
writable : boolean;
volumes : PLinkedListBase;
writeCallback : PPHIOHook;
readCallback : PPHIOHook;
maxSectorCount : uint32;
sectorSize : uint32;
end;
TDrive_Error = record
code : uint16;
description : pchar;
recoverable : boolean;
end;
implementation
end.

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

@ -16,6 +16,7 @@
Include->Strings - String Manipulation. Include->Strings - String Manipulation.
@author(Kieron Morris <kjm@kieronmorris.me>) @author(Kieron Morris <kjm@kieronmorris.me>)
@author(Aaron Hance <ah@aaronhance.me>)
} }
unit strings; unit strings;
@ -33,6 +34,10 @@ function stringCopy(str : pchar) : pchar;
function stringNew(size : uint32) : pchar; function stringNew(size : uint32) : pchar;
function stringSize(str : pchar) : uint32; function stringSize(str : pchar) : uint32;
function stringConcat(str1, str2 : pchar) : pchar; function stringConcat(str1, str2 : pchar) : pchar;
function stringTrim(str : pchar; length : uint32) : pchar;
function stringSub(str : pchar; start, size : uint32) : pchar;
function stringReplace(str, find, replace : pchar) : pchar;
function stringIndexOf(str, find : pchar) : sint32;
function stringContains(str : pchar; sub : pchar) : boolean; function stringContains(str : pchar; sub : pchar) : boolean;
function stringToInt(str : pchar) : uint32; function stringToInt(str : pchar) : uint32;
function hexStringToInt(str : pchar) : uint32; function hexStringToInt(str : pchar) : uint32;
@ -151,6 +156,94 @@ begin
stringConcat:= result; stringConcat:= result;
end; end;
// Trim the string to the specified length.
function stringTrim(str : pchar; length : uInt32) : pchar;
var
result : pchar;
begin
result:= stringNew(length);
memcpy(uint32(str), uint32(result), length);
stringTrim:= result;
end;
// Return a substring of the string.
function stringSub(str : pchar; start, size : uint32) : pchar;
var
result : pchar;
begin
result:= stringNew(size);
memcpy(uint32(str)+start, uint32(result), size);
stringSub:= result;
end;
// Replace first instance of a string with another.
function stringReplace(str, find, replace : pchar) : pchar;
var
result : pchar;
i, j, k : uint32;
found : boolean;
begin
// Find the first instance of the find string.
i:= 0;
found:= false;
while (i < stringSize(str)) and (not found) do begin
if stringEquals(str+i, find) then begin
found:= true;
end else begin
inc(i);
end;
end;
// If we found the find string, replace it.
if found then begin
result:= stringNew(stringSize(str) - stringSize(find) + stringSize(replace));
j:= 0;
k:= 0;
while i < stringSize(str) do begin
if stringEquals(str+i, find) then begin
memcpy(uint32(replace), uint32(result+j), stringSize(replace));
j:= j + stringSize(replace);
inc(i, stringSize(find));
end else begin
result[j]:= str[i];
inc(j);
inc(i);
end;
end;
stringReplace:= result;
end else begin
stringReplace:= stringCopy(str);
end;
// Return the result.
stringReplace:= result;
end;
// Find the index of the first instance of a string.
function stringIndexOf(str, find : pchar) : sint32;
var
i : uint32;
found : boolean;
begin
i:= 0;
found:= false;
while (i < stringSize(str)) and (not found) do begin
if stringEquals(str+i, find) then begin
found:= true;
end else begin
inc(i);
end;
end;
if found then begin
stringIndexOf:= i;
end else begin
stringIndexOf:= -1;
end;
end;
function stringContains(str : pchar; sub : pchar) : boolean; function stringContains(str : pchar; sub : pchar) : boolean;
var var
strEnd, subEnd, i, j, count : uint32; strEnd, subEnd, i, j, count : uint32;

View File

@ -41,9 +41,12 @@ uses
E1000, E1000,
IDE, IDE,
storagemanagement, storagemanagement,
drivemanager,
volumemanager,
lists, lists,
net, net,
fat32, fat32,
flatfs,
isrmanager, isrmanager,
faults, faults,
fonts, fonts,
@ -205,7 +208,9 @@ begin
tracer.push_trace('kmain.DRVMGMT'); tracer.push_trace('kmain.DRVMGMT');
drivermanagement.init(); drivermanagement.init();
tracer.push_trace('kmain.STRMGMT'); tracer.push_trace('kmain.STRMGMT');
storagemanagement.init(); // storagemanagement.init();
drivemanager.init();
volumemanager.init();
{ Hook Timer for Ticks } { Hook Timer for Ticks }
tracer.push_trace('kmain.TMR'); tracer.push_trace('kmain.TMR');
@ -214,6 +219,7 @@ begin
{ Filsystems } { Filsystems }
fat32.init(); fat32.init();
flatfs.init();
{ Device Drivers } { Device Drivers }
tracer.push_trace('kmain.DEVDRV'); tracer.push_trace('kmain.DEVDRV');

58
virtualbox-wrapper.ps1 Normal file
View File

@ -0,0 +1,58 @@
<#
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
)
$Config = Get-Content .\localenv.json | ConvertFrom-Json
$MachineName = $Config.virtualbox.MachineName
$LogLocation = $Config.virtualbox.LogLocation
$LogOutputEnabled = $LogLocation -ne $null
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) {
$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
}