Compare commits
	
		
			37 Commits
		
	
	
		
			feature/st
			...
			feature/vi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8be364c990 | |||
| 0e2c6b2936 | |||
| 632c3fa66b | |||
| 875e3e4765 | |||
| e28d68128d | |||
| a9969d58f8 | |||
| d7a54d858d | |||
| 4e991c3e6f | |||
| a3217de71a | |||
| 19b433a19f | |||
| 69d1d22a18 | |||
| 5c15343ed0 | |||
| 3ae349fbc8 | |||
| 78c060c114 | |||
| cd925e96c2 | |||
| 142dd486dd | |||
| beeeabd441 | |||
| b73c66f6d6 | |||
| 189526cab8 | |||
| 595dd4fbac | |||
| ba6d8037d2 | |||
| 208bda92c8 | |||
| a7111d3cac | |||
| d182fd7f46 | |||
| 4c5038b001 | |||
| 98481ea1ce | |||
| b5582b1284 | |||
| 161cea4920 | |||
| 6b81c4ece0 | |||
| ee17f69115 | |||
| 81c19bff16 | |||
| e7cda58113 | |||
| 44f18554e1 | |||
| 52b42ec975 | |||
| 2815dd9e4d | |||
| d057bfc3ff | |||
| e4621c8aaa | 
							
								
								
									
										52
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | kind: pipeline | ||||||
|  | type: docker | ||||||
|  | name: build | ||||||
|  |  | ||||||
|  | steps: | ||||||
|  |   - name: build-image | ||||||
|  |     image: plugins/docker | ||||||
|  |     settings: | ||||||
|  |       repo: t3hn3rd/asuro-build | ||||||
|  |       tags: latest | ||||||
|  |       dockerfile: Dockerfile | ||||||
|  |       registry: docker.io | ||||||
|  |       username: | ||||||
|  |         from_secret: docker_username | ||||||
|  |       password: | ||||||
|  |         from_secret: docker_password | ||||||
|  |  | ||||||
|  |   - name: compile | ||||||
|  |     image: t3hn3rd/asuro-build:latest | ||||||
|  |     depends_on: | ||||||
|  |       - build-image | ||||||
|  |     commands: | ||||||
|  |       - git fetch --tags | ||||||
|  |       - find . -type f -print0 | xargs -0 dos2unix | ||||||
|  |       - chmod +x /drone/src/*.sh | ||||||
|  |       - /drone/src/compile.sh | ||||||
|  |  | ||||||
|  |   - name: upload-iso-artifact | ||||||
|  |     image: alpine/git | ||||||
|  |     depends_on: | ||||||
|  |       - compile | ||||||
|  |     when: | ||||||
|  |       branch: | ||||||
|  |         - master | ||||||
|  |     environment: | ||||||
|  |       GITEA_TOKEN: | ||||||
|  |         from_secret: gitea_token | ||||||
|  |     commands: | ||||||
|  |       - apk add --no-cache curl | ||||||
|  |       - chmod +w Asuro.iso | ||||||
|  |       - cp Asuro.iso "Asuro-$(git rev-parse --short HEAD).iso" | ||||||
|  |       - echo "Uploading Asuro-$(git rev-parse --short HEAD).iso to Gitea Packages..." | ||||||
|  |       - | | ||||||
|  |          curl -X PUT "https://gitea.spexeah.com/api/packages/Spexeah/generic/asuro-iso/$(git rev-parse --short HEAD)/Asuro.iso" \ | ||||||
|  |          -H "Authorization: token $GITEA_TOKEN" --upload-file "Asuro-$(git rev-parse --short HEAD).iso" | ||||||
|  |       - echo "Updating latest ISO reference..." | ||||||
|  |       - | | ||||||
|  |         curl -X DELETE https://gitea.spexeah.com/api/packages/Spexeah/generic/asuro-iso/latest/Asuro.iso \ | ||||||
|  |         -H "Authorization: token $GITEA_TOKEN" || echo "No previous latest version found." | ||||||
|  |       - | | ||||||
|  |         curl -X PUT https://gitea.spexeah.com/api/packages/Spexeah/generic/asuro-iso/latest/Asuro.iso \ | ||||||
|  |         -H "Authorization: token $GITEA_TOKEN" --upload-file "Asuro-$(git rev-parse --short HEAD).iso" | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| stages: |  | ||||||
|   - Compile Versions |  | ||||||
|   - Compile Sources |  | ||||||
|   - Link |  | ||||||
|   - Generate Documentation |  | ||||||
|   - Deploy |  | ||||||
|  |  | ||||||
| cache: |  | ||||||
|   - key: ${CI_COMMIT_REF_SLUG} |  | ||||||
|     paths: |  | ||||||
|       - lib/*.o |  | ||||||
|       - bin/kernel.bin |  | ||||||
|       - doc |  | ||||||
|  |  | ||||||
| before_script: |  | ||||||
|   - chmod +x *.sh |  | ||||||
|  |  | ||||||
| versions: |  | ||||||
|   stage: Compile Versions |  | ||||||
|   script: |  | ||||||
|     - ./compile_vergen.sh |  | ||||||
|   artifacts: |  | ||||||
|     paths: |  | ||||||
|       - release/*.svg |  | ||||||
|       - src/include/asuro.pas |  | ||||||
|  |  | ||||||
| compile_sources: |  | ||||||
|   stage: Compile Sources |  | ||||||
|   script: |  | ||||||
|     - rm -f lib/*.so |  | ||||||
|     - ./compile_sources.sh |  | ||||||
|   needs: |  | ||||||
|     - versions |  | ||||||
|  |  | ||||||
| link: |  | ||||||
|   stage: Link |  | ||||||
|   script: |  | ||||||
|     - ./compile_stub.sh |  | ||||||
|     - ./compile_link.sh |  | ||||||
|   needs: |  | ||||||
|     - versions |  | ||||||
|     - compile_sources |  | ||||||
|  |  | ||||||
| isogen: |  | ||||||
|   stage: Deploy |  | ||||||
|   script: |  | ||||||
|     - ./compile_isogen.sh |  | ||||||
|     - ./compile_sumgen.sh |  | ||||||
|   artifacts: |  | ||||||
|     paths: |  | ||||||
|       - ./Asuro.iso |  | ||||||
|       - ./release/checksum.svg |  | ||||||
|   needs: |  | ||||||
|     - link |  | ||||||
|  |  | ||||||
| docgen: |  | ||||||
|   stage: Generate Documentation |  | ||||||
|   only: |  | ||||||
|     - master |  | ||||||
|     - develop |  | ||||||
|   script: |  | ||||||
|     - ./compile_sourcelist.sh |  | ||||||
|     - ./compile_docs.sh |  | ||||||
|     # Remove comments when we want to use gitlab pages. |  | ||||||
|     #- cp doc public |  | ||||||
|   allow_failure: true |  | ||||||
|   artifacts: |  | ||||||
|     paths: |  | ||||||
|       - doc |  | ||||||
|       #- public/* |  | ||||||
|       #- ./sources.list |  | ||||||
|   needs: |  | ||||||
|     - versions |  | ||||||
| @@ -16,7 +16,7 @@ RUN curl -sL https://sourceforge.net/projects/freepascal/files/Linux/$FPC_VERSIO | |||||||
|  |  | ||||||
| COPY compile.sh /compile.sh | COPY compile.sh /compile.sh | ||||||
| ADD https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver /usr/bin/semver | ADD https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver /usr/bin/semver | ||||||
| RUN mkdir /code && chmod +x /usr/bin/semver | RUN chmod +x /usr/bin/semver | ||||||
| WORKDIR /code | WORKDIR /code | ||||||
| RUN find . -type f -print0 | xargs -0 dos2unix | RUN find . -type f -print0 | xargs -0 dos2unix | ||||||
| ENTRYPOINT ["/bin/bash", "-c"] | ENTRYPOINT ["/bin/bash", "-c"] | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								compile.sh
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								compile.sh
									
									
									
									
									
								
							| @@ -20,26 +20,30 @@ runOrFail() { | |||||||
| 	fi | 	fi | ||||||
| } | } | ||||||
|  |  | ||||||
| runOrFail $(pwd)/compile_stub.sh "Failed to compile stub!" | declare -a run_steps=( | ||||||
|  | 	"compile_stub.sh" "Failed to compile stub!" | ||||||
|  | 	"compile_vergen.sh" "Versions failed to compile" | ||||||
|  | 	"compile_sources.sh" "Failed to compile FPC Sources!" | ||||||
|  | 	"compile_link.sh" "Failed linking!" | ||||||
|  | 	"compile_isogen.sh" "Failed to create ISO!" | ||||||
|  | ) | ||||||
|  |  | ||||||
| #Generate .pas with versioning headers. | for ((i=0; i<${#run_steps[@]}; i+=2)) | ||||||
| runOrFail $(pwd)/compile_vergen.sh "Versions failed to compile" | do | ||||||
|  | 	if [ "$ERRCOUNT" -eq "0" ] | ||||||
| #Compile all .pas sources | 	then | ||||||
| runOrFail $(pwd)/compile_sources.sh "Failed to compile FPC Sources!" | 			script=$(pwd)/"${run_steps[$i]}" | ||||||
|  | 			message="${run_steps[$i+1]}" | ||||||
| #Link into a binary. | 			runOrFail "$script" "$message" | ||||||
| runOrFail $(pwd)/compile_link.sh "Failed linking!" | 	fi | ||||||
|  | done | ||||||
| #Generate an ISO with GRUB as the Bootloader. |  | ||||||
| runOrFail ./compile_isogen.sh "Failed to create ISO!" |  | ||||||
|  |  | ||||||
| #Call generate final artifacts based on failure or success of the above. | #Call generate final artifacts based on failure or success of the above. | ||||||
| if [ "$ERRCOUNT" -ne "0" ] | if [ "$ERRCOUNT" -ne "0" ] | ||||||
| then | then | ||||||
| 	./compile_finish.sh "failed" | 	. ./compile_finish.sh "failed" | ||||||
| else | else | ||||||
| 	./compile_finish.sh "success" | 	. ./compile_finish.sh "success" | ||||||
| fi | fi | ||||||
|  |  | ||||||
| cd .. | cd .. | ||||||
| @@ -4,4 +4,4 @@ echo "=======================" | |||||||
| echo " " | echo " " | ||||||
| echo "Compiling FPC Sources..." | echo "Compiling FPC Sources..." | ||||||
| echo " " | echo " " | ||||||
| fpc -Aelf -gw -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 | fpc -Aelf -gw -g -gl -n -vlewn -O3 -Op3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| #Flat filesystem |  | ||||||
|  |  | ||||||
| A super simple filesystem for asuro. Folders are emulated in filenames. |  | ||||||
|  |  | ||||||
| Starts with disk info sector, sector 0 of volume |  | ||||||
|  |  | ||||||
| --- |  | ||||||
| #### disk info |  | ||||||
|  |  | ||||||
| jmp2boot        : ubit24; |  | ||||||
| OEMName         : array[0..7] of char; |  | ||||||
| version         : uint16 // numerical version of filesystem |  | ||||||
| sectorCount      : uint16; |  | ||||||
| fileCount       : uint16 |  | ||||||
| signature       : uint32 = 0x0B00B1E5 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| the Rest of the sector is reserved |  | ||||||
|  |  | ||||||
| --- |  | ||||||
|  |  | ||||||
| Starting from sector 1 is the file table. Table size is determined by entry size (64) * fileCount |  | ||||||
|  |  | ||||||
| --- |  | ||||||
| ####File entry |  | ||||||
|  |  | ||||||
| name : array[0..59] of char //file name max 60 chars |  | ||||||
| fileStart : 16bit // start sector of data |  | ||||||
| fileSize : 16bit // data size in sectors |  | ||||||
|  |  | ||||||
| --- |  | ||||||
|  |  | ||||||
| @@ -2,7 +2,7 @@ ENTRY(loader) | |||||||
| SECTIONS | SECTIONS | ||||||
| { | { | ||||||
|   . = 0xC0100000; |   . = 0xC0100000; | ||||||
|  |   kernel_start = .; | ||||||
|   .text : AT(ADDR(.text) - 0xC0000000) |   .text : AT(ADDR(.text) - 0xC0000000) | ||||||
|   { |   { | ||||||
|     text = .; _text = .; __text = .; |     text = .; _text = .; __text = .; | ||||||
| @@ -33,4 +33,5 @@ SECTIONS | |||||||
|     . = ALIGN(4096); |     . = ALIGN(4096); | ||||||
|   } |   } | ||||||
|   end = .; _end = .; __end = .; |   end = .; _end = .; __end = .; | ||||||
|  |   kernel_end = .; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1776,14 +1776,15 @@ var | |||||||
|    fb: puint32; |    fb: puint32; | ||||||
|  |  | ||||||
| Begin | Begin | ||||||
|  |      Ready:= False; | ||||||
|      fb:= puint32(uint32(multibootinfo^.framebuffer_addr)); |      fb:= puint32(uint32(multibootinfo^.framebuffer_addr)); | ||||||
|      Console_Properties.Width:= multibootinfo^.framebuffer_width; |      Console_Properties.Width:= multibootinfo^.framebuffer_width; | ||||||
|      Console_Properties.Height:= multibootinfo^.framebuffer_height; |      Console_Properties.Height:= multibootinfo^.framebuffer_height; | ||||||
|      Console_Properties.BitsPerPixel:= multibootinfo^.framebuffer_bpp; |      Console_Properties.BitsPerPixel:= multibootinfo^.framebuffer_bpp; | ||||||
|      Console_Properties.MAX_CELL_X:= (Console_Properties.Width div 8) - 1; |      Console_Properties.MAX_CELL_X:= (Console_Properties.Width div 8) - 1; | ||||||
|      Console_Properties.MAX_CELL_Y:= (Console_Properties.Height div 16) - 1; |      Console_Properties.MAX_CELL_Y:= (Console_Properties.Height div 16) - 1; | ||||||
|      If Console_Properties.BitsPerPixel <> 16 then while true do begin |      If Console_Properties.BitsPerPixel <> 16 then begin | ||||||
|  |         exit; | ||||||
|      end; |      end; | ||||||
|      kpalloc(uint32(fb)); |      kpalloc(uint32(fb)); | ||||||
|      keyboard.hook(@keyhook); |      keyboard.hook(@keyhook); | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								src/cpu.pas
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/cpu.pas
									
									
									
									
									
								
							| @@ -291,6 +291,28 @@ begin | |||||||
|     end; |     end; | ||||||
| end; | end; | ||||||
|  |  | ||||||
|  | procedure enableAVX(); | ||||||
|  | begin | ||||||
|  |     if CPUID.Capabilities1^.AVX then begin | ||||||
|  |         asm | ||||||
|  |             PUSH EAX | ||||||
|  |             PUSH ECX | ||||||
|  |             PUSH EDX | ||||||
|  |             XOR ECX, ECX | ||||||
|  |             db $0F | ||||||
|  |             db $01 | ||||||
|  |             db $D0 | ||||||
|  |             OR EAX, 7 | ||||||
|  |             db $0F | ||||||
|  |             db $01 | ||||||
|  |             db $D1 | ||||||
|  |             POP EDX | ||||||
|  |             POP ECX | ||||||
|  |             POP EAX | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
|  | end; | ||||||
|  |  | ||||||
| procedure init(); | procedure init(); | ||||||
| begin | begin | ||||||
|     terminal.registerCommand('CPU', @Terminal_Command_CPU, 'CPU Info.'); |     terminal.registerCommand('CPU', @Terminal_Command_CPU, 'CPU Info.'); | ||||||
| @@ -300,6 +322,7 @@ begin | |||||||
|     getCPUCapabilities; |     getCPUCapabilities; | ||||||
|     getCPUClockSpeed; |     getCPUClockSpeed; | ||||||
|     enableSSE; |     enableSSE; | ||||||
|  |     enableAVX; | ||||||
| end; | end; | ||||||
|  |  | ||||||
| end. | end. | ||||||
| @@ -91,7 +91,6 @@ 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  | ||||||
|  |  | ||||||
| @@ -443,34 +442,4 @@ 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,29 +21,6 @@ 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; | ||||||
| @@ -67,7 +44,6 @@ 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; | ||||||
|   | |||||||
							
								
								
									
										296
									
								
								src/driver/storage/AHCI.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								src/driver/storage/AHCI.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,296 @@ | |||||||
|  | //  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; | ||||||
| @@ -1,899 +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 - 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. |  | ||||||
| @@ -1,320 +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->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. |  | ||||||
|  |  | ||||||
							
								
								
									
										85
									
								
								src/driver/storage/ATA_ISR.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/driver/storage/ATA_ISR.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | //  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,506 +1,246 @@ | |||||||
| //  Copyright 2021 Aaron Hance | { ************************************************ | ||||||
| // |   * Asuro | ||||||
| //  Licensed under the Apache License, Version 2.0 (the "License"); |   * Unit: Drivers/storage/IDE | ||||||
| //  you may not use this file except in compliance with the License. |   * Description: IDE ATA Driver | ||||||
| //  You may obtain a copy of the License at |   *  | ||||||
| // |   ************************************************ | ||||||
| //  http://www.apache.org/licenses/LICENSE-2.0 |   * Author: Aaron Hance | ||||||
| // |   * Contributors:  | ||||||
| //  Unless required by applicable law or agreed to in writing, software |   ************************************************ } | ||||||
| //  distributed under the License is distributed on an "AS IS" BASIS, | unit IDE; | ||||||
| //  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 | ||||||
|     ata, |  | ||||||
|     atapi, |  | ||||||
|     console, |  | ||||||
|     drivermanagement, |  | ||||||
|     drivertypes, |  | ||||||
|     idetypes, |  | ||||||
|     isrmanager, |  | ||||||
|     lmemorymanager, |  | ||||||
|     storagetypes, |  | ||||||
|     strings, |  | ||||||
|     terminal, |  | ||||||
|     tracer, |  | ||||||
|     util, |     util, | ||||||
|     vmemorymanager; |     drivertypes, | ||||||
|  |     console, | ||||||
|  |     terminal, | ||||||
|  |     drivermanagement, | ||||||
|  |     vmemorymanager, | ||||||
|  |     lmemorymanager, | ||||||
|  |     storagemanagement, | ||||||
|  |     strings, | ||||||
|  |     tracer; | ||||||
|  |  | ||||||
|  | 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 | ||||||
|     primaryDevices: array[0..1] of TIDE_Device = ( |     controller : PPCI_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), |  | ||||||
|  |  | ||||||
|         (exists: false; isPrimary: true; isMaster: false; isATAPI: false;  |     bar0 : uint32; | ||||||
|          status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false); |     bar1 : uint32; | ||||||
|          base: ATA_PRIMARY_BASE; blockSize: 0; info: nil) |     bar4 : uint32; | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     secondaryDevices: array[0..1] of TIDE_Device = ( |     IDEDevices : array[0..3] 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), |  | ||||||
|  |  | ||||||
|         (exists: false; isPrimary: false; isMaster: false; isATAPI: false;  |     buffer : Puint32; | ||||||
|          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; | ||||||
|  |  | ||||||
|     function load(ptr: void) : boolean; | // procedure flush(); | ||||||
|     procedure init(); | procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8); | ||||||
|     function get_status(var device : TIDE_Device) : TIDE_Status; | procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8); | ||||||
|     function wait_for_device(device : TIDE_Device; ioop : boolean) : boolean; | //read/write must be capable of reading/writting any amknt of data upto disk size | ||||||
|     procedure no_interrupt(isPrimary : boolean); |  | ||||||
|     procedure enable_interrupt(isPrimary : boolean); | procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32); | ||||||
|     procedure reset_device(device : TIDE_Device); | procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32); | ||||||
|     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 | ||||||
|     if isPrimary then begin |     port_read:= inb(ATA_PRIMARY_BASE + register); | ||||||
|         outb(ATA_INTERRUPT_PRIMARY, inb(ATA_INTERRUPT_PRIMARY) or (1 shl 1)); | end; | ||||||
|     end else begin |  | ||||||
|         outb(ATA_INTERRUPT_SECONDARY, inb(ATA_INTERRUPT_SECONDARY) or (1 shl 1)); | procedure port_write(register : uint8; data : uint8); | ||||||
|  | var | ||||||
|  |     i : uint8; | ||||||
|  | begin | ||||||
|  |     outb(ATA_PRIMARY_BASE + register, data); | ||||||
|  |     util.psleep(1); | ||||||
|  |     if register = ATA_REG_COMMAND then begin | ||||||
|  |         for i:= 0 to 5 do begin  | ||||||
|  |             port_read(ATA_REG_STATUS); | ||||||
|  |         end; | ||||||
|     end; |     end; | ||||||
| end; | end; | ||||||
|  |  | ||||||
| procedure enable_interrupt(isPrimary : boolean); | procedure no_interrupt(device : uint8); | ||||||
| var |  | ||||||
|     reg : uint8; |  | ||||||
| begin | begin | ||||||
|     if isPrimary then begin |     outb($3F6, inb($3f6) or (1 shl 1)); | ||||||
|         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; | end; | ||||||
|  |  | ||||||
| //soft reset | procedure device_select(device : uint8); | ||||||
| procedure reset_device(device : TIDE_Device); |  | ||||||
| var |  | ||||||
|     reg : uint8; |  | ||||||
| begin | begin | ||||||
|     if device.isPrimary then begin |     outb($1F6, device); //TODO clean | ||||||
|         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; | end; | ||||||
|  |  | ||||||
| {  | function is_ready() : boolean; | ||||||
|     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  | var  | ||||||
|     status : TIDE_Status; |     status : uint8; | ||||||
|     i : uint32; |     i : uint32; | ||||||
| begin | begin | ||||||
|     push_trace('ide.wait_for_device()'); |     //wait for drive to be ready | ||||||
|  |     while true do begin  | ||||||
|     i := 0; |         status := port_read(ATA_REG_COMMAND); | ||||||
|  |  | ||||||
|     while (i < 50000) do begin |  | ||||||
|         status := get_status(device); |  | ||||||
|  |  | ||||||
|         if (status.BUSY = false) and (status.DRQ or (not ioop)) then begin //todo test |  | ||||||
|             wait_for_device := true; |  | ||||||
|             pop_trace(); |  | ||||||
|             exit; |  | ||||||
|         end; |  | ||||||
|  |  | ||||||
|         i := i + 1; |  | ||||||
|     end; |  | ||||||
|  |  | ||||||
|     wait_for_device := false; |  | ||||||
|     pop_trace(); |  | ||||||
| end; |  | ||||||
|  |  | ||||||
| {  |  | ||||||
|     Select the active device on the IDE bus  |  | ||||||
|     @param(device The device to select) |  | ||||||
|  |  | ||||||
|     Function can set the device to either master or slave, |  | ||||||
|     one device per bus/channel can be active at a time. |  | ||||||
| } |  | ||||||
| procedure select_device(device : TIDE_Device); |  | ||||||
| var |  | ||||||
|     dev : uint8; |  | ||||||
|     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'); |  | ||||||
|  |  | ||||||
|  |         if(status and ATA_SR_ERR) = ATA_SR_ERR then begin | ||||||
|  |             console.writestringln('[IDE] (IDENTIFY_DEVICE) DRIVE ERROR!'); | ||||||
|             console.redrawWindows(); |             console.redrawWindows(); | ||||||
|  |             is_ready := false; | ||||||
|  |             break; | ||||||
|         end; |         end; | ||||||
|  |  | ||||||
|  |         if (status and ATA_SR_BUSY) <> ATA_SR_BUSY then begin | ||||||
|  |             is_ready := true; | ||||||
|  |             break; | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
| end; | end; | ||||||
|  |  | ||||||
| {  | function validate_28bit_address(addr : uint32) : boolean; | ||||||
|     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 | begin | ||||||
|     push_trace('ide.is_device_present()'); |     validate_28bit_address := (addr and $F0000000) = 0; | ||||||
|  |  | ||||||
|     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; | end; | ||||||
|  |  | ||||||
| {  | function identify_device(bus : uint8; device : uint8) : TIdentResponse; | ||||||
|     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 | var | ||||||
|     sec, lba0, lba1, lba2 : uint8; |     status : uint8; | ||||||
| begin |     identResponse : TIdentResponse; | ||||||
|     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.load()'); |     push_trace('IDE.Identify_Device'); | ||||||
|     console.writestringln('[IDE] (load) Loading IDE Devices'); |     device_select(device); | ||||||
|     console.redrawWindows(); |     no_interrupt(device); | ||||||
|     registerISR(14, @atapi.ide_irq); |     port_write(ATA_REG_CONTROL, 0); | ||||||
|     registerISR(15, @atapi.ide_irq); |  | ||||||
|     console.writestringln('[IDE] (load) Loading IDE Devices 2'); |  | ||||||
|     console.redrawWindows(); |  | ||||||
|     pciDevice := PPCI_Device(ptr); |  | ||||||
|  |  | ||||||
|     load_device(primaryDevices[0]); |     //check if bus is floating | ||||||
|     load_device(primaryDevices[1]); |     status := port_read(ATA_REG_COMMAND); | ||||||
|     load_device(secondaryDevices[0]); |     if status = $FF then exit; | ||||||
|     load_device(secondaryDevices[1]); |  | ||||||
|  |  | ||||||
|     pop_trace(); |     port_write(ATA_REG_SECCOUNT, 0); | ||||||
|     load := true; |     port_write(ATA_REG_LBA0, 0); | ||||||
|  |     port_write(ATA_REG_LBA1, 0); | ||||||
|  |     port_write(ATA_REG_LBA2, 0); | ||||||
|  |  | ||||||
|     console.writestringln('[IDE] (load) IDE Device Loading Finished'); |     port_write(ATA_REG_COMMAND, ATA_CMD_IDENTIFY); | ||||||
|  |  | ||||||
|     i := 0; |     //check if drive is present | ||||||
|  |     status := port_read(ATA_REG_COMMAND); | ||||||
|  |     if status = $00 then exit; | ||||||
|  |  | ||||||
|     if (primaryDevices[0].exists) then begin |     if not is_ready() then exit; | ||||||
|         console.writestringln('[IDE] (load) FOUND Primary Master Device 0'); |  | ||||||
|         i := i + 1; |     for i:=0 to 255 do begin | ||||||
|  |         identResponse[i] := inw(ATA_PRIMARY_BASE + ATA_REG_DATA); | ||||||
|     end; |     end; | ||||||
|  |  | ||||||
|     if (primaryDevices[1].exists) then begin |     identify_device := identResponse;  | ||||||
|         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();   | ||||||
| @@ -516,8 +256,193 @@ begin | |||||||
|     devID.id3:= idANY; |     devID.id3:= idANY; | ||||||
|     devID.id4:= idANY; |     devID.id4:= idANY; | ||||||
|     devID.ex:= nil; |     devID.ex:= nil; | ||||||
|     drivermanagement.register_driver('IDE ATA/ATAPI Driver', @devID, @load); |     drivermanagement.register_driver('IDE ATA Driver', @devID, @load); | ||||||
|     console.writestringln('[IDE] (INIT) END'); |     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. | ||||||
| @@ -1,81 +0,0 @@ | |||||||
| { |  | ||||||
|     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. |  | ||||||
| @@ -1,306 +0,0 @@ | |||||||
| //  Copyright 2021 Aaron Hance |  | ||||||
| // |  | ||||||
| //  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| //  you may not use this file except in compliance with the License. |  | ||||||
| //  You may obtain a copy of the License at |  | ||||||
| // |  | ||||||
| //  http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| // |  | ||||||
| //  Unless required by applicable law or agreed to in writing, software |  | ||||||
| //  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| //  See the License for the specific language governing permissions and |  | ||||||
| //  limitations under the License. |  | ||||||
|  |  | ||||||
| { |  | ||||||
|     Driver->Storage->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. |  | ||||||
| @@ -1,429 +0,0 @@ | |||||||
| //  Copyright 2021 Aaron Hance |  | ||||||
| // |  | ||||||
| //  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| //  you may not use this file except in compliance with the License. |  | ||||||
| //  You may obtain a copy of the License at |  | ||||||
| // |  | ||||||
| //  http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| // |  | ||||||
| //  Unless required by applicable law or agreed to in writing, software |  | ||||||
| //  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| //  See the License for the specific language governing permissions and |  | ||||||
| //  limitations under the License. |  | ||||||
|  |  | ||||||
| { |  | ||||||
|     Driver->Storage->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. |  | ||||||
| @@ -1,251 +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 - 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. |  | ||||||
| @@ -1,448 +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->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,16 +10,14 @@ interface | |||||||
|  |  | ||||||
| uses | uses | ||||||
|     console, |     console, | ||||||
|     util, |     storagemanagement, | ||||||
|     terminal, |     util, terminal, | ||||||
|     lmemorymanager, |     lmemorymanager, | ||||||
|     strings, |     strings, | ||||||
|     lists, |     lists, | ||||||
|     tracer, |     tracer, | ||||||
|     serial, |     serial, | ||||||
|     rtc, |     rtc; | ||||||
|     volumemanager, |  | ||||||
|     storagetypes; |  | ||||||
|  |  | ||||||
| type  | type  | ||||||
|  |  | ||||||
| @@ -91,7 +89,7 @@ var | |||||||
|     filesystem : TFilesystem; |     filesystem : TFilesystem; | ||||||
|  |  | ||||||
| procedure init; | procedure init; | ||||||
| procedure create_volume(volume : PStorage_Volume; sectors : uint32; start : uint32; config : puint32); | procedure create_volume(disk : PStorage_Device; 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 | ||||||
| @@ -753,7 +751,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(volume : PStorage_Volume; sectors : uint32; start : uint32; config : puint32); | procedure create_volume(disk : PStorage_Device; sectors : uint32; start : uint32; config : puint32); | ||||||
| var | var | ||||||
|     buffer     : puint32; |     buffer     : puint32; | ||||||
|     bt: puint32; |     bt: puint32; | ||||||
| @@ -774,18 +772,9 @@ 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); | ||||||
|  |  | ||||||
| @@ -822,7 +811,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             := 1; |     bootRecord^.spc             := config^; | ||||||
|     bootRecord^.rsvSectors      := 32; //32 is standard |     bootRecord^.rsvSectors      := 32; //32 is standard | ||||||
|     bootRecord^.numFats         := 1; |     bootRecord^.numFats         := 1; | ||||||
|     bootRecord^.mediaDescp      := $F8; |     bootRecord^.mediaDescp      := $F8; | ||||||
| @@ -884,16 +873,8 @@ 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); | ||||||
| @@ -922,11 +903,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; //THIS MAKE SURE IF NOT FUCKY, cos im getting info from 2 |         volume^.sectorStart:= 1; | ||||||
|         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); TODO repalce with new thing |         storagemanagement.register_volume(disk, volume); | ||||||
|     end; |     end; | ||||||
|  |  | ||||||
|     kfree(buffer); |     kfree(buffer); | ||||||
| @@ -936,7 +917,6 @@ 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; | ||||||
| @@ -944,7 +924,7 @@ begin | |||||||
|     filesystem.writecallback:= @writeFile; |     filesystem.writecallback:= @writeFile; | ||||||
|     filesystem.readcallback := @readFile; |     filesystem.readcallback := @readFile; | ||||||
|  |  | ||||||
|     volumemanager.register_filesystem(@filesystem); |     storagemanagement.register_filesystem(@filesystem); | ||||||
| end; | end; | ||||||
|  |  | ||||||
| end. | end. | ||||||
| @@ -1,725 +0,0 @@ | |||||||
| //  Copyright 2021 Aaron Hance |  | ||||||
| // |  | ||||||
| //  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| //  you may not use this file except in compliance with the License. |  | ||||||
| //  You may obtain a copy of the License at |  | ||||||
| // |  | ||||||
| //  http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| // |  | ||||||
| //  Unless required by applicable law or agreed to in writing, software |  | ||||||
| //  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| //  See the License for the specific language governing permissions and |  | ||||||
| //  limitations under the License. |  | ||||||
|  |  | ||||||
| { |  | ||||||
|     Driver->Storage->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. |  | ||||||
| @@ -1,148 +0,0 @@ | |||||||
| //  Copyright 2021 Aaron Hance |  | ||||||
| // |  | ||||||
| //  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| //  you may not use this file except in compliance with the License. |  | ||||||
| //  You may obtain a copy of the License at |  | ||||||
| // |  | ||||||
| //  http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| // |  | ||||||
| //  Unless required by applicable law or agreed to in writing, software |  | ||||||
| //  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| //  See the License for the specific language governing permissions and |  | ||||||
| //  limitations under the License. |  | ||||||
|  |  | ||||||
| {  |  | ||||||
| 	Driver->Storage->IDE->idetypes - IDE device types and constants. |  | ||||||
| 	 |  | ||||||
| 	@author(Aaron Hance <ah@aaronhance.me>) |  | ||||||
| } |  | ||||||
| unit idetypes; |  | ||||||
|  |  | ||||||
| interface |  | ||||||
|  |  | ||||||
| const |  | ||||||
|  |  | ||||||
|     ATA_SR_BUSY = $80; //BUSY |  | ||||||
|     ATA_SR_DRDY = $40; //DRIVE READY |  | ||||||
|     ATA_SR_DF   = $20; //DRIVE WRITE FAULT |  | ||||||
|     ATA_SR_DSC  = $10; //DRIVE SEEK COMPLETE |  | ||||||
|     ATA_SR_DRQ  = $08; //DATA REQUEST READY |  | ||||||
|     ATA_SR_CORR = $04; //CORRECTED DATA |  | ||||||
|     ATA_SR_IDX  = $02; //INLEX |  | ||||||
|     ATA_SR_ERR  = $01; //ERROR |  | ||||||
|  |  | ||||||
|     ATA_ER_BBK   = $80; //BAD SECTOR |  | ||||||
|     ATA_ER_UNC   = $40; //UNCORRECTABLE DATA |  | ||||||
|     ATA_ER_MC    = $20; //NO MEDIA |  | ||||||
|     ATA_ER_IDNF  = $10; //ID MARK NOT FOUND |  | ||||||
|     ATA_ER_MCR   = $08; //NO MEDIA |  | ||||||
|     ATA_ER_ABRT  = $04; //COMMAND ABORTED |  | ||||||
|     ATA_ER_TK0NF = $02; //TRACK 0 NOT FOUND |  | ||||||
|     ATA_ER_AMNF  = $01; //NO ADDRESS MARK |  | ||||||
|  |  | ||||||
|     ATA_CMD_READ_PIO        = $20;  |  | ||||||
|     ATA_CMD_READ_PIO_EXT    = $24;  |  | ||||||
|     ATA_CMD_READ_DMA        = $C8;  |  | ||||||
|     ATA_CMD_READ_DMA_EXT    = $25;  |  | ||||||
|     ATA_CMD_WRITE_PIO       = $30;  |  | ||||||
|     ATA_CMD_WRITE_PIO_EXT   = $34;  |  | ||||||
|     ATA_CMD_WRITE_DMA       = $CA;  |  | ||||||
|     ATA_CMD_WRITE_DMA_EXT   = $35;  |  | ||||||
|     ATA_CMD_CACHE_FLUSH     = $E7;  |  | ||||||
|     ATA_CMD_CACHE_FLUSH_EXT = $EA;  |  | ||||||
|     ATA_CMD_PACKET          = $A0;  |  | ||||||
|     ATA_CMD_IDENTIFY_PACKET = $A1;  |  | ||||||
|     ATA_CMD_IDENTIFY        = $EC;  |  | ||||||
|  |  | ||||||
|     ATAPI_CMD_READ  = $A8; |  | ||||||
|     ATAPI_CMD_EJECT = $1B; |  | ||||||
|  |  | ||||||
|     ATA_IDENT_DEVICETYPE   = $0;     |  | ||||||
|     ATA_IDENT_CYLINDERS    = $2;     |  | ||||||
|     ATA_IDENT_HEADS        = $6;     |  | ||||||
|     ATA_IDENT_SECOTRS      = $12;     |  | ||||||
|     ATA_IDENT_SERIAL       = $20;     |  | ||||||
|     ATA_IDENT_MODEL        = $54;     |  | ||||||
|     ATA_IDENT_CAPABILITIES = $98;     |  | ||||||
|     ATA_IDENT_FIELDVALID   = $106;    |  | ||||||
|     ATA_IDENT_MAX_LBA      = $120;    |  | ||||||
|     ATA_IDENT_COMMANDSETS  = $164;        |  | ||||||
|     ATA_IDENT_MAX_LBA_EXT  = $200; |  | ||||||
|  |  | ||||||
|     ATA_REG_DATA       = $00; |  | ||||||
|     ATA_REG_ERROR      = $01; |  | ||||||
|     ATA_REG_FEATURES   = $01; |  | ||||||
|     ATA_REG_SECCOUNT  = $02; |  | ||||||
|     ATA_REG_LBA0       = $03; |  | ||||||
|     ATA_REG_LBA1       = $04; |  | ||||||
|     ATA_REG_LBA2       = $05; |  | ||||||
|     ATA_REG_HDDEVSEL   = $06; |  | ||||||
|     ATA_REG_COMMAND    = $07; |  | ||||||
|     ATA_REG_STATUS     = $07; |  | ||||||
|     ATA_REG_SECCOUNT1  = $08; |  | ||||||
|     ATA_REG_LBA3       = $09; |  | ||||||
|     ATA_REG_LBA4       = $0A; |  | ||||||
|     ATA_REG_LBA5       = $0B; |  | ||||||
|     ATA_REG_CONTROL    = $0C; //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. |  | ||||||
| @@ -15,8 +15,6 @@ | |||||||
| { | { | ||||||
|     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; | ||||||
| @@ -33,14 +31,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; | ||||||
| @@ -56,6 +54,41 @@ 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 } | ||||||
| @@ -77,13 +110,20 @@ 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 | ||||||
|         ControllerATA : controller_type_2_string:= 'ATA'; |         ControllerIDE : controller_type_2_string:= 'IDE'; | ||||||
|         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'; | ||||||
| @@ -129,57 +169,18 @@ 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^:= 1; |     spc^:= 4; | ||||||
| 
 | 
 | ||||||
|     driveIndex:= stringToInt( getParam(1, params) ); |     driveIndex:= stringToInt( getParam(1, params) ); | ||||||
|     drive:= PStorage_Device(LL_Get(storageDevices, driveIndex)); |     drive:= PStorage_Device(LL_Get(storageDevices, driveIndex)); | ||||||
| 
 | 
 | ||||||
|     filesystemString := getParam(2, params); |     //todo change b4 adding in aniother filesytem | ||||||
| 
 |     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); | ||||||
| @@ -216,6 +217,10 @@ 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; | ||||||
| 
 | 
 | ||||||
| @@ -226,8 +231,10 @@ 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 } | ||||||
| @@ -246,7 +253,9 @@ 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; | ||||||
| @@ -256,4 +265,23 @@ 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. | ||||||
| @@ -1,95 +0,0 @@ | |||||||
| //  Copyright 2021 Aaron Hance |  | ||||||
| // |  | ||||||
| //  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| //  you may not use this file except in compliance with the License. |  | ||||||
| //  You may obtain a copy of the License at |  | ||||||
| // |  | ||||||
| //  http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| // |  | ||||||
| //  Unless required by applicable law or agreed to in writing, software |  | ||||||
| //  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| //  See the License for the specific language governing permissions and |  | ||||||
| //  limitations under the License. |  | ||||||
|  |  | ||||||
| {  |  | ||||||
| 	Driver->Storage->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. |  | ||||||
| @@ -1,108 +0,0 @@ | |||||||
| //  Copyright 2021 Aaron Hance |  | ||||||
| // |  | ||||||
| //  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| //  you may not use this file except in compliance with the License. |  | ||||||
| //  You may obtain a copy of the License at |  | ||||||
| // |  | ||||||
| //  http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| // |  | ||||||
| //  Unless required by applicable law or agreed to in writing, software |  | ||||||
| //  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| //  See the License for the specific language governing permissions and |  | ||||||
| //  limitations under the License. |  | ||||||
|  |  | ||||||
| { |  | ||||||
|     Driver->Storage->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. |  | ||||||
							
								
								
									
										100
									
								
								src/driver/video/doublebuffer.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/driver/video/doublebuffer.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->Doublebuffer - Implements a very basic double buffer, tested with VESA drivers. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit doublebuffer; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     lmemorymanager, tracer, videotypes, serial, util; | ||||||
|  |  | ||||||
|  | //Init the driver, and register with the video interface in a state ready for execution. | ||||||
|  | procedure init(Register : FRegisterDriver); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | function allocateBackBuffer(Width : uint32; Height : uint32; BitsPerPixel : uint8) : uint64; | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('doublebuffer.allocateBackBuffer.enter'); | ||||||
|  |     //This doesn't currently work... Needs a rework of lmemorymanager | ||||||
|  |     allocateBackBuffer:= uint64(klalloc((Width * Height) * BitsPerPixel)); | ||||||
|  |     tracer.push_trace('doublebuffer.allocateBackBuffer.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure initBackBuffer(VInterface : PVideoInterface; Width : uint32; Height : uint32; BitsPerPixel : uint8); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('doublebuffer.initBackBuffer.enter'); | ||||||
|  |     if not(VInterface^.BackBuffer.Initialized) then begin | ||||||
|  |         VInterface^.BackBuffer.Location:= allocateBackBuffer(Width, Height, BitsPerPixel); | ||||||
|  |         if (VInterface^.BackBuffer.Location <> 0) then begin | ||||||
|  |             VInterface^.BackBuffer.Width:= Width; | ||||||
|  |             VInterface^.BackBuffer.Height:= Height; | ||||||
|  |             VInterface^.BackBuffer.BitsPerPixel:= BitsPerPixel; | ||||||
|  |             VInterface^.BackBuffer.Initialized:= True; | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
|  |     tracer.push_trace('doublebuffer.initBackBuffer.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure Flush(FrontBuffer : PVideoBuffer; BackBuffer : PVideoBuffer); | ||||||
|  | var | ||||||
|  |     idx : uint32; | ||||||
|  |     Back,Front : uint32; | ||||||
|  |     BufferSize : uint32; | ||||||
|  |  | ||||||
|  | const | ||||||
|  |     //COPY_WIDTH = 64; //Use this for 64bit copies | ||||||
|  |     COPY_WIDTH = 128; //Use this for SSE copies | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     //tracer.push_trace('doublebuffer.Flush.enter'); | ||||||
|  |     if not(BackBuffer^.Initialized) then exit; | ||||||
|  |     if ((FrontBuffer^.Width > BackBuffer^.Width) or (FrontBuffer^.Height > BackBuffer^.Height)) then exit; | ||||||
|  |     Back:= BackBuffer^.Location; | ||||||
|  |     Front:= FrontBuffer^.Location; | ||||||
|  |     BufferSize:= ( ( BackBuffer^.Width * BackBuffer^.Height * BackBuffer^.BitsPerPixel) div COPY_WIDTH ) - 1; | ||||||
|  |     for idx:=0 to BufferSize do begin | ||||||
|  |         //Front[idx]:= Back[idx]; | ||||||
|  |         // -- TODO: Get SSE working here for 128bit copies -- | ||||||
|  |         __SSE_128_memcpy(Back + (idx * 16), Front + (idx * 16));   | ||||||
|  |     end; | ||||||
|  |     //tracer.push_trace('doublebuffer.Flush.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function enable(VideoInterface : PVideoInterface) : boolean; | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('doublebuffer.enable.enter'); | ||||||
|  |     enable:= false; | ||||||
|  |     initBackBuffer(VideoInterface, VideoInterface^.FrontBuffer.Width, VideoInterface^.FrontBuffer.Height, VideoInterface^.FrontBuffer.BitsPerPixel); | ||||||
|  |     if VideoInterface^.BackBuffer.Initialized then begin | ||||||
|  |         VideoInterface^.DefaultBuffer:= @VideoInterface^.BackBuffer; | ||||||
|  |         VideoInterface^.DrawRoutines.Flush:= @Flush; | ||||||
|  |         enable:= true; | ||||||
|  |     end; | ||||||
|  |     tracer.push_trace('doublebuffer.enable.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure init(Register : FRegisterDriver); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('doublebuffer.init.enter'); | ||||||
|  |     Register('BASIC_DOUBLE_BUFFER', @enable); | ||||||
|  |     tracer.push_trace('doublebuffer.init.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										87
									
								
								src/driver/video/vesa.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/driver/video/vesa.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->VESA - VESA Display Driver. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit vesa; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     videotypes, tracer, multiboot, lmemorymanager; | ||||||
|  |  | ||||||
|  | //Init the driver, and register with the video interface in a state ready for execution. | ||||||
|  | procedure init(Register : FRegisterDriver); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     VESA8, VESA16, VESA24, VESA32; | ||||||
|  |  | ||||||
|  | procedure allocateVESAFrameBuffer(Address : uint32; Width : uint32; Height : uint32); | ||||||
|  | var | ||||||
|  |     LowerAddress, UpperAddress : uint32; | ||||||
|  |     Block : uint32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('VESA.allocateFrameBuffer.enter'); | ||||||
|  |     LowerAddress:= ((Address) SHR 22)-1; | ||||||
|  |     UpperAddress:= ((Address + (Width * Height)) SHR 22)+1; | ||||||
|  |     For Block:=LowerAddress to UpperAddress do begin | ||||||
|  |         kpalloc(Block SHL 22); | ||||||
|  |     end; | ||||||
|  |     tracer.push_trace('VESA.allocateFrameBuffer.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure initVESAFrameBuffer(VideoBuffer : PVideoBuffer; Location : uint64; Width : uint32; Height : uint32; BitsPerPixel : uint8); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('VESA.initVESAFrameBuffer.enter'); | ||||||
|  |     if not(VideoBuffer^.Initialized) then begin | ||||||
|  |         VideoBuffer^.Location:= Location; | ||||||
|  |         VideoBuffer^.BitsPerPixel:= BitsPerPixel; | ||||||
|  |         VideoBuffer^.Width:= Width; | ||||||
|  |         VideoBuffer^.Height:= Height; | ||||||
|  |         allocateVESAFrameBuffer(VideoBuffer^.Location, VideoBuffer^.Width, VideoBuffer^.Height); | ||||||
|  |         if VideoBuffer^.Location <> 0 then | ||||||
|  |             VideoBuffer^.Initialized:= True; | ||||||
|  |     end; | ||||||
|  |     tracer.push_trace('VESA.initVESAFrameBuffer.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function enable(VideoInterface : PVideoInterface) : boolean; | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('VESA.enable.enter'); | ||||||
|  |     initVESAFrameBuffer(@VideoInterface^.FrontBuffer, multiboot.multibootinfo^.framebuffer_addr, multiboot.multibootinfo^.framebuffer_width, multiboot.multibootinfo^.framebuffer_height, multiboot.multibootinfo^.framebuffer_bpp); | ||||||
|  |     case (VideoInterface^.FrontBuffer.BitsPerPixel) of | ||||||
|  |         08:VESA8.init(@VideoInterface^.DrawRoutines); | ||||||
|  |         16:VESA16.init(@VideoInterface^.DrawRoutines); | ||||||
|  |         24:VESA24.init(@VideoInterface^.DrawRoutines); | ||||||
|  |         32:VESA32.init(@VideoInterface^.DrawRoutines); | ||||||
|  |     end; | ||||||
|  |     enable:= VideoInterface^.FrontBuffer.Initialized;   | ||||||
|  |     tracer.push_trace('VESA.enable.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure init(Register : FRegisterDriver); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('VESA.init.enter'); | ||||||
|  |     if Register <> nil then | ||||||
|  |         Register('VESA', @enable);    | ||||||
|  |     tracer.push_trace('VESA.init.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										43
									
								
								src/driver/video/vesa16.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/driver/video/vesa16.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->VESA16 - Implementation of VESA 16bpp draw routines for the VESA Driver. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit vesa16; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     videotypes, vesa, tracer, color; | ||||||
|  |  | ||||||
|  | //Init the draw routines by providing what we support through the DrawRoutines struct. | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | procedure DrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  | begin | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('vesa16.init.enter');    | ||||||
|  |     tracer.push_trace('vesa16.init.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										43
									
								
								src/driver/video/vesa24.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/driver/video/vesa24.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->VESA24 - Implementation of VESA 24bpp draw routines for the VESA Driver. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit vesa24; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     videotypes, vesa, tracer, color; | ||||||
|  |  | ||||||
|  | //Init the draw routines by providing what we support through the DrawRoutines struct. | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | procedure DrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  | begin | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  | begin | ||||||
|  | 	tracer.push_trace('vesa24.init.enter'); | ||||||
|  | 	tracer.push_trace('vesa24.init.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										52
									
								
								src/driver/video/vesa32.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/driver/video/vesa32.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->VESA32 - Implementation of VESA 32bpp draw routines for the VESA Driver. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit vesa32; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     videotypes, vesa, tracer, color; | ||||||
|  |  | ||||||
|  | //Init the draw routines by providing what we support through the DrawRoutines struct. | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | procedure DrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  | var | ||||||
|  |     Location : PuInt32; | ||||||
|  |     LocationIndex : Uint32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     //tracer.push_trace('vesa32.DrawPixel.enter'); | ||||||
|  |     Location:= Puint32(Buffer^.Location); | ||||||
|  |     LocationIndex:= (Y * Buffer^.Width) + X; | ||||||
|  |     Location[LocationIndex]:= uint32(Pixel); | ||||||
|  |     //tracer.push_trace('vesa32.DrawPixel.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('vesa32.init.enter'); | ||||||
|  |     DrawRoutines^.DrawPixel:= @DrawPixel; | ||||||
|  |     tracer.push_trace('vesa32.init.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										43
									
								
								src/driver/video/vesa8.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/driver/video/vesa8.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->VESA8 - Implementation of VESA 8bpp draw routines for the VESA Driver. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit vesa8; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     videotypes, vesa, tracer, color; | ||||||
|  |  | ||||||
|  | //Init the draw routines by providing what we support through the DrawRoutines struct. | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | procedure DrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  | begin | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure init(DrawRoutines : PDrawRoutines); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('vesa8.init.enter');    | ||||||
|  |     tracer.push_trace('vesa8.init.exit');   | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										318
									
								
								src/driver/video/video.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								src/driver/video/video.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,318 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->Video - Provides an abstract rasterization/drawing interface. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit video; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     lmemorymanager, tracer, color, videotypes, hashmap, util, texture; | ||||||
|  |  | ||||||
|  | procedure init(); | ||||||
|  | procedure DrawPixel(X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  | procedure DrawLine(x1,y1,x2,y2 : uint32; thickness : uint32; Color : TRGB32); | ||||||
|  | procedure DrawRect(x1,y1,x2,y2 : uint32; line_thickness : uint32; Color : TRGB32); | ||||||
|  | procedure FillRect(x1,y1,x2,y2 : uint32; line_thickness : uint32; Line_Color : TRGB32; Fill_Color : TRGB32); | ||||||
|  | procedure Flush(); | ||||||
|  |  | ||||||
|  | function register(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean; | ||||||
|  | function enable(DriverIdentifier : pchar) : boolean; | ||||||
|  |  | ||||||
|  | function frontBufferWidth : uint32; | ||||||
|  | function frontBufferHeight : uint32; | ||||||
|  | function frontBufferBpp : uint8; | ||||||
|  | function backBufferWidth : uint32; | ||||||
|  | function backBufferHeight : uint32; | ||||||
|  | function backBufferBpp : uint8; | ||||||
|  |  | ||||||
|  | Procedure basicFDrawTexture(Buffer : PVideoBuffer; X : uint32; Y : uint32; Texture : PTexture); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | Procedure dummyFDrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('video.dummyFDrawPixel.enter'); | ||||||
|  |     //Do nothing, this is the most basic function that must be implemented by a driver. | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | Procedure basicFFlush(FrontBuffer : PVideoBuffer; BackBuffer : PVideoBuffer); | ||||||
|  | var | ||||||
|  |     idx : uint32; | ||||||
|  |     Back,Front : puint32; | ||||||
|  |     BufferSize : uint32; | ||||||
|  |  | ||||||
|  | const | ||||||
|  |     COPY_WIDTH = 32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     //tracer.push_trace('video.basicFFlush.enter'); | ||||||
|  |     If not(FrontBuffer^.Initialized and BackBuffer^.Initialized) then exit; | ||||||
|  |     if (BackBuffer^.Width > FrontBuffer^.Width) or (BackBuffer^.Height > FrontBuffer^.Height) then exit; | ||||||
|  |     Back:= puint32(BackBuffer^.Location); | ||||||
|  |     Front:= puint32(FrontBuffer^.Location); | ||||||
|  |     BufferSize:= ( (BackBuffer^.Width * BackBuffer^.Height * BackBuffer^.BitsPerPixel ) div COPY_WIDTH ) - 1; | ||||||
|  |     for idx:=0 to BufferSize do begin | ||||||
|  |         Front[idx]:= Back[idx]; | ||||||
|  |     end; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | Procedure basicFDrawTexture(Buffer : PVideoBuffer; X : uint32; Y : uint32; Texture : PTexture); | ||||||
|  | var | ||||||
|  |     i, j : uint32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     //Draw texture to Buffer at x and y | ||||||
|  |     for i:=0 to Texture^.Height - 1 do begin | ||||||
|  |         for j:=0 to Texture^.Width - 1 do begin | ||||||
|  |             DrawPixel(X + j, Y + i, Texture^.Pixels[(i * Texture^.Width) + j]); | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure basicFDrawLine(Buffer : PVideoBuffer; x1,y1,x2,y2 : uint32; thickness : uint32; Color : TRGB32); | ||||||
|  | var | ||||||
|  |     X, Y, DX, DY, DX1, DY1, PX, PY, XE, YE, I : sint32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('video.basicFDrawLine.enter'); | ||||||
|  |  | ||||||
|  |     if(x1 = x2) then begin | ||||||
|  |         for Y:=Y1 to Y2 do begin | ||||||
|  |             DrawPixel(X1,Y,Color); | ||||||
|  |         end; | ||||||
|  |     end else if (y1 = y2) then begin | ||||||
|  |         for X:=X1 to X2 do begin | ||||||
|  |             DrawPixel(X,Y1,Color); | ||||||
|  |         end; | ||||||
|  |     end else begin | ||||||
|  |         DX:= X2 - X1; | ||||||
|  |         DY:= Y2 - Y1; | ||||||
|  |  | ||||||
|  |         DX1:= util.abs(DX); | ||||||
|  |         DY1:= util.abs(DY); | ||||||
|  |  | ||||||
|  |         PX:= 2 * DY1 - DX1; | ||||||
|  |         PY:= 2 * DX1 - DY1; | ||||||
|  |  | ||||||
|  |         if (DY1 <= DX1) then begin | ||||||
|  |             if (dx >= 0) then begin | ||||||
|  |                 X:= X1; Y:= Y1; XE:= X2; | ||||||
|  |             end else begin | ||||||
|  |                 X:= X2; Y:= Y2; XE:= X1; | ||||||
|  |             end; | ||||||
|  |  | ||||||
|  |             DrawPixel(X, Y, Color); | ||||||
|  |  | ||||||
|  |             I:=0; | ||||||
|  |             while (x < xe) do begin | ||||||
|  |                 X:= X + 1; | ||||||
|  |                 if (PX < 0) then begin | ||||||
|  |                     PX:= PX + 2 + DY1;  | ||||||
|  |                 end else begin | ||||||
|  |                     if(((dx < 0) and (dy < 0)) OR ((dx > 0) and (dy > 0))) then begin | ||||||
|  |                         Y:= Y + 1;   | ||||||
|  |                     end else begin | ||||||
|  |                         Y:= Y - 1; | ||||||
|  |                     end; | ||||||
|  |                     PX:= PX + 2 * (DY1 - DX1); | ||||||
|  |                 end; | ||||||
|  |                 DrawPixel(X,Y,Color); | ||||||
|  |                 I:= I + 1; | ||||||
|  |             end; | ||||||
|  |         end else begin | ||||||
|  |             if (DY >= 0) then begin | ||||||
|  |                 X:= X1; Y:= Y1; YE:= Y2;  | ||||||
|  |             end else begin | ||||||
|  |                 X:= X2; Y:= Y2; YE:= Y1; | ||||||
|  |             end; | ||||||
|  |  | ||||||
|  |             DrawPixel(X, Y, Color); | ||||||
|  |  | ||||||
|  |             I:=0; | ||||||
|  |             while (Y < YE) do begin | ||||||
|  |                 Y:= Y + 1; | ||||||
|  |                 if (PY <= 0) then begin | ||||||
|  |                     PY:= PY + 2 * DX1; | ||||||
|  |                 end else begin | ||||||
|  |                     if (((dx < 0) and (dy < 0)) OR ((dx > 0) and (dy > 0))) then begin | ||||||
|  |                         X:= X + 1;  | ||||||
|  |                     end else begin | ||||||
|  |                         X:= X - 1; | ||||||
|  |                     end; | ||||||
|  |                     PY:= PY + 2 * (dx1 - dy1); | ||||||
|  |                 end; | ||||||
|  |                 DrawPixel(X,Y,Color); | ||||||
|  |                 I:= I + 1; | ||||||
|  |             end; | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure basicFDrawRect(Buffer : PVideoBuffer; x1,y1,x2,y2 : uint32; line_thickness : uint32; Color : TRGB32); | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('video.basicFDrawRect.enter'); | ||||||
|  |     DrawLine(x1,y1,x2,y1,line_thickness,Color); | ||||||
|  |     DrawLine(x1,y2,x2,y2,line_thickness,Color); | ||||||
|  |     DrawLine(x1,y1,x1,y2,line_thickness,Color); | ||||||
|  |     DrawLine(x2,y1,x2,y2,line_thickness,Color); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure basicFFillRect(Buffer : PVideoBuffer; x1,y1,x2,y2 : uint32; line_thickness : uint32; Line_Color : TRGB32; Fill_Color : TRGB32); | ||||||
|  | var | ||||||
|  |     Y : uint32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('video.basicFFillRect.enter');    | ||||||
|  |     for Y:=y1 to y2 do begin | ||||||
|  |         DrawLine(x1,y,x2,y,line_thickness,Fill_Color); | ||||||
|  |     end; | ||||||
|  |     DrawRect(x1,y1,x2,y2,line_thickness,Line_Color); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | var | ||||||
|  |     VideoInterface : TVideoInterface; | ||||||
|  |     DriverMap      : PHashMap; | ||||||
|  |  | ||||||
|  | procedure init(); | ||||||
|  | var | ||||||
|  |     RGB : TRGB32; | ||||||
|  |     x,y : uint32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('video.init.enter'); | ||||||
|  |     //Ensure the frontbuffer is empty & nil, ready for initialization by a driver. | ||||||
|  |     VideoInterface.FrontBuffer.Initialized:= false; | ||||||
|  |     VideoInterface.FrontBuffer.Width:= 0; | ||||||
|  |     VideoInterface.FrontBuffer.Height:= 0; | ||||||
|  |     VideoInterface.FrontBuffer.BitsPerPixel:= 0; | ||||||
|  |     VideoInterface.FrontBuffer.Location:= 0; | ||||||
|  |  | ||||||
|  |     //Ensure the backbuffer is empty & nil, ready for initialization by a driver. | ||||||
|  |     VideoInterface.BackBuffer.Initialized:= false; | ||||||
|  |     VideoInterface.BackBuffer.Width:= 0; | ||||||
|  |     VideoInterface.BackBuffer.Height:= 0; | ||||||
|  |     VideoInterface.BackBuffer.BitsPerPixel:= 0; | ||||||
|  |     VideoInterface.BackBuffer.Location:= 0; | ||||||
|  |  | ||||||
|  |     //Set the default buffer to be the FrontBuffer, assume no double buffering to begin with. | ||||||
|  |     VideoInterface.DefaultBuffer:= @VideoInterface.FrontBuffer; | ||||||
|  |  | ||||||
|  |     { Set the draw routines to point to dummy/empty routines. | ||||||
|  |       Calls will still succeed but do nothing until a driver has registered. } | ||||||
|  |     VideoInterface.DrawRoutines.DrawPixel:= @dummyFDrawPixel; | ||||||
|  |     VideoInterface.DrawRoutines.Flush:= @basicFFlush; | ||||||
|  |     VideoInterface.DrawRoutines.DrawLine:= @basicFDrawLine; | ||||||
|  |     VideoInterface.DrawRoutines.DrawRect:= @basicFDrawRect; | ||||||
|  |     VideoInterface.DrawRoutines.FillRect:= @basicFFillRect; | ||||||
|  |  | ||||||
|  |     //Initialize our 'DriverMap', a hashmap of loadable display drivers. | ||||||
|  |     DriverMap:= hashmap.new; | ||||||
|  |  | ||||||
|  |     tracer.push_trace('video.init.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function register(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean; | ||||||
|  | var | ||||||
|  |     Value : Void; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('video.register.enter'); | ||||||
|  |     register:= false; | ||||||
|  |     Value:= Hashmap.get(DriverMap, DriverIdentifier); | ||||||
|  |     if (Value = nil) then begin | ||||||
|  |         Hashmap.add(DriverMap, DriverIdentifier, void(EnableCallback)); | ||||||
|  |         register:= true; | ||||||
|  |     end; | ||||||
|  |     tracer.push_trace('video.register.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function enable(DriverIdentifier : pchar) : boolean; | ||||||
|  | var | ||||||
|  |     Value : Void; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     tracer.push_trace('video.enable.enter'); | ||||||
|  |     enable:= false; | ||||||
|  |     Value:= Hashmap.get(DriverMap, DriverIdentifier); | ||||||
|  |     if (Value <> nil) then begin | ||||||
|  |         enable:= FEnableDriver(Value)(@VideoInterface); | ||||||
|  |     end; | ||||||
|  |     tracer.push_trace('video.enable.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure DrawPixel(X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  | begin | ||||||
|  |     //tracer.push_trace('video.DrawPixel.enter'); | ||||||
|  |     VideoInterface.DrawRoutines.DrawPixel(VideoInterface.DefaultBuffer, X, Y, Pixel); | ||||||
|  |     //tracer.push_trace('video.DrawPixel.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure Flush(); | ||||||
|  | begin | ||||||
|  |     //tracer.push_trace('video.Flush.enter'); | ||||||
|  |     VideoInterface.DrawRoutines.Flush(@VideoInterface.FrontBuffer, @VideoInterface.BackBuffer); | ||||||
|  |     //tracer.push_trace('video.Flush.exit'); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure DrawLine(x1,y1,x2,y2 : uint32; thickness : uint32; Color : TRGB32); | ||||||
|  | begin | ||||||
|  |     VideoInterface.DrawRoutines.DrawLine(VideoInterface.DefaultBuffer,x1,y1,x2,y2,thickness,Color); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure DrawRect(x1,y1,x2,y2 : uint32; line_thickness : uint32; Color : TRGB32); | ||||||
|  | begin | ||||||
|  |     VideoInterface.DrawRoutines.DrawRect(VideoInterface.DefaultBuffer,x1,y1,x2,y2,line_thickness,color); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | procedure FillRect(x1,y1,x2,y2 : uint32; line_thickness : uint32; Line_Color : TRGB32; Fill_Color : TRGB32); | ||||||
|  | begin | ||||||
|  |     VideoInterface.DrawRoutines.FillRect(VideoInterface.DefaultBuffer,x1,y1,x2,y2,line_thickness,Line_Color,Fill_Color); | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function frontBufferWidth : uint32; | ||||||
|  | begin | ||||||
|  |     frontBufferWidth:= VideoInterface.FrontBuffer.Width; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function frontBufferHeight : uint32; | ||||||
|  | begin | ||||||
|  |     frontBufferHeight:= VideoInterface.FrontBuffer.Height; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function frontBufferBpp : uint8; | ||||||
|  | begin | ||||||
|  |     frontBufferBpp:= VideoInterface.FrontBuffer.BitsPerPixel; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function backBufferWidth : uint32; | ||||||
|  | begin | ||||||
|  |     backBufferWidth:= VideoInterface.BackBuffer.Width; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function backBufferHeight : uint32; | ||||||
|  | begin | ||||||
|  |     backBufferHeight:= VideoInterface.BackBuffer.Height; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | function backBufferBpp : uint8; | ||||||
|  | begin | ||||||
|  |     backBufferBpp:= VideoInterface.BackBuffer.BitsPerPixel; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										92
									
								
								src/driver/video/videotypes.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/driver/video/videotypes.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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->Video->Videotypes - Provides types relating to the video framework & driver interface. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit videotypes; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     color; | ||||||
|  |  | ||||||
|  | type | ||||||
|  |     //Arbitrary pointer to a raw video buffer in memory | ||||||
|  |     VideoBuffer = uint32; | ||||||
|  |  | ||||||
|  |     //Struct representing a Memory Mapped Video Buffer | ||||||
|  |     TVideoBuffer = record | ||||||
|  |         //Has this buffer been initialized? Has it been paged/created in memory? | ||||||
|  |         Initialized     : Boolean; | ||||||
|  |         //Location of the video buffer in memory as a QWORD. | ||||||
|  |         Location        : VideoBuffer; | ||||||
|  |         //How many bits per pixel? | ||||||
|  |         BitsPerPixel    : uint8; | ||||||
|  |         //Width of the buffer. | ||||||
|  |         Width           : uint32; | ||||||
|  |         //Height of the buffer. | ||||||
|  |         Height          : uint32; | ||||||
|  |     end; | ||||||
|  |     //Pointer to a video buffer | ||||||
|  |     PVideoBuffer = ^TVideoBuffer; | ||||||
|  |  | ||||||
|  |     //(Abstract) Draw a pixel to screenspace | ||||||
|  |     FDrawPixel = procedure(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); | ||||||
|  |     //(Abstract) Flush backbuffer to MMIO Buffer | ||||||
|  |     FFlush     = procedure(FrontBuffer : PVideoBuffer; BackBuffer : PVideoBuffer); | ||||||
|  |     //(Abstract) Draw a line to the screen | ||||||
|  |     FDrawLine = procedure(Buffer : PVideoBuffer; x1,y1,x2,y2 : uint32; thickness : uint32; Color : TRGB32); | ||||||
|  |     //(Abstract) Draw a rect to the screen | ||||||
|  |     FDrawRect = procedure(Buffer : PVideoBuffer; x1,y1,x2,y2 : uint32; line_thickness : uint32; Color : TRGB32); | ||||||
|  |     //(Abstract) Draw a filled rect to the screen | ||||||
|  |     FFillRect = procedure(Buffer : PVideoBuffer; x1,y1,x2,y2 : uint32; line_thickness : uint32; Line_Color : TRGB32; Fill_Color : TRGB32); | ||||||
|  |  | ||||||
|  |     //Routines for drawing to the screen | ||||||
|  |     TDrawRoutines = record | ||||||
|  |         DrawPixel : FDrawPixel; | ||||||
|  |         Flush     : FFlush; | ||||||
|  |         DrawLine  : FDrawLine; | ||||||
|  |         DrawRect  : FDrawRect; | ||||||
|  |         FillRect  : FFillRect; | ||||||
|  |     end; | ||||||
|  |     //Pointer to drawing routines | ||||||
|  |     PDrawRoutines = ^TDrawRoutines; | ||||||
|  |  | ||||||
|  |     //Struct representing the whole video driver. | ||||||
|  |     TVideoInterface = record | ||||||
|  |         //Default buffer to be used when rendering, front buffer for no double buffering, back buffer otherwise. | ||||||
|  |         DefaultBuffer   : PVideoBuffer; | ||||||
|  |         //Memory Mapped IO Buffer for raw rasterization. | ||||||
|  |         FrontBuffer     : TVideoBuffer; | ||||||
|  |         //Back buffer used for double buffering, this is flushed to FrontBuffer with flush(); | ||||||
|  |         BackBuffer      : TVideoBuffer; | ||||||
|  |         //Drawing Routines | ||||||
|  |         DrawRoutines    : TDrawRoutines; | ||||||
|  |     end; | ||||||
|  |     //Pointer to a video interface struct. | ||||||
|  |     PVideoInterface = ^TVideoInterface; | ||||||
|  |  | ||||||
|  |     //(Abstract) Enable method for a driver, called from video to enable driver. | ||||||
|  |     FEnableDriver = function(VideoInterface : PVideoInterface) : boolean; | ||||||
|  |     //(Abstract) Register driver, called from a driver to register with the video interface. | ||||||
|  |     FRegisterDriver = function(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean; | ||||||
|  |     //(Abstract) Init driver, called from _somewhere_ to start the driver and register it with the video interface. | ||||||
|  |     FInitDriver = procedure(Register : FRegisterDriver); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										63
									
								
								src/include/color.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/include/color.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | //  Copyright 2021 Kieron Morris | ||||||
|  | // | ||||||
|  | //  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. | ||||||
|  |  | ||||||
|  | {  | ||||||
|  | 	Include->Color - Provides types relating to color/graphics. | ||||||
|  | 	 | ||||||
|  | 	@author(Kieron Morris <kjm@kieronmorris.me>) | ||||||
|  | } | ||||||
|  | unit color; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | type | ||||||
|  |     TRGB32 = bitpacked record | ||||||
|  |         B : uint8; | ||||||
|  |         G : uint8; | ||||||
|  |         R : uint8; | ||||||
|  |         A : uint8; | ||||||
|  |     end; | ||||||
|  |     PRGB32 = ^TRGB32; | ||||||
|  |  | ||||||
|  |     TRGB24 = bitpacked record | ||||||
|  |         B : uint8; | ||||||
|  |         G : uint8; | ||||||
|  |         R : uint8; | ||||||
|  |     end; | ||||||
|  |     PRGB23 = ^TRGB24; | ||||||
|  |  | ||||||
|  |     TRGB16 = bitpacked record | ||||||
|  |         B : UBit5; | ||||||
|  |         G : UBit6; | ||||||
|  |         R : UBit5; | ||||||
|  |     end; | ||||||
|  |     PRGB16 = ^TRGB16; | ||||||
|  |  | ||||||
|  |     TRGB8 = bitpacked record | ||||||
|  |         B : UBit2; | ||||||
|  |         G : UBit4; | ||||||
|  |         R : UBit2; | ||||||
|  |     end; | ||||||
|  |     PRGB8 = ^TRGB8; | ||||||
|  |  | ||||||
|  | const | ||||||
|  |     black : TRGB32 = (B: 000; G: 000; R: 000; A: 000); | ||||||
|  |     white : TRGB32 = (B: 255; G: 255; R: 255; A: 000); | ||||||
|  |     red   : TRGB32 = (B: 000; G: 000; R: 255; A: 000); | ||||||
|  |     green : TRGB32 = (B: 000; G: 255; R: 000; A: 000); | ||||||
|  |     blue  : TRGB32 = (B: 255; G: 000; R: 000; A: 000); | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | end. | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -143,6 +143,22 @@ type | |||||||
|  |  | ||||||
|     PText = ^Text; |     PText = ^Text; | ||||||
|  |  | ||||||
|  | var | ||||||
|  |   AK_START : uint32; external name 'kernel_start'; | ||||||
|  |   AK_END   : uint32; external name 'kernel_end'; | ||||||
|  |   ASURO_KERNEL_START : uint32; | ||||||
|  |   ASURO_KERNEL_END   : uint32; | ||||||
|  |   ASURO_KERNEL_SIZE  : uint32; | ||||||
|  |  | ||||||
|  | procedure init(); | ||||||
|  |  | ||||||
| implementation | implementation | ||||||
|  |  | ||||||
|  | procedure init(); | ||||||
|  | begin | ||||||
|  |     ASURO_KERNEL_START := uint32(@AK_START); | ||||||
|  |     ASURO_KERNEL_END := uint32(@AK_END); | ||||||
|  |     ASURO_KERNEL_SIZE:= ASURO_KERNEL_END - ASURO_KERNEL_START; | ||||||
|  | end; | ||||||
|  |  | ||||||
| end. | end. | ||||||
|   | |||||||
							
								
								
									
										67
									
								
								src/include/targa.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/include/targa.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | unit targa; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     lmemorymanager, texture; | ||||||
|  |  | ||||||
|  | type | ||||||
|  |     TTARGAColor = packed record | ||||||
|  |       b, g, r, a: uint8; | ||||||
|  |     end; | ||||||
|  |     PTARGAColor = ^TTARGAColor; | ||||||
|  |  | ||||||
|  |     TTARGAHeader = packed record | ||||||
|  |         Magic: uint8; | ||||||
|  |         ColorMapType: uint8; | ||||||
|  |         ImageType: uint8; | ||||||
|  |         ColorMapOrigin: uint16; | ||||||
|  |         ColorMapLength: uint16; | ||||||
|  |         ColorMapDepth: uint8; | ||||||
|  |         XOrigin: uint16; | ||||||
|  |         YOrigin: uint16; | ||||||
|  |         Width: uint16; | ||||||
|  |         Height: uint16; | ||||||
|  |         PixelDepth: uint8; | ||||||
|  |         ImageDescriptor: uint8; | ||||||
|  |         Data : PTARGAColor; | ||||||
|  |     end; | ||||||
|  |     PTARGAHeader = ^TTARGAHeader; | ||||||
|  |  | ||||||
|  | Function Parse(buffer : puint8; len : uint32) : PTexture; | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | Function Parse(buffer : puint8; len : uint32) : PTexture; | ||||||
|  | var | ||||||
|  |     header : PTARGAHeader; | ||||||
|  |     i, j : uint32; | ||||||
|  |     data : PTARGAColor; | ||||||
|  |     tex : PTexture; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     if (len < sizeof(TTARGAHeader)) then exit; | ||||||
|  |  | ||||||
|  |     header := PTARGAHeader(buffer); | ||||||
|  |     if (header^.Magic <> $0) or (header^.ImageType <> 2) or (header^.PixelDepth <> 32) then exit; | ||||||
|  |      | ||||||
|  |     //Create a new texture | ||||||
|  |     tex:= texture.newTexture(header^.Width, header^.Height); | ||||||
|  |     tex^.Width:= header^.Width; | ||||||
|  |     tex^.Height:= header^.Height; | ||||||
|  |      | ||||||
|  |     //Copy the data | ||||||
|  |     data := PTARGAColor(header^.Data); | ||||||
|  |     for i := 0 to header^.Height - 1 do begin | ||||||
|  |         for j := 0 to header^.Width - 1 do begin | ||||||
|  |             tex^.Pixels[i * header^.Width + j].r := data^.r; | ||||||
|  |             tex^.Pixels[i * header^.Width + j].g := data^.g; | ||||||
|  |             tex^.Pixels[i * header^.Width + j].b := data^.b; | ||||||
|  |             tex^.Pixels[i * header^.Width + j].a := data^.a; | ||||||
|  |         end; | ||||||
|  |     end; | ||||||
|  |  | ||||||
|  |     Parse := tex; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
							
								
								
									
										34
									
								
								src/include/texture.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/include/texture.pas
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | unit texture; | ||||||
|  |  | ||||||
|  | interface | ||||||
|  |  | ||||||
|  | uses | ||||||
|  |     lmemorymanager, color; | ||||||
|  |  | ||||||
|  | type | ||||||
|  |     TTexture = packed record | ||||||
|  |         Width  : uint32;  | ||||||
|  |         Height : uint32;  | ||||||
|  |         Size   : uint32; | ||||||
|  |         Pixels : PRGB32; | ||||||
|  |     end; | ||||||
|  |     PTexture = ^TTexture; | ||||||
|  |  | ||||||
|  | Function newTexture(width, height: uint32): PTexture; | ||||||
|  |  | ||||||
|  | implementation | ||||||
|  |  | ||||||
|  | Function newTexture(width, height: uint32): PTexture; | ||||||
|  | var | ||||||
|  |     texture: PTexture; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     texture:= PTexture(kalloc(sizeof(TTexture))); | ||||||
|  |     texture^.Pixels:= PRGB32(kalloc(width * height * sizeof(TRGB32))); | ||||||
|  |     texture^.Width:= width; | ||||||
|  |     texture^.Height:= height; | ||||||
|  |     texture^.Size:= width * height; | ||||||
|  |     newTexture:= texture; | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | end. | ||||||
| @@ -49,6 +49,7 @@ procedure io_wait; | |||||||
|  |  | ||||||
| procedure memset(location : uint32; value : uint8; size : uint32); | procedure memset(location : uint32; value : uint8; size : uint32); | ||||||
| procedure memcpy(source : uint32; dest : uint32; size : uint32); | procedure memcpy(source : uint32; dest : uint32; size : uint32); | ||||||
|  | procedure __SSE_128_memcpy(source : uint32; dest : uint32); | ||||||
|  |  | ||||||
| procedure printmemory(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean); | procedure printmemory(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean); | ||||||
| procedure printmemoryWND(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean; WND : HWND); | procedure printmemoryWND(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean; WND : HWND); | ||||||
| @@ -80,6 +81,8 @@ function RorDWord(AValue : uint32; Dist : uint8) : uint32; | |||||||
|  |  | ||||||
| function MsSinceSystemBoot : uint64; | function MsSinceSystemBoot : uint64; | ||||||
|  |  | ||||||
|  | function abs(x : sint32) : uint32; | ||||||
|  |  | ||||||
| var | var | ||||||
|     endptr : uint32; external name '__end'; |     endptr : uint32; external name '__end'; | ||||||
|     stack  : uint32; external name 'KERNEL_STACK'; |     stack  : uint32; external name 'KERNEL_STACK'; | ||||||
| @@ -89,6 +92,15 @@ implementation | |||||||
| uses | uses | ||||||
|     console, RTC, cpu, serial, strings, isr_types; |     console, RTC, cpu, serial, strings, isr_types; | ||||||
|  |  | ||||||
|  | function abs(x : sint32) : uint32; | ||||||
|  | var | ||||||
|  |     y : uint32; | ||||||
|  |  | ||||||
|  | begin | ||||||
|  |     y:= x SHR 31; | ||||||
|  |     abs:= (x XOR y) - y; | ||||||
|  | end; | ||||||
|  |  | ||||||
| function MsSinceSystemBoot : uint64; | function MsSinceSystemBoot : uint64; | ||||||
| begin | begin | ||||||
|     MsSinceSystemBoot:= div6432(getTSC, (CPUID.ClockSpeed.Hz div 1000)); |     MsSinceSystemBoot:= div6432(getTSC, (CPUID.ClockSpeed.Hz div 1000)); | ||||||
| @@ -116,6 +128,14 @@ begin | |||||||
|     div6432:= (r0 SHL 32) OR r4; |     div6432:= (r0 SHL 32) OR r4; | ||||||
| end; | end; | ||||||
|  |  | ||||||
|  | procedure __SSE_128_memcpy(source : uint32; dest : uint32); assembler; | ||||||
|  | asm | ||||||
|  |     MOV EAX, Source | ||||||
|  |     MOVAPS XMM1, [EAX] | ||||||
|  |     MOV EAX, Dest | ||||||
|  |     MOVAPS [EAX], XMM1 | ||||||
|  | end; | ||||||
|  |  | ||||||
| function switchendian16(b : uint16) : uint16; | function switchendian16(b : uint16) : uint16; | ||||||
| begin | begin | ||||||
|     switchendian16:= ((b AND $FF00) SHR 8) OR ((b AND $00FF) SHL 8); |     switchendian16:= ((b AND $FF00) SHR 8) OR ((b AND $00FF) SHL 8); | ||||||
| @@ -335,7 +355,6 @@ 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,8 +33,6 @@ 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; | ||||||
| @@ -58,13 +56,6 @@ 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,13 +40,10 @@ uses | |||||||
|      testdriver, |      testdriver, | ||||||
|      E1000, |      E1000, | ||||||
|      IDE, |      IDE, | ||||||
|     //  storagemanagement, |      storagemanagement, | ||||||
|     //  drivemanager, |  | ||||||
|      volumemanager, |  | ||||||
|      lists, |      lists, | ||||||
|      net, |      net, | ||||||
|     //  fat32, |      fat32, | ||||||
|     //  flatfs, |  | ||||||
|      isrmanager, |      isrmanager, | ||||||
|      faults, |      faults, | ||||||
|      fonts, |      fonts, | ||||||
| @@ -58,7 +55,7 @@ uses | |||||||
|      rand, |      rand, | ||||||
|      terminal, |      terminal, | ||||||
|      hashmap, vfs,  |      hashmap, vfs,  | ||||||
|      AHCI; |      video, vesa, doublebuffer, color; | ||||||
|   |   | ||||||
| procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall; | procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall; | ||||||
|   |   | ||||||
| @@ -128,7 +125,15 @@ var | |||||||
|  |  | ||||||
|    HM              : PHashMap; |    HM              : PHashMap; | ||||||
|  |  | ||||||
|  |    colour          : TRGB32; | ||||||
|  |  | ||||||
|  |    array1          : Array[0..255] of char; | ||||||
|  |    array2          : Array[0..255] of char; | ||||||
|  |     | ||||||
| begin | begin | ||||||
|  |      { Init the base system unit } | ||||||
|  |      System.init(); | ||||||
|  |  | ||||||
|      { Serial Init } |      { Serial Init } | ||||||
|      serial.init(); |      serial.init(); | ||||||
|  |  | ||||||
| @@ -136,6 +141,8 @@ begin | |||||||
|      multibootinfo:= mbinfo; |      multibootinfo:= mbinfo; | ||||||
|      multibootmagic:= mbmagic; |      multibootmagic:= mbmagic; | ||||||
|  |  | ||||||
|  |     //video.init(); | ||||||
|  |  | ||||||
|      { Ensure tracer is frozen } |      { Ensure tracer is frozen } | ||||||
|      tracer.freeze(); |      tracer.freeze(); | ||||||
|  |  | ||||||
| @@ -202,6 +209,53 @@ begin | |||||||
|      { Call Tracer } |      { Call Tracer } | ||||||
|      tracer.init(); |      tracer.init(); | ||||||
|  |  | ||||||
|  |      video.init(); | ||||||
|  |      vesa.init(@video.register); | ||||||
|  |      doublebuffer.init(@video.register); | ||||||
|  |      video.enable('VESA'); | ||||||
|  |      video.enable('BASIC_DOUBLE_BUFFER'); | ||||||
|  |      colour:= color.white; | ||||||
|  |  | ||||||
|  |     //  serial.sendHex(uint32(@array1[8])); | ||||||
|  |     //  serial.sendHex(uint32(@array2[8])); | ||||||
|  |     //  for i:=8 to 23 do begin | ||||||
|  |     //     array2[i]:= '?'; | ||||||
|  |     //  end; | ||||||
|  |     //  array2[24]:= #0; | ||||||
|  |  | ||||||
|  |     //  array1[8]:= 'H'; | ||||||
|  |     //  array1[9]:= 'e'; | ||||||
|  |     //  array1[10]:= 'l'; | ||||||
|  |     //  array1[11]:= 'l'; | ||||||
|  |     //  array1[12]:= 'o'; | ||||||
|  |     //  array1[13]:= 'w'; | ||||||
|  |     //  array1[14]:= 'o'; | ||||||
|  |     //  array1[15]:= 'r'; | ||||||
|  |     //  array1[16]:= 'l'; | ||||||
|  |     //  array1[17]:= 'd'; | ||||||
|  |     //  array1[18]:= '1'; | ||||||
|  |     //  array1[19]:= '2'; | ||||||
|  |     //  array1[20]:= '3'; | ||||||
|  |     //  array1[21]:= '4'; | ||||||
|  |     //  array1[22]:= '5'; | ||||||
|  |     //  array1[23]:= '!'; | ||||||
|  |     //  __SSE_128_memcpy(uint32(@array1[8]), uint32(@array2[8])); | ||||||
|  |     //  serial.sendString(pchar(@array2[8])); | ||||||
|  |  | ||||||
|  |      for i:=0 to video.frontBufferWidth-1 do begin | ||||||
|  |         for z:=0 to video.frontBufferHeight-1 do begin | ||||||
|  |             video.DrawPixel(i, z, colour); | ||||||
|  |         end; | ||||||
|  |      end; | ||||||
|  |  | ||||||
|  |      video.DrawLine(50,50,100,100,1,color.black); | ||||||
|  |      video.DrawRect(50,150,100,200,1,color.black); | ||||||
|  |      video.FillRect(50,250,100,300,1,color.black,color.red); | ||||||
|  |      video.DrawLine(50,350,100,350,1,color.black); | ||||||
|  |      video.Flush(); | ||||||
|  |  | ||||||
|  |      while true do begin end; | ||||||
|  |  | ||||||
|      { VFS Init } |      { VFS Init } | ||||||
|      vfs.init(); |      vfs.init(); | ||||||
|  |  | ||||||
| @@ -209,9 +263,7 @@ 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'); | ||||||
| @@ -219,8 +271,7 @@ 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'); | ||||||
| @@ -229,8 +280,7 @@ 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,7 +57,6 @@ 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; | ||||||
| @@ -218,11 +217,6 @@ 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,15 +22,7 @@ unit edit; | |||||||
| interface | interface | ||||||
|  |  | ||||||
| uses | uses | ||||||
|     console, |     console, terminal, keyboard, shell, strings, tracer, storagemanagement, lmemorymanager, util; | ||||||
|     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,  | ||||||
|      netlog, themer, |     edit, 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'); | ||||||
|   | |||||||
| @@ -77,9 +77,9 @@ dd 0 | |||||||
| dd 0 | dd 0 | ||||||
| dd 0 | dd 0 | ||||||
| dd 0 | dd 0 | ||||||
| dd 1280 | dd 1600 | ||||||
| dd 1024 | dd 1200 | ||||||
| dd 16 | dd 32 | ||||||
|  |  | ||||||
| ; | ; | ||||||
| ; Entrypoint | ; Entrypoint | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user