duskos

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

commit f8f78e92da936ffbd9b1ed00f18ec3d61a1b9f32
parent 53e59e63ddb85c84c1d7aba4a56a73385d7a2e04
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Sun, 31 Jul 2022 08:36:33 -0400

Introduce the Drive API

Diffstat:
Afs/doc/drive.txt | 25+++++++++++++++++++++++++
Mfs/doc/io.txt | 3---
Mfs/drv/pc/ata.fs | 11+++++++++--
Mfs/drv/pc/int13h.fs | 11+++++++++--
Mfs/drv/ramdrive.fs | 15+++++++++------
Mfs/fs/fat.fs | 8++++----
Mfs/fs/fatlo.fs | 14+++++++-------
Dfs/sys/drive.fs | 41-----------------------------------------
Mfs/tests/sys/all.fs | 1-
Dfs/tests/sys/drive.fs | 6------
Mfs/xcomp/bootlo.fs | 9+++++----
Mfs/xcomp/pc/glue1.fs | 2+-
Mfs/xcomp/pc/init.fs | 2+-
Mposix/glue1.fs | 3+--
Mposix/init.fs | 5-----
15 files changed, 71 insertions(+), 85 deletions(-)

diff --git a/fs/doc/drive.txt b/fs/doc/drive.txt @@ -0,0 +1,25 @@ +# Drive API + +The sys/drive subsystem offers a unified API to read and write to mass storage. +It does so in blocks of bytes of a definite size which we call "sector". +Sectors in the Drive API are organized in a linear manner (LBA, Logical Block +Addressing). If the underlying mass storage driver interfaces with a CHS +(cylinder, head, sector) system, it's its responsibility to convert LBA to CHS. + +The drive API exposes the features of the underlying driver through a specific +data structure, called a Drive, which is 12 bytes in length in the form of 3 +fields of 4 bytes: + +sectorsize +drv@ +drv! + +sectorsize is an integer describing, in bytes, the size of sectors read and +written by the driver. It's often 512 bytes. + +drv@ ( sec dst drv -- ) + Read sector "sec" in memory address "dst", which needs to be a buffer at least + "sectorsize" in size. "drv" is a pointer to a Drive structure. + +drv! ( sec src drv -- ) + Write sector "sec" from memory address "src". diff --git a/fs/doc/io.txt b/fs/doc/io.txt @@ -1,8 +1,5 @@ # Input/Output -(this document doesn't describe things as they are now, but as they're going to -be soon) - The lib/io subsystem offers a unified API to read and write on any device or filesystem. All words in this API revolves around a structures that we call the "IO handle". These handle represent one "place" we read and write to, saving, if diff --git a/fs/drv/pc/ata.fs b/fs/drv/pc/ata.fs @@ -42,13 +42,20 @@ $ec const IDENTIFY dup 8 rshift _cyllo pc! 16 rshift _cylhi pc! ; -: ata@ ( sec dst -- ) - swap _locate $20 ( read sectors ) _cmd pc! _wait ( dst ) +: ata@ ( sec dst drv -- ) + drop swap _locate $20 ( read sectors ) _cmd pc! _wait ( dst ) A>r ( dst ) >A $100 >r begin _data pw@ A> w! A+ A+ next r>A ; +: ata! abort" ATA driver doesn't support writing" ; + : .ata ( -- ) atabus . ':' emit atadrive . spc> ataidentify .x1 ; : .ataall ( -- ) atadrive atabus 0 to atabus 0 to atadrive .ata nl> 1 to atadrive .ata nl> 1 to atabus 0 to atadrive .ata nl> 1 to atadrive .ata nl> to atabus to atadrive ; + +create ATADrive + ATASECSZ , + ' ata@ , + ' ata! , diff --git a/fs/drv/pc/int13h.fs b/fs/drv/pc/int13h.fs @@ -8,6 +8,13 @@ $7c1a w@ const NUMHEADS $7c24 c@ const DRVNO $80 const DRVNO -: biossec@ ( sec dst -- ) - >r DRVNO swap SECPERTRK /mod ( drv sec trk ) +: biossec@ ( sec dst drv -- ) + drop >r DRVNO swap SECPERTRK /mod ( drv sec trk ) NUMHEADS /mod ( drv sec head cyl ) rot 1+ r> int13h ; + +: biossec! abort" int13h driver doesn't support writing" ; + +create INT13hDrive + BIOSSECSZ , + ' biossec@ , + ' biossec! , diff --git a/fs/drv/ramdrive.fs b/fs/drv/ramdrive.fs @@ -1,14 +1,17 @@ \ Drive in RAM -\ This implements the "drive" protocol, which for now is undocumented, on top -\ of an area in RAM. +\ TODO: support more than one RAM drive at once. 512 const RAMDRVSECSZ 0 value ramdrv( : _addr ( blkno -- a ) RAMDRVSECSZ * ramdrv( + ; -: ramdrv@ ( blkno buf -- ) - swap _addr swap ( src buf ) RAMDRVSECSZ move ; -: ramdrv! ( blkno buf -- ) - swap _addr ( buf dst ) RAMDRVSECSZ move ; +: ramdrv@ ( blkno buf drv -- ) + drop swap _addr swap ( src buf ) RAMDRVSECSZ move ; +: ramdrv! ( blkno buf drv -- ) + drop swap _addr ( buf dst ) RAMDRVSECSZ move ; +create RAMDrive + RAMDRVSECSZ , + ' ramdrv@ , + ' ramdrv! , diff --git a/fs/fs/fat.fs b/fs/fs/fat.fs @@ -22,7 +22,7 @@ $ffff const EOC -: writecursector ( -- ) bufsec fatbuf( (drv!) ; +: writecursector ( -- ) bufsec fatbuf( fatdrv drv! ; : FAT12! ( entry cluster -- ) dup FAT@ ( entry cl old ) over FAT12' ( entry cl old a ) @@ -31,14 +31,14 @@ $ffff const EOC else ( entry a old ) $f000 and rot $fff and or then ( a n ) over w! ( a ) )fatbuf 1- = if \ end-of-sector cross-over! - bufsec 1+ (drv@) )fatbuf 1+ c@ fatbuf( c! bufsec 1+ (drv!) then ; + bufsec 1+ fatdrv drv@ )fatbuf 1+ c@ fatbuf( c! bufsec 1+ fatdrv drv! then ; : FAT16! ( entry cluster -- ) FAT16' w! ; : FAT! ( entry cluster ) FAT12? if FAT12! else FAT16! then writecursector ; : zerocluster ( cluster -- ) fatbuf( BPB_BytsPerSec 0 fill FirstSectorOfCluster ( sec ) BPB_SecPerClus >r begin ( sec ) - fatbuf( (drv!) 1+ next drop ; + fatbuf( fatdrv drv! 1+ next drop ; \ find a free cluster in the FAT : findfreecluster ( -- cluster ) @@ -77,7 +77,7 @@ $ffff const EOC \ write multiple sectors from buf : writesectors ( sec u buf -- ) A>r swap >r swap >A begin ( buf ) - A> over (drv!) A+ drvblksz + next ( buf ) drop r>A ; + A> over fatdrv drv! A+ fatdrv sectorsize + next ( buf ) drop r>A ; : writecluster ( cluster src -- ) over 2 - $fff6 > if abort" cluster out of range!" then diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs @@ -10,13 +10,13 @@ \ of logic from this unit in fs/fat. All in all, "read and core stucture" is \ here, "write" is in fs/fat. -\ This unit has access to a very small set of words, that it, words implemented -\ by boot.fs as well as (drv@) and drvblksz from the "drive" protocol, which is -\ implemented by a driver that is also inserted in the boot sequence. +\ Before loading this unit, you need to define a "fatdrv" value that is a +\ pointer to a Drive (doc/drive) structure. \ See fs/fat.fs for complete implementation details. -create bpb 0 here (drv@) $18 allot +\ TODO: assert that fatdrv's sector size is the same as in the FAT's BPB +create bpb 0 here fatdrv drv@ $18 allot : BPB_BytsPerSec bpb $0b + w@ ; : BPB_SecPerClus bpb $0d + c@ ; @@ -50,13 +50,13 @@ here const )fatbuf \ "cnt" is the number of sectors ahead of "sec" that are available for a \ seqential read. -: readsector ( sec cnt -- ) to bufseccnt dup to bufsec fatbuf( (drv@) ; +: readsector ( sec cnt -- ) to bufseccnt dup to bufsec fatbuf( fatdrv drv@ ; : FAT12' ( cluster -- 'entry ) dup >> + ( cl offset ) BPB_BytsPerSec /mod ( cl secoff sec ) BPB_RsvdSecCnt + over 1+ BPB_BytsPerSec = if \ end-of-sector cross-over! - dup 1 + fatbuf( (drv@) fatbuf( c@ )fatbuf c! then + dup 1 + fatbuf( fatdrv drv@ fatbuf( c@ )fatbuf c! then 0 readsector ( cl secoff ) fatbuf( + ; : FAT12@ ( cluster -- entry ) @@ -182,7 +182,7 @@ create fcursors( FCursorSize FCURSORCNT * allot0 \ read multiple sectors in buf : readsectors ( sec u buf -- ) A>r swap >r swap >A begin ( buf ) - A> over (drv@) A+ drvblksz + next ( buf ) drop r>A ; + A> over fatdrv drv@ A+ BPB_BytsPerSec + next ( buf ) drop r>A ; : readcluster ( cluster dst -- ) over 2 - $fff6 > if abort" cluster out of range!" then diff --git a/fs/sys/drive.fs b/fs/sys/drive.fs @@ -1,41 +0,0 @@ -\ Drive subsystem - -\ Allow access to mass storage in a standardized manner. This subsystem -\ defines the (drv@) and (drv!) aliases and a storage driver is expected to plug -\ into it. - -\ Blocks: this subsystem deals with the concept of "blocks", which is a bunch -\ of bytes of a definite size, always the same for a given device. It's the -\ driver that defines the size of those blocks and sets the "drvblksz" value to -\ this proper value. - -\ (drv@) and (drv!) expect block number arguments, which means that we consider -\ the data held by the storage device to be an array of contiguous blocks of -\ "drvblksz" bytes in size. - -\ The Drive subsystem holds a temporary buffer and manages it. This buffer -\ should be at least twice as large as the largest drvblksz it's ever going to -\ handle. Being able to hold 2 blocks in memory is necessary for "drvseek". - -$1000 const DRVBUFSZ -create drvbuf( DRVBUFSZ allot -DRVBUFSZ >> value drvblksz -\ Block number currently in drvbuf( --1 value drvcurblk - -\ (drv@) is declared in /xcomp/bootlo - -( blkno buf -- ) -alias abort (drv!) - -: drv@ ( blkno -- ) dup to drvcurblk drvbuf( (drv@) ; -: ?drv@ ( blkno -- ) dup drvcurblk = if drop else drv@ then ; - -\ Ensure that the block containing offset "off" (in bytes) is loaded and that -\ there's at least u bytes following that offset that is present in the buffer. -\ u cannot be larger than drvblksz. -: drvseek ( off u -- a ) - dup drvblksz > if abort" can't ensure that many bytes in drv buffer" then - swap drvblksz /mod ( u r q ) ?drv@ ( u r ) - tuck + drvblksz >= if drvcurblk 1+ drvbuf( drvblksz + (drv@) then ( r ) - drvbuf( + ( a ) ; diff --git a/fs/tests/sys/all.fs b/fs/tests/sys/all.fs @@ -1,3 +1,2 @@ \ Run all sys test suites -f<< /tests/sys/drive.fs f<< /tests/sys/file.fs diff --git a/fs/tests/sys/drive.fs b/fs/tests/sys/drive.fs @@ -1,6 +0,0 @@ -?f<< tests/harness.fs -testrequires /sys/drive.fs -testbegin -\ Tests for sys/ramdrive (already loaded in init.fs) -$36 8 drvseek ( a ) 8 []>str S" FAT12 " #s= -testend diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs @@ -99,10 +99,11 @@ alias else endof immediate \ Return whether strings s1 and s2 are equal : s= ( s1 s2 -- f ) over c@ 1+ []= ; -\ These aliases belong to /sys/drive, but we need them earlier in the boot -\ process, so we anticipate. -$200 value drvblksz -alias abort (drv@) +\ Drive API +\ Anticipating lib/drive +: sectorsize ( drv -- ) @ ; +: drv@ ( sec dst drv -- ) dup 4 + @ execute ; +: drv! ( sec src drv -- ) dup 8 + @ execute ; \ Autoloading 0 value floaded \ address of the current "loaded file" structure diff --git a/fs/xcomp/pc/glue1.fs b/fs/xcomp/pc/glue1.fs @@ -1 +1 @@ -' biossec@ to (drv@) +INT13hDrive value fatdrv diff --git a/fs/xcomp/pc/init.fs b/fs/xcomp/pc/init.fs @@ -14,7 +14,7 @@ f<< /drv/pc/ata.fs \ under QEMU, but not on real hardware. \ Update: hum no, it seems that my notebook doesn't list anything at all on its \ IDE buses. Maybe I'll have to go straight to AHCI... -\ ' ata@ to (drv@) +\ ATADrive to fatdrv f<< /drv/pc/idt.fs diff --git a/posix/glue1.fs b/posix/glue1.fs @@ -1,4 +1,3 @@ \ Glue code between the storage driver and the FS handler fatfs( to ramdrv( -RAMDRVSECSZ to drvblksz -' ramdrv@ to (drv@) +RAMDrive value fatdrv diff --git a/posix/init.fs b/posix/init.fs @@ -2,9 +2,4 @@ 0 S" sys" fchild S" file.fs" fchild fload \ We now have f<< f<< sys/doc.fs -f<< sys/drive.fs -RAMDRVSECSZ to drvblksz -fatfs( to ramdrv( -' ramdrv@ to (drv@) -' ramdrv! to (drv!) f<< fs/fat.fs