Compare commits
37 Commits
develop
...
feature/st
Author | SHA1 | Date | |
---|---|---|---|
569b2f0bca | |||
ed0f8d9c08 | |||
a2f6d7e76d | |||
babe4290e4 | |||
05eab23956 | |||
f04f8aa411 | |||
6a3ebf1387 | |||
b2ecbe58da | |||
2014ce4f9c | |||
6cd9ae4f46 | |||
0855abfd41 | |||
fd0de9f1d2 | |||
920aca5bbf | |||
837d69a44b | |||
f0d5eb21f1 | |||
07e9095582 | |||
72769fbef7 | |||
95599c0e7c | |||
fcaafa0d12 | |||
e490b95f1d | |||
b601080960 | |||
27177979a2 | |||
f88a282893 | |||
ff4c597ff3 | |||
24c371cab1 | |||
7588a4c9cb | |||
5cb415c76b | |||
118d8b0c03 | |||
28caca3bcc | |||
6476a774dc | |||
e791edb02a | |||
da36f6fabb | |||
97e1a18253 | |||
88a850e8fc | |||
10c9194c5f | |||
94b477d8f7 | |||
ba38f4fd19 |
65
.drone.yml
65
.drone.yml
@ -1,65 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: build
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build-image
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
repo: t3hn3rd/asuro-build
|
|
||||||
tags: latest
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
registry: docker.io
|
|
||||||
username:
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
|
|
||||||
- name: compile
|
|
||||||
image: t3hn3rd/asuro-build:latest
|
|
||||||
depends_on:
|
|
||||||
- build-image
|
|
||||||
commands:
|
|
||||||
- git fetch --tags
|
|
||||||
- find . -type f -print0 | xargs -0 dos2unix
|
|
||||||
- chmod +x /drone/src/*.sh
|
|
||||||
- /drone/src/compile.sh
|
|
||||||
|
|
||||||
- name: upload-iso-artifact
|
|
||||||
image: alpine/git
|
|
||||||
depends_on:
|
|
||||||
- compile
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
environment:
|
|
||||||
GITEA_TOKEN:
|
|
||||||
from_secret: gitea_token
|
|
||||||
commands:
|
|
||||||
- apk add --no-cache curl
|
|
||||||
- chmod +w Asuro.iso
|
|
||||||
- cp Asuro.iso "Asuro-$(git rev-parse --short HEAD).iso"
|
|
||||||
- echo "Uploading Asuro-$(git rev-parse --short HEAD).iso to Gitea Packages..."
|
|
||||||
- |
|
|
||||||
curl -X PUT "https://gitea.spexeah.com/api/packages/Spexeah/generic/asuro-iso/$(git rev-parse --short HEAD)/Asuro.iso" \
|
|
||||||
-H "Authorization: token $GITEA_TOKEN" --upload-file "Asuro-$(git rev-parse --short HEAD).iso"
|
|
||||||
- echo "Updating latest ISO reference..."
|
|
||||||
- |
|
|
||||||
curl -X DELETE https://gitea.spexeah.com/api/packages/Spexeah/generic/asuro-iso/latest/Asuro.iso \
|
|
||||||
-H "Authorization: token $GITEA_TOKEN" || echo "No previous latest version found."
|
|
||||||
- |
|
|
||||||
curl -X PUT https://gitea.spexeah.com/api/packages/Spexeah/generic/asuro-iso/latest/Asuro.iso \
|
|
||||||
-H "Authorization: token $GITEA_TOKEN" --upload-file "Asuro-$(git rev-parse --short HEAD).iso"
|
|
||||||
|
|
||||||
- name: msg status
|
|
||||||
image: appleboy/drone-discord
|
|
||||||
depends_on:
|
|
||||||
- compile
|
|
||||||
when:
|
|
||||||
status: [success, failure, changed]
|
|
||||||
settings:
|
|
||||||
webhook_id:
|
|
||||||
from_secret: discord_webhook_id
|
|
||||||
webhook_token:
|
|
||||||
from_secret: discord_webhook_secret
|
|
||||||
message: "**Asuro Build**\n\n{{#success build.status}}✅ Build successful!\n\n{{else}}❌ Build failed!\n\n{{/success}}Repository: `{{repo.namespace}}/{{repo.name}}`\nBranch: `{{commit.branch}}`\nCommit: `{{commit.sha}}`\nAuthor: `{{commit.author}} <{{commit.email}}>`\n\nGitea Diff: [Link](<{{commit.link}}>)\nDrone Build: [Link](<{{build.link}}>)\n\nMessage: {{commit.message}}"
|
|
73
.gitlab-ci.yml
Normal file
73
.gitlab-ci.yml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
stages:
|
||||||
|
- Compile Versions
|
||||||
|
- Compile Sources
|
||||||
|
- Link
|
||||||
|
- Generate Documentation
|
||||||
|
- Deploy
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- key: ${CI_COMMIT_REF_SLUG}
|
||||||
|
paths:
|
||||||
|
- lib/*.o
|
||||||
|
- bin/kernel.bin
|
||||||
|
- doc
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- chmod +x *.sh
|
||||||
|
|
||||||
|
versions:
|
||||||
|
stage: Compile Versions
|
||||||
|
script:
|
||||||
|
- ./compile_vergen.sh
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- release/*.svg
|
||||||
|
- src/include/asuro.pas
|
||||||
|
|
||||||
|
compile_sources:
|
||||||
|
stage: Compile Sources
|
||||||
|
script:
|
||||||
|
- rm -f lib/*.so
|
||||||
|
- ./compile_sources.sh
|
||||||
|
needs:
|
||||||
|
- versions
|
||||||
|
|
||||||
|
link:
|
||||||
|
stage: Link
|
||||||
|
script:
|
||||||
|
- ./compile_stub.sh
|
||||||
|
- ./compile_link.sh
|
||||||
|
needs:
|
||||||
|
- versions
|
||||||
|
- compile_sources
|
||||||
|
|
||||||
|
isogen:
|
||||||
|
stage: Deploy
|
||||||
|
script:
|
||||||
|
- ./compile_isogen.sh
|
||||||
|
- ./compile_sumgen.sh
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- ./Asuro.iso
|
||||||
|
- ./release/checksum.svg
|
||||||
|
needs:
|
||||||
|
- link
|
||||||
|
|
||||||
|
docgen:
|
||||||
|
stage: Generate Documentation
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
script:
|
||||||
|
- ./compile_sourcelist.sh
|
||||||
|
- ./compile_docs.sh
|
||||||
|
# Remove comments when we want to use gitlab pages.
|
||||||
|
#- cp doc public
|
||||||
|
allow_failure: true
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- doc
|
||||||
|
#- public/*
|
||||||
|
#- ./sources.list
|
||||||
|
needs:
|
||||||
|
- versions
|
13
.mailmap
13
.mailmap
@ -1,13 +0,0 @@
|
|||||||
# Map all Aaron identities to a single preferred identity
|
|
||||||
Aaron Hance <ah@aaronhance.me> aaron <aaron@6dbc8c32-bb84-406f-8558-d1cf31a0ab0c>
|
|
||||||
Aaron Hance <ah@aaronhance.me> aaronhance <ah@aaronhance.me>
|
|
||||||
Aaron Hance <ah@aaronhance.me> aaron hance <ah@aaronhance.me>
|
|
||||||
Aaron Hance <ah@aaronhance.me> Aaron <ah@aaronhance.me>
|
|
||||||
|
|
||||||
# Map all Kieron identities to a single preferred identity
|
|
||||||
Kieron Morris <kjm@kieronmorris.me> kieron <kieron@6dbc8c32-bb84-406f-8558-d1cf31a0ab0c>
|
|
||||||
Kieron Morris <kjm@kieronmorris.me> Kieron <kjm@kieronmorris.me>
|
|
||||||
Kieron Morris <kjm@kieronmorris.me> t3hn3rd <kjm@kieronmorris.me>
|
|
||||||
|
|
||||||
# Map goose's multiple identities
|
|
||||||
goose <goose@6dbc8c32-bb84-406f-8558-d1cf31a0ab0c> goose <angus@actm.uk>
|
|
@ -16,7 +16,7 @@ RUN curl -sL https://sourceforge.net/projects/freepascal/files/Linux/$FPC_VERSIO
|
|||||||
|
|
||||||
COPY compile.sh /compile.sh
|
COPY compile.sh /compile.sh
|
||||||
ADD https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver /usr/bin/semver
|
ADD https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver /usr/bin/semver
|
||||||
RUN chmod +x /usr/bin/semver
|
RUN mkdir /code && chmod +x /usr/bin/semver
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
RUN find . -type f -print0 | xargs -0 dos2unix
|
RUN find . -type f -print0 | xargs -0 dos2unix
|
||||||
ENTRYPOINT ["/bin/bash", "-c"]
|
ENTRYPOINT ["/bin/bash", "-c"]
|
||||||
|
32
compile.sh
32
compile.sh
@ -20,30 +20,26 @@ runOrFail() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
declare -a run_steps=(
|
runOrFail $(pwd)/compile_stub.sh "Failed to compile stub!"
|
||||||
"compile_stub.sh" "Failed to compile stub!"
|
|
||||||
"compile_vergen.sh" "Versions failed to compile"
|
|
||||||
"compile_sources.sh" "Failed to compile FPC Sources!"
|
|
||||||
"compile_link.sh" "Failed linking!"
|
|
||||||
"compile_isogen.sh" "Failed to create ISO!"
|
|
||||||
)
|
|
||||||
|
|
||||||
for ((i=0; i<${#run_steps[@]}; i+=2))
|
#Generate .pas with versioning headers.
|
||||||
do
|
runOrFail $(pwd)/compile_vergen.sh "Versions failed to compile"
|
||||||
if [ "$ERRCOUNT" -eq "0" ]
|
|
||||||
then
|
#Compile all .pas sources
|
||||||
script=$(pwd)/"${run_steps[$i]}"
|
runOrFail $(pwd)/compile_sources.sh "Failed to compile FPC Sources!"
|
||||||
message="${run_steps[$i+1]}"
|
|
||||||
runOrFail "$script" "$message"
|
#Link into a binary.
|
||||||
fi
|
runOrFail $(pwd)/compile_link.sh "Failed linking!"
|
||||||
done
|
|
||||||
|
#Generate an ISO with GRUB as the Bootloader.
|
||||||
|
runOrFail ./compile_isogen.sh "Failed to create ISO!"
|
||||||
|
|
||||||
#Call generate final artifacts based on failure or success of the above.
|
#Call generate final artifacts based on failure or success of the above.
|
||||||
if [ "$ERRCOUNT" -ne "0" ]
|
if [ "$ERRCOUNT" -ne "0" ]
|
||||||
then
|
then
|
||||||
. ./compile_finish.sh "failed"
|
./compile_finish.sh "failed"
|
||||||
else
|
else
|
||||||
. ./compile_finish.sh "success"
|
./compile_finish.sh "success"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd ..
|
cd ..
|
@ -4,4 +4,4 @@ echo "======================="
|
|||||||
echo " "
|
echo " "
|
||||||
echo "Compiling FPC Sources..."
|
echo "Compiling FPC Sources..."
|
||||||
echo " "
|
echo " "
|
||||||
fpc -Aelf -gw -g -gl -n -vlewn -O3 -Op3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas
|
fpc -Aelf -gw -n -O3 -Op3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/storage/* -Fusrc/driver/storage/AHCI/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas
|
32
doc/flatfs.md
Normal file
32
doc/flatfs.md
Normal 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
@ -2,7 +2,7 @@ ENTRY(loader)
|
|||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0xC0100000;
|
. = 0xC0100000;
|
||||||
kernel_start = .;
|
|
||||||
.text : AT(ADDR(.text) - 0xC0000000)
|
.text : AT(ADDR(.text) - 0xC0000000)
|
||||||
{
|
{
|
||||||
text = .; _text = .; __text = .;
|
text = .; _text = .; __text = .;
|
||||||
@ -33,5 +33,4 @@ SECTIONS
|
|||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
}
|
}
|
||||||
end = .; _end = .; __end = .;
|
end = .; _end = .; __end = .;
|
||||||
kernel_end = .;
|
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ function getDeviceInfo(class_code : uint8; subclass_code : uint8; prog_if : uint
|
|||||||
procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8);
|
procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8);
|
||||||
procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32);
|
procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32);
|
||||||
procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean);
|
procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean);
|
||||||
|
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -442,4 +443,34 @@ begin
|
|||||||
pop_trace;
|
pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
//Enable device inturrupts and set bus master
|
||||||
|
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
|
||||||
|
var
|
||||||
|
addr : uint32;
|
||||||
|
cmd : uint32;
|
||||||
|
begin
|
||||||
|
push_trace('PCI.enableDevice');
|
||||||
|
|
||||||
|
addr := ($1 shl 31);
|
||||||
|
addr := addr or (bus shl 16);
|
||||||
|
addr := addr or ((slot) shl 11);
|
||||||
|
addr := addr or ((func) shl 8);
|
||||||
|
addr := addr or ($04 and $FC);
|
||||||
|
|
||||||
|
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||||
|
cmd := inl(PCI_CONFIG_DATA_PORT);
|
||||||
|
cmd := cmd or PCI_COMMAND_MEM_SPACE;
|
||||||
|
cmd := cmd or PCI_COMMAND_BUS_MASTER;
|
||||||
|
cmd := cmd or (3 shl 1);
|
||||||
|
|
||||||
|
//enable interrupts, remove disable interrupt bit maybe
|
||||||
|
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
|
||||||
|
// cmd := cmd and not (1 shl 9);
|
||||||
|
|
||||||
|
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||||
|
outl(PCI_CONFIG_DATA_PORT, cmd);
|
||||||
|
|
||||||
|
pop_trace;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
@ -21,6 +21,29 @@ unit drivertypes;
|
|||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
const
|
||||||
|
PCI_CONFIG_ADDRESS_PORT = $0CF8;
|
||||||
|
PCI_CONFIG_DATA_PORT = $0CFC;
|
||||||
|
|
||||||
|
PCI_COMMAND_IO_SPACE = $0001;
|
||||||
|
PCI_COMMAND_MEM_SPACE = $0002;
|
||||||
|
PCI_COMMAND_BUS_MASTER = $0004;
|
||||||
|
PCI_COMMAND_SPECIAL_CYC = $0008;
|
||||||
|
PCI_COMMAND_MEM_WRITE = $0010;
|
||||||
|
PCI_COMMAND_VGA_PALETTE = $0020;
|
||||||
|
PCI_COMMAND_PARITY = $0040;
|
||||||
|
PCI_COMMAND_WAIT = $0080;
|
||||||
|
PCI_COMMAND_SERR = $0100;
|
||||||
|
PCI_COMMAND_FAST_BACK = $0200;
|
||||||
|
PCI_COMMAND_INT_DISABLE = $0400;
|
||||||
|
PCI_COMMAND_SERR_ENABLE = $8000;
|
||||||
|
|
||||||
|
PCI_CAP_ID_MSI = $05;
|
||||||
|
|
||||||
|
// Bits in the MSI Control register (16-bit):
|
||||||
|
MSI_CONTROL_ENABLE = 1 shl 0; // Bit 0
|
||||||
|
MSI_CONTROL_64BIT = 1 shl 7; // Bit 7
|
||||||
|
MSI_CONTROL_PVMASK = 1 shl 8; // Bit 8 (optional: per-vector masking)
|
||||||
type
|
type
|
||||||
|
|
||||||
PPCI_Device = ^TPCI_Device;
|
PPCI_Device = ^TPCI_Device;
|
||||||
@ -44,6 +67,7 @@ type
|
|||||||
address1 : uint32;
|
address1 : uint32;
|
||||||
address2 : uint32;
|
address2 : uint32;
|
||||||
address3 : uint32;
|
address3 : uint32;
|
||||||
|
|
||||||
address4 : uint32;
|
address4 : uint32;
|
||||||
address5 : uint32;
|
address5 : uint32;
|
||||||
CIS_pointer : uint32;
|
CIS_pointer : uint32;
|
||||||
|
@ -491,26 +491,22 @@ begin
|
|||||||
|
|
||||||
{ Create a new header to the use in our DHCP REQUEST packet }
|
{ Create a new header to the use in our DHCP REQUEST packet }
|
||||||
SendHeader:= createHeader();
|
SendHeader:= createHeader();
|
||||||
CopyIPv4(@getIPv4Config^.Address[0], puint8(@SendHeader^.Client_IP[0]));
|
CopyIPv4(puint8(@Header^.Your_IP[0]), puint8(@SendHeader^.Client_IP[0]));
|
||||||
CopyIPv4(puint8(@Header^.Server_IP[0]), puint8(@SendHeader^.Server_IP[0]));
|
CopyIPv4(puint8(@Header^.Server_IP[0]), puint8(@SendHeader^.Server_IP[0]));
|
||||||
processHeader(SendHeader);
|
processHeader(SendHeader);
|
||||||
|
|
||||||
{ Setup Options }
|
{ Setup Options }
|
||||||
SendOptions:= newOptions();
|
SendOptions:= newOptions();
|
||||||
|
|
||||||
{ Create a message type option and assign it the value REQUEST }
|
{ Create a message type option and assign it the value REQUEST }
|
||||||
SendMsgType:= ord(TDHCPMessageType.REQUEST);
|
SendMsgType:= ord(TDHCPMessageType.REQUEST);
|
||||||
NewOption(SendOptions, TDHCPOpCode.DHCP_MESSAGE_TYPE, void(@SendMsgType), 1, false);
|
NewOption(SendOptions, TDHCPOpCode.DHCP_MESSAGE_TYPE, void(@SendMsgType), 1, false);
|
||||||
|
|
||||||
{ Create a Requested IP option and assign it the value from the OFFER packet header }
|
{ Create a Requested IP option and assign it the value from the OFFER packet header }
|
||||||
NewOption(SendOptions, TDHCPOpCode.REQUESTED_IP_ADDRESS, void(@Header^.Your_IP[0]), 4, false);
|
NewOption(SendOptions, TDHCPOpCode.REQUESTED_IP_ADDRESS, void(@SendHeader^.Client_IP[0]), 4, false);
|
||||||
|
|
||||||
{ Create a Server Identifier Option and assign it the value from the OFFER packet options }
|
{ Create a Server Identifier Option and assign it the value from the OFFER packet options }
|
||||||
Option:= getOptionByOpcode(Options, TDHCPOpCode.SERVER_IDENTIFIER);
|
Option:= getOptionByOpcode(Options, TDHCPOpCode.SERVER_IDENTIFIER);
|
||||||
if Option <> nil then begin
|
if Option <> nil then begin
|
||||||
NewOption(SendOptions, TDHCPOpCode.SERVER_IDENTIFIER, void(@Option^.Value[0]), 4, false);
|
NewOption(SendOptions, TDHCPOpCode.SERVER_IDENTIFIER, void(@Option^.Value[0]), 4, false);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Create a Parameter Request List, Request the following: Netmask, Gateway, DNS Name & DNS Server }
|
{ Create a Parameter Request List, Request the following: Netmask, Gateway, DNS Name & DNS Server }
|
||||||
RequestParams[0]:= Ord(TDHCPOpCode.SUBNET_MASK);
|
RequestParams[0]:= Ord(TDHCPOpCode.SUBNET_MASK);
|
||||||
RequestParams[1]:= Ord(TDHCPOpCode.ROUTER);
|
RequestParams[1]:= Ord(TDHCPOpCode.ROUTER);
|
||||||
@ -526,13 +522,9 @@ begin
|
|||||||
MAC:= getMAC();
|
MAC:= getMAC();
|
||||||
packetCtx:= PPacketContext(Kalloc(sizeof(TPacketContext)));
|
packetCtx:= PPacketContext(Kalloc(sizeof(TPacketContext)));
|
||||||
packetCtx^.TTL:= 128;
|
packetCtx^.TTL:= 128;
|
||||||
|
|
||||||
{ Copy over MAC - src: broadcast - dst: DHCP Server }
|
|
||||||
copyMAC(MAC, @packetCtx^.MAC.Source[0]);
|
|
||||||
copyMAC(@BROADCAST_MAC[0], @packetCtx^.MAC.Destination[0]);
|
copyMAC(@BROADCAST_MAC[0], @packetCtx^.MAC.Destination[0]);
|
||||||
|
copyMAC(MAC, @packetCtx^.MAC.Source[0]);
|
||||||
{ Copy over IP - src: NULL - dst: Broadcast }
|
copyIPv4(@NULL_IP[0], @packetCtx^.IP.Source[0]);
|
||||||
CopyIPv4(@getIPv4Config^.Address[0], @packetCtx^.IP.Source[0]);
|
|
||||||
copyIPv4(@BROADCAST_IP[0], @packetCtx^.IP.Destination[0]);
|
copyIPv4(@BROADCAST_IP[0], @packetCtx^.IP.Destination[0]);
|
||||||
|
|
||||||
{ Setup UDPContext (UDP) & copy in the correct details }
|
{ Setup UDPContext (UDP) & copy in the correct details }
|
||||||
@ -578,7 +570,7 @@ begin
|
|||||||
|
|
||||||
{ Check the frame is for us and then process }
|
{ Check the frame is for us and then process }
|
||||||
MAC:= getMAC;
|
MAC:= getMAC;
|
||||||
if MACEqual(@context^.PacketContext^.MAC.Destination[0], MAC) or MACEqual(@context^.PacketContext^.MAC.Destination[0], BROADCAST_MAC) then begin
|
if MACEqual(@context^.PacketContext^.MAC.Destination[0], MAC) then begin
|
||||||
Outputln('DHCP','Frame is addressed to us.');
|
Outputln('DHCP','Frame is addressed to us.');
|
||||||
{ Check the message type is client specific }
|
{ Check the message type is client specific }
|
||||||
If Header^.Message_Type = $02 then begin
|
If Header^.Message_Type = $02 then begin
|
||||||
@ -663,7 +655,7 @@ begin
|
|||||||
copyMAC(@BROADCAST_MAC[0], @packetCtx^.MAC.Destination[0]);
|
copyMAC(@BROADCAST_MAC[0], @packetCtx^.MAC.Destination[0]);
|
||||||
MAC:= getMAC;
|
MAC:= getMAC;
|
||||||
copyMAC(MAC, @packetCtx^.MAC.Source[0]);
|
copyMAC(MAC, @packetCtx^.MAC.Source[0]);
|
||||||
CopyIPv4(@getIPv4Config^.Address[0], @packetCtx^.IP.Source[0]);
|
copyIPv4(@NULL_IP[0], @packetCtx^.IP.Source[0]);
|
||||||
copyIPv4(@BROADCAST_IP[0], @packetCtx^.IP.Destination[0]);
|
copyIPv4(@BROADCAST_IP[0], @packetCtx^.IP.Destination[0]);
|
||||||
|
|
||||||
{ Setup UDPContext (UDP) }
|
{ Setup UDPContext (UDP) }
|
||||||
|
@ -1,296 +0,0 @@
|
|||||||
// Copyright 2021 Aaron Hance
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
{
|
|
||||||
Drivers->Storage->AHCI - AHCI SATA Driver.
|
|
||||||
|
|
||||||
@author(Aaron Hance <ah@aaronhance.me>)
|
|
||||||
}
|
|
||||||
unit AHCI;
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
uses
|
|
||||||
util,
|
|
||||||
PCI,
|
|
||||||
drivertypes,
|
|
||||||
drivermanagement,
|
|
||||||
lmemorymanager,
|
|
||||||
console,
|
|
||||||
vmemorymanager;
|
|
||||||
|
|
||||||
type
|
|
||||||
|
|
||||||
//Struct hell
|
|
||||||
|
|
||||||
TFIS_Type = (
|
|
||||||
REG_H2D = $27,
|
|
||||||
REG_D2H = $34,
|
|
||||||
DMA_ACT = $39,
|
|
||||||
DMA_SETUP = $41,
|
|
||||||
DATA = $46,
|
|
||||||
BIST = $58,
|
|
||||||
PIO_SETUP = $5F,
|
|
||||||
DEV_BITS = $A0
|
|
||||||
);
|
|
||||||
|
|
||||||
PFIS_REG_H2D = ^TFIS_REG_H2D;
|
|
||||||
TFIS_REG_H2D = bitpacked record
|
|
||||||
fis_type : uint8;
|
|
||||||
port_mult : UBit4;
|
|
||||||
rsv0 : UBit3;
|
|
||||||
coc : boolean;
|
|
||||||
command : uint8;
|
|
||||||
feature_low : uint8;
|
|
||||||
lba0 : uint8;
|
|
||||||
lba1 : uint8;
|
|
||||||
lba2 : uint8;
|
|
||||||
device : uint8;
|
|
||||||
lba3 : uint8;
|
|
||||||
lba4 : uint8;
|
|
||||||
lba5 : uint8;
|
|
||||||
feature_high : uint8;
|
|
||||||
count_low : uint8;
|
|
||||||
count_high : uint8;
|
|
||||||
icc : uint8;
|
|
||||||
control : uint8;
|
|
||||||
rsvl : uint32;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TFIS_REG_D2H = bitpacked record
|
|
||||||
fis_type : uint8;
|
|
||||||
port_mult : UBit4;
|
|
||||||
rsv0 : UBit2;
|
|
||||||
i : boolean;
|
|
||||||
rsvl : boolean;
|
|
||||||
status : uint8;
|
|
||||||
error : uint8;
|
|
||||||
lba0 : uint8;
|
|
||||||
lba1 : uint8;
|
|
||||||
lba2 : uint8;
|
|
||||||
device : uint8;
|
|
||||||
lba3 : uint8;
|
|
||||||
lba4 : uint8;
|
|
||||||
lba5 : uint8;
|
|
||||||
rsv2 : uint8;
|
|
||||||
count_low : uint8;
|
|
||||||
count_high : uint8;
|
|
||||||
rsv3 : uint16;
|
|
||||||
rsv4 : uint32;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TFIS_Data = bitpacked record
|
|
||||||
fis_type : uint8;
|
|
||||||
port_mult : UBit4;
|
|
||||||
rsv0 : UBit4;
|
|
||||||
rsv1 : uint16;
|
|
||||||
data : ^uint32;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TFIS_PIO_Setup = bitpacked record
|
|
||||||
fis_type : uint8;
|
|
||||||
pmport : UBit4;
|
|
||||||
rsv0 : boolean;
|
|
||||||
d : boolean;
|
|
||||||
i : boolean;
|
|
||||||
rsv1 : boolean;
|
|
||||||
status : uint8;
|
|
||||||
error : uint8;
|
|
||||||
lba0 : uint8;
|
|
||||||
lba1 : uint8;
|
|
||||||
lba2 : uint8;
|
|
||||||
device : uint8;
|
|
||||||
lba3 : uint8;
|
|
||||||
lba4 : uint8;
|
|
||||||
lba5 : uint8;
|
|
||||||
rsv2 : uint8;
|
|
||||||
countl : uint8;
|
|
||||||
counth : uint8;
|
|
||||||
rsv3 : uint8;
|
|
||||||
e_status : uint8;
|
|
||||||
tc : uint16;
|
|
||||||
rsv4 : uint16;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// TFIS_DMA_Setup = bitpacked record
|
|
||||||
// end;
|
|
||||||
|
|
||||||
// THBA_Memory = bitpacked record
|
|
||||||
// end;
|
|
||||||
|
|
||||||
// THBA_Port = bitpacked record
|
|
||||||
// end;
|
|
||||||
|
|
||||||
// THBA_FIS = bitpacked record
|
|
||||||
// end;
|
|
||||||
|
|
||||||
PHBA_PORT = ^THBA_PORT;
|
|
||||||
THBA_PORT = bitpacked record
|
|
||||||
clb : uint32;
|
|
||||||
clbu : uint32;
|
|
||||||
fb : uint32;
|
|
||||||
fbu : uint32;
|
|
||||||
istat : uint32;
|
|
||||||
ie : uint32;
|
|
||||||
cmd : uint32;
|
|
||||||
rsv0 : uint32;
|
|
||||||
tfd : uint32;
|
|
||||||
sig : uint32;
|
|
||||||
ssts : uint32;
|
|
||||||
sctl : uint32;
|
|
||||||
serr : uint32;
|
|
||||||
sact : uint32;
|
|
||||||
ci : uint32;
|
|
||||||
sntf : uint32;
|
|
||||||
fbs : uint32;
|
|
||||||
rsv1 : array[0..11] of uint32;
|
|
||||||
vendor : array[0..4] of uint32;
|
|
||||||
end;
|
|
||||||
|
|
||||||
THBA_MEM = bitpacked record
|
|
||||||
cap : uint32; //0
|
|
||||||
global_host_control : uint32; //4
|
|
||||||
interrupt_status : uint32; //8
|
|
||||||
port_implemented : uint32; //c
|
|
||||||
version : uint32; //10
|
|
||||||
ccc_control : uint32; //14
|
|
||||||
ccc_ports : uint32; //18
|
|
||||||
em_location : uint32; //1c
|
|
||||||
em_Control : uint32; //20
|
|
||||||
hcap2 : uint32; //24
|
|
||||||
bohc : uint32; //28
|
|
||||||
rsv0 : array[0..210] of boolean;
|
|
||||||
ports : array[0..31] of THBA_Port;
|
|
||||||
end;
|
|
||||||
|
|
||||||
PHBA = ^THBA_MEM;
|
|
||||||
|
|
||||||
PCMDHeader = ^ TCommand_Header;
|
|
||||||
TCommand_Header = bitpacked record
|
|
||||||
cfl : ubit5;
|
|
||||||
a : boolean;
|
|
||||||
w : boolean;
|
|
||||||
p : boolean;
|
|
||||||
r : boolean;
|
|
||||||
b : boolean;
|
|
||||||
c : boolean;
|
|
||||||
rsv0 : boolean;
|
|
||||||
pmp : ubit4;
|
|
||||||
PRDTL : uint16;
|
|
||||||
PRDTBC : uint32;
|
|
||||||
CTBA : uint32;
|
|
||||||
CTBAU : uint32;
|
|
||||||
rsv1 : array[0..3] of uint32;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TPRD_Entry = bitpacked record
|
|
||||||
data_base_address : uint32;
|
|
||||||
data_bade_address_U : uint32;
|
|
||||||
rsv0 : uint32;
|
|
||||||
data_byte_count : ubit22;
|
|
||||||
rsv1 : ubit9;
|
|
||||||
interrupt_oc : boolean;
|
|
||||||
end;
|
|
||||||
|
|
||||||
PCommand_Table = ^TCommand_Table;
|
|
||||||
TCommand_Table = bitpacked record
|
|
||||||
cfis : array[0..64] of uint8;
|
|
||||||
acmd : array[0..16] of uint8;
|
|
||||||
rsv : array[0..48] of uint8;
|
|
||||||
prdt : array[0..7] of TPRD_Entry;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TSataDevice = record
|
|
||||||
controller : uint8;
|
|
||||||
port : uint8;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
|
||||||
//constants
|
|
||||||
//SATA_SIG_ATA := $101;
|
|
||||||
//SATA_SIG_ATAPI := $EB140101;
|
|
||||||
//STA_SIG_SEMB := $C33C0101;
|
|
||||||
//STAT_SIG_PM := $96690101;
|
|
||||||
AHCI_BASE: uint32 = $400000; //irrelivent
|
|
||||||
|
|
||||||
//other
|
|
||||||
ahciControllers : array[0.16] of PuInt32;
|
|
||||||
ahciControllerCount : uint8 = 0;
|
|
||||||
hba : array[0..16] of PHBA;
|
|
||||||
|
|
||||||
sataDevices : array[0..127] of TSataDevice;
|
|
||||||
sataDeviceCount : uint8;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
procedure init();
|
|
||||||
procedure check_ports(controller : uint8);
|
|
||||||
procedure enable_cmd(port : uint8);
|
|
||||||
procedure disable_cmd(port : uint8);
|
|
||||||
procedure port_rebase(port : uint8);
|
|
||||||
function load(ptr:void): boolean;
|
|
||||||
function read(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean;
|
|
||||||
function write(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean;
|
|
||||||
function find_cmd_slot(port : uint8) : uint32;
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
procedure init();
|
|
||||||
var
|
|
||||||
devID : TDeviceIdentifier;
|
|
||||||
begin
|
|
||||||
console.writestringln('AHCI: Registering driver');
|
|
||||||
devID.bus:= biPCI;
|
|
||||||
devID.id0:= idANY;
|
|
||||||
devID.id1:= $00000001;
|
|
||||||
devID.id2:= $00000006;
|
|
||||||
devID.id3:= $00000001;
|
|
||||||
devID.id4:= idANY;
|
|
||||||
devID.ex:= nil;
|
|
||||||
drivermanagement.register_driver('AHCI Driver', @devID, @load);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure load(ptr : void);
|
|
||||||
begin
|
|
||||||
console.writestringln('AHCI: initilizing a new controller');
|
|
||||||
ahciControllers[ahciControllerCount] := ptr;
|
|
||||||
hba[ahciControllerCount] := PPCI_Device(ptr)^.address5;
|
|
||||||
new_page_at_address(hba[ahciControllerCount]);
|
|
||||||
|
|
||||||
//here would be any controller setup needed
|
|
||||||
|
|
||||||
check_ports(ahciControllerCount);
|
|
||||||
ahciControllerCount += 1;
|
|
||||||
exit(true);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure check_ports(controller : uint8);
|
|
||||||
var
|
|
||||||
d : uint32 = 1;
|
|
||||||
i : uint32;
|
|
||||||
begin
|
|
||||||
for i:=0 to 31 do begin
|
|
||||||
if (d > 0) and (hba[controller]^.port_implemented shr i) = 1 then begin
|
|
||||||
if (hba[controller]^.ports[i].ssts shr 8) <> 1 and (hba[controller]^.ports[i].ssts and $0F) <> 3 then begin
|
|
||||||
if hba[controller]^.ports[i].sig = 1 then begin
|
|
||||||
//device is sata
|
|
||||||
sataDevices[sataDeviceCount].controller := controller;
|
|
||||||
sataDevices[sataDeviceCount].port := i;
|
|
||||||
sataDeviceCount += 1;
|
|
||||||
end;
|
|
||||||
//TODO implement ATAPI
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
899
src/driver/storage/AHCI/AHCI.pas
Normal file
899
src/driver/storage/AHCI/AHCI.pas
Normal file
@ -0,0 +1,899 @@
|
|||||||
|
|
||||||
|
// Copyright 2021 Aaron Hance
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
{
|
||||||
|
Drivers->Storage->AHCI->AHCI - AHCI Driver.
|
||||||
|
|
||||||
|
@author(Aaron Hance <ah@aaronhance.me>)
|
||||||
|
}
|
||||||
|
unit AHCI;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
AHCITypes,
|
||||||
|
console,
|
||||||
|
drivermanagement,
|
||||||
|
drivertypes,
|
||||||
|
idetypes,
|
||||||
|
isrmanager,
|
||||||
|
lists,
|
||||||
|
lmemorymanager,
|
||||||
|
PCI,
|
||||||
|
util,
|
||||||
|
vmemorymanager;
|
||||||
|
|
||||||
|
var
|
||||||
|
ahciControllers : PDList;
|
||||||
|
page_base : puint32;
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
function load(ptr : void) : boolean;
|
||||||
|
procedure check_ports(controller : PAHCI_Controller);
|
||||||
|
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean);
|
||||||
|
procedure ahci_isr();
|
||||||
|
function find_cmd_slot(device : PAHCI_Device) : uint32;
|
||||||
|
function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
// function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
var
|
||||||
|
devID : TDeviceIdentifier;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Registering driver');
|
||||||
|
devID.bus:= biPCI;
|
||||||
|
devID.id0:= idANY;
|
||||||
|
devID.id1:= $00000001;
|
||||||
|
devID.id2:= $00000006;
|
||||||
|
devID.id3:= $00000001;
|
||||||
|
devID.id4:= idANY;
|
||||||
|
devID.ex:= nil;
|
||||||
|
drivermanagement.register_driver('ATA/PI AHCI Driver', @devID, @load);
|
||||||
|
//TODO check IDE devices in ide for sata devices
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure stop_port(port : PHBA_Port);
|
||||||
|
begin
|
||||||
|
port^.cmd := port^.cmd and not $1;
|
||||||
|
port^.cmd := port^.cmd and not $100;
|
||||||
|
while ((port^.cmd and $4000) or (port^.cmd and $8000)) <> 0 do begin
|
||||||
|
//wait for the port to stop
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure start_port(port : PHBA_Port);
|
||||||
|
begin
|
||||||
|
|
||||||
|
while (port^.cmd and $8000) <> 0 do begin
|
||||||
|
//wait for port to not be busy
|
||||||
|
end;
|
||||||
|
port^.cmd := port^.cmd or $100;
|
||||||
|
port^.cmd := port^.cmd or $1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure reset_port(port : PHBA_Port);
|
||||||
|
var
|
||||||
|
ssts, serr, timeout : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Performing a full port reset.');
|
||||||
|
|
||||||
|
port^.cmd := port^.cmd and not $1;
|
||||||
|
|
||||||
|
// Wait until CR (bit 15) is cleared.
|
||||||
|
timeout := 0;
|
||||||
|
while (port^.cmd and $8000) <> 0 do begin
|
||||||
|
timeout := timeout + 1;
|
||||||
|
if timeout > 1000000 then begin
|
||||||
|
console.writestringln('AHCI: Port reset timeout.');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
port^.sata_ctrl := port^.sata_ctrl or $FFFF0000;
|
||||||
|
|
||||||
|
while (port^.sata_status and $F) <> 3 do begin
|
||||||
|
//wait for the port to be ready
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Clear the SERR register by writing 1s to it.
|
||||||
|
port^.sata_error := $FFFFFFFF;
|
||||||
|
|
||||||
|
start_port(port);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// procedure reset_port(port : PHBA_Port);
|
||||||
|
// var
|
||||||
|
// ssts, serr, timeout : uint32;
|
||||||
|
// begin
|
||||||
|
// console.writestringln('AHCI: Performing a full port reset.');
|
||||||
|
|
||||||
|
// port^.cmd := port^.cmd and not $1;
|
||||||
|
|
||||||
|
// // Wait until CR (bit 15) is cleared.
|
||||||
|
// timeout := 0;
|
||||||
|
// while (port^.cmd and $8000) <> 0 do begin
|
||||||
|
// timeout := timeout + 1;
|
||||||
|
// if timeout > 1000000 then begin
|
||||||
|
// console.writestringln('AHCI: Port reset timeout.');
|
||||||
|
// break;
|
||||||
|
// end;
|
||||||
|
// end;
|
||||||
|
|
||||||
|
// port^.sata_ctrl := port^.sata_ctrl and $FFFF0000;
|
||||||
|
// port^.sata_ctrl := port^.sata_ctrl or $1;
|
||||||
|
// psleep(10);
|
||||||
|
// port^.sata_ctrl := port^.sata_ctrl and $FFFF0000;
|
||||||
|
|
||||||
|
// while (port^.sata_status and $F) <> $3 do begin
|
||||||
|
// //wait for the port to be ready
|
||||||
|
// end;
|
||||||
|
|
||||||
|
// // Clear the SERR register by writing 1s to it.
|
||||||
|
// port^.sata_error := $FFFFFFFF;
|
||||||
|
|
||||||
|
// // start_port(port);
|
||||||
|
// end;
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
Check the ports on the controller and setup the command list, FIS, and command table
|
||||||
|
}
|
||||||
|
procedure check_ports(controller : PAHCI_Controller);
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
ii : uint32;
|
||||||
|
port : PHBA_Port;
|
||||||
|
device : PAHCI_Device;
|
||||||
|
cmd_list_base : puint32;
|
||||||
|
fis_base : puint32;
|
||||||
|
cmd_table_base : puint32;
|
||||||
|
command_header : PHBA_CMD_HEADER;
|
||||||
|
begin
|
||||||
|
|
||||||
|
console.writestring('AHCI: active ports: ');
|
||||||
|
console.writehexln(controller^.mio^.ports_implimented);
|
||||||
|
|
||||||
|
for i:=0 to 31 do begin
|
||||||
|
port := @controller^.mio^.ports[i];
|
||||||
|
console.writehex(port^.signature);
|
||||||
|
console.writestring(' ');
|
||||||
|
end;
|
||||||
|
|
||||||
|
for i:=0 to 31 do begin
|
||||||
|
if ((controller^.mio^.ports_implimented shr i) and 1) = 1 then begin
|
||||||
|
port := @controller^.mio^.ports[i];
|
||||||
|
console.writestring('AHCI: Port ');
|
||||||
|
console.writeint(i);
|
||||||
|
console.writestring(' implemented on controller ');
|
||||||
|
console.writehexln(uint32(controller^.pci_device^.address5));
|
||||||
|
|
||||||
|
device := PAHCI_Device(@controller^.devices[i]);
|
||||||
|
device^.port := port;
|
||||||
|
|
||||||
|
//check if the port is active TODO
|
||||||
|
|
||||||
|
console.writestring('AHCI: signature: ');
|
||||||
|
console.writehexln(port^.signature);
|
||||||
|
|
||||||
|
//check device type
|
||||||
|
case port^.signature of
|
||||||
|
SATA_SIG_ATA: begin
|
||||||
|
console.writestringln('AHCI: Device is SATA');
|
||||||
|
device^.device_type := SATA;
|
||||||
|
end;
|
||||||
|
SATA_SIG_ATAPI: begin
|
||||||
|
console.writestringln('AHCI: Device is ATAPI');
|
||||||
|
device^.device_type := ATAPI;
|
||||||
|
end;
|
||||||
|
SATA_SIG_SEMB: begin
|
||||||
|
console.writestringln('AHCI: Device is SEMB');
|
||||||
|
device^.device_type := SEMB;
|
||||||
|
end;
|
||||||
|
SATA_SIG_PM: begin
|
||||||
|
console.writestringln('AHCI: Device is PM');
|
||||||
|
device^.device_type := PM;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//NEEED TO STOP the port before doing anything
|
||||||
|
stop_port(port);
|
||||||
|
console.writestringln('AHCI: Port stopped');
|
||||||
|
|
||||||
|
//allocate memory for the command list and ensure it is aligned to 1024 bytes
|
||||||
|
cmd_list_base := kalloc(sizeof(THBA_CMD_HEADER) * 64);
|
||||||
|
cmd_list_base := puint32((uint32(cmd_list_base) + 1023) and $FFFFFC00);
|
||||||
|
memset(uint32(cmd_list_base), 0, sizeof(THBA_CMD_HEADER) * 32);
|
||||||
|
|
||||||
|
//set the command list base address
|
||||||
|
port^.cmdl_basel := vtop(uint32(cmd_list_base)); //todo set virtual address in device
|
||||||
|
port^.cmdl_baseu := 0;
|
||||||
|
|
||||||
|
device^.command_list := PHBA_CMD_HEADER(cmd_list_base);
|
||||||
|
|
||||||
|
|
||||||
|
//print the command list base address
|
||||||
|
console.writestring('AHCI: Command list base address: ');
|
||||||
|
console.writehexln(uint32(cmd_list_base));
|
||||||
|
|
||||||
|
//allocate memory for the FIS and ensure it is aligned to 256 bytes
|
||||||
|
fis_base := kalloc(sizeof(THBA_FIS) * 8);
|
||||||
|
fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00);
|
||||||
|
|
||||||
|
//set the FIS base address
|
||||||
|
port^.fis_basel := vtop(uint32(fis_base));
|
||||||
|
port^.fis_baseu := 0;
|
||||||
|
|
||||||
|
memset(uint32(fis_base), 0, sizeof(THBA_FIS));
|
||||||
|
|
||||||
|
device^.fis := PHBA_FIS(fis_base);
|
||||||
|
//todo check how many simultaneous commands are supported
|
||||||
|
|
||||||
|
//allocate memory for the command table and ensure it is aligned to 128 bytes
|
||||||
|
cmd_table_base := kalloc(sizeof(THBA_CMD_TABLE) * 64);
|
||||||
|
cmd_table_base := puint32((uint32(cmd_table_base) + 127) and $FFFFFF80);
|
||||||
|
memset(uint32(cmd_table_base), 0, sizeof(THBA_CMD_TABLE) * 32);
|
||||||
|
|
||||||
|
device^.command_table := PHBA_CMD_TABLE(cmd_table_base);
|
||||||
|
|
||||||
|
//set the command table base address and setup command table
|
||||||
|
for ii:=0 to 31 do begin
|
||||||
|
//set command header locations
|
||||||
|
command_header := PHBA_CMD_HEADER(uint32(cmd_list_base) + (ii * sizeof(THBA_CMD_HEADER)));
|
||||||
|
command_header^.prdtl := 32;
|
||||||
|
command_header^.cmd_table_base := vtop(uint32(cmd_table_base)) + (ii * sizeof(THBA_CMD_TABLE));
|
||||||
|
command_header^.cmd_table_baseu := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//reset the port
|
||||||
|
reset_port(port);
|
||||||
|
|
||||||
|
//print sata status
|
||||||
|
console.writestring('AHCI: sata status: ');
|
||||||
|
console.writehexln(port^.sata_status);
|
||||||
|
|
||||||
|
// //pass devices count as second param
|
||||||
|
if (device^.device_type = SATA) then begin
|
||||||
|
identify_device(controller, i, false);
|
||||||
|
end else if (device^.device_type = ATAPI) then begin
|
||||||
|
identify_device(controller, i, true);
|
||||||
|
end else begin
|
||||||
|
console.writestringln('AHCI: Unsupported device type');
|
||||||
|
end;
|
||||||
|
|
||||||
|
controller^.mio^.int_status := $FFFFFFFF;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean);
|
||||||
|
var
|
||||||
|
fis : PHBA_FIS_REG_H2D;
|
||||||
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
|
cmd_table : PHBA_CMD_TABLE;
|
||||||
|
cmd : uint32;
|
||||||
|
i, timeout : uint32;
|
||||||
|
buffer : puint32;
|
||||||
|
device : PAHCI_Device;
|
||||||
|
tfd : uint32;
|
||||||
|
sec_count : uint32;
|
||||||
|
b8 : puint16;
|
||||||
|
begin
|
||||||
|
console.writestring('AHCI: Identifying device ');
|
||||||
|
console.writeintln(portIndex);
|
||||||
|
device := PAHCI_Device(@controller^.devices[portIndex]);
|
||||||
|
|
||||||
|
// (Optional) Print the device type if you store it:
|
||||||
|
console.writestring('AHCI: Device type: ');
|
||||||
|
// For example: if device^.device_type = SATA then ...
|
||||||
|
console.writestring('AHCI: sata status: ');
|
||||||
|
console.writehexln(device^.port^.sata_status);
|
||||||
|
console.writestring('AHCI: signature: ');
|
||||||
|
console.writehexln(device^.port^.signature);
|
||||||
|
console.writestring('AHCI: device type: ');
|
||||||
|
console.writeintln(uint32(device^.device_type));
|
||||||
|
|
||||||
|
//clear any pending interrupts
|
||||||
|
device^.port^.int_status := $FFFFFFFF;
|
||||||
|
device^.port^.int_enable := $0;
|
||||||
|
|
||||||
|
// Allocate a 512-byte DMA buffer for the IDENTIFY data
|
||||||
|
buffer := kalloc(512);
|
||||||
|
memset(uint32(buffer), 0, 512);
|
||||||
|
|
||||||
|
// Use command slot 0 for the IDENTIFY command.
|
||||||
|
cmd_header := device^.command_list; // Assuming slot 0 is at the beginning.
|
||||||
|
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||||
|
cmd_header^.wrt := 0;
|
||||||
|
cmd_header^.prdtl := 1;
|
||||||
|
cmd_header^.clear_busy := 1;
|
||||||
|
if isATAPI then begin
|
||||||
|
cmd_header^.atapi := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
// Setup the command table (using slot 0)
|
||||||
|
cmd_table := device^.command_table;
|
||||||
|
cmd_table^.prdt[0].dba := vtop(uint32(buffer));
|
||||||
|
cmd_table^.prdt[0].dbc := 511; // 512 bytes (0-based count)
|
||||||
|
cmd_table^.prdt[0].int := 1; // Interrupt on completion
|
||||||
|
|
||||||
|
// if isATAPI then begin
|
||||||
|
// // ATAPI Identify Device command
|
||||||
|
// buffer[0] := $A1; // ATAPI Identify Device
|
||||||
|
// end;
|
||||||
|
|
||||||
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
|
fis := PHBA_FIS_REG_H2D(@device^.command_table^.cmd_fis);
|
||||||
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
|
fis^.c := $1;
|
||||||
|
if isATAPI then begin
|
||||||
|
fis^.command := ATA_CMD_IDENTIFY_PACKET;
|
||||||
|
end else begin
|
||||||
|
fis^.command := ATA_CMD_IDENTIFY;
|
||||||
|
end;
|
||||||
|
fis^.device := $A0; // LBA mode 40?
|
||||||
|
|
||||||
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
|
// console.writestring('AHCI: tfd: ');
|
||||||
|
// console.writehexln(device^.port^.tfd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
|
cmd := device^.port^.cmd_issue;
|
||||||
|
cmd := cmd or $1;
|
||||||
|
device^.port^.cmd_issue := cmd;
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Sent identify command');
|
||||||
|
|
||||||
|
|
||||||
|
// Wait for command completion with a timeout.
|
||||||
|
timeout := 0;
|
||||||
|
repeat
|
||||||
|
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||||
|
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||||
|
device^.port^.int_status := $FFFFFFFF; // Clear any pending interrupts
|
||||||
|
timeout := timeout + 10;
|
||||||
|
if timeout > 100000 then begin
|
||||||
|
console.writestringln('AHCI: IDENTIFY command timeout');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
// check for bit 30 in the tfd register
|
||||||
|
if (tfd and $40000000) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: error');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
until ((device^.port^.cmd_issue and $1) = 0); // Wait until slot 0 is cleared
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Command complete');
|
||||||
|
|
||||||
|
// Check for an error flag in the command register (bit 1)
|
||||||
|
if (cmd and $2) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Error sending identify command');
|
||||||
|
|
||||||
|
// Check the error register for more information
|
||||||
|
console.writestring('AHCI: Error register: ');
|
||||||
|
console.writehexln(device^.port^.sata_error);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Dump the 512-byte IDENTIFY data for debugging (display 64 DWORDs)
|
||||||
|
for i := 0 to 63 do begin
|
||||||
|
console.writehex(uint32(buffer[i]));
|
||||||
|
console.writestring(' ');
|
||||||
|
end;
|
||||||
|
|
||||||
|
console.writestringln('');
|
||||||
|
|
||||||
|
b8 := puint16(buffer);
|
||||||
|
sec_count := (b8[61] shl 16) or b8[60];
|
||||||
|
console.writestring('AHCI: Sector count: ');
|
||||||
|
console.writeintln(sec_count);
|
||||||
|
console.writestring('AHCI: Device size: ');
|
||||||
|
console.writeint(sec_count * 512 div 1024 div 1024);
|
||||||
|
console.writestringln(' MB');
|
||||||
|
|
||||||
|
|
||||||
|
console.writestringln('');
|
||||||
|
|
||||||
|
buffer := puint32(kalloc(2048));
|
||||||
|
memset(uint32(buffer), 0, 2048);
|
||||||
|
|
||||||
|
//send a read DMA command to the device
|
||||||
|
if isATAPI then begin
|
||||||
|
read_atapi(device, 0, 2048, buffer);
|
||||||
|
end else begin
|
||||||
|
memset(uint32(buffer), $77, 2048);
|
||||||
|
send_write_dma(device, 22, 512, buffer);
|
||||||
|
memset(uint32(buffer), 0, 2048);
|
||||||
|
|
||||||
|
send_read_dma(device, 22, 512, buffer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
//print the buffer
|
||||||
|
for i:=0 to 63 do begin
|
||||||
|
console.writehex(puInt8(buffer)[i]);
|
||||||
|
console.writestring(' ');
|
||||||
|
end;
|
||||||
|
console.writestringln('');
|
||||||
|
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function load(ptr : void) : boolean;
|
||||||
|
var
|
||||||
|
device : PPCI_Device;
|
||||||
|
controller : PAHCI_Controller;
|
||||||
|
i : uint32;
|
||||||
|
base : PHBA_Memory;
|
||||||
|
cmd_list_base : puint32;
|
||||||
|
fis_base : puint32;
|
||||||
|
cmd_table_base : puint32;
|
||||||
|
int_no : uInt8;
|
||||||
|
timeout : uint32;
|
||||||
|
bohc : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: initilizing a new controller');
|
||||||
|
|
||||||
|
if ahciControllers = nil then begin
|
||||||
|
console.writestringln('AHCI: Initializing controller list');
|
||||||
|
ahciControllers := DL_New(SizeOf(TAHCI_Controller));
|
||||||
|
end;
|
||||||
|
|
||||||
|
device := PPCI_Device(ptr);
|
||||||
|
|
||||||
|
pci.enableDevice(device^.bus, device^.slot, device^.func);
|
||||||
|
psleep(5);
|
||||||
|
int_no := device^.interrupt_line + 32;
|
||||||
|
|
||||||
|
|
||||||
|
//print interrupt number
|
||||||
|
console.writestring('AHCI: Interrupt number: ');
|
||||||
|
console.writehexln(int_no);
|
||||||
|
|
||||||
|
controller := PAHCI_Controller(DL_Add(ahciControllers));
|
||||||
|
|
||||||
|
controller^.pci_device := PPCI_Device(device);
|
||||||
|
|
||||||
|
// Perform BIOS/OS handoff (if the bit in the extended capabilities is set)
|
||||||
|
// Reset controller
|
||||||
|
|
||||||
|
//get the base address of the controller
|
||||||
|
page_base := kpalloc(device^.address5); // TODO MEM memory manager need to be improved
|
||||||
|
base := PHBA_Memory(device^.address5);
|
||||||
|
controller^.mio := base;
|
||||||
|
|
||||||
|
if (controller^.mio^.capabilites2 and $28) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Controller needs to be handed off to the OS');
|
||||||
|
end;
|
||||||
|
|
||||||
|
console.writestring('AHCI: Controller at: ');
|
||||||
|
console.writehexln(device^.address5);
|
||||||
|
console.writehexln(uint32(page_base));
|
||||||
|
|
||||||
|
bohc := controller^.mio^.bohc;
|
||||||
|
|
||||||
|
if (bohc and $1) <> 0 or (bohc and not (1 shl 1)) then begin
|
||||||
|
console.writestringln('AHCI: BIOS Owned Semaphore is set, initiating handoff.');
|
||||||
|
|
||||||
|
// Set the OS Owned Semaphore (typically bit 1).
|
||||||
|
bohc := bohc or (1 shl 1);
|
||||||
|
controller^.mio^.bohc := bohc;
|
||||||
|
|
||||||
|
// Wait until the BIOS Owned Semaphore (bit 0) is cleared.
|
||||||
|
timeout := 0;
|
||||||
|
while ((controller^.mio^.bohc and $1) <> 0) and (timeout < 1000000) do begin
|
||||||
|
timeout := timeout + 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if timeout = 1000000 then begin
|
||||||
|
console.writestringln('AHCI: BIOS/OS handoff timed out.');
|
||||||
|
end else begin
|
||||||
|
console.writestringln('AHCI: BIOS/OS handoff successful.');
|
||||||
|
end;
|
||||||
|
end else begin
|
||||||
|
console.writestringln('AHCI: BIOS not holding controller or handoff already complete.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
base^.global_ctrl := base^.global_ctrl or 1;
|
||||||
|
|
||||||
|
while (base^.global_ctrl and 1) <> 0 do begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
registerISR(int_no, @ahci_isr);
|
||||||
|
|
||||||
|
//enable AHCI mode, TODO check if is not already in AHCI mode and enable it, also perhaps remove if loaded as IDE
|
||||||
|
base^.global_ctrl := base^.global_ctrl or AHCI_CONTROLLER_MODE;
|
||||||
|
// base^.global_ctrl := base^.global_ctrl or $2; //enable interrupts
|
||||||
|
|
||||||
|
//disable interrupts
|
||||||
|
base^.global_ctrl := base^.global_ctrl or $2;
|
||||||
|
|
||||||
|
//clear any pending interrupts
|
||||||
|
base^.int_status := $FFFFFFFF;
|
||||||
|
|
||||||
|
check_ports(controller);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ahci_isr();
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: ISR');
|
||||||
|
console.redrawWindows();
|
||||||
|
//welp there is no way to know what port caused the interrupt or even if it was the controller
|
||||||
|
//so we will just have to check all ports, and figure the operation that caused the interrupt
|
||||||
|
end;
|
||||||
|
|
||||||
|
function find_cmd_slot(device : PAHCI_Device) : uint32;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
begin
|
||||||
|
// for i:=0 to 31 do begin
|
||||||
|
// if (device^.port^.cmd_issue[i] and $80000000) = 0 then begin
|
||||||
|
// exit(i);
|
||||||
|
// end;
|
||||||
|
// end;
|
||||||
|
exit(0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
var
|
||||||
|
fis : PHBA_FIS_REG_H2D;
|
||||||
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
|
cmd_table : PHBA_CMD_TABLE;
|
||||||
|
cmd : uint32;
|
||||||
|
i, timeout : uint32;
|
||||||
|
tfd : uint32;
|
||||||
|
sec_count : uint32;
|
||||||
|
prdt_count : uint32;
|
||||||
|
b8 : puint16;
|
||||||
|
slot : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Sending read DMA command');
|
||||||
|
|
||||||
|
reset_port(device^.port);
|
||||||
|
|
||||||
|
//prdt count is 22 bits
|
||||||
|
prdt_count := (count div 4194304) + 1;
|
||||||
|
|
||||||
|
if prdt_count > 32 then begin
|
||||||
|
send_read_dma := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use command slot 0 for the IDENTIFY command.
|
||||||
|
slot := find_cmd_slot(device);
|
||||||
|
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
|
||||||
|
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||||
|
cmd_header^.wrt := 0;
|
||||||
|
cmd_header^.prdtl := prdt_count;
|
||||||
|
cmd_header^.clear_busy := 1;
|
||||||
|
|
||||||
|
// Setup the command table (using slot 0)
|
||||||
|
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
|
||||||
|
|
||||||
|
for i:=0 to prdt_count - 1 do begin
|
||||||
|
cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304));
|
||||||
|
|
||||||
|
if i = prdt_count - 1 then begin
|
||||||
|
cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count)
|
||||||
|
end else begin
|
||||||
|
cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count)
|
||||||
|
end;
|
||||||
|
|
||||||
|
cmd_table^.prdt[i].int := 1; // Interrupt on completion
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
|
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
|
||||||
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
|
fis^.c := $1;
|
||||||
|
fis^.command := ATA_CMD_READ_DMA_EXT;
|
||||||
|
fis^.device := $40; // LBA mode 48?
|
||||||
|
|
||||||
|
fis^.lba0 := lba and $FF;
|
||||||
|
fis^.lba1 := (lba shr 8) and $FF;
|
||||||
|
fis^.lba2 := (lba shr 16) and $FF;
|
||||||
|
fis^.lba3 := (lba shr 24) and $FF;
|
||||||
|
fis^.lba4 := (lba shr 32) and $FF;
|
||||||
|
|
||||||
|
fis^.countl := count and $FF;
|
||||||
|
fis^.counth := (count shr 8) and $FF;
|
||||||
|
|
||||||
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
|
// console.writestring('AHCI: tfd: ');
|
||||||
|
// console.writehexln(device^.port^.tfd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
|
cmd := device^.port^.cmd_issue;
|
||||||
|
cmd := cmd or (1 shl slot);
|
||||||
|
device^.port^.cmd_issue := cmd;
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Sent read DMA command');
|
||||||
|
|
||||||
|
// Wait for command completion with a timeout.
|
||||||
|
timeout := 0;
|
||||||
|
repeat
|
||||||
|
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||||
|
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||||
|
timeout := timeout + 10;
|
||||||
|
if timeout > 100000 then begin
|
||||||
|
console.writestringln('AHCI: Read DMA command timeout');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
// check for bit 30 in the tfd register
|
||||||
|
if (tfd and $40000000) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: error');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Command complete');
|
||||||
|
|
||||||
|
// Check for an error flag in the command register (bit 1)
|
||||||
|
if (cmd and (1 shl slot)) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Error sending read DMA command');
|
||||||
|
|
||||||
|
// Check the error register for more information
|
||||||
|
console.writestring('AHCI: Error register: ');
|
||||||
|
console.writehexln(device^.port^.sata_error);
|
||||||
|
end;
|
||||||
|
|
||||||
|
send_read_dma := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
var
|
||||||
|
fis : PHBA_FIS_REG_H2D;
|
||||||
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
|
cmd_table : PHBA_CMD_TABLE;
|
||||||
|
cmd : uint32;
|
||||||
|
i, timeout : uint32;
|
||||||
|
tfd : uint32;
|
||||||
|
sec_count : uint32;
|
||||||
|
prdt_count : uint32;
|
||||||
|
b8 : puint16;
|
||||||
|
slot : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Sending write DMA command');
|
||||||
|
|
||||||
|
reset_port(device^.port);
|
||||||
|
|
||||||
|
//prdt count is 22 bits
|
||||||
|
prdt_count := (count div 4194304) + 1;
|
||||||
|
|
||||||
|
if prdt_count > 32 then begin
|
||||||
|
send_write_dma := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use command slot 0 for the IDENTIFY command.
|
||||||
|
slot := find_cmd_slot(device);
|
||||||
|
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
|
||||||
|
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||||
|
cmd_header^.wrt := 1;
|
||||||
|
cmd_header^.prdtl := prdt_count;
|
||||||
|
cmd_header^.clear_busy := 1;
|
||||||
|
|
||||||
|
// Setup the command table (using slot 0)
|
||||||
|
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
|
||||||
|
|
||||||
|
for i:=0 to prdt_count - 1 do begin
|
||||||
|
cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304));
|
||||||
|
|
||||||
|
if i = prdt_count - 1 then begin
|
||||||
|
cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count)
|
||||||
|
end else begin
|
||||||
|
cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count)
|
||||||
|
end;
|
||||||
|
|
||||||
|
cmd_table^.prdt[i].int := 1; // Interrupt on completion
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
|
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
|
||||||
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
|
fis^.c := $1;
|
||||||
|
fis^.command := ATA_CMD_WRITE_DMA_EXT;
|
||||||
|
fis^.device := $40; // LBA mode 48?
|
||||||
|
|
||||||
|
count:= count div 512;
|
||||||
|
|
||||||
|
fis^.lba0 := lba and $FF;
|
||||||
|
fis^.lba1 := (
|
||||||
|
lba shr 8) and $FF;
|
||||||
|
fis^.lba2 := (
|
||||||
|
lba shr 16) and $FF;
|
||||||
|
fis^.lba3 := (
|
||||||
|
lba shr 24) and $FF;
|
||||||
|
fis^.lba4 := (
|
||||||
|
lba shr 32) and $FF;
|
||||||
|
|
||||||
|
fis^.countl := count and $FF;
|
||||||
|
fis^.counth := (
|
||||||
|
count shr 8) and $FF;
|
||||||
|
|
||||||
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
|
// console.writestring('AHCI: tfd: ');
|
||||||
|
// console.writehexln(device^.port^.tfd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
|
cmd := device^.port^.cmd_issue;
|
||||||
|
cmd := cmd or (1 shl slot);
|
||||||
|
device^.port^.cmd_issue := cmd;
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Sent write DMA command');
|
||||||
|
|
||||||
|
// Wait for command completion with a timeout.
|
||||||
|
timeout := 0;
|
||||||
|
repeat
|
||||||
|
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||||
|
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||||
|
timeout := timeout + 10;
|
||||||
|
if timeout > 100000 then begin
|
||||||
|
console.writestringln('AHCI: Write DMA command timeout');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
// check for bit 30 in the tfd register
|
||||||
|
if (tfd and $40000000) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: error');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Command complete');
|
||||||
|
|
||||||
|
// Check for an error flag in the command register (bit 1)
|
||||||
|
if (cmd and (1 shl slot)) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Error sending write DMA command');
|
||||||
|
|
||||||
|
// Check the error register for more information
|
||||||
|
console.writestring('AHCI: Error register: ');
|
||||||
|
console.writehexln(device^.port^.sata_error);
|
||||||
|
end;
|
||||||
|
|
||||||
|
send_write_dma := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//read atapi
|
||||||
|
function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean;
|
||||||
|
var
|
||||||
|
fis : PHBA_FIS_REG_H2D;
|
||||||
|
cmd_header : PHBA_CMD_HEADER;
|
||||||
|
cmd_table : PHBA_CMD_TABLE;
|
||||||
|
cmd : uint32;
|
||||||
|
i, timeout : uint32;
|
||||||
|
tfd : uint32;
|
||||||
|
sec_count : uint32;
|
||||||
|
prdt_count : uint32;
|
||||||
|
b8 : puint16;
|
||||||
|
slot : uint32;
|
||||||
|
begin
|
||||||
|
console.writestringln('AHCI: Sending read ATAPI command');
|
||||||
|
|
||||||
|
reset_port(device^.port);
|
||||||
|
|
||||||
|
//prdt count is 22 bits
|
||||||
|
prdt_count := (count div 4194304) + 1;
|
||||||
|
|
||||||
|
if prdt_count > 32 then begin
|
||||||
|
read_atapi := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use command slot 0 for the IDENTIFY command.
|
||||||
|
slot := find_cmd_slot(device);
|
||||||
|
cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER)));
|
||||||
|
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||||
|
cmd_header^.wrt := 0;
|
||||||
|
cmd_header^.prdtl := 1;
|
||||||
|
cmd_header^.atapi := 1;
|
||||||
|
cmd_header^.clear_busy := 1;
|
||||||
|
|
||||||
|
// Setup the command table (using slot 0)
|
||||||
|
cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE)));
|
||||||
|
|
||||||
|
cmd_table^.prdt[0].dba := vtop(uint32(buffer));
|
||||||
|
cmd_table^.prdt[0].dbc := 2048 - 1; // 512 bytes (0-based count
|
||||||
|
cmd_table^.prdt[0].int := 1; // Interrupt on completion
|
||||||
|
|
||||||
|
// Construct the Command FIS in the command table's CFIS area
|
||||||
|
fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis);
|
||||||
|
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||||
|
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||||
|
fis^.c := $1;
|
||||||
|
fis^.command := ATA_CMD_PACKET;
|
||||||
|
fis^.device := $A0;
|
||||||
|
|
||||||
|
fis^.featurel := fis^.featurel or 1; //setting both of these might not work on real hardware
|
||||||
|
fis^.featurel := fis^.featurel or (1 shl 2);
|
||||||
|
|
||||||
|
cmd_table^.acmd[0] := $A8; //ATAPI command
|
||||||
|
cmd_table^.acmd[1] := $0; //ATAPI command
|
||||||
|
|
||||||
|
cmd_table^.acmd[2] := uInt8((lba shr 24) and $FF);
|
||||||
|
cmd_table^.acmd[3] := uInt8((lba shr 16) and $FF);
|
||||||
|
cmd_table^.acmd[4] := uInt8((lba shr 8) and $FF);
|
||||||
|
cmd_table^.acmd[5] := uInt8(lba and $FF);
|
||||||
|
|
||||||
|
cmd_table^.acmd[9] := uInt8((1) and $FF);
|
||||||
|
|
||||||
|
|
||||||
|
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||||
|
while (device^.port^.tfd and $88) <> 0 do begin
|
||||||
|
// console.writestring('AHCI: tfd: ');
|
||||||
|
// console.writehexln(device^.port^.tfd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||||
|
cmd := device^.port^.cmd_issue;
|
||||||
|
cmd := cmd or (1 shl slot);
|
||||||
|
device^.port^.cmd_issue := cmd;
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Sent read ATAPI command');
|
||||||
|
|
||||||
|
// Wait for command completion with a timeout.
|
||||||
|
timeout := 0;
|
||||||
|
repeat
|
||||||
|
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||||
|
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||||
|
timeout := timeout + 10;
|
||||||
|
if timeout > 100000 then begin
|
||||||
|
console.writestringln('AHCI: Read ATAPI command timeout');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
// check for bit 30 in the tfd register
|
||||||
|
if (tfd and $40000000) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: error');
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
until ((device^.port^.cmd_issue and (1 shl slot)) = 0); // Wait until slot 0 is cleared
|
||||||
|
|
||||||
|
console.writestringln('AHCI: Command complete');
|
||||||
|
|
||||||
|
// Check for an error flag in the command register (bit 1)
|
||||||
|
if (cmd and (1 shl slot)) <> 0 then begin
|
||||||
|
console.writestringln('AHCI: Error sending read ATAPI command');
|
||||||
|
|
||||||
|
// Check the error register for more information
|
||||||
|
console.writestring('AHCI: Error register: ');
|
||||||
|
console.writehexln(device^.port^.sata_error);
|
||||||
|
end;
|
||||||
|
|
||||||
|
read_atapi := true;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
320
src/driver/storage/AHCI/AHCITypes.pas
Normal file
320
src/driver/storage/AHCI/AHCITypes.pas
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
// Copyright 2021 Aaron Hance
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
{
|
||||||
|
Drivers->Storage->AHCI->AHCITypes - AHCI Driver Types.
|
||||||
|
|
||||||
|
@author(Aaron Hance <ah@aaronhance.me>)
|
||||||
|
}
|
||||||
|
unit AHCITypes;
|
||||||
|
interface
|
||||||
|
uses
|
||||||
|
util,
|
||||||
|
PCI,
|
||||||
|
drivertypes,
|
||||||
|
drivermanagement,
|
||||||
|
lmemorymanager,
|
||||||
|
console,
|
||||||
|
vmemorymanager,
|
||||||
|
idetypes,
|
||||||
|
lists;
|
||||||
|
|
||||||
|
const
|
||||||
|
AHCI_CONTROLLER_MODE = $80000000;
|
||||||
|
|
||||||
|
CMD_LIST_ALIGN = 1024;
|
||||||
|
CMD_TBL_ALIGN = 128;
|
||||||
|
|
||||||
|
NUM_CMD_ENTRIES = 32;
|
||||||
|
|
||||||
|
//device type signatures
|
||||||
|
SATA_SIG_ATA = $00000101;
|
||||||
|
SATA_SIG_ATAPI = $EB140101;
|
||||||
|
SATA_SIG_SEMB = $C33C0101;
|
||||||
|
SATA_SIG_PM = $96690101;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI Host Bus Adapter (HBA) Memory-Mapped Register Interface
|
||||||
|
This structure is used to access the AHCI HBA's memory-mapped registers.
|
||||||
|
The AHCI HBA's memory-mapped registers are used to configure the HBA and
|
||||||
|
to issue commands to the SATA devices connected to the HBA.
|
||||||
|
|
||||||
|
The AHCI HBA's memory-mapped registers are accessed by reading and writing
|
||||||
|
to the HBA's memory-mapped I/O space. The HBA's memory-mapped I/O space is
|
||||||
|
typically mapped to a region of physical memory by the system's BIOS or
|
||||||
|
UEFI firmware. The HBA's memory-mapped I/O space is typically mapped to a
|
||||||
|
region of physical memory that is accessible to the system's CPU(s) and
|
||||||
|
other devices.
|
||||||
|
}
|
||||||
|
THBA_Port = bitpacked record
|
||||||
|
cmdl_basel: uint32; // Command List Base Address Lower 32-bits
|
||||||
|
cmdl_baseu: uint32; // Command List Base Address Upper 32-bits
|
||||||
|
fis_basel: uint32; // FIS Base Address Lower 32-bits
|
||||||
|
fis_baseu: uint32; // FIS Base Address Upper 32-bits
|
||||||
|
int_status: uint32; // Interrupt Status
|
||||||
|
int_enable: uint32; // Interrupt Enable
|
||||||
|
cmd: uint32; // Command and Status
|
||||||
|
rsv0: uint32; // Reserved
|
||||||
|
tfd: uint32; // Task File Data
|
||||||
|
signature: uint32; // Signature
|
||||||
|
sata_status: uint32; // SATA Status (SCR0:SStatus)
|
||||||
|
sata_ctrl: uint32; // SATA Control (SCR2:SControl)
|
||||||
|
sata_error: uint32; // SATA Error (SCR1:SError)
|
||||||
|
sata_active: uint32; // SATA Active
|
||||||
|
cmd_issue: uint32; // Command Issue
|
||||||
|
sata_noti: uint32; // SATA Notification
|
||||||
|
fis_switch_ctrl: uint32;// FIS-based Switch Control
|
||||||
|
rsv1: array[0..10] of uint32;
|
||||||
|
vendor: array[0..3] of uint32;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PHBA_Port = ^THBA_Port;
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI Host Bus Adapter (HBA) Memory-Mapped Register Interface
|
||||||
|
This structure is used to access the AHCI's memory-mapped registers.
|
||||||
|
The AHCI's memory-mapped registers are used to configure the HBA and to
|
||||||
|
issue commands to the SATA devices connected to the HBA.
|
||||||
|
}
|
||||||
|
THBA_Memory = bitpacked record
|
||||||
|
capabilites: uint32; // Host Capabilities
|
||||||
|
global_ctrl: uint32; // Global Host Control
|
||||||
|
int_status: uint32; // Interrupt Status
|
||||||
|
ports_implimented: uint32;// Ports Implemented
|
||||||
|
version: uint32; // Version
|
||||||
|
ccc_control: uint32; // Command Completion Coalescing Control
|
||||||
|
ccc_ports: uint32; // Command Completion Coalescing Ports
|
||||||
|
em_location: uint32; // Enclosure Management Location
|
||||||
|
em_control: uint32; // Enclosure Management Control
|
||||||
|
capabilites2: uint32; // Host Capabilities Extended
|
||||||
|
bohc: uint32; // BIOS/OS Handoff Control and Status
|
||||||
|
|
||||||
|
//0x2c to 0x9f reserved
|
||||||
|
rsv0: array[0..115] of uint8;
|
||||||
|
|
||||||
|
//vendor specific
|
||||||
|
vendor: array[0..95] of uint8;
|
||||||
|
|
||||||
|
//port registers
|
||||||
|
ports: array[0..31] of THBA_Port;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
PHBA_Memory = ^THBA_Memory;
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface
|
||||||
|
This structure is used to access the AHCI HBA's FIS (Frame Information Structure)
|
||||||
|
memory-mapped registers. RX
|
||||||
|
}
|
||||||
|
THBA_FIS = bitpacked record
|
||||||
|
dsfis: array[0..$1F] of uint32; // DMA Setup FIS
|
||||||
|
rsv0: array[0..$1F] of uint32;
|
||||||
|
psfis: array[0..$1F] of uint32; // PIO Setup FIS
|
||||||
|
rsv1: array[0..$1F] of uint32;
|
||||||
|
rfis: array[0..$1F] of uint32; // D2H Register FIS
|
||||||
|
rsv2: array[0..$1F] of uint32;
|
||||||
|
sdbfis: array[0..$F] of uint32; // Set Device Bits FIS
|
||||||
|
ufis: array[0..$1F] of uint32; // Unknown FIS
|
||||||
|
rsv3: array[0..$67] of uint32;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PHBA_FIS = ^THBA_FIS;
|
||||||
|
|
||||||
|
//enum fis type
|
||||||
|
TFISType = (
|
||||||
|
FIS_TYPE_REG_H2D = $27, // Register FIS - Host to Device
|
||||||
|
FIS_TYPE_REG_D2H = $34, // Register FIS - Device to Host
|
||||||
|
FIS_TYPE_DMA_ACT = $39, // DMA Activate FIS - Device to Host
|
||||||
|
FIS_TYPE_DMA_SETUP = $41, // DMA Setup FIS - Bidirectional
|
||||||
|
FIS_TYPE_DATA = $46, // Data FIS - Bidirectional
|
||||||
|
FIS_TYPE_BIST = $58, // BIST Activate FIS - Bidirectional
|
||||||
|
FIS_TYPE_PIO_SETUP = $5F, // PIO Setup FIS - Device to Host
|
||||||
|
FIS_TYPE_DEV_BITS = $A1 // Set Device Bits FIS - Device to Host
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface
|
||||||
|
This structure is used to access the AHCI HBA's FIS (Frame Information Structure)
|
||||||
|
}
|
||||||
|
THBA_FIS_REG_H2D = bitpacked record
|
||||||
|
fis_type: uint8; // FIS Type
|
||||||
|
// pmport: uint8; // Port Multiplier Port is pmport:4 and rsv0:3 and i:1
|
||||||
|
pmport: ubit4; // Port Multiplier Port
|
||||||
|
rsv: ubit3; // Reserved
|
||||||
|
c: ubit1; // command or control
|
||||||
|
command: uint8; // Command
|
||||||
|
featurel: uint8; // Feature Lower 8-bits
|
||||||
|
lba0: uint8; // LBA0
|
||||||
|
lba1: uint8; // LBA1
|
||||||
|
lba2: uint8; // LBA2
|
||||||
|
device: uint8; // Device
|
||||||
|
lba3: uint8; // LBA3
|
||||||
|
lba4: uint8; // LBA4
|
||||||
|
lba5: uint8; // LBA5
|
||||||
|
featureh: uint8; // Feature Upper 8-bits
|
||||||
|
countl: uint8; // Count Lower 8-bits
|
||||||
|
counth: uint8; // Count Upper 8-bits
|
||||||
|
icc: uint8; // Isochronous Command Completion
|
||||||
|
control: uint8; // Control
|
||||||
|
rsv0: array[0..3] of uint8;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PHBA_FIS_REG_H2D = ^THBA_FIS_REG_H2D;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI Host Bus Adapter (HBA) Command Header Interface
|
||||||
|
}
|
||||||
|
THBA_CMD_HEADER = bitpacked record
|
||||||
|
cmd_fis_length: UBit5; // Command FIS Length
|
||||||
|
atapi: UBit1; // ATAPI
|
||||||
|
wrt: UBit1; // Write
|
||||||
|
prefetchable: UBit1; // Prefetchable
|
||||||
|
|
||||||
|
reset: UBit1; // Reset
|
||||||
|
bist: UBit1; // BIST
|
||||||
|
clear_busy: UBit1; // Clear Busy
|
||||||
|
reserved0: UBit1; // Reserved
|
||||||
|
port_multiplier: UBit4; // Port Multiplier Port
|
||||||
|
|
||||||
|
prdtl: uint16; // Physical Region Descriptor Table Length
|
||||||
|
prdbc: uint32; // Physical Region Descriptor Byte Count
|
||||||
|
cmd_table_base: uint32; // Command Table Base Address
|
||||||
|
cmd_table_baseu: uint32; // Command Table Base Address Upper 32-bits
|
||||||
|
rsv0: array[0..3] of uint32;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PHBA_CMD_HEADER = ^THBA_CMD_HEADER;
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI Host Bus Adapter (HBA) Command Table Interface
|
||||||
|
}
|
||||||
|
THBA_PRD = bitpacked record
|
||||||
|
dba: uint32; // Data Base Address
|
||||||
|
dbau: uint32; // Data Base Address Upper 32-bits
|
||||||
|
rsv0: uint32; // Reserved
|
||||||
|
dbc: ubit22; // Data Byte Count
|
||||||
|
reserved: ubit9; // Reserved
|
||||||
|
int: ubit1; // Interrupt
|
||||||
|
// dbc: uint32; // Data Byte Count, bit 1 is Interrupt, then 22 bits of Byte Count, then 9 bits of Reserved
|
||||||
|
end;
|
||||||
|
|
||||||
|
TPRDT = array[0..31] of THBA_PRD;
|
||||||
|
PPRDT = ^TPRDT;
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI Host Bus Adapter (HBA) Command Table Interface
|
||||||
|
}
|
||||||
|
THBA_CMD_TABLE = bitpacked record
|
||||||
|
cmd_fis: array[0..63] of uint8; // Command FIS
|
||||||
|
acmd: array[0..15] of uint8; // ATAPI Command
|
||||||
|
rsv0: array[0..47] of uint8;
|
||||||
|
prdt: array[0..31] of THBA_PRD; // Physical Region Descriptor Table
|
||||||
|
end;
|
||||||
|
|
||||||
|
PHBA_CMD_TABLE = ^THBA_CMD_TABLE;
|
||||||
|
|
||||||
|
TCMD_LIST = array[0..255] of THBA_CMD_HEADER;
|
||||||
|
PCMD_LIST = ^TCMD_LIST;
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
//////////// Asuro AHCI types ////////////
|
||||||
|
//////////////////////////////////////////
|
||||||
|
|
||||||
|
{
|
||||||
|
Device type enum
|
||||||
|
}
|
||||||
|
TDeviceType = (
|
||||||
|
SATA = 1,
|
||||||
|
ATAPI = 2,
|
||||||
|
SEMB,
|
||||||
|
PM
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
AHCI device reference
|
||||||
|
}
|
||||||
|
TAHCI_Device = bitpacked record
|
||||||
|
port : PHBA_Port;
|
||||||
|
device_type : TDeviceType;
|
||||||
|
ata_info : TIdentResponse;
|
||||||
|
command_list : PHBA_CMD_HEADER;
|
||||||
|
fis : PHBA_FIS;
|
||||||
|
command_table : PHBA_CMD_TABLE;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PAHCI_Device = ^TAHCI_Device;
|
||||||
|
|
||||||
|
{
|
||||||
|
controller reference
|
||||||
|
}
|
||||||
|
TAHCI_Controller = bitpacked record
|
||||||
|
pci_device : PPCI_Device;
|
||||||
|
mio: PHBA_Memory;
|
||||||
|
ata_info : TIdentResponse;
|
||||||
|
devices : array[0..31] of TAHCI_Device;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PAHCI_Controller = ^TAHCI_Controller;
|
||||||
|
|
||||||
|
|
||||||
|
function get_device_type(sig : uint32) : TDeviceType;
|
||||||
|
// function get_device_type_string(deive_type : TDeviceType) : string;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function get_device_type(sig : uint32) : TDeviceType;
|
||||||
|
begin
|
||||||
|
case sig of
|
||||||
|
SATA_SIG_ATA: begin
|
||||||
|
get_device_type := SATA;
|
||||||
|
end;
|
||||||
|
SATA_SIG_ATAPI: begin
|
||||||
|
get_device_type := ATAPI;
|
||||||
|
end;
|
||||||
|
SATA_SIG_SEMB: begin
|
||||||
|
get_device_type := SEMB;
|
||||||
|
end;
|
||||||
|
SATA_SIG_PM: begin
|
||||||
|
get_device_type := PM;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// function get_device_type_string(deive_type : TDeviceType) : string;
|
||||||
|
// begin
|
||||||
|
// case deive_type of
|
||||||
|
// SATA: begin
|
||||||
|
// get_device_type_string := 'SATA';
|
||||||
|
// end;
|
||||||
|
// ATAPI: begin
|
||||||
|
// get_device_type_string := 'ATAPI';
|
||||||
|
// end;
|
||||||
|
// SEMB: begin
|
||||||
|
// get_device_type_string := 'SEMB';
|
||||||
|
// end;
|
||||||
|
// PM: begin
|
||||||
|
// get_device_type_string := 'PM';
|
||||||
|
// end;
|
||||||
|
// end;
|
||||||
|
// end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -1,85 +0,0 @@
|
|||||||
// Copyright 2021 Aaron Hance
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
{
|
|
||||||
Drivers->Storage->ATA_ISR - Primary ATA IRQ.
|
|
||||||
|
|
||||||
@author(Aaron Hance <ah@aaronhance.me>)
|
|
||||||
}
|
|
||||||
unit ATA_ISR;
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
uses
|
|
||||||
util,
|
|
||||||
console,
|
|
||||||
isr_types,
|
|
||||||
isrmanager,
|
|
||||||
IDT;
|
|
||||||
|
|
||||||
procedure register();
|
|
||||||
procedure hook(hook_method : uint32);
|
|
||||||
procedure unhook(hook_method : uint32);
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
var
|
|
||||||
Hooks : Array[1..MAX_HOOKS] of pp_hook_method;
|
|
||||||
|
|
||||||
procedure Main(); interrupt;
|
|
||||||
var
|
|
||||||
i : integer;
|
|
||||||
|
|
||||||
begin
|
|
||||||
CLI;
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
if uint32(Hooks[i]) <> 0 then Hooks[i](void($00000000));
|
|
||||||
end;
|
|
||||||
console.writestringln('Disk Operation Complete');
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure register();
|
|
||||||
begin
|
|
||||||
memset(uint32(@Hooks[0]), 0, sizeof(pp_hook_method)*MAX_HOOKS);
|
|
||||||
//isrmanager.registerISR(76, @Main);
|
|
||||||
//IDT.set_gate(76, uint32(@Main), $08, ISR_RING_0);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure hook(hook_method : uint32);
|
|
||||||
var
|
|
||||||
i : uint32;
|
|
||||||
|
|
||||||
begin
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
if uint32(Hooks[i]) = hook_method then exit;
|
|
||||||
end;
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
if uint32(Hooks[i]) = 0 then begin
|
|
||||||
Hooks[i]:= pp_hook_method(hook_method);
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure unhook(hook_method : uint32);
|
|
||||||
var
|
|
||||||
i : uint32;
|
|
||||||
begin
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
If uint32(Hooks[i]) = hook_method then Hooks[i]:= nil;
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
|
@ -1,246 +1,506 @@
|
|||||||
{ ************************************************
|
// Copyright 2021 Aaron Hance
|
||||||
* Asuro
|
//
|
||||||
* Unit: Drivers/storage/IDE
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* Description: IDE ATA Driver
|
// you may not use this file except in compliance with the License.
|
||||||
*
|
// You may obtain a copy of the License at
|
||||||
************************************************
|
//
|
||||||
* Author: Aaron Hance
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* Contributors:
|
//
|
||||||
************************************************ }
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
unit IDE;
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
{
|
||||||
|
Drivers->Storage->ide - IDE Driver.
|
||||||
|
|
||||||
|
NOT FINSIHED NEEDS WORK
|
||||||
|
|
||||||
|
@author(Aaron Hance <ah@aaronhance.me>)
|
||||||
|
}
|
||||||
|
unit ide;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
util,
|
ata,
|
||||||
drivertypes,
|
atapi,
|
||||||
console,
|
console,
|
||||||
terminal,
|
|
||||||
drivermanagement,
|
drivermanagement,
|
||||||
vmemorymanager,
|
drivertypes,
|
||||||
|
idetypes,
|
||||||
|
isrmanager,
|
||||||
lmemorymanager,
|
lmemorymanager,
|
||||||
storagemanagement,
|
storagetypes,
|
||||||
strings,
|
strings,
|
||||||
tracer;
|
terminal,
|
||||||
|
tracer,
|
||||||
|
util,
|
||||||
|
vmemorymanager;
|
||||||
|
|
||||||
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
|
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; blockSize: 0; 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; blockSize: 0; 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; blockSize: 0; 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; blockSize: 0; 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; ioop : boolean) : boolean;
|
||||||
|
procedure no_interrupt(isPrimary : boolean);
|
||||||
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
|
procedure enable_interrupt(isPrimary : boolean);
|
||||||
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
|
procedure reset_device(device : TIDE_Device);
|
||||||
|
procedure select_device(device : TIDE_Device);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
function port_read(register : uint8) : uint8;
|
{
|
||||||
|
Disable interrupts on the IDE bus
|
||||||
|
@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);
|
procedure enable_interrupt(isPrimary : boolean);
|
||||||
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
|
var
|
||||||
status : uint8;
|
reg : uint8;
|
||||||
|
begin
|
||||||
|
if isPrimary then begin
|
||||||
|
reg := inb(ATA_INTERRUPT_PRIMARY);
|
||||||
|
reg := reg and not (1 shl 1);
|
||||||
|
outb(ATA_INTERRUPT_PRIMARY, reg);
|
||||||
|
end else begin
|
||||||
|
reg := inb(ATA_INTERRUPT_SECONDARY);
|
||||||
|
reg := reg and not (1 shl 1);
|
||||||
|
outb(ATA_INTERRUPT_SECONDARY, reg);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//soft reset
|
||||||
|
procedure reset_device(device : TIDE_Device);
|
||||||
|
var
|
||||||
|
reg : uint8;
|
||||||
|
begin
|
||||||
|
if device.isPrimary then begin
|
||||||
|
reg := inb(ATA_INTERRUPT_PRIMARY);
|
||||||
|
reg := reg and (1 shl 2);
|
||||||
|
outb(ATA_INTERRUPT_PRIMARY, reg);
|
||||||
|
end else begin
|
||||||
|
reg := inb(ATA_INTERRUPT_SECONDARY);
|
||||||
|
reg := reg and (1 shl 2);
|
||||||
|
outb(ATA_INTERRUPT_SECONDARY, reg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
sleep(20);
|
||||||
|
|
||||||
|
if device.isPrimary then begin
|
||||||
|
reg := inb(ATA_INTERRUPT_PRIMARY);
|
||||||
|
reg := reg and not (1 shl 2);
|
||||||
|
outb(ATA_INTERRUPT_PRIMARY, reg);
|
||||||
|
end else begin
|
||||||
|
reg := inb(ATA_INTERRUPT_SECONDARY);
|
||||||
|
reg := reg and not (1 shl 2);
|
||||||
|
outb(ATA_INTERRUPT_SECONDARY, reg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Wait for the device to be ready on the IDE bus
|
||||||
|
|
||||||
|
@param(device The device to wait for)
|
||||||
|
@returns(@True if the device is ready, @False otherwise)
|
||||||
|
}
|
||||||
|
function wait_for_device(device : TIDE_Device; ioop : boolean) : boolean;
|
||||||
|
var
|
||||||
|
status : TIDE_Status;
|
||||||
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 < 50000) do begin
|
||||||
is_ready := false;
|
status := get_status(device);
|
||||||
break;
|
|
||||||
|
if (status.BUSY = false) and (status.DRQ or (not ioop)) 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;
|
reg : uint8;
|
||||||
|
begin
|
||||||
|
push_trace('ide.select_device()');
|
||||||
|
|
||||||
|
dev := ATA_DEVICE_SLAVE;
|
||||||
|
|
||||||
|
if device.isMaster then begin
|
||||||
|
dev := ATA_DEVICE_MASTER;
|
||||||
|
end;
|
||||||
|
|
||||||
|
reg := inb(device.base + ATA_REG_HDDEVSEL);
|
||||||
|
reg := (reg and $F0) or dev;
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_HDDEVSEL, reg);
|
||||||
|
|
||||||
|
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;
|
||||||
|
errorReg : uint8;
|
||||||
|
begin
|
||||||
|
push_trace('ide.get_status()');
|
||||||
|
|
||||||
|
// select_device(device);
|
||||||
|
|
||||||
|
status := TIDE_Status(inb(device.base + ATA_REG_STATUS));
|
||||||
|
|
||||||
|
device.status := status;
|
||||||
|
|
||||||
|
if status.ERROR then begin
|
||||||
|
errorReg := inb(device.base + ATA_REG_ERROR);
|
||||||
|
|
||||||
|
console.writestringln('[IDE] ERROR detected!');
|
||||||
|
console.writestring('[IDE] ERROR REGISTER: ');
|
||||||
|
console.writebin8ln(errorReg);
|
||||||
|
|
||||||
|
if (errorReg and $04) <> 0 then console.writestringln('[IDE] ERROR: Aborted Command');
|
||||||
|
if (errorReg and $10) <> 0 then console.writestringln('[IDE] ERROR: ID Not Found');
|
||||||
|
if (errorReg and $40) <> 0 then console.writestringln('[IDE] ERROR: Uncorrectable Data');
|
||||||
|
if (errorReg and $80) <> 0 then console.writestringln('[IDE] ERROR: Bad Block');
|
||||||
|
|
||||||
|
console.redrawWindows();
|
||||||
|
end;
|
||||||
|
|
||||||
|
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
|
||||||
|
//reset any device signature
|
||||||
|
{
|
||||||
|
Write 0x04 to the Control Register (0x3F6 for primary bus, 0x376 for secondary).
|
||||||
|
Wait ~5 microseconds.
|
||||||
|
Write 0x00 back to Control Register to complete reset.
|
||||||
|
// }
|
||||||
|
outb(ATA_PRIMARY_BASE1, $04);
|
||||||
|
outb(ATA_SECONDARY_BASE1, $04);
|
||||||
|
sleep(1);
|
||||||
|
// outb(ATA_PRIMARY_BASE1, $00);
|
||||||
|
// outb(ATA_SECONDARY_BASE1, $00);
|
||||||
|
select_device(device);
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
console.writestring('[IDE] (check_device_type) SEC: ');
|
||||||
|
console.writehexln(sec);
|
||||||
|
console.writestring('[IDE] (check_device_type) LBA0: ');
|
||||||
|
console.writehexln(lba0);
|
||||||
|
console.writestring('[IDE] (check_device_type) LBA1: ');
|
||||||
|
console.writehexln(lba1);
|
||||||
|
console.writestring('[IDE] (check_device_type) LBA2: ');
|
||||||
|
console.writehexln(lba2);
|
||||||
|
|
||||||
|
|
||||||
|
//check if the device is an ATAPI device
|
||||||
|
if ((sec = 3) or (lba2 = $EB)) then begin
|
||||||
|
check_device_type := true;
|
||||||
|
device.isATAPI := true;
|
||||||
|
end else if sec = 1 then begin
|
||||||
|
check_device_type := true;
|
||||||
|
device.isATAPI := false;
|
||||||
|
end else begin
|
||||||
|
check_device_type := false;
|
||||||
|
end;
|
||||||
|
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;
|
||||||
|
size : uint32;
|
||||||
|
begin
|
||||||
|
push_trace('ide.load_device()');
|
||||||
|
success := check_device_type(device);
|
||||||
|
|
||||||
|
if (is_device_present(device) and success) then begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is present');
|
||||||
|
|
||||||
|
if (device.isATAPI) then begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is ATAPI');
|
||||||
|
//todo load device info
|
||||||
|
success := atapi.identify_device(device);
|
||||||
|
|
||||||
|
device.exists := true;
|
||||||
|
device.isATAPI := true;
|
||||||
|
|
||||||
|
end else begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is ATA');
|
||||||
|
success:= ata.identify_device(device);
|
||||||
|
|
||||||
|
//check if atapi device using info from identify_device
|
||||||
|
console.writestringln('[IDE] (load_device) Device info: ');
|
||||||
|
console.writecharln(char(puint8(device.info)[252]));
|
||||||
|
console.writecharln(char(puint8(device.info)[253]));
|
||||||
|
|
||||||
|
if (puint8(device.info)[253] = $FF) then begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is ATAPI');
|
||||||
|
device.isATAPI := true;
|
||||||
|
device.exists := true;
|
||||||
|
|
||||||
|
success := atapi.identify_device(device);
|
||||||
|
end;
|
||||||
|
|
||||||
|
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
|
||||||
|
size := atapi.get_device_size(device);
|
||||||
|
storageDevice^.maxSectorCount := size;
|
||||||
|
storageDevice^.sectorSize := device.blockSize;
|
||||||
|
|
||||||
|
if (device.isMaster) then begin
|
||||||
|
storageDevice^.controllerId0 := 0;
|
||||||
|
end else begin
|
||||||
|
storageDevice^.controllerId0 := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//read and print first sector
|
||||||
|
buffer := puint8(kalloc(2048));
|
||||||
|
memset(uint32(buffer), 11, 2048);
|
||||||
|
atapi.read_pio28(device, 11, 1, puint16(buffer));
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (load_device) First sector of ATAPI device: ');
|
||||||
|
for i:=0 to 16 do begin
|
||||||
|
console.writehexln(buffer[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
memset(uint32(buffer), 0, 2048);
|
||||||
|
|
||||||
|
atapi.read_pio28(device, 5200, 1, puint16(buffer));
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (load_device) First sector of ATAPI device: ');
|
||||||
|
for i:=0 to 16 do begin
|
||||||
|
console.writehexln(buffer[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
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(1024));
|
||||||
|
// memset(uint32(buffer), $02, 1024);
|
||||||
|
|
||||||
|
// uint8(buffer[0]) := $1F;
|
||||||
|
// uint8(buffer[1]) := $2F;
|
||||||
|
// uint8(buffer[2]) := $3F;
|
||||||
|
// uint8(buffer[3]) := $4F;
|
||||||
|
// uint8(buffer[4]) := $5F;
|
||||||
|
// uint8(buffer[5]) := $6F;
|
||||||
|
// uint8(buffer[6]) := $7F;
|
||||||
|
// uint8(buffer[7]) := $8F;
|
||||||
|
|
||||||
|
// //write to the first sector
|
||||||
|
// ata.write_pio28(device, 10, 2, puint16(buffer));
|
||||||
|
|
||||||
|
// //read the first sector
|
||||||
|
// memset(uint32(buffer), 0, 512);
|
||||||
|
// ata.read_pio28(device, 10, 1, puint16(buffer));
|
||||||
|
|
||||||
|
// //check if the data is the same
|
||||||
|
// for i:=0 to 10 do begin
|
||||||
|
// console.writehexln(buffer[i]);
|
||||||
|
// end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//register the device TODO
|
||||||
|
// 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;
|
i : uint8;
|
||||||
begin
|
begin
|
||||||
push_trace('IDE.Identify_Device');
|
push_trace('ide.load()');
|
||||||
device_select(device);
|
console.writestringln('[IDE] (load) Loading IDE Devices');
|
||||||
no_interrupt(device);
|
console.redrawWindows();
|
||||||
port_write(ATA_REG_CONTROL, 0);
|
registerISR(14, @atapi.ide_irq);
|
||||||
|
registerISR(15, @atapi.ide_irq);
|
||||||
|
console.writestringln('[IDE] (load) Loading IDE Devices 2');
|
||||||
|
console.redrawWindows();
|
||||||
|
pciDevice := PPCI_Device(ptr);
|
||||||
|
|
||||||
//check if bus is floating
|
load_device(primaryDevices[0]);
|
||||||
status := port_read(ATA_REG_COMMAND);
|
load_device(primaryDevices[1]);
|
||||||
if status = $FF then exit;
|
load_device(secondaryDevices[0]);
|
||||||
|
load_device(secondaryDevices[1]);
|
||||||
|
|
||||||
port_write(ATA_REG_SECCOUNT, 0);
|
pop_trace();
|
||||||
port_write(ATA_REG_LBA0, 0);
|
load := true;
|
||||||
port_write(ATA_REG_LBA1, 0);
|
|
||||||
port_write(ATA_REG_LBA2, 0);
|
|
||||||
|
|
||||||
port_write(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
|
console.writestringln('[IDE] (load) IDE Device Loading Finished');
|
||||||
|
|
||||||
//check if drive is present
|
i := 0;
|
||||||
status := port_read(ATA_REG_COMMAND);
|
|
||||||
if status = $00 then exit;
|
|
||||||
|
|
||||||
if not is_ready() then exit;
|
if (primaryDevices[0].exists) then begin
|
||||||
|
console.writestringln('[IDE] (load) FOUND Primary Master Device 0');
|
||||||
for i:=0 to 255 do begin
|
i := i + 1;
|
||||||
identResponse[i] := inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
identify_device := identResponse;
|
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 +516,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.
|
81
src/driver/storage/MBR.pas
Normal file
81
src/driver/storage/MBR.pas
Normal 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.
|
306
src/driver/storage/OLD_drivemanager.pas
Normal file
306
src/driver/storage/OLD_drivemanager.pas
Normal 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.
|
@ -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.
|
429
src/driver/storage/OLD_volumemanager.pas
Normal file
429
src/driver/storage/OLD_volumemanager.pas
Normal 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.
|
251
src/driver/storage/ata.pas
Normal file
251
src/driver/storage/ata.pas
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
// Copyright 2021 Aaron Hance
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
{
|
||||||
|
Drivers->Storage->ATA - ATA Driver.
|
||||||
|
|
||||||
|
@author(Aaron Hance <ah@aaronhance.me>)
|
||||||
|
}
|
||||||
|
unit ata;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
console,
|
||||||
|
drivermanagement,
|
||||||
|
drivertypes,
|
||||||
|
idetypes,
|
||||||
|
lmemorymanager,
|
||||||
|
storagetypes,
|
||||||
|
strings,
|
||||||
|
terminal,
|
||||||
|
tracer,
|
||||||
|
util,
|
||||||
|
vmemorymanager;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
procedure outb(port : uint16; value : uint8);
|
||||||
|
begin
|
||||||
|
util.outb(port, value);
|
||||||
|
psleep(1);
|
||||||
|
// get_status(primaryDevices[0]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
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, false);
|
||||||
|
|
||||||
|
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);
|
||||||
|
psleep(50);
|
||||||
|
no_interrupt(device.isPrimary);
|
||||||
|
psleep(50);
|
||||||
|
set_lba_mode(device, lba);
|
||||||
|
psleep(50);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_SECCOUNT, count);
|
||||||
|
psleep(50);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_LBA0, (lba and $000000FF));
|
||||||
|
psleep(50);
|
||||||
|
outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8);
|
||||||
|
psleep(50);
|
||||||
|
outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16);
|
||||||
|
psleep(50);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
|
||||||
|
psleep(50);
|
||||||
|
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
|
||||||
|
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
|
||||||
|
ii:=0;
|
||||||
|
while ii < 256 do begin
|
||||||
|
buffer[ii+(i*256)] := inw(device.base + ATA_REG_DATA);
|
||||||
|
ii := ii + 1;
|
||||||
|
psleep(50);
|
||||||
|
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, false);
|
||||||
|
|
||||||
|
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
|
||||||
|
ii:=0;
|
||||||
|
while ii < 256 do begin
|
||||||
|
outw(ATA_PRIMARY_BASE + ATA_REG_DATA, buffer[ii+(i*256)]);
|
||||||
|
ii := ii + 1;
|
||||||
|
psleep(50);
|
||||||
|
end;
|
||||||
|
|
||||||
|
psleep(50); //todo check
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
448
src/driver/storage/atapi.pas
Normal file
448
src/driver/storage/atapi.pas
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
// Copyright 2021 Aaron Hance
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
{
|
||||||
|
Drivers->Storage->ATAPI - ATAPI Driver.
|
||||||
|
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!! CURRENTLY NOT FUNCTIONAL !!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
@author(Aaron Hance <ah@aaronhance.me>)
|
||||||
|
}
|
||||||
|
|
||||||
|
unit atapi;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
console,
|
||||||
|
drivermanagement,
|
||||||
|
drivertypes,
|
||||||
|
idetypes,
|
||||||
|
lmemorymanager,
|
||||||
|
storagetypes,
|
||||||
|
strings,
|
||||||
|
terminal,
|
||||||
|
tracer,
|
||||||
|
util,
|
||||||
|
vmemorymanager;
|
||||||
|
|
||||||
|
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;
|
||||||
|
function get_device_size(var device : TIDE_Device) : uint32;
|
||||||
|
procedure ide_irq();
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
uses
|
||||||
|
ata,
|
||||||
|
ide;
|
||||||
|
|
||||||
|
|
||||||
|
procedure ide_irq();
|
||||||
|
begin
|
||||||
|
console.writestringln('IDE IRQ Handler');
|
||||||
|
console.redrawWindows();
|
||||||
|
end;
|
||||||
|
|
||||||
|
//print status of the device, alt status register
|
||||||
|
procedure print_status(device : TIDE_Device);
|
||||||
|
begin
|
||||||
|
get_status(device);
|
||||||
|
|
||||||
|
console.writestring('Status: ');
|
||||||
|
// console.writeintln(uint32(device.status));
|
||||||
|
|
||||||
|
console.writestring('Busy: ');
|
||||||
|
console.writeintln(uint32(device.status.Busy));
|
||||||
|
console.writestring('Ready: ');
|
||||||
|
console.writeintln(uint32(device.status.Ready));
|
||||||
|
console.writestring('Fault: ');
|
||||||
|
console.writeintln(uint32(device.status.Fault));
|
||||||
|
console.writestring('Seek: ');
|
||||||
|
console.writeintln(uint32(device.status.Seek));
|
||||||
|
console.writestring('DRQ: ');
|
||||||
|
console.writeintln(uint32(device.status.DRQ));
|
||||||
|
console.writestring('CORR: ');
|
||||||
|
console.writeintln(uint32(device.status.CORR));
|
||||||
|
console.writestring('IDDEX: ');
|
||||||
|
console.writeintln(uint32(device.status.IDDEX));
|
||||||
|
console.writestring('ERROR: ');
|
||||||
|
console.writeintln(uint32(device.status.ERROR));
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure outb(port : uint16; value : uint8);
|
||||||
|
begin
|
||||||
|
util.outb(port, value);
|
||||||
|
psleep(1);
|
||||||
|
// get_status(primaryDevices[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);
|
||||||
|
|
||||||
|
// outb(ATA_PRIMARY_BASE1, $04);
|
||||||
|
// outb(ATA_SECONDARY_BASE1, $04);
|
||||||
|
// sleep(1);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
psleep(1);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
|
||||||
|
|
||||||
|
status := get_status(device);
|
||||||
|
|
||||||
|
if status.ERROR then begin
|
||||||
|
console.writestringln('Error identifying device, maybe'); //todo
|
||||||
|
end;
|
||||||
|
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
console.writestringln('ATAPI Device identified: ');
|
||||||
|
|
||||||
|
for i:=0 to 255 do begin
|
||||||
|
buffer[i] := inw(device.base + ATA_REG_DATA);
|
||||||
|
console.writestring('[');
|
||||||
|
console.writehexpair(buffer[i]);
|
||||||
|
console.writestring('] ');
|
||||||
|
if (i mod 4) = 0 then begin
|
||||||
|
console.writestringln('');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//bits 14 and 15 of word 0
|
||||||
|
{
|
||||||
|
00h
|
||||||
|
01h
|
||||||
|
Direct-access device
|
||||||
|
Sequential-access device
|
||||||
|
02h
|
||||||
|
03h
|
||||||
|
Printer device
|
||||||
|
Processor device
|
||||||
|
04h
|
||||||
|
05h
|
||||||
|
Write-once device
|
||||||
|
CD-ROM device
|
||||||
|
06h
|
||||||
|
07h
|
||||||
|
Scanner device
|
||||||
|
Optical memory device
|
||||||
|
08h
|
||||||
|
09h
|
||||||
|
Medium changer device
|
||||||
|
Communications device
|
||||||
|
0A-0Bh
|
||||||
|
0Ch
|
||||||
|
Reserved for ACS IT8 (Graphic arts pre-press devices)
|
||||||
|
Array controller device
|
||||||
|
0Dh
|
||||||
|
0Eh
|
||||||
|
Enclosure services device
|
||||||
|
Reduced block command devices
|
||||||
|
0Fh
|
||||||
|
10-1Eh
|
||||||
|
Optical card reader/writer device
|
||||||
|
Reserved
|
||||||
|
1Fh
|
||||||
|
Unknown or no device type}
|
||||||
|
|
||||||
|
//print device type
|
||||||
|
console.writestring('Device Type: ');
|
||||||
|
case (buffer[0] shr 8) and $3 of
|
||||||
|
0: console.writestringln('Direct-access device');
|
||||||
|
1: console.writestringln('Sequential-access device');
|
||||||
|
2: console.writestringln('Printer device');
|
||||||
|
3: console.writestringln('Processor device');
|
||||||
|
4: console.writestringln('Write-once device');
|
||||||
|
5: console.writestringln('CD-ROM device');
|
||||||
|
6: console.writestringln('Scanner device');
|
||||||
|
7: console.writestringln('Optical memory device');
|
||||||
|
8: console.writestringln('Medium changer device');
|
||||||
|
9: console.writestringln('Communications device');
|
||||||
|
10: console.writestringln('Reserved for ACS IT8 (Graphic arts pre-press devices)');
|
||||||
|
11: console.writestringln('Array controller device');
|
||||||
|
12: console.writestringln('Reserved');
|
||||||
|
13: console.writestringln('Enclosure services device');
|
||||||
|
14: console.writestringln('Reduced block command devices');
|
||||||
|
15: console.writestringln('Unknown or no device type');
|
||||||
|
end;
|
||||||
|
|
||||||
|
outb(ATA_PRIMARY_BASE1, $04);
|
||||||
|
outb(ATA_SECONDARY_BASE1, $04);
|
||||||
|
sleep(10);
|
||||||
|
|
||||||
|
device.info := @buffer;
|
||||||
|
|
||||||
|
identify_device := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function read_PIO28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
|
||||||
|
var
|
||||||
|
i, j : uint16;
|
||||||
|
status : TIDE_Status;
|
||||||
|
ready : boolean;
|
||||||
|
packet : array[0..11] of uint8;
|
||||||
|
begin
|
||||||
|
push_trace('read_PIO28()');
|
||||||
|
|
||||||
|
if not device.isATAPI then begin
|
||||||
|
console.writestringln('[ATAPI] Device is not an ATAPI device!');
|
||||||
|
read_PIO28 := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
select_device(device);
|
||||||
|
no_interrupt(device.isPrimary);
|
||||||
|
|
||||||
|
// Step 1: Send PACKET command
|
||||||
|
outb(device.base + ATA_REG_FEATURES, 0); // No special features
|
||||||
|
outb(device.base + ATA_REG_SECCOUNT, 0); // ATAPI requires this to be 0
|
||||||
|
outb(device.base + ATA_REG_LBA0, (2048 shr 0) and $FF); // Byte size of transfer (2048 for CDs)
|
||||||
|
outb(device.base + ATA_REG_LBA1, (2048 shr 8) and $FF);
|
||||||
|
outb(device.base + ATA_REG_LBA2, 0); // Reserved
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_PACKET);
|
||||||
|
|
||||||
|
// Step 2: Wait for DRQ=1 (drive wants a command packet)
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
if not ready then begin
|
||||||
|
console.writestringln('[ATAPI] Timeout waiting for PACKET DRQ!');
|
||||||
|
read_PIO28 := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Step 3: Prepare 12-byte SCSI CDB (Read Sectors Command 0xA8)
|
||||||
|
packet[0] := $A8; // ATAPI READ (10) command
|
||||||
|
packet[1] := 0; // Reserved
|
||||||
|
packet[2] := (lba shr 24) and $FF; // LBA high byte
|
||||||
|
packet[3] := (lba shr 16) and $FF;
|
||||||
|
packet[4] := (lba shr 8) and $FF;
|
||||||
|
packet[5] := (lba shr 0) and $FF;
|
||||||
|
packet[6] := 0; // Reserved
|
||||||
|
packet[7] := count; // Number of sectors to read
|
||||||
|
packet[8] := 0; // Reserved
|
||||||
|
packet[9] := 0; // Control
|
||||||
|
packet[10] := 0; // Reserved
|
||||||
|
packet[11] := 0; // Reserved
|
||||||
|
|
||||||
|
// Step 4: Send the command packet
|
||||||
|
for i := 0 to 5 do
|
||||||
|
outw(device.base + ATA_REG_DATA, (packet[i*2] or (packet[i*2+1] shl 8)));
|
||||||
|
|
||||||
|
// Step 6: Read the data (count * 2048 bytes)
|
||||||
|
for i := 0 to (count) - 1 do begin
|
||||||
|
for j := 0 to 1023 do begin
|
||||||
|
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
if not ready then begin
|
||||||
|
console.writestringln('[ATAPI] Timeout waiting for data DRQ!');
|
||||||
|
read_PIO28 := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
buffer[i * 256 + j] := inw(device.base + ATA_REG_DATA);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Success
|
||||||
|
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
|
||||||
|
write_pio28 := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_device_size(var device: TIDE_Device): uint32;
|
||||||
|
var
|
||||||
|
i: uint8;
|
||||||
|
ready: boolean;
|
||||||
|
packet: puint16; // Will hold our 10-byte CDB (as 5 words)
|
||||||
|
response: puint16; // Will hold the 8-byte capacity response
|
||||||
|
xferCount: uint16;
|
||||||
|
temp: uInt32;
|
||||||
|
data: uint16;
|
||||||
|
begin
|
||||||
|
get_device_size := 0;
|
||||||
|
|
||||||
|
// 1) Select the device (Master/Slave) - presumably your function
|
||||||
|
select_device(device);
|
||||||
|
enable_interrupt(device.isPrimary);
|
||||||
|
|
||||||
|
// 2) We set "no special features" for ATAPI
|
||||||
|
outb(device.base + ATA_REG_FEATURES, 0);
|
||||||
|
|
||||||
|
// 3) Indicate how many bytes we expect from the drive.
|
||||||
|
// Usually we place "MaxByteCount" in LBA1:LBA2.
|
||||||
|
// We need at least 8 bytes for READ CAPACITY(10).
|
||||||
|
// We'll do 8 => low byte in LBA1, high byte in LBA2.
|
||||||
|
outb(device.base + ATA_REG_LBA1, $08);
|
||||||
|
outb(device.base + ATA_REG_LBA2, $00);
|
||||||
|
|
||||||
|
// 4) Send the "PACKET" command (0xA0) to start an ATAPI packet transfer
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_PACKET);
|
||||||
|
|
||||||
|
// 5) Build our 10-byte SCSI "READ CAPACITY(10)" command descriptor block (CDB)
|
||||||
|
// We'll store it in 5 words = 10 bytes
|
||||||
|
packet := puint16(kalloc(12)); // 5 * 2 = 10 bytes
|
||||||
|
memset(uint32(packet), 0, 12);
|
||||||
|
|
||||||
|
// READ CAPACITY(10) = opcode 0x25
|
||||||
|
// The rest can be 0 for a basic capacity read
|
||||||
|
// We'll store it as little-endian 16-bit words:
|
||||||
|
// packet[0] = 0x0025 means low byte=0x25 (opcode), high byte=0x00
|
||||||
|
packet[0] := $0025; // cdb[0..1]
|
||||||
|
packet[1] := 0; // cdb[2..3]
|
||||||
|
packet[2] := 0; // cdb[4..5]
|
||||||
|
packet[3] := 0; // cdb[6..7]
|
||||||
|
packet[4] := 0; // cdb[8..9]
|
||||||
|
packet[5] := 0; // cdb[10..11]
|
||||||
|
|
||||||
|
// 6) Wait for drive to be ready to receive the CDB
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
if not ready then
|
||||||
|
begin
|
||||||
|
console.writestringln('Device not ready to receive READ CAPACITY(10) CDB.');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// 7) Write our 5 words (10 bytes) of CDB to the drive
|
||||||
|
for i := 0 to 5 do
|
||||||
|
begin
|
||||||
|
outw(device.base + ATA_REG_DATA, packet[i]);
|
||||||
|
psleep(1); // short delay
|
||||||
|
end;
|
||||||
|
// Free the CDB memory
|
||||||
|
// kfree(uint32(packet));
|
||||||
|
|
||||||
|
// 8) Wait for next phase (the data phase). The device should assert DRQ
|
||||||
|
// if it has data to send. We'll poll again.
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
psleep(1);
|
||||||
|
if not ready then
|
||||||
|
begin
|
||||||
|
console.writestringln('Drive not ready after sending the CDB.');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// 9) The drive indicates how many bytes it’s about to send in LBA1:LBA2
|
||||||
|
// xferCount := (inb(device.base + ATA_REG_LBA2) shl 8) or inb(device.base + ATA_REG_LBA1);
|
||||||
|
// if xferCount < 8 then
|
||||||
|
// begin
|
||||||
|
// console.writestringln('Drive is returning less than 8 bytes for capacity!');
|
||||||
|
// exit;
|
||||||
|
// end;
|
||||||
|
|
||||||
|
// 10) Allocate space for the 8-byte result
|
||||||
|
response := puint16(kalloc(8));
|
||||||
|
memset(uint32(response), 0, 8);
|
||||||
|
|
||||||
|
// We'll read 4 words = 8 bytes from the data register
|
||||||
|
for i := 0 to 3 do
|
||||||
|
begin
|
||||||
|
ready := wait_for_device(device, false);
|
||||||
|
if not ready then
|
||||||
|
begin
|
||||||
|
console.writestringln('Device got stuck while reading capacity data!');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
psleep(3);
|
||||||
|
|
||||||
|
data := inw(device.base + ATA_REG_DATA);
|
||||||
|
|
||||||
|
response[i] := data;
|
||||||
|
|
||||||
|
psleep(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// //fix the order of the bytes of each number
|
||||||
|
// endiness of device sector count
|
||||||
|
temp := puint32(response)[0];
|
||||||
|
puint32(response)[0] := 0;
|
||||||
|
for i := 0 to 31 do begin
|
||||||
|
puint32(response)[0] := puint32(response)[0] or ((temp shr i) and 1) shl (31 - i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
//endiness of device sector size
|
||||||
|
temp := puint32(response)[1];
|
||||||
|
puint32(response)[1] := 0;
|
||||||
|
for i := 0 to 31 do begin
|
||||||
|
puint32(response)[1] := puint32(response)[1] or ((temp shr i) and 1) shl (31 - i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// 11) Now parse the returned 8 bytes:
|
||||||
|
// - first 4 bytes = last LBA
|
||||||
|
// - next 4 bytes = block size
|
||||||
|
console.writestring('Device sector count: ');
|
||||||
|
console.writeintln(puint32(response)[0]); // last LBA
|
||||||
|
console.writebin32ln(puint32(response)[0]);
|
||||||
|
|
||||||
|
|
||||||
|
console.writestring('Device sector size: ');
|
||||||
|
console.writeintln(puint32(response)[1] ); // block size
|
||||||
|
console.writebin32ln(puint32(response)[1]);
|
||||||
|
|
||||||
|
device.blockSize := puint32(response)[1];
|
||||||
|
|
||||||
|
console.writestringln('Device size: ');
|
||||||
|
console.writeintln(puint32(response)[0] * (puint32(response)[1]) );
|
||||||
|
|
||||||
|
// Return the LBA as "size" (some drivers do lastLBA+1).
|
||||||
|
get_device_size := puint32(response)[0];
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
@ -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.
|
725
src/driver/storage/flatfs.pas
Normal file
725
src/driver/storage/flatfs.pas
Normal 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.
|
148
src/driver/storage/idetypes.pas
Normal file
148
src/driver/storage/idetypes.pas
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// 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; //1FC on some systems, 3F6 on all
|
||||||
|
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;
|
||||||
|
blockSize : uint32;
|
||||||
|
info : PIdentResponse;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TIDE_PACKET = record
|
||||||
|
command : uint8;
|
||||||
|
lba : uint32;
|
||||||
|
count : uint8;
|
||||||
|
buffer : puint16;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
end.
|
95
src/driver/storage/storagetypes.pas
Normal file
95
src/driver/storage/storagetypes.pas
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// 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,
|
||||||
|
ControllerAHCI_ATAPI,
|
||||||
|
ControllerNVMe,
|
||||||
|
ControllerNET,
|
||||||
|
ControllerRAM,
|
||||||
|
ControllerSCSI
|
||||||
|
);
|
||||||
|
|
||||||
|
TFileSystemType = (
|
||||||
|
FileSystemFAT32,
|
||||||
|
FileSystemExFAT,
|
||||||
|
FileSystemEXT,
|
||||||
|
FileSystemEXT2,
|
||||||
|
FileSystemCDFS,
|
||||||
|
FileSystemOther
|
||||||
|
);
|
||||||
|
|
||||||
|
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 : PDList;
|
||||||
|
writeCallback : PPHIOHook;
|
||||||
|
readCallback : PPHIOHook;
|
||||||
|
maxSectorCount : uint32;
|
||||||
|
sectorSize : uint32; //in bytes
|
||||||
|
start : uint32; //start of device in sectors
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Generic storage volume }
|
||||||
|
TStorage_Volume = record
|
||||||
|
id : uint32;
|
||||||
|
device : PStorage_device;
|
||||||
|
name : pchar;
|
||||||
|
fileSystem : TFileSystemType;
|
||||||
|
size : uint32; //size of volume in sectors
|
||||||
|
start : uint32; //start of volume in sectors
|
||||||
|
end;
|
||||||
|
|
||||||
|
PStorage_Volume = ^TStorage_Volume;
|
||||||
|
|
||||||
|
TDrive_Error = record
|
||||||
|
code : uint16;
|
||||||
|
description : pchar;
|
||||||
|
recoverable : boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
108
src/driver/storage/volumemanager.pas
Normal file
108
src/driver/storage/volumemanager.pas
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// 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 - Volume manager for storage devices.
|
||||||
|
|
||||||
|
@author(Aaron Hance ah@aaronhance.me)
|
||||||
|
}
|
||||||
|
|
||||||
|
unit volumemanager;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
console,
|
||||||
|
drivermanagement,
|
||||||
|
drivertypes,
|
||||||
|
lists,
|
||||||
|
lmemorymanager,
|
||||||
|
MBR,
|
||||||
|
rtc,
|
||||||
|
serial,
|
||||||
|
storagetypes,
|
||||||
|
strings,
|
||||||
|
terminal,
|
||||||
|
tracer,
|
||||||
|
util;
|
||||||
|
|
||||||
|
var
|
||||||
|
storageDevices : PDList; //index in this array is global drive id
|
||||||
|
volumes : PDList;
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
procedure register_device(device : PStorage_Device);
|
||||||
|
function discover_volumes(device : PStorage_device) : PDList;
|
||||||
|
|
||||||
|
function get_volume_list() : PDList;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
begin
|
||||||
|
push_trace('VolumeManager.init');
|
||||||
|
|
||||||
|
storageDevices := DL_New(sizeof(PStorage_Device));
|
||||||
|
volumes := DL_New(sizeof(PStorage_Volume));
|
||||||
|
|
||||||
|
//TODO register commnads
|
||||||
|
pop_trace();
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure register_device(device : PStorage_Device);
|
||||||
|
var
|
||||||
|
diskVolumes : PDList;
|
||||||
|
begin
|
||||||
|
push_trace('VolumeManager.register_device');
|
||||||
|
|
||||||
|
DL_Add(storageDevices);
|
||||||
|
DL_Set(storageDevices, DL_Size(storageDevices) - 1, puint32(device));
|
||||||
|
|
||||||
|
diskVolumes := discover_volumes(device);
|
||||||
|
|
||||||
|
if volumes <> nil then begin
|
||||||
|
volumes := DL_Concat(volumes, diskVolumes);
|
||||||
|
end;
|
||||||
|
|
||||||
|
pop_trace();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function discover_volumes(device : PStorage_device) : PDList;
|
||||||
|
begin
|
||||||
|
push_trace('VolumeManager.discover_volumes');
|
||||||
|
|
||||||
|
discover_volumes := nil;
|
||||||
|
//TODO implement
|
||||||
|
|
||||||
|
pop_trace();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_volume_list() : PDList;
|
||||||
|
var
|
||||||
|
newList : PDList;
|
||||||
|
i : uint32;
|
||||||
|
begin
|
||||||
|
push_trace('VolumeManager.get_volume_list');
|
||||||
|
|
||||||
|
//get copy of volume list
|
||||||
|
newList := DL_New(sizeof(PStorage_Volume)); //TODO need to add DL_Copy function
|
||||||
|
|
||||||
|
for i := 0 to DL_Size(volumes) - 1 do begin
|
||||||
|
DL_Add(newList);
|
||||||
|
DL_Set(newList, i, DL_Get(volumes, i));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
@ -143,22 +143,6 @@ type
|
|||||||
|
|
||||||
PText = ^Text;
|
PText = ^Text;
|
||||||
|
|
||||||
var
|
|
||||||
AK_START : uint32; external name 'kernel_start';
|
|
||||||
AK_END : uint32; external name 'kernel_end';
|
|
||||||
ASURO_KERNEL_START : uint32;
|
|
||||||
ASURO_KERNEL_END : uint32;
|
|
||||||
ASURO_KERNEL_SIZE : uint32;
|
|
||||||
|
|
||||||
procedure init();
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
procedure init();
|
|
||||||
begin
|
|
||||||
ASURO_KERNEL_START := uint32(@AK_START);
|
|
||||||
ASURO_KERNEL_END := uint32(@AK_END);
|
|
||||||
ASURO_KERNEL_SIZE:= ASURO_KERNEL_END - ASURO_KERNEL_START;
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -335,6 +335,7 @@ begin
|
|||||||
//serial.sendString('[outb]');
|
//serial.sendString('[outb]');
|
||||||
//serial.sendHex(port);
|
//serial.sendHex(port);
|
||||||
//serial.sendHex(val);
|
//serial.sendHex(val);
|
||||||
|
psleep(1);
|
||||||
asm
|
asm
|
||||||
PUSH EAX
|
PUSH EAX
|
||||||
PUSH EDX
|
PUSH EDX
|
||||||
|
@ -33,6 +33,8 @@ procedure init;
|
|||||||
procedure registerISR(INT_N : uint8; callback : TISRHook);
|
procedure registerISR(INT_N : uint8; callback : TISRHook);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
uses
|
||||||
|
console;
|
||||||
|
|
||||||
var
|
var
|
||||||
Hooks : TISRHookArray;
|
Hooks : TISRHookArray;
|
||||||
@ -56,6 +58,13 @@ var
|
|||||||
i : uint8;
|
i : uint8;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
// if int_n <> $20 then begin
|
||||||
|
// console.writestring('ISR: ');
|
||||||
|
// console.writehexpair(Int_N);
|
||||||
|
// console.writestringln(' called');
|
||||||
|
// end;
|
||||||
|
|
||||||
for i:=0 to MAX_HOOKS do begin
|
for i:=0 to MAX_HOOKS do begin
|
||||||
if Hooks[INT_N][i] <> nil then Hooks[INT_N][i]();
|
if Hooks[INT_N][i] <> nil then Hooks[INT_N][i]();
|
||||||
end;
|
end;
|
||||||
|
@ -40,10 +40,13 @@ uses
|
|||||||
testdriver,
|
testdriver,
|
||||||
E1000,
|
E1000,
|
||||||
IDE,
|
IDE,
|
||||||
storagemanagement,
|
// storagemanagement,
|
||||||
|
// drivemanager,
|
||||||
|
volumemanager,
|
||||||
lists,
|
lists,
|
||||||
net,
|
net,
|
||||||
fat32,
|
// fat32,
|
||||||
|
// flatfs,
|
||||||
isrmanager,
|
isrmanager,
|
||||||
faults,
|
faults,
|
||||||
fonts,
|
fonts,
|
||||||
@ -54,7 +57,8 @@ uses
|
|||||||
base64,
|
base64,
|
||||||
rand,
|
rand,
|
||||||
terminal,
|
terminal,
|
||||||
hashmap, vfs;
|
hashmap, vfs,
|
||||||
|
AHCI;
|
||||||
|
|
||||||
procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall;
|
procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall;
|
||||||
|
|
||||||
@ -125,9 +129,6 @@ var
|
|||||||
HM : PHashMap;
|
HM : PHashMap;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
{ Init the base system unit }
|
|
||||||
System.init();
|
|
||||||
|
|
||||||
{ Serial Init }
|
{ Serial Init }
|
||||||
serial.init();
|
serial.init();
|
||||||
|
|
||||||
@ -208,7 +209,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');
|
||||||
@ -216,7 +219,8 @@ begin
|
|||||||
TMR_0_ISR.hook(uint32(@bios_data_area.tick_update));
|
TMR_0_ISR.hook(uint32(@bios_data_area.tick_update));
|
||||||
|
|
||||||
{ Filsystems }
|
{ Filsystems }
|
||||||
fat32.init();
|
// fat32.init();
|
||||||
|
// flatfs.init();
|
||||||
|
|
||||||
{ Device Drivers }
|
{ Device Drivers }
|
||||||
tracer.push_trace('kmain.DEVDRV');
|
tracer.push_trace('kmain.DEVDRV');
|
||||||
@ -225,7 +229,8 @@ begin
|
|||||||
mouse.init();
|
mouse.init();
|
||||||
testdriver.init();
|
testdriver.init();
|
||||||
E1000.init();
|
E1000.init();
|
||||||
IDE.init();
|
// IDE.init();
|
||||||
|
AHCI.init();
|
||||||
console.outputln('KERNEL', 'DEVICE DRIVERS: INIT END.');
|
console.outputln('KERNEL', 'DEVICE DRIVERS: INIT END.');
|
||||||
|
|
||||||
{ Bus Drivers }
|
{ Bus Drivers }
|
||||||
|
@ -57,6 +57,7 @@ var
|
|||||||
|
|
||||||
procedure init;
|
procedure init;
|
||||||
function kalloc(size : uint32) : void;
|
function kalloc(size : uint32) : void;
|
||||||
|
function kalloc(size : uint32; isPersistent : boolean) : void;
|
||||||
function klalloc(size : uint32) : void;
|
function klalloc(size : uint32) : void;
|
||||||
procedure klfree(size : uint32); //Todo ??? Profit?
|
procedure klfree(size : uint32); //Todo ??? Profit?
|
||||||
function kpalloc(address : uint32) : void;
|
function kpalloc(address : uint32) : void;
|
||||||
@ -217,6 +218,11 @@ begin
|
|||||||
//pop_trace;
|
//pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function kalloc(size : uint32; isPersistent : boolean) : void;
|
||||||
|
begin
|
||||||
|
kalloc:= kalloc(size);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure kfree(area : void);
|
procedure kfree(area : void);
|
||||||
var
|
var
|
||||||
hp : PHeapPage;
|
hp : PHeapPage;
|
||||||
|
@ -22,7 +22,15 @@ unit edit;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
console, terminal, keyboard, shell, strings, tracer, storagemanagement, lmemorymanager, util;
|
console,
|
||||||
|
keyboard,
|
||||||
|
lmemorymanager,
|
||||||
|
shell,
|
||||||
|
storagemanagement,
|
||||||
|
strings,
|
||||||
|
terminal,
|
||||||
|
tracer,
|
||||||
|
util;
|
||||||
|
|
||||||
procedure init();
|
procedure init();
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ uses
|
|||||||
tracer, console,
|
tracer, console,
|
||||||
//progs
|
//progs
|
||||||
base64_prog, md5sum, shell, terminal,
|
base64_prog, md5sum, shell, terminal,
|
||||||
edit, netlog, themer,
|
netlog, themer,
|
||||||
memview, udpcat, dhclient, vbeinfo;
|
memview, udpcat, dhclient, vbeinfo;
|
||||||
|
|
||||||
{ Initialize all baked-in programs }
|
{ Initialize all baked-in programs }
|
||||||
@ -43,8 +43,8 @@ begin
|
|||||||
themer.init();
|
themer.init();
|
||||||
tracer.push_trace('progmanager.netlog.init');
|
tracer.push_trace('progmanager.netlog.init');
|
||||||
netlog.init();
|
netlog.init();
|
||||||
tracer.push_trace('progmanager.edit.init');
|
// tracer.push_trace('progmanager.edit.init');
|
||||||
edit.init();
|
// edit.init();
|
||||||
tracer.push_trace('progmanager.udpcat.init');
|
tracer.push_trace('progmanager.udpcat.init');
|
||||||
udpcat.init();
|
udpcat.init();
|
||||||
tracer.push_trace('progmanager.md5sum.init');
|
tracer.push_trace('progmanager.md5sum.init');
|
||||||
|
@ -52,7 +52,6 @@ if ($Command -eq 'up') {
|
|||||||
}
|
}
|
||||||
Receive-Job $MonitorJob
|
Receive-Job $MonitorJob
|
||||||
}
|
}
|
||||||
Get-Job | Stop-Job | Remove-Job -Force
|
|
||||||
} elseif ($Command -eq 'down') {
|
} elseif ($Command -eq 'down') {
|
||||||
Write-Output "Stopping $MachineName"
|
Write-Output "Stopping $MachineName"
|
||||||
VBoxManage.exe controlvm $MachineName poweroff
|
VBoxManage.exe controlvm $MachineName poweroff
|
||||||
|
Loading…
x
Reference in New Issue
Block a user