Compare commits
	
		
			41 Commits
		
	
	
		
			1.1.2
			...
			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 | |||
| 346dc4e4c9 | |||
| b2eee58df4 | |||
| 170b93dd69 | |||
| 34d6873a6a | |||
| 94b477d8f7 | |||
| ba38f4fd19 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -10,5 +10,4 @@ | |||||||
| /*.sh~ | /*.sh~ | ||||||
| /*.img | /*.img | ||||||
| src/include/asuro.pas | src/include/asuro.pas | ||||||
| .vscode/launch.json | localenv.json | ||||||
| .vscode |  | ||||||
|   | |||||||
| @@ -61,11 +61,13 @@ docgen: | |||||||
|   script: |   script: | ||||||
|     - ./compile_sourcelist.sh |     - ./compile_sourcelist.sh | ||||||
|     - ./compile_docs.sh |     - ./compile_docs.sh | ||||||
|     - ln -s doc public |     # Remove comments when we want to use gitlab pages. | ||||||
|  |     #- cp doc public | ||||||
|   allow_failure: true |   allow_failure: true | ||||||
|   artifacts: |   artifacts: | ||||||
|     paths: |     paths: | ||||||
|       - public |       - doc | ||||||
|       - ./sources.list |       #- public/* | ||||||
|  |       #- ./sources.list | ||||||
|   needs: |   needs: | ||||||
|     - versions |     - versions | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @@ -3,18 +3,11 @@ | |||||||
|         { |         { | ||||||
|             "name":"Run", |             "name":"Run", | ||||||
|             "request": "launch", |             "request": "launch", | ||||||
|             "type": "coreclr", |             "type": "PowerShell", | ||||||
|             "preLaunchTask": "Build", |             "preLaunchTask": "Build", | ||||||
|             "program": "VBoxSDL", |             "script": "${workspaceFolder}/virtualbox-wrapper.ps1", | ||||||
|             "args": [ |             "args": ["-Command", "up"], | ||||||
|                 "--comment",  |  | ||||||
|                 "Asuro",  |  | ||||||
|                 "--startvm",  |  | ||||||
|                 "7d395c96-891c-4139-b77d-9b6b144b0b93" |  | ||||||
|             ], |  | ||||||
|             "cwd": "${workspaceFolder}", |             "cwd": "${workspaceFolder}", | ||||||
|             "console": "internalConsole", |  | ||||||
|             "internalConsoleOptions": "neverOpen" |  | ||||||
|         } |         } | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
							
								
								
									
										26
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							| @@ -9,14 +9,18 @@ | |||||||
|             "command": "docker-compose", |             "command": "docker-compose", | ||||||
|             "args": [ |             "args": [ | ||||||
|                 "run", |                 "run", | ||||||
|                 "builder" |                 "builder", | ||||||
|             ], |             ], | ||||||
|             "type": "shell", |             "type": "shell", | ||||||
|             "problemMatcher": [], |             "problemMatcher": [], | ||||||
|             "group": { |             "group": { | ||||||
|                 "kind": "build", |                 "kind": "build", | ||||||
|                 "isDefault": true |                 "isDefault": true | ||||||
|             } |             }, | ||||||
|  |             "dependsOn": [ | ||||||
|  |                 "Close VirtualBox", | ||||||
|  |                 "Clean" | ||||||
|  |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "label": "Build (Builder)", |             "label": "Build (Builder)", | ||||||
| @@ -26,6 +30,24 @@ | |||||||
|                 "builder" |                 "builder" | ||||||
|             ], |             ], | ||||||
|             "type": "shell" |             "type": "shell" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Clean", | ||||||
|  |             "command": "docker-compose", | ||||||
|  |             "args": [ | ||||||
|  |                 "down", | ||||||
|  |                 "--remove-orphans" | ||||||
|  |             ], | ||||||
|  |             "type": "shell" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Close VirtualBox", | ||||||
|  |             "command": "./virtualbox-wrapper.ps1", | ||||||
|  |             "args": [ | ||||||
|  |                 "-Command",  | ||||||
|  |                 "down" | ||||||
|  |             ], | ||||||
|  |             "type": "shell" | ||||||
|         } |         } | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
| @@ -4,4 +4,4 @@ echo "=======================" | |||||||
| echo " " | echo " " | ||||||
| echo "Compiling FPC Sources..." | echo "Compiling FPC Sources..." | ||||||
| echo " " | echo " " | ||||||
| fpc -Aelf -gw -n -va -O3 -Op3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas | fpc -Aelf -gw -n -O3 -Op3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/storage/* -Fusrc/driver/storage/AHCI/* -Fusrc/driver/* -Fusrc/driver/net/*  src/kernel.pas | ||||||
							
								
								
									
										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 | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
| @@ -1,4 +1,3 @@ | |||||||
| version: "3.9" |  | ||||||
| services: | services: | ||||||
|   builder: |   builder: | ||||||
|     build: . |     build: . | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								readme.md
									
									
									
									
									
								
							| @@ -13,8 +13,8 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f | |||||||
|     I don't think this needs an explaination. |     I don't think this needs an explaination. | ||||||
| * [VSCode (Optional, but highly recommended)](https://code.visualstudio.com/) | * [VSCode (Optional, but highly recommended)](https://code.visualstudio.com/) | ||||||
|     Visual Studio code is our IDE of choice, and we have a number of recommended plugins. |     Visual Studio code is our IDE of choice, and we have a number of recommended plugins. | ||||||
|     * [C# Plugin by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) |     * [PowerShell Plugin by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-vscode.powershell) | ||||||
|         This plugin gives you the ability to use the 'coreclr' task type, allowing the automatic launching of virtualbox with the resulting image generated during compilation of Asuro. |         This plugin gives you the ability to use the 'PowerShell' task type, allowing the automatic launching of virtualbox with the resulting image generated during compilation of Asuro. | ||||||
| * [VirtualBox](https://www.virtualbox.org/) | * [VirtualBox](https://www.virtualbox.org/) | ||||||
|     Virtualbox is our Virtualisation environment of choice, don't ask why, it just is. |     Virtualbox is our Virtualisation environment of choice, don't ask why, it just is. | ||||||
|  |  | ||||||
| @@ -27,15 +27,15 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f | |||||||
| 3. Install Docker for Windows. | 3. Install Docker for Windows. | ||||||
| 4. Install Git for Windows. | 4. Install Git for Windows. | ||||||
| 5. Install VSCode & the listed plugins. | 5. Install VSCode & the listed plugins. | ||||||
| 6. Install VirtualBox. | 6. Install VirtualBox (v7+). | ||||||
| 7. Clone this repository. | 7. Clone this repository. | ||||||
| 8. Run the following command in the root of the repo to build the docker image: | 8. Run the following command in the root of the repo to build the docker image: | ||||||
|     ```powershell |     ```powershell | ||||||
|     docker-compose build builder |     docker compose build builder | ||||||
|     ``` |     ``` | ||||||
| 9. Run the following command to compile Asuro: | 9. Run the following command to compile Asuro: | ||||||
|     ```powershell |     ```powershell | ||||||
|     docker-compose run builder |     docker compose run builder | ||||||
|     ``` |     ``` | ||||||
| 10. Create a new virtual machine in Virtualbox and mount the `Asuro.iso` generated in step 9 as a boot image. | 10. Create a new virtual machine in Virtualbox and mount the `Asuro.iso` generated in step 9 as a boot image. | ||||||
| 11. Add the virtualbox installation directory to your `%PATH%` environment variable, usually: | 11. Add the virtualbox installation directory to your `%PATH%` environment variable, usually: | ||||||
| @@ -50,32 +50,29 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f | |||||||
|     ```xml |     ```xml | ||||||
|     <Machine uuid="{7d395c96-891c-4139-b77d-9b6b144b0b93}" name="Asuro" OSType="Linux" snapshotFolder="Snapshots" lastStateChange="2021-06-20T20:33:07Z"> |     <Machine uuid="{7d395c96-891c-4139-b77d-9b6b144b0b93}" name="Asuro" OSType="Linux" snapshotFolder="Snapshots" lastStateChange="2021-06-20T20:33:07Z"> | ||||||
|     ``` |     ``` | ||||||
|     Copy the uuid, in our case `7d395c96-891c-4139-b77d-9b6b144b0b93` and replace the uuid found in `.vscode\launch.json` under `args`, so that it looks something like this: |     Copy the uuid, in our case `7d395c96-891c-4139-b77d-9b6b144b0b93` & create a `localenv.json` file in the project root with the following content: | ||||||
|     ```json |     ```json | ||||||
|     { |     { | ||||||
|         "configurations": [ |         "VirtualBox":{ | ||||||
|             { |             "MachineName":"<YOUR_UUID_OR_MACHINE_NAME>" | ||||||
|                 "name":"Run", |  | ||||||
|                 "request": "launch", |  | ||||||
|                 "type": "coreclr", |  | ||||||
|                 "preLaunchTask": "Build", |  | ||||||
|                 "program": "VBoxSDL", |  | ||||||
|                 "args": [ |  | ||||||
|                     "--comment",  |  | ||||||
|                     "Asuro",  |  | ||||||
|                     "--startvm",  |  | ||||||
|                     "<YOUR UUID HERE>" |  | ||||||
|                 ], |  | ||||||
|                 "cwd": "${workspaceFolder}", |  | ||||||
|                 "console": "internalConsole", |  | ||||||
|                 "internalConsoleOptions": "neverOpen" |  | ||||||
|         } |         } | ||||||
|         ] |  | ||||||
|     } |     } | ||||||
|     ``` |     ``` | ||||||
|     This will allow VSCode to automatically launch VirtualBox once Asuro has been compiled. |     This will allow VSCode to automatically launch VirtualBox once Asuro has been compiled. | ||||||
|  |      | ||||||
|  |     You can also enable the serial adapter "COM1" in mode "Raw File", give it a path, and provide this path in the `localenv.json` as follows: | ||||||
|  |     ```json | ||||||
|  |     { | ||||||
|  |         "VirtualBox" : { | ||||||
|  |             "MachineName": "<YOUR_UUID_OR_MACHINE_NAME>", | ||||||
|  |             "LogLocation": "Fully\\Qualified\\Path\\To\\Your\\Log\\File" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ``` | ||||||
|  |     This will allow you to see the console output from Asuro in your host terminal. | ||||||
| 13. Open your project folder in VSCode, use CTRL+SHIFT+B to build & F5 to build + run in VBox. | 13. Open your project folder in VSCode, use CTRL+SHIFT+B to build & F5 to build + run in VBox. | ||||||
| 14. Congratulations! You can now play with Asuro! | 14. Congratulations! You can now play with Asuro! | ||||||
|  |  | ||||||
| ### Gotchas | ### Notes & Gotchas | ||||||
|  | - The above process has been updated to be compatible with VirtualBox 7+, in which VBoxSDL was removed and vboxmanage should be used in its place. A small wrapper powershell script is used to achieve this. | ||||||
| - It was noted that Windows builds above `20H2` seem to have issues installing WSL2. We may have to wait for a patch from Microsoft to fix this. Our devs are currently using build `20H2`. | - It was noted that Windows builds above `20H2` seem to have issues installing WSL2. We may have to wait for a patch from Microsoft to fix this. Our devs are currently using build `20H2`. | ||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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. | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -16,6 +16,7 @@ | |||||||
| 	Include->Strings - String Manipulation. | 	Include->Strings - String Manipulation. | ||||||
| 	 | 	 | ||||||
| 	@author(Kieron Morris <kjm@kieronmorris.me>) | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  |     @author(Aaron Hance <ah@aaronhance.me>) | ||||||
| } | } | ||||||
| unit strings; | unit strings; | ||||||
|  |  | ||||||
| @@ -33,6 +34,10 @@ function stringCopy(str : pchar) : pchar; | |||||||
| function stringNew(size : uint32) : pchar; | function stringNew(size : uint32) : pchar; | ||||||
| function stringSize(str : pchar) : uint32; | function stringSize(str : pchar) : uint32; | ||||||
| function stringConcat(str1, str2 : pchar) : pchar; | function stringConcat(str1, str2 : pchar) : pchar; | ||||||
|  | function stringTrim(str : pchar; length : uint32) : pchar; | ||||||
|  | function stringSub(str : pchar; start, size : uint32) : pchar; | ||||||
|  | function stringReplace(str, find, replace : pchar) : pchar; | ||||||
|  | function stringIndexOf(str, find : pchar) : sint32; | ||||||
| function stringContains(str : pchar; sub : pchar) : boolean; | function stringContains(str : pchar; sub : pchar) : boolean; | ||||||
| function stringToInt(str : pchar) : uint32; | function stringToInt(str : pchar) : uint32; | ||||||
| function hexStringToInt(str : pchar) : uint32; | function hexStringToInt(str : pchar) : uint32; | ||||||
| @@ -151,6 +156,94 @@ begin | |||||||
|     stringConcat:= result; |     stringConcat:= result; | ||||||
| end; | end; | ||||||
|  |  | ||||||
|  | // Trim the string to the specified length. | ||||||
|  | function stringTrim(str : pchar; length : uInt32) : pchar; | ||||||
|  | var | ||||||
|  |     result : pchar; | ||||||
|  | begin | ||||||
|  |     result:= stringNew(length); | ||||||
|  |     memcpy(uint32(str), uint32(result), length); | ||||||
|  |     stringTrim:= result; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | // Return a substring of the string. | ||||||
|  | function stringSub(str : pchar; start, size : uint32) : pchar; | ||||||
|  | var | ||||||
|  |     result : pchar; | ||||||
|  | begin | ||||||
|  |     result:= stringNew(size); | ||||||
|  |     memcpy(uint32(str)+start, uint32(result), size); | ||||||
|  |     stringSub:= result; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | // Replace first instance of a string with another. | ||||||
|  | function stringReplace(str, find, replace : pchar) : pchar; | ||||||
|  | var | ||||||
|  |     result : pchar; | ||||||
|  |     i, j, k : uint32; | ||||||
|  |     found : boolean; | ||||||
|  | begin | ||||||
|  |  | ||||||
|  |     // Find the first instance of the find string. | ||||||
|  |     i:= 0; | ||||||
|  |     found:= false; | ||||||
|  |     while (i < stringSize(str)) and (not found) do begin | ||||||
|  |         if stringEquals(str+i, find) then begin | ||||||
|  |             found:= true; | ||||||
|  |         end else begin | ||||||
|  |             inc(i); | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
|  |  | ||||||
|  |     // If we found the find string, replace it. | ||||||
|  |     if found then begin | ||||||
|  |         result:= stringNew(stringSize(str) - stringSize(find) + stringSize(replace)); | ||||||
|  |         j:= 0; | ||||||
|  |         k:= 0; | ||||||
|  |         while i < stringSize(str) do begin | ||||||
|  |             if stringEquals(str+i, find) then begin | ||||||
|  |                 memcpy(uint32(replace), uint32(result+j), stringSize(replace)); | ||||||
|  |                 j:= j + stringSize(replace); | ||||||
|  |                 inc(i, stringSize(find)); | ||||||
|  |             end else begin | ||||||
|  |                 result[j]:= str[i]; | ||||||
|  |                 inc(j); | ||||||
|  |                 inc(i); | ||||||
|  |             end; | ||||||
|  |         end; | ||||||
|  |         stringReplace:= result; | ||||||
|  |     end else begin | ||||||
|  |         stringReplace:= stringCopy(str); | ||||||
|  |     end; | ||||||
|  |  | ||||||
|  |     // Return the result. | ||||||
|  |     stringReplace:= result; | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Find the index of the first instance of a string. | ||||||
|  | function stringIndexOf(str, find : pchar) : sint32; | ||||||
|  | var  | ||||||
|  |     i : uint32; | ||||||
|  |     found : boolean; | ||||||
|  | begin | ||||||
|  |     i:= 0; | ||||||
|  |     found:= false; | ||||||
|  |     while (i < stringSize(str)) and (not found) do begin | ||||||
|  |         if stringEquals(str+i, find) then begin | ||||||
|  |             found:= true; | ||||||
|  |         end else begin | ||||||
|  |             inc(i); | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
|  |     if found then begin | ||||||
|  |         stringIndexOf:= i; | ||||||
|  |     end else begin | ||||||
|  |         stringIndexOf:= -1; | ||||||
|  |     end; | ||||||
|  | end; | ||||||
|  |  | ||||||
| function stringContains(str : pchar; sub : pchar) : boolean; | function stringContains(str : pchar; sub : pchar) : boolean; | ||||||
| var | var | ||||||
|     strEnd, subEnd, i, j, count : uint32; |     strEnd, subEnd, i, j, count : uint32; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   |   | ||||||
| @@ -205,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'); | ||||||
| @@ -213,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'); | ||||||
| @@ -222,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'); | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								virtualbox-wrapper.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								virtualbox-wrapper.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | <#  | ||||||
|  | You need a local git-ignored localenv.json file with the following content: | ||||||
|  | { | ||||||
|  |   "virtualbox": { | ||||||
|  |     "MachineName": "your-machine-name or guid" | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | #> | ||||||
|  |  | ||||||
|  | param ( | ||||||
|  |   [Parameter(Mandatory=$true)] | ||||||
|  |   [ValidateSet('up', 'down')] | ||||||
|  |   [String]$Command | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | $Config = Get-Content .\localenv.json | ConvertFrom-Json | ||||||
|  | $MachineName = $Config.virtualbox.MachineName | ||||||
|  | $LogLocation = $Config.virtualbox.LogLocation | ||||||
|  | $LogOutputEnabled = $LogLocation -ne $null | ||||||
|  |  | ||||||
|  | if ($Command -eq 'up') { | ||||||
|  |  | ||||||
|  |   if($LogOutputEnabled) { | ||||||
|  |     Clear-Content $LogLocation | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   $MonitorJob = Start-Job -ArgumentList $MachineName -ScriptBlock { | ||||||
|  |     param($MachineName) | ||||||
|  |     Write-Output "Starting $MachineName" | ||||||
|  |     VBoxManage.exe startvm $MachineName | ||||||
|  |     $running=$true | ||||||
|  |     while($running) { | ||||||
|  |       $status=(VBoxManage.exe list runningvms) | ||||||
|  |       if($status) { | ||||||
|  |         $running=$status.contains($MachineName) | ||||||
|  |       } else { | ||||||
|  |         $running=$false | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   if($LogOutputEnabled) { | ||||||
|  |     $LogJob = Start-Job -ArgumentList $LogLocation -ScriptBlock { | ||||||
|  |       param($LogLocation) | ||||||
|  |       Get-Content -Path $LogLocation -Wait | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   while($MonitorJob.State -eq 'Running') { | ||||||
|  |     if($LogOutputEnabled) { | ||||||
|  |       Receive-Job $LogJob | ||||||
|  |     } | ||||||
|  |     Receive-Job $MonitorJob | ||||||
|  |   } | ||||||
|  | } elseif ($Command -eq 'down') { | ||||||
|  |   Write-Output "Stopping $MachineName" | ||||||
|  |   VBoxManage.exe controlvm $MachineName poweroff | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user