duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit 2d45f46cd48a9523b98b8abe12e1159e142fb743
parent a33b782973b52f099b08f8f28aa587631d55b8fe
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Wed, 19 Oct 2022 20:16:20 -0400

drv/pc/ahci: getting up to the IDENTIFY phase! (in QEMU)

To try, change the "pcrun" make target to add "-machine q35" and then do this
at the Dusk prompt:

ahci$
.ahci
\ Locate the port number of an appropriate device
( portno ) AHCIDevice :new value dev
dev AHCIDevice :enable
dev AHCIDevice :identify .x
\ Should print something like 00000058, the same status than .ataall under the
\ "pc" QEMU machine.

Diffstat:
MREFS.md | 4++++
Mfs/drv/pc/ahci.fs | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Afs/drv/pc/sata.fs | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfs/tests/kernel.fs | 2+-
Mfs/xcomp/bootlo.fs | 3++-
5 files changed, 170 insertions(+), 18 deletions(-)

diff --git a/REFS.md b/REFS.md @@ -25,8 +25,12 @@ helpful: * [FreeVGA][freevga] * [Ralf Brown's x86 interrupt list][ralfint] * [Intel's ICH7 datasheet][ich7] +* [AHCI 1.3.1 specifications][ahci] +* [Serial ATA 1.0 specifications][sata] [osdev]: https://wiki.osdev.org/ [freevga]: http://www.osdever.net/FreeVGA/home.htm [ralfint]: http://www.cs.cmu.edu/~ralf/files.html [ich7]: https://www.intel.com/content/dam/doc/datasheet/i-o-controller-hub-7-datasheet.pdf +[ahci]: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1-3-1.pdf +[sata]: https://www.seagate.com/support/disc/manuals/sata/sata_im.pdf diff --git a/fs/drv/pc/ahci.fs b/fs/drv/pc/ahci.fs @@ -1,5 +1,9 @@ \ AHCI driver ?f<< /drv/pc/pci.fs +?f<< /drv/pc/sata.fs + +\ Align here to n bytes, n being a power of 2. +: alignn ( n -- ) dup 1- here and dup if - allot else 2drop then ; struct[ HBAPort sfield clb @@ -21,6 +25,66 @@ struct[ HBAPort sfield fbs 11 CELLSZ * sallot \ reserved 4 CELLSZ * sfield' vendor + + : :waitcmd begin dup cmd $8000 ( CR ) and not until drop ; + : :startcmd + dup :waitcmd + \ ST can only be set *after* FRE + dup cmd $10 ( FRE ) or over to cmd + dup cmd 1 ( ST ) or swap to cmd ; + : :stopcmd dup cmd $ffffffee ( ~FRE+~ST ) and swap to cmd ; + : :ci! 1 over to ci begin dup ci not until drop ; + : :sigstr ( self -- str ) sig case + $101 of = S" ATA" endof + $eb140101 of = S" ATAPI" endof + $c33c0101 of = S" bridge" endof + $96690101 of = S" multiplier" endof + S" unknown" endcase ; +]struct + +struct[ RsvdFIS \ buffer for receiving FIS from AHCI controller + $20 sfield' dma + $20 sfield' pio + $18 sfield' d2h + $02 sfield' sdb \ set device bits + $40 sfield' unknown + $60 sallot \ reserved + + : :new ( -- self ) $100 alignn here SZ allot0 ; +]struct + +struct[ PRDTable + sfield addr \ address of data, 2-bit aligned + sfield addrhi + 4 sallot \ reserved + sfieldw bytecount \ 0-indexed! 0=1 byte 1=2 bytes etc. must be odd. + sfieldb bytecounthi \ bytecount's maximum is 4 MB + sfieldb flags \ b7=Interrupt on Completion +]struct + +struct[ CmdHeader + sfieldw flags + sfieldw prdtl \ Physical Region Descriptor Table Length + sfield prdbc \ PRD byte count + sfield cmdtba \ address of a CmdTable, 128-bit aligned + sfield cmdtbau + $10 sallot \ reserved + + : :cfl! ( n self -- ) tuck flags $fff0 and or swap to flags ; + : :new ( -- cmdlist ) $400 alignn here SZ $20 * allot0 ; +]struct + +struct[ CmdTable + $40 sfield' fis + $10 sfield' atapicmd + $30 sallot \ reserved + 0 sfield' prdt \ variable length, list of PRDTable + + : :new ( cmdhdr prdt-count -- cmdt ) + $80 alignn here swap PRDTable SZ * SZ + allot0 ( cmdhdr cmdt ) + FISH2D TYPE over fis c! ( cmdhdr cmdt ) + 2dup swap to CmdHeader cmdtba ( cmdhdr cmdt ) + FISH2D SZ >> >> rot CmdHeader :cfl! ( cmdt ) ; ]struct struct[ HBAMem @@ -37,10 +101,37 @@ struct[ HBAMem sfield bohc $a0 SZ - sallot \ reserved $100 SZ - sfield' vendor - HBAPort SZ 32 * sfield' ports + HBAPort SZ $20 * sfield' ports + + : :port ( n self -- 'port ) ports swap HBAPort SZ * + ; ]struct -0 structbind HBAMem hba +0 structbind HBAMem ahci + +struct[ AHCIDevice + sconst portno + sconst port \ HBAPort + sconst cmds \ CmdHeader * 32 + sconst rsvdfis \ RsvdFIS + + : :new ( portno -- self ) + RsvdFIS :new CmdHeader :new here >r ( portno rsvdfis cmds ) + rot dup ( portno ) , ahci :port , ( cmds ) , ( rsvdfis ) , + r@ port HBAPort :stopcmd + r@ cmds to r@ port HBAPort clb + r@ rsvdfis to r@ port HBAPort fb + \ We only need a single command table, which itself only needs a single PRDT + r@ cmds 1 CmdTable :new + r> ; + : :enable port HBAPort :startcmd ; + : :cmd0 cmds CmdHeader cmdtba ; + : :fis0 :cmd0 CmdTable fis ; + : :identify ( self -- status ) + dup :fis0 $ec ( IDENTIFY ) over to FISH2D command ( fis ) + $80 ( enable C ) swap to FISH2D flags ( self ) + dup port HBAPort :ci! + dup rsvdfis RsvdFIS pio FISPIOSetup status ; +]struct \ Search PCI bus for a AHCI controller and if found, bind "hba" to its BAR5 \ value. @@ -49,27 +140,20 @@ struct[ HBAMem 0 >r 0 >r begin \ V1=slot V2=func V1 $20 < while 0 V1 V2 pcisel if - pci.class 1 = pci.subclass 6 = and if pci0.bar5 ['] hba rebind then then + pci.class 1 = pci.subclass 6 = and if pci0.bar5 ['] ahci rebind then then 1 to+ V2 V2 8 = if 0 to V2 1 to+ V1 then repeat rfree ; \ Do we have a AHCI controller? -: ahci? hba :self bool ; - -: sigstr ( sig -- str ) case - $101 of = S" ATA" endof - $eb140101 of = S" ATAPI" endof - $c33c0101 of = S" bridge" endof - $96690101 of = S" multiplier" endof - S" unknown" endcase ; +: ahci? ahci :self bool ; : .ahci ahci? not if abort" No AHCI controller" then - ." HBA addr: " hba :self .x nl> - ." Ports implemented: " hba pi .x nl> - $20 >r hba pi 0 begin ( pi id ) + ." HBA addr: " ahci :self .x nl> + ." Ports implemented: " ahci pi .x nl> + $20 >r ahci pi 0 begin ( pi id ) 2dup bit? if - hba ports over HBAPort SZ * + dup HBAPort ssts $0f0f and $0103 = if + dup ahci :port dup HBAPort ssts $0f0f and $0103 = if ( pi id port ) \ detected and active - ." Device " over . ." type: " HBAPort sig sigstr stype nl> + ." Device " over . ." type: " HBAPort :sigstr stype nl> else drop then then ( pi id ) 1+ next ; diff --git a/fs/drv/pc/sata.fs b/fs/drv/pc/sata.fs @@ -0,0 +1,63 @@ +\ SATA Driver + +struct[ FIS + sfieldb type +]struct + +extends FIS struct[ FISH2D + sfieldb flags \ b7=C + sfieldb command + sfieldb features + sfieldb sector + sfieldw cylinder + sfieldb device + sfieldb sectorhi + sfieldw cylinderhi + sfieldb featureshi + sfieldw count + 1 sallot \ reserved + sfieldb control + 4 sallot \ reserved + + $27 const TYPE +]struct + +extends FIS struct[ FISD2H + sfieldb flags \ b6=I + sfieldb status + sfieldb error + sfieldb sector + sfieldw cylinder + sfieldb device + sfieldb sectorhi + sfieldw cylinderhi + 1 sallot \ reserved + sfieldw count + 6 sallot \ reserved + + $34 const TYPE +]struct + +extends FIS struct[ FISPIOSetup + sfieldb flags \ b6=I b5=D + sfieldb status + sfieldb error + sfieldb sector + sfieldw cylinder + sfieldb device + sfieldb sectorhi + sfieldw cylinderhi + 1 sallot \ reserved + sfieldb e_status + 4 sallot \ reserved + sfieldw transfercount + 2 sallot \ reserved + + $5f const TYPE +]struct + +extends FIS struct[ FISData + 3 sallot \ reserved + 0 sfield' data \ variable length + $46 const TYPE +]struct diff --git a/fs/tests/kernel.fs b/fs/tests/kernel.fs @@ -125,7 +125,7 @@ data1 Foo :bleh 46 #eq myword 46 #eq extends Foo struct[ Bazooka - sfield bling + sconst bling ]struct create data3 7 , 9 c, ' mybleh , 999 , data3 Bazooka bling 999 #eq diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs @@ -258,7 +258,8 @@ does> ( 'struct ) : sfield CELLSZ _svalue ; : sfieldw 2 _svalue ; : sfieldb 1 _svalue ; -: sfield' ( sz -- ) _cur e>w structsz &+ _sfield ; +: sfield' ( sz -- ) doer _sfield does> CELLSZ + @ ( a off ) + ; +: sconst doer CELLSZ _sfield does> CELLSZ + @ ( a off ) + @ ; : smethod doer _cur e>w structsz , CELLSZ sallot does> @ over + @ execute ; struct[ Struct