Fixed some Task stuff, added DOSFS filesystem
This commit is contained in:
		
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,11 +1,11 @@
 | 
			
		||||
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o
 | 
			
		||||
objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o dosfs/dosfs.o
 | 
			
		||||
CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding -march=pentium-m -fno-stack-protector -nostdlib -c
 | 
			
		||||
 | 
			
		||||
%.o: %.nasm
 | 
			
		||||
	nasm -f elf32 -o $@ $<
 | 
			
		||||
 | 
			
		||||
%.o: %.c
 | 
			
		||||
	clang $(CFLAGS) -O2 $<
 | 
			
		||||
	clang $(CFLAGS) -O2 -o $@ $<
 | 
			
		||||
 | 
			
		||||
all: $(objects)
 | 
			
		||||
	nasm boot.nasm -o boot.bin
 | 
			
		||||
@@ -17,3 +17,5 @@ virtdisk:
 | 
			
		||||
	dd bs=1M count=32 if=/dev/zero of=virtdisk.bin
 | 
			
		||||
	echo -n -e '\x55\xaa' | dd bs=1 seek=510 conv=notrunc of=virtdisk.bin
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm $(objects)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,6 @@ string: db 'DISK ERROR'
 | 
			
		||||
 | 
			
		||||
addr_packet:
 | 
			
		||||
db 0x10, 0x00 ; size, reserved
 | 
			
		||||
dw 0x20 ; blocks
 | 
			
		||||
dw 0x39 ; blocks
 | 
			
		||||
dd 0x8000 ; transfer buffer
 | 
			
		||||
dq 1 ; start block
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1273
									
								
								dosfs/dosfs.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1273
									
								
								dosfs/dosfs.c
									
									
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										374
									
								
								dosfs/dosfs.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										374
									
								
								dosfs/dosfs.h
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,374 @@
 | 
			
		||||
/*
 | 
			
		||||
	DOSFS Embedded FAT-Compatible Filesystem
 | 
			
		||||
	(C) 2005 Lewin A.R.W. Edwards (sysadm@zws.com)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef _DOSFS_H
 | 
			
		||||
#define _DOSFS_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
//===================================================================
 | 
			
		||||
// User-supplied functions
 | 
			
		||||
uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count);
 | 
			
		||||
uint32_t DFS_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//===================================================================
 | 
			
		||||
// Configurable items
 | 
			
		||||
#define MAX_PATH		64		// Maximum path length (increasing this will
 | 
			
		||||
								// GREATLY increase stack requirements!)
 | 
			
		||||
#define DIR_SEPARATOR	'/'		// character separating directory components
 | 
			
		||||
 | 
			
		||||
// End of configurable items
 | 
			
		||||
//===================================================================
 | 
			
		||||
 | 
			
		||||
//===================================================================
 | 
			
		||||
// 32-bit error codes
 | 
			
		||||
#define DFS_OK			0			// no error
 | 
			
		||||
#define DFS_EOF			1			// end of file (not an error)
 | 
			
		||||
#define DFS_WRITEPROT	2			// volume is write protected
 | 
			
		||||
#define DFS_NOTFOUND	3			// path or file not found
 | 
			
		||||
#define DFS_PATHLEN		4			// path too long
 | 
			
		||||
#define DFS_ALLOCNEW	5			// must allocate new directory cluster
 | 
			
		||||
#define DFS_ERRMISC		0xffffffff	// generic error
 | 
			
		||||
 | 
			
		||||
//===================================================================
 | 
			
		||||
// File access modes
 | 
			
		||||
#define DFS_READ		1			// read-only
 | 
			
		||||
#define DFS_WRITE		2			// write-only
 | 
			
		||||
 | 
			
		||||
//===================================================================
 | 
			
		||||
// Miscellaneous constants
 | 
			
		||||
#define SECTOR_SIZE		512		// sector size in bytes
 | 
			
		||||
 | 
			
		||||
//===================================================================
 | 
			
		||||
// Internal subformat identifiers
 | 
			
		||||
#define FAT12			0
 | 
			
		||||
#define FAT16			1
 | 
			
		||||
#define FAT32			2
 | 
			
		||||
 | 
			
		||||
//===================================================================
 | 
			
		||||
// DOS attribute bits
 | 
			
		||||
#define ATTR_READ_ONLY	0x01
 | 
			
		||||
#define ATTR_HIDDEN		0x02
 | 
			
		||||
#define ATTR_SYSTEM		0x04
 | 
			
		||||
#define ATTR_VOLUME_ID	0x08
 | 
			
		||||
#define ATTR_DIRECTORY	0x10
 | 
			
		||||
#define ATTR_ARCHIVE	0x20
 | 
			
		||||
#define ATTR_LONG_NAME	(ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Directory entry structure
 | 
			
		||||
	note: if name[0] == 0xe5, this is a free dir entry
 | 
			
		||||
	      if name[0] == 0x00, this is a free entry and all subsequent entries are free
 | 
			
		||||
		  if name[0] == 0x05, the first character of the name is 0xe5 [a kanji nicety]
 | 
			
		||||
 | 
			
		||||
	Date format: bit 0-4  = day of month (1-31)
 | 
			
		||||
	             bit 5-8  = month, 1=Jan..12=Dec
 | 
			
		||||
				 bit 9-15 =	count of years since 1980 (0-127)
 | 
			
		||||
	Time format: bit 0-4  = 2-second count, (0-29)
 | 
			
		||||
	             bit 5-10 = minutes (0-59)
 | 
			
		||||
				 bit 11-15= hours (0-23)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagDIRENT {
 | 
			
		||||
	uint8_t name[11];			// filename
 | 
			
		||||
	uint8_t attr;				// attributes (see ATTR_* constant definitions)
 | 
			
		||||
	uint8_t reserved;			// reserved, must be 0
 | 
			
		||||
	uint8_t crttimetenth;		// create time, 10ths of a second (0-199 are valid)
 | 
			
		||||
	uint8_t crttime_l;			// creation time low byte
 | 
			
		||||
	uint8_t crttime_h;			// creation time high byte
 | 
			
		||||
	uint8_t crtdate_l;			// creation date low byte
 | 
			
		||||
	uint8_t crtdate_h;			// creation date high byte
 | 
			
		||||
	uint8_t lstaccdate_l;		// last access date low byte
 | 
			
		||||
	uint8_t lstaccdate_h;		// last access date high byte
 | 
			
		||||
	uint8_t startclus_h_l;		// high word of first cluster, low byte (FAT32)
 | 
			
		||||
	uint8_t startclus_h_h;		// high word of first cluster, high byte (FAT32)
 | 
			
		||||
	uint8_t wrttime_l;			// last write time low byte
 | 
			
		||||
	uint8_t wrttime_h;			// last write time high byte
 | 
			
		||||
	uint8_t wrtdate_l;			// last write date low byte
 | 
			
		||||
	uint8_t wrtdate_h;			// last write date high byte
 | 
			
		||||
	uint8_t startclus_l_l;		// low word of first cluster, low byte
 | 
			
		||||
	uint8_t startclus_l_h;		// low word of first cluster, high byte
 | 
			
		||||
	uint8_t filesize_0;			// file size, low byte
 | 
			
		||||
	uint8_t filesize_1;			//
 | 
			
		||||
	uint8_t filesize_2;			//
 | 
			
		||||
	uint8_t filesize_3;			// file size, high byte
 | 
			
		||||
} DIRENT, *PDIRENT;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Partition table entry structure
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagPTINFO {
 | 
			
		||||
	uint8_t		active;			// 0x80 if partition active
 | 
			
		||||
	uint8_t		start_h;		// starting head
 | 
			
		||||
	uint8_t		start_cs_l;		// starting cylinder and sector (low byte)
 | 
			
		||||
	uint8_t		start_cs_h;		// starting cylinder and sector (high byte)
 | 
			
		||||
	uint8_t		type;			// type ID byte
 | 
			
		||||
	uint8_t		end_h;			// ending head
 | 
			
		||||
	uint8_t		end_cs_l;		// ending cylinder and sector (low byte)
 | 
			
		||||
	uint8_t		end_cs_h;		// ending cylinder and sector (high byte)
 | 
			
		||||
	uint8_t		start_0;		// starting sector# (low byte)
 | 
			
		||||
	uint8_t		start_1;		//
 | 
			
		||||
	uint8_t		start_2;		//
 | 
			
		||||
	uint8_t		start_3;		// starting sector# (high byte)
 | 
			
		||||
	uint8_t		size_0;			// size of partition (low byte)
 | 
			
		||||
	uint8_t		size_1;			//
 | 
			
		||||
	uint8_t		size_2;			//
 | 
			
		||||
	uint8_t		size_3;			// size of partition (high byte)
 | 
			
		||||
} PTINFO, *PPTINFO;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Master Boot Record structure
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagMBR {
 | 
			
		||||
	uint8_t bootcode[0x1be];	// boot sector
 | 
			
		||||
	PTINFO ptable[4];			// four partition table structures
 | 
			
		||||
	uint8_t sig_55;				// 0x55 signature byte
 | 
			
		||||
	uint8_t sig_aa;				// 0xaa signature byte
 | 
			
		||||
} MBR, *PMBR;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	BIOS Parameter Block structure (FAT12/16)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagBPB {
 | 
			
		||||
	uint8_t bytepersec_l;		// bytes per sector low byte (0x00)
 | 
			
		||||
	uint8_t bytepersec_h;		// bytes per sector high byte (0x02)
 | 
			
		||||
	uint8_t	secperclus;			// sectors per cluster (1,2,4,8,16,32,64,128 are valid)
 | 
			
		||||
	uint8_t reserved_l;			// reserved sectors low byte
 | 
			
		||||
	uint8_t reserved_h;			// reserved sectors high byte
 | 
			
		||||
	uint8_t numfats;			// number of FAT copies (2)
 | 
			
		||||
	uint8_t rootentries_l;		// number of root dir entries low byte (0x00 normally)
 | 
			
		||||
	uint8_t rootentries_h;		// number of root dir entries high byte (0x02 normally)
 | 
			
		||||
	uint8_t sectors_s_l;		// small num sectors low byte
 | 
			
		||||
	uint8_t sectors_s_h;		// small num sectors high byte
 | 
			
		||||
	uint8_t mediatype;			// media descriptor byte
 | 
			
		||||
	uint8_t secperfat_l;		// sectors per FAT low byte
 | 
			
		||||
	uint8_t secperfat_h;		// sectors per FAT high byte
 | 
			
		||||
	uint8_t secpertrk_l;		// sectors per track low byte
 | 
			
		||||
	uint8_t secpertrk_h;		// sectors per track high byte
 | 
			
		||||
	uint8_t heads_l;			// heads low byte
 | 
			
		||||
	uint8_t heads_h;			// heads high byte
 | 
			
		||||
	uint8_t hidden_0;			// hidden sectors low byte
 | 
			
		||||
	uint8_t hidden_1;			// (note - this is the number of MEDIA sectors before
 | 
			
		||||
	uint8_t hidden_2;			// first sector of VOLUME - we rely on the MBR instead)
 | 
			
		||||
	uint8_t hidden_3;			// hidden sectors high byte
 | 
			
		||||
	uint8_t sectors_l_0;		// large num sectors low byte
 | 
			
		||||
	uint8_t sectors_l_1;		//
 | 
			
		||||
	uint8_t sectors_l_2;		//
 | 
			
		||||
	uint8_t sectors_l_3;		// large num sectors high byte
 | 
			
		||||
} BPB, *PBPB;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Extended BIOS Parameter Block structure (FAT12/16)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagEBPB {
 | 
			
		||||
	uint8_t unit;				// int 13h drive#
 | 
			
		||||
	uint8_t head;				// archaic, used by Windows NT-class OSes for flags
 | 
			
		||||
	uint8_t signature;			// 0x28 or 0x29
 | 
			
		||||
	uint8_t serial_0;			// serial#
 | 
			
		||||
	uint8_t serial_1;			// serial#
 | 
			
		||||
	uint8_t serial_2;			// serial#
 | 
			
		||||
	uint8_t serial_3;			// serial#
 | 
			
		||||
	uint8_t label[11];			// volume label
 | 
			
		||||
	uint8_t system[8];			// filesystem ID
 | 
			
		||||
} EBPB, *PEBPB;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Extended BIOS Parameter Block structure (FAT32)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagEBPB32 {
 | 
			
		||||
	uint8_t fatsize_0;			// big FAT size in sectors low byte
 | 
			
		||||
	uint8_t fatsize_1;			//
 | 
			
		||||
	uint8_t fatsize_2;			//
 | 
			
		||||
	uint8_t fatsize_3;			// big FAT size in sectors high byte
 | 
			
		||||
	uint8_t extflags_l;			// extended flags low byte
 | 
			
		||||
	uint8_t extflags_h;			// extended flags high byte
 | 
			
		||||
	uint8_t fsver_l;			// filesystem version (0x00) low byte
 | 
			
		||||
	uint8_t fsver_h;			// filesystem version (0x00) high byte
 | 
			
		||||
	uint8_t root_0;				// cluster of root dir, low byte
 | 
			
		||||
	uint8_t root_1;				//
 | 
			
		||||
	uint8_t root_2;				//
 | 
			
		||||
	uint8_t root_3;				// cluster of root dir, high byte
 | 
			
		||||
	uint8_t fsinfo_l;			// sector pointer to FSINFO within reserved area, low byte (2)
 | 
			
		||||
	uint8_t fsinfo_h;			// sector pointer to FSINFO within reserved area, high byte (0)
 | 
			
		||||
	uint8_t bkboot_l;			// sector pointer to backup boot sector within reserved area, low byte (6)
 | 
			
		||||
	uint8_t bkboot_h;			// sector pointer to backup boot sector within reserved area, high byte (0)
 | 
			
		||||
	uint8_t reserved[12];		// reserved, should be 0
 | 
			
		||||
 | 
			
		||||
	uint8_t unit;				// int 13h drive#
 | 
			
		||||
	uint8_t head;				// archaic, used by Windows NT-class OSes for flags
 | 
			
		||||
	uint8_t signature;			// 0x28 or 0x29
 | 
			
		||||
	uint8_t serial_0;			// serial#
 | 
			
		||||
	uint8_t serial_1;			// serial#
 | 
			
		||||
	uint8_t serial_2;			// serial#
 | 
			
		||||
	uint8_t serial_3;			// serial#
 | 
			
		||||
	uint8_t label[11];			// volume label
 | 
			
		||||
	uint8_t system[8];			// filesystem ID
 | 
			
		||||
} EBPB32, *PEBPB32;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Logical Boot Record structure (volume boot sector)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagLBR {
 | 
			
		||||
	uint8_t jump[3];			// JMP instruction
 | 
			
		||||
	uint8_t oemid[8];			// OEM ID, space-padded
 | 
			
		||||
	BPB bpb;					// BIOS Parameter Block
 | 
			
		||||
	union {
 | 
			
		||||
		EBPB ebpb;				// FAT12/16 Extended BIOS Parameter Block
 | 
			
		||||
		EBPB32 ebpb32;			// FAT32 Extended BIOS Parameter Block
 | 
			
		||||
	} ebpb;
 | 
			
		||||
	uint8_t code[420];			// boot sector code
 | 
			
		||||
	uint8_t sig_55;				// 0x55 signature byte
 | 
			
		||||
	uint8_t sig_aa;				// 0xaa signature byte
 | 
			
		||||
} LBR, *PLBR;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Volume information structure (Internal to DOSFS)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagVOLINFO {
 | 
			
		||||
	uint8_t unit;				// unit on which this volume resides
 | 
			
		||||
	uint8_t filesystem;			// formatted filesystem
 | 
			
		||||
 | 
			
		||||
// These two fields aren't very useful, so support for them has been commented out to
 | 
			
		||||
// save memory. (Note that the "system" tag is not actually used by DOS to determine
 | 
			
		||||
// filesystem type - that decision is made entirely on the basis of how many clusters
 | 
			
		||||
// the drive contains. DOSFS works the same way).
 | 
			
		||||
// See tag: OEMID in dosfs.c
 | 
			
		||||
//	uint8_t oemid[9];			// OEM ID ASCIIZ
 | 
			
		||||
//	uint8_t system[9];			// system ID ASCIIZ
 | 
			
		||||
	uint8_t label[12];			// volume label ASCIIZ
 | 
			
		||||
	uint32_t startsector;		// starting sector of filesystem
 | 
			
		||||
	uint8_t secperclus;			// sectors per cluster
 | 
			
		||||
	uint16_t reservedsecs;		// reserved sectors
 | 
			
		||||
	uint32_t numsecs;			// number of sectors in volume
 | 
			
		||||
	uint32_t secperfat;			// sectors per FAT
 | 
			
		||||
	uint16_t rootentries;		// number of root dir entries
 | 
			
		||||
 | 
			
		||||
	uint32_t numclusters;		// number of clusters on drive
 | 
			
		||||
 | 
			
		||||
	// The fields below are PHYSICAL SECTOR NUMBERS.
 | 
			
		||||
	uint32_t fat1;				// starting sector# of FAT copy 1
 | 
			
		||||
	uint32_t rootdir;			// starting sector# of root directory (FAT12/FAT16) or cluster (FAT32)
 | 
			
		||||
	uint32_t dataarea;			// starting sector# of data area (cluster #2)
 | 
			
		||||
} VOLINFO, *PVOLINFO;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Flags in DIRINFO.flags
 | 
			
		||||
*/
 | 
			
		||||
#define DFS_DI_BLANKENT		0x01	// Searching for blank entry
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Directory search structure (Internal to DOSFS)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagDIRINFO {
 | 
			
		||||
	uint32_t currentcluster;	// current cluster in dir
 | 
			
		||||
	uint8_t currentsector;		// current sector in cluster
 | 
			
		||||
	uint8_t currententry;		// current dir entry in sector
 | 
			
		||||
	uint8_t *scratch;			// ptr to user-supplied scratch buffer (one sector)
 | 
			
		||||
	uint8_t flags;				// internal DOSFS flags
 | 
			
		||||
} DIRINFO, *PDIRINFO;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	File handle structure (Internal to DOSFS)
 | 
			
		||||
*/
 | 
			
		||||
typedef struct _tagFILEINFO {
 | 
			
		||||
	PVOLINFO volinfo;			// VOLINFO used to open this file
 | 
			
		||||
	uint32_t dirsector;			// physical sector containing dir entry of this file
 | 
			
		||||
	uint8_t diroffset;			// # of this entry within the dir sector
 | 
			
		||||
	uint8_t mode;				// mode in which this file was opened
 | 
			
		||||
	uint32_t firstcluster;		// first cluster of file
 | 
			
		||||
	uint32_t filelen;			// byte length of file
 | 
			
		||||
 | 
			
		||||
	uint32_t cluster;			// current cluster
 | 
			
		||||
	uint32_t pointer;			// current (BYTE) pointer
 | 
			
		||||
} FILEINFO, *PFILEINFO;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Get starting sector# of specified partition on drive #unit
 | 
			
		||||
	NOTE: This code ASSUMES an MBR on the disk.
 | 
			
		||||
	scratchsector should point to a SECTOR_SIZE scratch area
 | 
			
		||||
	Returns 0xffffffff for any error.
 | 
			
		||||
	If pactive is non-NULL, this function also returns the partition active flag.
 | 
			
		||||
	If pptype is non-NULL, this function also returns the partition type.
 | 
			
		||||
	If psize is non-NULL, this function also returns the partition size.
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_GetPtnStart(uint8_t unit, uint8_t *scratchsector, uint8_t pnum, uint8_t *pactive, uint8_t *pptype, uint32_t *psize);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Retrieve volume info from BPB and store it in a VOLINFO structure
 | 
			
		||||
	You must provide the unit and starting sector of the filesystem, and
 | 
			
		||||
	a pointer to a sector buffer for scratch
 | 
			
		||||
	Attempts to read BPB and glean information about the FS from that.
 | 
			
		||||
	Returns 0 OK, nonzero for any error.
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_GetVolInfo(uint8_t unit, uint8_t *scratchsector, uint32_t startsector, PVOLINFO volinfo);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Open a directory for enumeration by DFS_GetNextDirEnt
 | 
			
		||||
	You must supply a populated VOLINFO (see DFS_GetVolInfo)
 | 
			
		||||
	The empty string or a string containing only the directory separator are
 | 
			
		||||
	considered to be the root directory.
 | 
			
		||||
	Returns 0 OK, nonzero for any error.
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_OpenDir(PVOLINFO volinfo, uint8_t *dirname, PDIRINFO dirinfo);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Get next entry in opened directory structure. Copies fields into the dirent
 | 
			
		||||
	structure, updates dirinfo. Note that it is the _caller's_ responsibility to
 | 
			
		||||
	handle the '.' and '..' entries.
 | 
			
		||||
	A deleted file will be returned as a NULL entry (first char of filename=0)
 | 
			
		||||
	by this code. Filenames beginning with 0x05 will be translated to 0xE5
 | 
			
		||||
	automatically. Long file name entries will be returned as NULL.
 | 
			
		||||
	returns DFS_EOF if there are no more entries, DFS_OK if this entry is valid,
 | 
			
		||||
	or DFS_ERRMISC for a media error
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_GetNext(PVOLINFO volinfo, PDIRINFO dirinfo, PDIRENT dirent);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Open a file for reading or writing. You supply populated VOLINFO, a path to the file,
 | 
			
		||||
	mode (DFS_READ or DFS_WRITE) and an empty fileinfo structure. You also need to
 | 
			
		||||
	provide a pointer to a sector-sized scratch buffer.
 | 
			
		||||
	Returns various DFS_* error states. If the result is DFS_OK, fileinfo can be used
 | 
			
		||||
	to access the file from this point on.
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_OpenFile(PVOLINFO volinfo, uint8_t *path, uint8_t mode, uint8_t *scratch, PFILEINFO fileinfo);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Read an open file
 | 
			
		||||
	You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
 | 
			
		||||
	pointer to a SECTOR_SIZE scratch buffer.
 | 
			
		||||
	Note that returning DFS_EOF is not an error condition. This function updates the
 | 
			
		||||
	successcount field with the number of bytes actually read.
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_ReadFile(PFILEINFO fileinfo, uint8_t *scratch, uint8_t *buffer, uint32_t *successcount, uint32_t len);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Write an open file
 | 
			
		||||
	You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
 | 
			
		||||
	pointer to a SECTOR_SIZE scratch buffer.
 | 
			
		||||
	This function updates the successcount field with the number of bytes actually written.
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_WriteFile(PFILEINFO fileinfo, uint8_t *scratch, uint8_t *buffer, uint32_t *successcount, uint32_t len);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Seek file pointer to a given position
 | 
			
		||||
	This function does not return status - refer to the fileinfo->pointer value
 | 
			
		||||
	to see where the pointer wound up.
 | 
			
		||||
	Requires a SECTOR_SIZE scratch buffer
 | 
			
		||||
*/
 | 
			
		||||
void DFS_Seek(PFILEINFO fileinfo, uint32_t offset, uint8_t *scratch);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Delete a file
 | 
			
		||||
	scratch must point to a sector-sized buffer
 | 
			
		||||
*/
 | 
			
		||||
uint32_t DFS_UnlinkFile(PVOLINFO volinfo, uint8_t *path, uint8_t *scratch);
 | 
			
		||||
 | 
			
		||||
// If we are building a host-emulation version, include host support
 | 
			
		||||
#ifdef HOSTVER
 | 
			
		||||
#include "hostemu.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // _DOSFS_H
 | 
			
		||||
							
								
								
									
										366
									
								
								dosfs/readme.txt
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										366
									
								
								dosfs/readme.txt
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,366 @@
 | 
			
		||||
README.TXT                                         (C) Copyright 2006
 | 
			
		||||
DOSFS Level 1 Version 1.02      Lewin A.R.W. Edwards (sysadm@zws.com)
 | 
			
		||||
=====================================================================
 | 
			
		||||
 | 
			
		||||
Abstract
 | 
			
		||||
========
 | 
			
		||||
DOSFS is a FAT-compatible filesystem intended for fairly low-end
 | 
			
		||||
embedded applications. It is not the leanest possible implementation
 | 
			
		||||
(the leanest FAT implementations operate in << 512 bytes of RAM, with
 | 
			
		||||
heavy restrictions). This code strikes a good balance between size
 | 
			
		||||
and functionality, with an emphasis on RAM footprint.
 | 
			
		||||
 | 
			
		||||
Intended target systems would be in the ballpark of 1K RAM, 4K ROM
 | 
			
		||||
or more.
 | 
			
		||||
 | 
			
		||||
Features:
 | 
			
		||||
* Supports FAT12, FAT16 and FAT32 volumes
 | 
			
		||||
* Supports storage devices up to 2048Gbytes in size (LBA32)
 | 
			
		||||
* Supports devices with or without MBRs (hard disks vs. floppy disks
 | 
			
		||||
  or ZIP drives formatted as "big floppies")
 | 
			
		||||
* Supports multiple partitions on disks with MBRs
 | 
			
		||||
* Supports subdirectories
 | 
			
		||||
* Can be operated with a single global 512-byte sector buffer
 | 
			
		||||
* Fully reentrant code (assuming the underlying physical device driver
 | 
			
		||||
  is reentrant and global sector buffers are not used). There are no
 | 
			
		||||
  global variables in the filesystem
 | 
			
		||||
* Does not perform any memory allocation
 | 
			
		||||
* Partial support for random-access files
 | 
			
		||||
 | 
			
		||||
Applications:
 | 
			
		||||
* Firmware upgrades
 | 
			
		||||
* Failsafe IPL
 | 
			
		||||
* Media playback
 | 
			
		||||
* Data logging
 | 
			
		||||
* Configuration storage
 | 
			
		||||
 | 
			
		||||
There is no technical support for this free product; however, if you
 | 
			
		||||
have questions or suggestions, you are encouraged to email Lewin
 | 
			
		||||
Edwards at sysadm@zws.com. If you need custom additions to the code,
 | 
			
		||||
or if you have other projects for which you need engineering
 | 
			
		||||
assistance, please feel free to email or call (646) 549-3715.
 | 
			
		||||
 | 
			
		||||
License
 | 
			
		||||
=======
 | 
			
		||||
The license for DOSFS is very simple but verbose to state.
 | 
			
		||||
 | 
			
		||||
1. DOSFS is (C) Copyright 2006 by Lewin A.R.W. Edwards ("Author").
 | 
			
		||||
   All rights not explicitly granted herein are reserved. The DOSFS
 | 
			
		||||
   code is the permanent property of the Author and no transfer of
 | 
			
		||||
   ownership is implied by this license.
 | 
			
		||||
 | 
			
		||||
2. DOSFS is an educational project, provided as-is. No guarantee of
 | 
			
		||||
   performance or suitability for any application is stated or
 | 
			
		||||
   implied. You use this product entirely at your own risk. Use of
 | 
			
		||||
   this product in any manner automatically waives any right to seek
 | 
			
		||||
   compensation or damages of any sort from the Author.	Since the
 | 
			
		||||
   products you might make are entirely out of the Author's control,
 | 
			
		||||
   use of this product also constitutes an agreement by you to take
 | 
			
		||||
   full responsibility for and indemnify the Author against any
 | 
			
		||||
   action for any loss or damage (including economic loss of any
 | 
			
		||||
   type, and specifically including patent litigation) that arises
 | 
			
		||||
   from a product made by you that incorporates any portion of
 | 
			
		||||
   the DOSFS code.
 | 
			
		||||
 | 
			
		||||
3. If you live under the jurisdiction of any legislation that would
 | 
			
		||||
   prohibit or limit any condition in this license, you cannot be
 | 
			
		||||
   licensed to use this product.
 | 
			
		||||
 | 
			
		||||
4. If you do not fall into the excluded category in point 3, you are
 | 
			
		||||
   hereby licensed to use the DOSFS code in any application that you
 | 
			
		||||
   see fit. You are not required to pay any fee or notify the Author
 | 
			
		||||
   that you are using DOSFS. Any modifications made by you to the
 | 
			
		||||
   DOSFS code are your property and you may distribute the modified
 | 
			
		||||
   version in any manner that you wish. You are not required to
 | 
			
		||||
   disclose sourcecode to such modifications, either to the Author or
 | 
			
		||||
   to any third party. Any such disclosure made to the Author will
 | 
			
		||||
   irrevocably become the property of the Author in the absence of a
 | 
			
		||||
   formal agreement to the contrary, established prior to such
 | 
			
		||||
   disclosure being made.
 | 
			
		||||
 | 
			
		||||
To summarize the intent of the above: DOSFS is free. You can do what
 | 
			
		||||
you want with it. Anything that happens as a result is entirely your
 | 
			
		||||
responsibility. You can't take ownership of my code and stop me from
 | 
			
		||||
doing whatever I want with it. If you do something nifty with DOSFS
 | 
			
		||||
and send me the sourcecode, I may include your changes in the next
 | 
			
		||||
distribution and it will be released to the world as free software.
 | 
			
		||||
If someone sues you because your DOSFS-containing product causes
 | 
			
		||||
any sort of legal, financial or other problem, it's your lawsuit,
 | 
			
		||||
not mine, and you'll exclude me from the proceedings.
 | 
			
		||||
 | 
			
		||||
User-Supplied Functions
 | 
			
		||||
=======================
 | 
			
		||||
You must provide functions to read sectors into memory and write
 | 
			
		||||
them back to the target media. The demo suite includes an emulation
 | 
			
		||||
module that reads/writes a disk image file (#define HOSTVER pulls
 | 
			
		||||
in hostemu.h which wraps the prototypes for these functions).
 | 
			
		||||
There are various tools for UNIX, DOS, Windows et al, to create
 | 
			
		||||
images from storage media; my preferred utility is dd.
 | 
			
		||||
 | 
			
		||||
The functions you must supply in your embedded app are:
 | 
			
		||||
 | 
			
		||||
DFS_ReadSector(unit,buffer,sector,count)
 | 
			
		||||
DFS_WriteSector(unit,buffer,sector,count)
 | 
			
		||||
 | 
			
		||||
These two functions read and write, respectively, "count" sectors of
 | 
			
		||||
size SECTOR_SIZE (512 bytes; see below) from/to physical sector
 | 
			
		||||
#"sector" of device "unit", to/from the scratch buffer "buffer". They
 | 
			
		||||
should return 0 for success or nonzero for failure. In the current
 | 
			
		||||
implementation of DOSFS, count will always be 1.
 | 
			
		||||
 | 
			
		||||
The "unit" argument is designed to permit implementation of multiple
 | 
			
		||||
storage devices, for example multiple media slots on a single device,
 | 
			
		||||
or to differentiate between master and slave devices on an ATAPI bus.
 | 
			
		||||
		 
 | 
			
		||||
This code is designed for 512-byte sectors. Although the sector size
 | 
			
		||||
is a #define, you should not tinker with it because the vast majority
 | 
			
		||||
of FAT filesystems use 512-byte sectors, and the DOSFS code doesn't
 | 
			
		||||
support runtime determination of sector size. This will not affect the
 | 
			
		||||
vast majority of users.
 | 
			
		||||
 | 
			
		||||
Example Code
 | 
			
		||||
============
 | 
			
		||||
Refer to the tests in main.c to see how to call DOSFS functions.
 | 
			
		||||
(These tests are all commented out). Note that the only two files
 | 
			
		||||
you need to add to your project are dosfs.c and dosfs.h.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Mounting Volumes
 | 
			
		||||
================
 | 
			
		||||
--If the device has a partition table (practically all removable flash
 | 
			
		||||
  media are formatted this way), call DFS_GetPtnStart to get the
 | 
			
		||||
  starting sector# of the desired partition. You can optionally also
 | 
			
		||||
  retrieve the active state, partition type byte and partition size
 | 
			
		||||
  in this step. The reason this step is broken out separately is so
 | 
			
		||||
  you can support devices that are formatted like a floppy disk, i.e.
 | 
			
		||||
  the volume starts directly at physical sector 0 of the media.
 | 
			
		||||
 | 
			
		||||
--Call DFS_GetVolInfo to read filesystem info into a VOLINFO structure.
 | 
			
		||||
  DFS_GetVolInfo needs to know the unit number and partition starting
 | 
			
		||||
  sector (as returned by DFS_GetPtnStart, or 0 if this is a "floppy-
 | 
			
		||||
  format" volume without an MBR).
 | 
			
		||||
 | 
			
		||||
From this point on, the VOLINFO structure is all you'll need - you can
 | 
			
		||||
forget the unit and partition start sector numbers.
 | 
			
		||||
 | 
			
		||||
Enumerating Directory Contents
 | 
			
		||||
==============================
 | 
			
		||||
--Call DFS_Opendir and supply a path, populated VOLINFO and a
 | 
			
		||||
  DIRINFO structure to receive the results. Note - you must PREPOPULATE
 | 
			
		||||
  the DIRINFO.scratch field with a pointer to a sector scratch buffer.
 | 
			
		||||
  This buffer must remain unmolested while you have the directory open
 | 
			
		||||
  for searching.
 | 
			
		||||
--Call DFS_GetNext to receive the DIRENT contents for the next directory
 | 
			
		||||
  item. This function returns DFS_OK for no error, and DFS_EOF if there
 | 
			
		||||
  are no more entries in the directory being searched.
 | 
			
		||||
  Before using the DIRENT, check the first character of the name. If it
 | 
			
		||||
  is NULL, then this is an unusable entry - call DFS_GetNext again to
 | 
			
		||||
  keep searching. LFN directory entries are automatically tagged this way
 | 
			
		||||
  so your application will not be pestered by them.
 | 
			
		||||
 | 
			
		||||
  Note: A designed side-effect of this code is that when you locate the
 | 
			
		||||
  file of interest, the DIRINFO.currentcluster, DIRINFO.currentsector
 | 
			
		||||
  and DIRINFO.currententry-1 fields will identify the directory entry of
 | 
			
		||||
  interest.
 | 
			
		||||
 | 
			
		||||
Reading a File
 | 
			
		||||
==============
 | 
			
		||||
--Call DFS_OpenFile with mode = DFS_READ and supply a path and the relevant
 | 
			
		||||
  VOLINFO structure. DFS_OpenFile will populate a FILEINFO that can be used
 | 
			
		||||
  to refer to the file.
 | 
			
		||||
--Optionally call DFS_Seek to set the file pointer. If you attempt to set
 | 
			
		||||
  the file pointer past the end of file, the file will NOT be extended. Check
 | 
			
		||||
  the FILEINFO.pointer value after DFS_Seek to verify that the pointer is
 | 
			
		||||
  where you expect it to be.
 | 
			
		||||
--Observe that functionality similar to the "whence" parameter of fseek() can
 | 
			
		||||
  be obtained by using simple arithmetic on the FILEINFO.pointer and
 | 
			
		||||
  FILEINFO.filelen members.
 | 
			
		||||
--Call DFS_ReadFile with the FILEINFO you obtained from OpenFile, and a
 | 
			
		||||
  pointer to a buffer plus the desired number of bytes to read, and a
 | 
			
		||||
  pointer to a sector-sized scratch buffer. The reason a scratch sector is
 | 
			
		||||
  required is because the underlying sector read function doesn't know
 | 
			
		||||
  about partial reads.
 | 
			
		||||
--Note that a file opened for reading cannot be written. If you need r/w
 | 
			
		||||
  access, open with mode = DFS_WRITE (see below).
 | 
			
		||||
 | 
			
		||||
Writing a file
 | 
			
		||||
==============
 | 
			
		||||
--Call DFS_OpenFile with mode = DFS_WRITE and supply a path and the relevant
 | 
			
		||||
  VOLINFO structure. DFS_OpenFile will populate a FILEINFO that can be used to
 | 
			
		||||
  refer to the file.
 | 
			
		||||
--Optionally call DFS_Seek to set the file pointer. Refer to the notes on
 | 
			
		||||
  this topic in the section on reading files, above.
 | 
			
		||||
--Call DFS_WriteFile with the FILEINFO you obtained from OpenFile, and a
 | 
			
		||||
  pointer to the source buffer, and a pointer to a sector-sized scratch
 | 
			
		||||
  buffer.
 | 
			
		||||
--Note that a file open for writing can also be read.
 | 
			
		||||
--Files are created automatically if they do not exist. Subdirectories are
 | 
			
		||||
  NOT automatically created.
 | 
			
		||||
--If you open an existing file for writing, the file pointer will start at
 | 
			
		||||
  the beginning of the data; if you want to append, seek to the end before
 | 
			
		||||
  writing new data.
 | 
			
		||||
--If you perform random-access writes to a file, the length will NOT change
 | 
			
		||||
  unless you exceed the file's original length. There is currently no
 | 
			
		||||
  function to truncate a file at the current pointer position.
 | 
			
		||||
--On-disk consistency is guaranteed when DFS_WriteFile exits, unless your
 | 
			
		||||
  physical layer has a writeback cache in it.
 | 
			
		||||
 | 
			
		||||
Deleting a file
 | 
			
		||||
===============
 | 
			
		||||
--Call DFS_UnlinkFile
 | 
			
		||||
--WARNING: This call will delete a subdirectory (correctly) but will NOT
 | 
			
		||||
  first recurse the directory to delete the contents - so you will end up
 | 
			
		||||
  with lost clusters.
 | 
			
		||||
 | 
			
		||||
Notes
 | 
			
		||||
=====
 | 
			
		||||
Some platforms may require explicit pragmas or attributes to the structures
 | 
			
		||||
and unions. For example, arm-gcc will require __attribute__ ((__packed__))
 | 
			
		||||
otherwise it will try to be "smart" and place the uint8_t members on 4-byte
 | 
			
		||||
boundaries. There is no truly elegant compiler-independent method to get
 | 
			
		||||
around this sort of problem.
 | 
			
		||||
 | 
			
		||||
The code assumes either a von Neumann architecture, or a compiler that
 | 
			
		||||
is smart enough to understand where your pointers are aimed and emit
 | 
			
		||||
the right kind of memory read and write instructions. The implications
 | 
			
		||||
of this statement depend on your target processor and the compiler you
 | 
			
		||||
are using. Be very careful not to straddle bank boundaries on bank-
 | 
			
		||||
switched memory systems.
 | 
			
		||||
 | 
			
		||||
Physical 32-bit sector numbers are used throughout. Therefore, the
 | 
			
		||||
CHS geometry (if any) of the storage media is not known to DOSFS. Your
 | 
			
		||||
sector r/w functions may need to query the CHS geometry and perform
 | 
			
		||||
mapping.
 | 
			
		||||
 | 
			
		||||
File timestamps set by DOSFS are always 1:01:00am on Jan 1, 2006. If
 | 
			
		||||
your system has a concept of real time, you can enhance this.
 | 
			
		||||
 | 
			
		||||
FILEINFO structures contain a pointer to the corresponding VOLINFO
 | 
			
		||||
used to open the file, mainly in order to avoid mixups but also to
 | 
			
		||||
obviate the need for an extra parameter to every file read/write. DOSFS
 | 
			
		||||
assumes that the VOLINFO won't move around. If you need to move or
 | 
			
		||||
destroy VOLINFOs pertaining to open files, you'll have to fix up the
 | 
			
		||||
pointer in the FILEINFO structure yourself.
 | 
			
		||||
 | 
			
		||||
The subdirectory delimiter is a forward slash ( '/' ) by default. The
 | 
			
		||||
reason for this is to avoid the common programming error of forgetting
 | 
			
		||||
that backslash is an escape character in C strings; i.e. "\MYDIR\FILE"
 | 
			
		||||
is NOT what you want; "\\MYDIR\\FILE" is what you wanted to type. If you
 | 
			
		||||
are porting DOS code into an embedded environment, feel free to change
 | 
			
		||||
this #define.
 | 
			
		||||
 | 
			
		||||
DOSFS does not have a concept of "current directory". A current directory
 | 
			
		||||
is owned by a process, and a process is an operating system concept.
 | 
			
		||||
DOSFS is a filesystem library, not an operating system. Therefore, any
 | 
			
		||||
path you provide to a DOSFS call is assumed to be relative to the root of
 | 
			
		||||
the volume.
 | 
			
		||||
 | 
			
		||||
There is no call to close a file or directory that is open for reading or
 | 
			
		||||
writing. You can simply destroy or reuse the data structures allocated for
 | 
			
		||||
that operation; there is no internal state in DOSFS so no cleanup is
 | 
			
		||||
necessary. Similarly, there is no call to close a file that is open for
 | 
			
		||||
writing. (Observe that dosfs.c has no global variables. All state information
 | 
			
		||||
is stored in data structures provided by the caller).
 | 
			
		||||
 | 
			
		||||
MAX_PATH is defined as 64. MS-type DOS filesystems support 128 characters
 | 
			
		||||
or more in paths. You can increase this define, but it may GREATLY
 | 
			
		||||
increase memory requirements.
 | 
			
		||||
 | 
			
		||||
VFAT long filenames are not supported. There is a certain amount of
 | 
			
		||||
patent controversy about them, but more importantly they don't really
 | 
			
		||||
belong in the scope of a "minimalist embedded filesystem".
 | 
			
		||||
 | 
			
		||||
Improving Performance
 | 
			
		||||
=====================
 | 
			
		||||
Read performance is fairly good, but can be improved by implementing read
 | 
			
		||||
caching on the FAT (see below) and, depending on your hardware platform,
 | 
			
		||||
possibly by implementing multi-sector reads.
 | 
			
		||||
 | 
			
		||||
Write performance may benefit ENORMOUSLY from platform-specific
 | 
			
		||||
optimization, especially if you are working with a flash media type that
 | 
			
		||||
has a large erase block size. While it is not possible to offer detailed
 | 
			
		||||
platform-independent advice, my general advice is to implement writeback
 | 
			
		||||
caching on the FAT area. One method for doing this would be to have a
 | 
			
		||||
cache system that lives in the DFS_ReadSector/WriteSector functions (on
 | 
			
		||||
top of the physical sector r/w functions) and is initially switched off.
 | 
			
		||||
Once you have called DFS_GetVolInfo, you then extract the VOLINFO.fat1
 | 
			
		||||
and VOLINFO.rootdir parameters and pass them to your caching layer.
 | 
			
		||||
Sectors >= fat1 and < rootdir should be cached. The cache strategy is
 | 
			
		||||
determined by the physical storage medium underlying the filesystem.
 | 
			
		||||
 | 
			
		||||
CACHING HINT:
 | 
			
		||||
Observe that there will be numerous read-modify-write operations in the
 | 
			
		||||
region from VOLINFO.fat1 through VOLINFO.fat1+VOLINFO.secperfat-1, but
 | 
			
		||||
in the region from VOLINFO.fat1+VOLINFO.secperfat through VOLINFO.rootdir
 | 
			
		||||
there will ONLY be write operations.
 | 
			
		||||
 | 
			
		||||
Platform Compatibility
 | 
			
		||||
======================
 | 
			
		||||
DOSFS was derived from code originally written for ARM7TDMI but
 | 
			
		||||
designed to be portable. It has been tested on AVR (using avrgcc),
 | 
			
		||||
MSP430 (using Rowley's CrossWorks) and PPC603e (using gcc); the host
 | 
			
		||||
test suite has also been validated on x86 using gcc under both Cygwin
 | 
			
		||||
and 32-bit Fedora Core 4 Linux.
 | 
			
		||||
 | 
			
		||||
TODO list
 | 
			
		||||
=========
 | 
			
		||||
* Add function to create subdirectory
 | 
			
		||||
* Make DFS_UnlinkFile recognize non-empty subdirectories
 | 
			
		||||
* Support "fast write" files where the FAT is not updated, for
 | 
			
		||||
  logging applications where latency is important.
 | 
			
		||||
 | 
			
		||||
Test cases for V1.02
 | 
			
		||||
====================
 | 
			
		||||
Version 1.02 has NOT been through full regression testing. However the
 | 
			
		||||
bugs fixed in this version are important, and people have been asking
 | 
			
		||||
about them.
 | 
			
		||||
 | 
			
		||||
Test cases for V1.01
 | 
			
		||||
====================
 | 
			
		||||
See below.
 | 
			
		||||
 | 
			
		||||
Test cases for V1.00
 | 
			
		||||
====================
 | 
			
		||||
These are the test cases that were used to validate the correct
 | 
			
		||||
functionality of the DOSFS suite. Each test was performed on FAT12,
 | 
			
		||||
FAT16 and FAT32 volumes. P=Pass, F=Fail.
 | 
			
		||||
 | 
			
		||||
Case                                                      F12 F16 F32
 | 
			
		||||
---------------------------------------------------------------------
 | 
			
		||||
Get volume information                                    P   P   P
 | 
			
		||||
Open root directory                                       P   P   P
 | 
			
		||||
List contents of root directory (fully populated)         P   P   P
 | 
			
		||||
Open subdirectory                                         P   P   P
 | 
			
		||||
List contents of subdirectory (<= 1 cluster)              P   P   P
 | 
			
		||||
List contents of large subdirectory (> 1 cluster)         P   P   P
 | 
			
		||||
Open 5-level nested subdirectory                          P   P   P
 | 
			
		||||
Open existing file for reading                            P   P   P
 | 
			
		||||
Open nonexistent file for reading                         P   P   P
 | 
			
		||||
Seek past EOF, file open for reading                      P   P   P
 | 
			
		||||
Seek to cluster boundary                                  P   P   P
 | 
			
		||||
Seek past cluster boundary                                P   P   P
 | 
			
		||||
Seek backwards to nonzero offset, pointer > cluster size  P   P   P
 | 
			
		||||
Block-read entire file >1 cluster in size, odd size       P   P   P
 | 
			
		||||
Seek to odd location in file                              P   P   P
 | 
			
		||||
Perform <1 sector reads from random file locations        P   P   P
 | 
			
		||||
Open nonexistent file for writing in root dir             P   P   P
 | 
			
		||||
Open nonexistent file for writing in subdir               P   P   P
 | 
			
		||||
Repeat prev. 2 tests on volume with 0 free clusters       P   P   P
 | 
			
		||||
Seek past EOF, file open for writing                      P   P   P
 | 
			
		||||
Open existing file for writing in root dir                P   P   P
 | 
			
		||||
Write random-length records to file, 20 clusters total    P   P   P
 | 
			
		||||
MS-DOS 6.0 SCANDISK cross-check                           P   P   P
 | 
			
		||||
 | 
			
		||||
Revision History
 | 
			
		||||
================
 | 
			
		||||
Jan-06-2005 larwe Initial release (1.0)
 | 
			
		||||
Jan-29-2006 larwe Bugfix release (1.01)
 | 
			
		||||
 - Fixed error in FAT12 FAT read on boundary of sector
 | 
			
		||||
 - Improved compilability under avrgcc
 | 
			
		||||
Sep-16-2006 larwe Bugfix release (1.02)
 | 
			
		||||
 - DFS_Seek would not correctly rewind to start of file
 | 
			
		||||
 - DFS_Seek would not correctly seek to a position not on a cluster
 | 
			
		||||
   boundary
 | 
			
		||||
 - DFS_OpenFile fencepost error caused memory access at [start of
 | 
			
		||||
   string-1] with a local variable
 | 
			
		||||
 - DFS_OpenFile could not open a file in the root directory
 | 
			
		||||
							
								
								
									
										99
									
								
								dosfs/tmpstring.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								dosfs/tmpstring.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *d = dest;
 | 
			
		||||
	const unsigned char *s = src;
 | 
			
		||||
	for (; n; n--) *d++ = *s++;
 | 
			
		||||
	return dest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *memset(void *dest, int c, size_t n)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *s = dest;
 | 
			
		||||
	size_t k;
 | 
			
		||||
 | 
			
		||||
	/* Fill head and tail with minimal branching. Each
 | 
			
		||||
	 * conditional ensures that all the subsequently used
 | 
			
		||||
	 * offsets are well-defined and in the dest region. */
 | 
			
		||||
 | 
			
		||||
	if (!n) return dest;
 | 
			
		||||
	s[0] = c;
 | 
			
		||||
	s[n-1] = c;
 | 
			
		||||
	if (n <= 2) return dest;
 | 
			
		||||
	s[1] = c;
 | 
			
		||||
	s[2] = c;
 | 
			
		||||
	s[n-2] = c;
 | 
			
		||||
	s[n-3] = c;
 | 
			
		||||
	if (n <= 6) return dest;
 | 
			
		||||
	s[3] = c;
 | 
			
		||||
	s[n-4] = c;
 | 
			
		||||
	if (n <= 8) return dest;
 | 
			
		||||
 | 
			
		||||
	/* Advance pointer to align it at a 4-byte boundary,
 | 
			
		||||
	 * and truncate n to a multiple of 4. The previous code
 | 
			
		||||
	 * already took care of any head/tail that get cut off
 | 
			
		||||
	 * by the alignment. */
 | 
			
		||||
 | 
			
		||||
	k = -(uintptr_t)s & 3;
 | 
			
		||||
	s += k;
 | 
			
		||||
	n -= k;
 | 
			
		||||
	n &= -4;
 | 
			
		||||
 | 
			
		||||
	/* Pure C fallback with no aliasing violations. */
 | 
			
		||||
	for (; n; n--, s++) *s = c;
 | 
			
		||||
 | 
			
		||||
	return dest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t strlen(const char *s)
 | 
			
		||||
{
 | 
			
		||||
	const char *a = s;
 | 
			
		||||
	for (; *s; s++);
 | 
			
		||||
	return s-a;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int memcmp(const void *vl, const void *vr, size_t n)
 | 
			
		||||
{
 | 
			
		||||
	const unsigned char *l=vl, *r=vr;
 | 
			
		||||
	for (; n && *l == *r; n--, l++, r++);
 | 
			
		||||
	return n ? *l-*r : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *strncpy(char *restrict d, const char *restrict s, size_t n)
 | 
			
		||||
{
 | 
			
		||||
	for (; n && (*d=*s); n--, s++, d++);
 | 
			
		||||
	memset(d, 0, n);
 | 
			
		||||
	return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *strcpy(char *restrict dest, const char *restrict src)
 | 
			
		||||
{
 | 
			
		||||
	char *restrict d = dest;
 | 
			
		||||
	const char *restrict s = src;
 | 
			
		||||
	for (; (*d=*s); s++, d++);
 | 
			
		||||
 | 
			
		||||
	return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int strcmp(const char *l, const char *r)
 | 
			
		||||
{
 | 
			
		||||
	for (; *l==*r && *l; l++, r++);
 | 
			
		||||
	return *(unsigned char *)l - *(unsigned char *)r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* STDLIB DIV FUNCTIONS */
 | 
			
		||||
typedef struct { int quot, rem; } div_t;
 | 
			
		||||
typedef struct { long quot, rem; } ldiv_t;
 | 
			
		||||
div_t div(int num, int den)
 | 
			
		||||
{
 | 
			
		||||
	return (div_t){ num/den, num%den };
 | 
			
		||||
}
 | 
			
		||||
ldiv_t ldiv(long num, long den)
 | 
			
		||||
{
 | 
			
		||||
	return (ldiv_t){ num/den, num%den };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -77,7 +77,7 @@ div bl ; Unhandled DIV0 exception
 | 
			
		||||
global jmp_usermode_test
 | 
			
		||||
jmp_usermode_test:
 | 
			
		||||
pop eax ; return address
 | 
			
		||||
mov ebp, esp ; return stack
 | 
			
		||||
mov ecx, esp ; return stack
 | 
			
		||||
call save_current_task
 | 
			
		||||
mov esp, 0x500000 ; usermode stack
 | 
			
		||||
mov eax, 0x20 | 3
 | 
			
		||||
 
 | 
			
		||||
@@ -175,7 +175,7 @@ void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code) {
 | 
			
		||||
                frame->eip = (uint16_t)(frame->eip + 1);
 | 
			
		||||
                goto done;
 | 
			
		||||
            case 0xCD: // INT n
 | 
			
		||||
                vga[0] = 'I'; vga[2]++; if (vga[2] < '0') vga[2] = '0';
 | 
			
		||||
                //vga[0] = 'I'; vga[2]++; if (vga[2] < '0') vga[2] = '0';
 | 
			
		||||
                switch (ip[1]) {
 | 
			
		||||
                    case 0x30:
 | 
			
		||||
                        return_prev_task();
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ typedef uint32_t FARPTR;
 | 
			
		||||
#define EFLAG_IF ((uint32_t)1 << 9)
 | 
			
		||||
#define EFLAG_VM ((uint32_t)1 << 17)
 | 
			
		||||
 | 
			
		||||
FARPTR i386LinearToFp(void *ptr);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__attribute__ ((interrupt))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										122
									
								
								kernel.c
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								kernel.c
									
									
									
									
									
								
							@@ -1,5 +1,6 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "dosfs/dosfs.h"
 | 
			
		||||
#include "print.h"
 | 
			
		||||
#include "interrupt.h"
 | 
			
		||||
 | 
			
		||||
@@ -52,13 +53,21 @@ void print_cr4() {
 | 
			
		||||
    printDword(reg, 0xB8000 + (160*5) + 50 + 8*4 + 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute((__no_caller_saved_registers__))
 | 
			
		||||
struct __attribute((__packed__)) Int13DiskPacket_t {
 | 
			
		||||
    uint8_t size; // 0x10
 | 
			
		||||
    uint8_t reserved; // 0x00
 | 
			
		||||
    uint16_t blocks;
 | 
			
		||||
    uint32_t transfer_buffer; // 0x2300:0000
 | 
			
		||||
    uint64_t start_block;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct Int13DiskPacket_t v86disk_addr_packet;
 | 
			
		||||
 | 
			
		||||
extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip);
 | 
			
		||||
extern void v86Test();
 | 
			
		||||
extern void v86GfxMode();
 | 
			
		||||
extern void v86TextMode();
 | 
			
		||||
extern void v86DiskRead();
 | 
			
		||||
__attribute((__no_caller_saved_registers__))
 | 
			
		||||
extern char *jmp_usermode_test();
 | 
			
		||||
__attribute((__no_caller_saved_registers__))
 | 
			
		||||
extern void kbd_wait();
 | 
			
		||||
@@ -88,6 +97,92 @@ Protected Only (1MB+)
 | 
			
		||||
400000 - 500000 Usermode Stack (1mB)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
void TestV86() {
 | 
			
		||||
    FARPTR v86_entry = i386LinearToFp(v86Test);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
}
 | 
			
		||||
void TestGfx() {
 | 
			
		||||
    FARPTR v86_entry = i386LinearToFp(v86GfxMode);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
    char *vga = jmp_usermode_test();
 | 
			
		||||
    for (int i = 0; i < 320; i++) {
 | 
			
		||||
        vga[i] = i;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
void TestDiskRead() {
 | 
			
		||||
    FARPTR v86_entry = i386LinearToFp(v86TextMode);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
    v86_entry = i386LinearToFp(v86DiskRead);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
    word *vga_text = (word *)0xb8000;
 | 
			
		||||
    char *diskReadBuf = (char *)0x23000;
 | 
			
		||||
    for (int i = 0; i < (80*25)/2; i++) {
 | 
			
		||||
        printByte(diskReadBuf[i], &vga_text[i*2]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
void TestFAT() {
 | 
			
		||||
    word *vga_text = (word *)0xb8000;
 | 
			
		||||
    uint8_t *diskReadBuf = (uint8_t *)0x23000;
 | 
			
		||||
    for (int i = 0; i < 80*25; i++)
 | 
			
		||||
        vga_text[i] = 0x0f00;
 | 
			
		||||
    VOLINFO vi;
 | 
			
		||||
 | 
			
		||||
    uint8_t pactive, ptype;
 | 
			
		||||
    uint32_t pstart, psize;
 | 
			
		||||
    pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize);
 | 
			
		||||
    vga_text = (word *)0xb8000;
 | 
			
		||||
    vga_text += printStr("PartStart: ", vga_text);
 | 
			
		||||
    vga_text += printDword(pstart, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("PartSize: ", vga_text);
 | 
			
		||||
    vga_text += printDword(psize, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("PartActive: ", vga_text);
 | 
			
		||||
    vga_text += printByte(pactive, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("PartType: ", vga_text);
 | 
			
		||||
    vga_text += printByte(ptype, vga_text);
 | 
			
		||||
    vga_text = (word *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
 | 
			
		||||
 | 
			
		||||
    DFS_GetVolInfo(0, diskReadBuf, pstart, &vi);
 | 
			
		||||
    vga_text += printStr("Label: ", vga_text);
 | 
			
		||||
    vga_text += printStr((char*)vi.label, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("Sec/Clus: ", vga_text);
 | 
			
		||||
    vga_text += printByte(vi.secperclus, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("ResrvSec: ", vga_text);
 | 
			
		||||
    vga_text += printWord(vi.reservedsecs, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("NumSec: ", vga_text);
 | 
			
		||||
    vga_text += printDword(vi.numsecs, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("Sec/FAT: ", vga_text);
 | 
			
		||||
    vga_text += printDword(vi.secperfat, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("FAT1@: ", vga_text);
 | 
			
		||||
    vga_text += printDword(vi.fat1, vga_text);
 | 
			
		||||
    vga_text += 2;
 | 
			
		||||
    vga_text += printStr("ROOT@: ", vga_text);
 | 
			
		||||
    vga_text += printDword(vi.rootdir, vga_text);
 | 
			
		||||
    vga_text = (word *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
 | 
			
		||||
 | 
			
		||||
    vga_text += printStr("Files in root:", vga_text);
 | 
			
		||||
    vga_text = (word *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
 | 
			
		||||
    DIRINFO di;
 | 
			
		||||
    DIRENT de;
 | 
			
		||||
    di.scratch = 0x23000;
 | 
			
		||||
    while (!DFS_GetNext(&vi, &di, &de)) {
 | 
			
		||||
        if (de.name[0]) {
 | 
			
		||||
            for (int i = 0; i < 11 && de.name[i]; i++) {
 | 
			
		||||
                *(uint8_t *)vga_text = de.name[i];
 | 
			
		||||
                vga_text++;
 | 
			
		||||
            }
 | 
			
		||||
            vga_text = (word *)((((((uintptr_t)vga_text)-0xb8000) - ((((uintptr_t)vga_text)-0xb8000) % 160)) + 160)+0xb8000);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void start() {
 | 
			
		||||
    word *vga_text = (word *)0xb8000;
 | 
			
		||||
    char h[] = "LuciaOS";
 | 
			
		||||
@@ -122,25 +217,14 @@ void start() {
 | 
			
		||||
    print_cr0();
 | 
			
		||||
    print_cr3();
 | 
			
		||||
    print_cr4();
 | 
			
		||||
    FARPTR v86_entry = i386LinearToFp(v86Test);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
    v86_entry = i386LinearToFp(v86GfxMode);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
    char *vga = jmp_usermode_test();
 | 
			
		||||
    //asm ("xchgw %bx, %bx");
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 320; i++) {
 | 
			
		||||
        vga[i] = i;
 | 
			
		||||
    }
 | 
			
		||||
    TestV86(); // has int 3 wait in v86
 | 
			
		||||
    TestGfx();
 | 
			
		||||
    kbd_wait();
 | 
			
		||||
    TestDiskRead();
 | 
			
		||||
    kbd_wait();
 | 
			
		||||
    TestFAT();
 | 
			
		||||
    kbd_wait();
 | 
			
		||||
    v86_entry = i386LinearToFp(v86TextMode);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
    v86_entry = i386LinearToFp(v86DiskRead);
 | 
			
		||||
    enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry));
 | 
			
		||||
    vga_text = (word *)0xb8000;
 | 
			
		||||
    char *bootloader = (char *)0x23000;
 | 
			
		||||
    for (int i = 0; i < (80*25)/2; i++) {
 | 
			
		||||
        printByte(bootloader[i], &vga_text[i*2]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								print.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								print.c
									
									
									
									
									
								
							@@ -3,15 +3,25 @@
 | 
			
		||||
char nibbleToHex(uint8_t n) {
 | 
			
		||||
    return n > 9 ? (n - 10) + 'A' : n + '0';
 | 
			
		||||
}
 | 
			
		||||
void printByte(uint8_t v, uint16_t *buff) {
 | 
			
		||||
uintptr_t printByte(uint8_t v, uint16_t *buff) {
 | 
			
		||||
    *(char *)&buff[0] = nibbleToHex((v >> 4) & 0xF);
 | 
			
		||||
    *(char *)&buff[1] = nibbleToHex(v & 0xF);
 | 
			
		||||
    return 2;
 | 
			
		||||
}
 | 
			
		||||
void printWord(uint16_t v, uint16_t *buff) {
 | 
			
		||||
uintptr_t printWord(uint16_t v, uint16_t *buff) {
 | 
			
		||||
    printByte(v >> 8, buff);
 | 
			
		||||
    printByte(v, &buff[2]);
 | 
			
		||||
    return 4;
 | 
			
		||||
}
 | 
			
		||||
void printDword(uint32_t v, uint16_t *buff) {
 | 
			
		||||
uintptr_t printDword(uint32_t v, uint16_t *buff) {
 | 
			
		||||
    printWord(v >> 16, buff);
 | 
			
		||||
    printWord(v, &buff[4]);
 | 
			
		||||
    return 8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uintptr_t printStr(char *v, uint16_t *buff) {
 | 
			
		||||
    char *s;
 | 
			
		||||
    for (s = v;*s;s++,buff++)
 | 
			
		||||
        *(char*)buff = *s;
 | 
			
		||||
    return s - v;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								print.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								print.h
									
									
									
									
									
								
							@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
void printByte(uint8_t v, uint16_t *buff);
 | 
			
		||||
void printWord(uint16_t v, uint16_t *buff);
 | 
			
		||||
void printDword(uint32_t v, uint16_t *buff);
 | 
			
		||||
uintptr_t printByte(uint8_t v, uint16_t *buff);
 | 
			
		||||
uintptr_t printWord(uint16_t v, uint16_t *buff);
 | 
			
		||||
uintptr_t printDword(uint32_t v, uint16_t *buff);
 | 
			
		||||
uintptr_t printStr(char *v, uint16_t *buff);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										54
									
								
								task.nasm
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								task.nasm
									
									
									
									
									
								
							@@ -1,12 +1,16 @@
 | 
			
		||||
task_ptr: equ (0x310000-4)
 | 
			
		||||
 | 
			
		||||
; return address in EAX
 | 
			
		||||
; return stack in ECX
 | 
			
		||||
; we can modify EAX, ECX, EDX
 | 
			
		||||
; i.e. save all others in task
 | 
			
		||||
global save_current_task
 | 
			
		||||
save_current_task:
 | 
			
		||||
push ebx
 | 
			
		||||
mov ebx, esp
 | 
			
		||||
push edx
 | 
			
		||||
mov edx, esp ; EDX holds our tmp stack, unsaved
 | 
			
		||||
mov esp, dword [task_ptr] ; load current task pointer
 | 
			
		||||
push ss
 | 
			
		||||
push ebp ; return stack
 | 
			
		||||
push ecx ; return stack
 | 
			
		||||
pushfd
 | 
			
		||||
push cs
 | 
			
		||||
push eax ; return address
 | 
			
		||||
@@ -14,33 +18,41 @@ push ds ; other segs, pop
 | 
			
		||||
push es ; before iret
 | 
			
		||||
push fs ; in exit handler
 | 
			
		||||
push gs
 | 
			
		||||
push ebp ; saved
 | 
			
		||||
push ebx ; saved
 | 
			
		||||
push esi ; saved
 | 
			
		||||
push edi ; saved
 | 
			
		||||
mov dword [task_ptr], esp ; save new task pointer
 | 
			
		||||
mov esp, ebx
 | 
			
		||||
pop ebx
 | 
			
		||||
mov esp, edx
 | 
			
		||||
pop edx
 | 
			
		||||
ret
 | 
			
		||||
 | 
			
		||||
global return_prev_task
 | 
			
		||||
return_prev_task:
 | 
			
		||||
mov edi, eax ; save for later
 | 
			
		||||
mov esi, dword [task_ptr] ; load current task pointer
 | 
			
		||||
add dword [task_ptr], 36 ; adjust to last task pointer
 | 
			
		||||
mov eax, [esi+0] ; gs
 | 
			
		||||
mov ecx, eax ; save return value for later
 | 
			
		||||
mov edx, dword [task_ptr] ; load current task pointer
 | 
			
		||||
add dword [task_ptr], 52 ; adjust to last task pointer
 | 
			
		||||
mov edi, [edx+0]
 | 
			
		||||
mov esi, [edx+4]
 | 
			
		||||
mov ebx, [edx+8]
 | 
			
		||||
mov ebp, [edx+12]
 | 
			
		||||
mov eax, [edx+0+16] ; gs
 | 
			
		||||
mov gs, ax
 | 
			
		||||
mov eax, [esi+4] ; fs
 | 
			
		||||
mov eax, [edx+4+16] ; fs
 | 
			
		||||
mov fs, ax
 | 
			
		||||
mov eax, [esi+8] ; es
 | 
			
		||||
mov eax, [edx+8+16] ; es
 | 
			
		||||
mov es, ax
 | 
			
		||||
mov ebx, [esi+16] ; eip
 | 
			
		||||
mov ecx, [esi+20] ; cs
 | 
			
		||||
mov edx, [esi+24] ; eflags
 | 
			
		||||
; SS:ESP <- return stack
 | 
			
		||||
mov esp, [esi+28] ; esp
 | 
			
		||||
mov eax, [esi+32] ; ss
 | 
			
		||||
mov esp, [edx+28+16] ; esp
 | 
			
		||||
mov eax, [edx+32+16] ; ss
 | 
			
		||||
mov ss, ax
 | 
			
		||||
mov eax, [esi+12] ; ds
 | 
			
		||||
mov eax, [edx+24+16] ; eflags
 | 
			
		||||
push eax
 | 
			
		||||
mov eax, [edx+20+16] ; cs
 | 
			
		||||
push eax
 | 
			
		||||
mov eax, [edx+16+16] ; eip
 | 
			
		||||
push eax
 | 
			
		||||
mov eax, [edx+12+16] ; ds
 | 
			
		||||
mov ds, ax
 | 
			
		||||
push edx ; eflags
 | 
			
		||||
push ecx ; cs
 | 
			
		||||
push ebx ; eip
 | 
			
		||||
mov eax, edi ; restore return value
 | 
			
		||||
mov eax, ecx ; restore return value
 | 
			
		||||
iret
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								tss.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								tss.c
									
									
									
									
									
								
							@@ -42,7 +42,7 @@ void write_tss() {
 | 
			
		||||
 | 
			
		||||
    // not technically TSS but set up task pointer
 | 
			
		||||
    uint32_t *current_task_ptr = (uint32_t*)(0x310000-4);
 | 
			
		||||
    *current_task_ptr = 0x310000-40; // each task is 9 dwords, plus 1 for pointer
 | 
			
		||||
    *current_task_ptr = 0x310000-(20*4); // each task is 12 dwords, plus 1 for pointer
 | 
			
		||||
    /* TODO setup null recovery task at start */
 | 
			
		||||
}
 | 
			
		||||
extern void flushTSS();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								v86.nasm
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								v86.nasm
									
									
									
									
									
								
							@@ -67,18 +67,20 @@ mov si, v86disk_addr_packet ; ds:si
 | 
			
		||||
int 0x13
 | 
			
		||||
int 0x30
 | 
			
		||||
jmp $
 | 
			
		||||
global v86disk_addr_packet
 | 
			
		||||
v86disk_addr_packet:
 | 
			
		||||
db 0x10, 0x00 ; size, reserved
 | 
			
		||||
dw 0x20 ; blocks
 | 
			
		||||
dw 0x1 ; blocks
 | 
			
		||||
dd 0x23000000 ; transfer buffer 0x23000
 | 
			
		||||
dq 0 ; start block
 | 
			
		||||
dq 0x1 ; start block
 | 
			
		||||
[BITS 32]
 | 
			
		||||
; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip);
 | 
			
		||||
global enter_v86
 | 
			
		||||
enter_v86:
 | 
			
		||||
pop eax
 | 
			
		||||
mov ebp, esp               ; save stack pointer
 | 
			
		||||
pop eax ; return address
 | 
			
		||||
mov ecx, esp ; return stack
 | 
			
		||||
call save_current_task
 | 
			
		||||
mov ebp, esp               ; save stack pointer
 | 
			
		||||
push dword  [ebp+0]        ; ss
 | 
			
		||||
push dword  [ebp+4]        ; esp
 | 
			
		||||
pushfd                     ; eflags
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user