diff --git a/README.MD b/README.MD index 8bcda12..8f852cd 100644 --- a/README.MD +++ b/README.MD @@ -3,7 +3,9 @@ EttinOS EttinOS is a minimalist 16-bit DOS-like hobbyist operating system for the IBM Personal Computer and compatible machines. Its git repository -can be found at https://ahti.space/git/crazyettin/EttinOS. +can be found at https://ahti.space/git/crazyettin/EttinOS and that of +EttinOS-extra, a collection of programs for the system, at +https://ahti.space/git/crazyettin/EttinOS-extra. System requirements ------------------- @@ -38,11 +40,12 @@ overwrites the cursor location and the erase (=tab) key erases it. The space and backspace keys move the cursor. EttinOS assigns the drives letters from A to D and uses the FAT12 file -system. The extended BIOS parameter block, file attributes, and the file -access date are not supported and are ignored if present: as a result -disk labels and subdirectories are not supported. Drive letters and file -names are case-insensitive and the latter follow the 8.3 format. Text -files use CRLF line endings. +system. The hidden and total sectors entries of the BIOS parameter +block, the entire extended BIOS parameter block, file attributes, and +the file access date are not supported and are ignored if present: as a +result disk labels and subdirectories are not supported. Drive letters +and file names are case-insensitive and the latter follow the 8.3 +format. Text files use CRLF line endings. Drives and files are specified as ([A-D]:) and ([A-D]:)FILENAME.EXT respectively. Specifying the current drive, indicated in the prompt, is @@ -61,8 +64,8 @@ Commands included in EttinOS: * PRINT: Print a text file. Syntax: PRINT FILE Both LIST and PRINT page their output if all of it does not fit on the -screen at the same time. Press any key to continue printing after each -screen. +screen at the same time. Press any key other than escape to continue +printing after each screen or escape to quit the program. Programming ----------- diff --git a/src/BOOT.ASM b/src/BOOT.ASM index d134d08..3b112e3 100644 --- a/src/BOOT.ASM +++ b/src/BOOT.ASM @@ -1,122 +1,135 @@ -CPU 8086 -ORG 0x7c00 +cpu 8086 +org 0x7c00 +;Jump to the code jmp start + +;Padding nop -;Disk description tables +;OEM label +db "ETTINOS " %ifdef F1440 -;1.44 MB 3.5" floppy disk (enable with the argument -d F1440) -oemlabel db "ETTINOS " + +;1.44 MB 3.5" floppy disk BPB (enable with the argument -d F1440) sectorsize dw 0x200 ;bytes clustersize db 0x1 ;sectors -bootsectors dw 0x1 +reservedsectors dw 0x1 fats db 0x2 rootentries dw 0xe0 logicalsectors dw 0xb40 mediadescriptor db 0xf0 sectorsperfat dw 0x9 sectorspertrack dw 0x12 -sides dw 0x2 -hiddensectors dd 0x0 -largesectors dd 0x0 +heads dw 0x2 %else -;360 KiB 5.25" floppy disk (default) -oemlabel db "ETTINOS " + +;360 KiB 5.25" floppy disk BPB (default) sectorsize dw 0x200 ;bytes clustersize db 0x2 ;sectors -bootsectors dw 0x1 +reservedsectors dw 0x1 fats db 0x2 rootentries dw 0x70 logicalsectors dw 0x2d0 mediadescriptor db 0xfd sectorsperfat dw 0x2 sectorspertrack dw 0x9 -sides dw 0x2 -hiddensectors dd 0x0 -largesectors dd 0x0 +heads dw 0x2 %endif -start: ;Setup -;Set up the data, stack, and extra segments +;Set the segments +start: mov ax, 0x0 mov ds, ax mov ss, ax mov es, ax -;Set up the stack +;Set the stack cli mov sp, 0x0 sti ;Store the boot drive number mov [drive], dl -;Load the root -;Set the source +;Calculate and store variables not found in the BPB +;Start of the root mov ah, 0x0 mov al, [fats] mul word [sectorsperfat] -add ax, [bootsectors] -push ax -;Set the destination -mov si, buffer -mov bx, si -;Set the size +add ax, [reservedsectors] +mov [rootstart], ax +;Size of the root in sectors mov ax, [rootentries] mov dx, 0x20 mul dx mov dx, 0x0 div word [sectorsize] -mov cx, ax -pop ax +mov [rootsectors], ax +;Start of data +add ax, [rootstart] +mov [datastart], ax + +;Load the root +;Set the source +mov ax, [rootstart] +;Set the destination +mov si, buffer +mov bx, si +;Set the size +mov cx, [rootsectors] +;Store the source and the loop counter in the stack +loadrootsector: push ax push cx -loadroot: -push cx +;Set the source call calcsource ;Set the size -push ax mov al, 0x1 -;Load +;Load a sector mov ah, 0x2 int 0x13 +;Load the loop counter and the source from the stack +pop cx pop ax ;Set the next sector add ax, 0x1 add bx, word [sectorsize] -pop cx -loop loadroot +;Load the next sector +loop loadrootsector ;Search the root for the system entry ;Set DI to the root mov di, buffer -;Initialise the search loop +;Set the number of root entries mov cx, word [rootentries] +;Set the entry pointer mov ax, 0x0 +;Store the loop counter in the stack search: -;Store CX in the stack push cx ;Check for the system entry -mov si, sysfile +mov si, file mov cx, 0xb rep cmpsb -je loadentry -;Set DI to the next entry +je loadfat +;Set DI at the next entry add ax, 0x20 mov di, buffer add di, ax -;Load CX from the stack +;Load the loop counter from the stack pop cx +;Search the next entry loop search -;Print an error message if the system is not found -mov si, errormsg -printerror: +;Print an error message and hang if the system is not found +;Set SI at the file error message +mov si, filerrormsg ;Load a character +printstr: lodsb ;Check for the string end cmp al, 0x0 @@ -124,62 +137,61 @@ je $ ;Print the character mov ah, 0xe int 0x10 -;Repeat -jmp printerror +;Print the next character +jmp printstr -;Load the system entry -loadentry: +;Load the FAT ;Load CX from the stack +loadfat: pop cx -;Store the first cluster -mov ax, word [es:di+0xf] -mov word [cluster], ax +;Store the address of the first cluster +mov ax, [di + 0xf] +mov [cluster], ax ;Set the source -mov ax, 0x1 +mov ax, [reservedsectors] call calcsource ;Set the destination -mov di, buffer -mov bx, di +mov bx, buffer ;Set the size mov ax, [sectorsperfat] -;Load +;Load the FAT mov ah, 0x2 int 0x13 ;Load a cluster loadcluster: ;Set the source -pop cx -pop bx mov ax, word [cluster] sub ax, 0x2 mul byte [clustersize] -add ax, bx -add ax, cx -push bx -push cx +add ax, [datastart] ;Set the destination mov bx, word [pointer] -;Load a sector +;Set the size mov ch, 0x0 mov cl, byte [clustersize] -loadsector: +;Store the loop counter in the stack +loadclustersector: push cx +;Set the source call calcsource ;Set the size push ax mov al, 0x1 -;Load +;Load a sector mov ah, 0x2 int 0x13 pop ax ;Set the next sector add ax, 0x1 -add bx, word [sectorsize] +add bx, [sectorsize] +;Load the loop counter from the stack pop cx -loop loadsector +;Load the next sector +loop loadclustersector ;Calculate the next cluster +;Check if the cluster is even or odd mov ax, [cluster] mov dx, 0x0 mov bx, 0x3 @@ -188,67 +200,87 @@ mov bx, 0x2 div bx mov si, buffer add si, ax -mov ax, word [ds:si] +mov ax, word [si] or dx, dx jz even -odd: -shr ax, 1 -shr ax, 1 -shr ax, 1 -shr ax, 1 +;If the cluster is odd shift out the first four bits +times 0x4 shr ax, 0x1 jmp contcalc +;If the cluster is even mask out the final four bits even: and ax, 0xfff contcalc: -mov word [cluster], ax +;Check for the file end cmp ax, 0xff8 jge boot +;Store the address of the next cluster +mov word [cluster], ax +;Set the destination of the next cluster mov ax, [sectorsize] mul word [clustersize] add word [pointer], ax +;Load the next cluster jmp loadcluster -;Clear the stack and boot the system +;Boot the system +;Pass the boot drive number to the system boot: -;Clear -pop cx -pop bx -;Pass the drive number to the system mov dl, byte [drive] -;Boot +;Boot the system jmp 0x0:0x500 ;Data -drive db 0x0 -sysfile db "SYSTEM BIN" -errormsg db "System not found", 0xd, 0xa, 0x0 -cluster dw 0x0 -pointer dw 0x500 +drive db 0x0 +rootstart dw 0x0 +rootsectors dw 0x0 +datastart dw 0x0 +file db "SYSTEM BIN" +filerrormsg db "System not found", 0xd, 0xa, 0x0 +cluster dw 0x0 +pointer dw 0x500 + +;*** ;Calculate the source arguments for loading data from the disk calcsource: + +;Store AX and BX in the stack push ax push bx + +;Calculate the cylinder, head, and sector +;Store the logical sector in BX mov bx, ax +;Calculate the sector mov dx, 0x0 div word [sectorspertrack] add dl, 0x1 mov cl, dl +;Load the logical sector from BX mov ax, bx +;Calculate the head and cylinder mov dx, 0x0 div word [sectorspertrack] mov dx, 0x0 -div word [sides] -mov dh, dl -mov ch, al +div word [heads] +mov dh, dl ;Head +mov ch, al ;Cylinder + +;Load the boot drive number +mov dl, byte [drive] + +;Load BX and AX from the stack pop bx pop ax -mov dl, byte [drive] + +;Return ret -;Pad the binary to a full sector and make the disk bootable +;*** + ;Padding times 0x1fe-($-$$) db 0x0 + ;Boot signature dw 0xaa55 diff --git a/src/ECHO.ASM b/src/ECHO.ASM index e5ce8ad..0b51c81 100644 --- a/src/ECHO.ASM +++ b/src/ECHO.ASM @@ -1,12 +1,14 @@ -CPU 8086 -ORG 0x3000 +cpu 8086 +org 0x3000 -;Echo the tail ;Check for an empty tail cmp byte [si], 0x0 je done -;Echo + +;Print the message mov ah, 0x2 int 0x21 + +;Return to the system done: int 0x20 diff --git a/src/HELLO.ASM b/src/HELLO.ASM index 21c9d84..e05c35d 100644 --- a/src/HELLO.ASM +++ b/src/HELLO.ASM @@ -1,10 +1,12 @@ -CPU 8086 -ORG 0x3000 +cpu 8086 +org 0x3000 ;Print a hello world. mov si, hello mov ah, 0x2 int 0x21 + +;Return to the system int 0x20 ;Data diff --git a/src/LIST.ASM b/src/LIST.ASM index a41a161..06625d3 100644 --- a/src/LIST.ASM +++ b/src/LIST.ASM @@ -1,7 +1,5 @@ -CPU 8086 -ORG 0x3000 - -;List the files on a drive +cpu 8086 +org 0x3000 ;Store the drive number mov [drive], dl @@ -21,45 +19,36 @@ je changedrive ;Print an error message jmp driverror changedrive: +;Get the BIOS equipment list +int 0x11 +;Get the number of floppy drives +times 0x6 shr ax, 0x1 +and ax, 0x3 +inc ax +;Set the loop and drive letter counters and the drive letter and number +mov cx, ax +mov di, driveletters +mov al, [si] +mov dl, 0x0 ;Check which drive to change to -cmp byte [si], "a" -je cha -cmp byte [si], "A" -je cha -cmp byte [si], "b" -je chb -cmp byte [si], "B" -je chb -cmp byte [si], "c" -je chc -cmp byte [si], "C" -je chc -cmp byte [si], "d" -je chd -cmp byte [si], "D" -je chd +checkdrive: +cmp al, [di] +je contchdrive +inc di +cmp al, [di] +je contchdrive +inc di +inc dl +loop checkdrive ;Print an error message jmp driverror -;Change -cha: -mov dl, 0x0 -mov byte [drive], dl -jmp loadvalues -chb: -mov dl, 0x1 -mov byte [drive], dl -jmp loadvalues -chc: -mov dl, 0x2 -mov byte [drive], dl -jmp loadvalues -chd: -mov dl, 0x3 -mov byte [drive], dl +;Change the drive +contchdrive: +mov [drive], dl ;Load the disk description table -loadvalues: ;Set the source +loadvalues: mov dl, [drive] mov ch, 0x0 mov dh, 0x0 @@ -69,62 +58,68 @@ mov si, buffer mov bx, si ;Set the size mov al, 0x1 -;Load +;Load the disk description table mov ah, 0x2 int 0x13 jc diskerror ;Store the disk values used for the rest of the call -mov ax, word [buffer + 0xb] -mov word [sectorsize], ax -mov ax, word [buffer + 0xe] -mov word [bootsectors], ax -mov al, byte [buffer + 0x10] -mov byte [fats], al -mov ax, word [buffer + 0x11] -mov word [rootentries], ax -mov ax, word [buffer + 0x16] -mov word [sectorsperfat], ax -mov ax, word [buffer + 0x18] -mov word [sectorspertrack], ax -mov ax, word [buffer + 0x1a] -mov word [sides], ax +mov ax, [buffer + 0xb] +mov [sectorsize], ax +mov ax, [buffer + 0xe] +mov [reservedsectors], ax +mov al, [buffer + 0x10] +mov [fats], al +mov ax, [buffer + 0x11] +mov [rootentries], ax +mov ax, [buffer + 0x16] +mov [sectorsperfat], ax +mov ax, [buffer + 0x18] +mov [sectorspertrack], ax +mov ax, [buffer + 0x1a] +mov [heads], ax -;Load the root -;Set the source +;Calculate and store variables not found in the BPB +;Start of the root mov ah, 0x0 mov al, [fats] mul word [sectorsperfat] -add ax, [bootsectors] -push ax -;Set the destination -mov si, buffer -mov bx, si -;Set the size +add ax, [reservedsectors] +mov [rootstart], ax +;Size of the root in sectors mov ax, [rootentries] mov dx, 0x20 mul dx mov dx, 0x0 div word [sectorsize] -mov cx, ax -pop ax +mov [rootsectors], ax + +;Load the root +;Set the source +mov ax, [rootstart] +;Set the destination +mov si, buffer +mov bx, si +;Set the size +mov cx, [rootsectors] +;Store the source and the loop counter in the stack +loadrootsector: push ax push cx -loadroot: -push cx +;Set the source call calcsource ;Set the size -push ax mov al, 0x1 -;Load +;Load a sector mov ah, 0x2 int 0x13 +;Load the loop counter and the source from the stack +pop cx pop ax ;Set the next sector add ax, 0x1 add bx, word [sectorsize] -pop cx -loop loadroot +loop loadrootsector ;List ;Set SI to the root @@ -133,8 +128,8 @@ mov si, buffer mov cx, word [rootentries] mov ax, 0x0 mov bl, 0x17 -loop: ;Store CX in the stack +loop: push cx ;Check for an empty entry cmp byte [si], 0xe5 @@ -178,8 +173,8 @@ pop ax cmp bl, 0x0 jz page dec bl -skip: ;Set SI to the next entry +skip: add ax, 0x20 mov si, buffer add si, ax @@ -190,6 +185,8 @@ page: push ax mov ah, 0x0 int 0x16 +cmp al, 0x1b +je done pop ax mov bl, 0x17 jmp skip @@ -212,35 +209,56 @@ jmp done ;Data drive db 0x0 sectorsize dw 0x0 ;bytes -bootsectors dw 0x0 +reservedsectors dw 0x0 fats db 0x0 rootentries dw 0x0 sectorsperfat dw 0x0 sectorspertrack dw 0x0 -sides dw 0x0 +heads dw 0x0 +rootstart dw 0x0 +rootsectors dw 0x0 +driveletters db "AaBbCcDd" driverrormsg db "Drive not found", 0x0 diskerrormsg db "Unable to read disk", 0x0 +;*** + ;Calculate the source arguments for loading data from the disk calcsource: + +;Store AX and BX in the stack push ax push bx + +;Calculate the cylinder, head, and sector +;Store the logical sector in BX mov bx, ax +;Calculate the sector mov dx, 0x0 div word [sectorspertrack] add dl, 0x1 mov cl, dl +;Load the logical sector from BX mov ax, bx +;Calculate the head and cylinder mov dx, 0x0 div word [sectorspertrack] mov dx, 0x0 -div word [sides] -mov dh, dl -mov ch, al +div word [heads] +mov dh, dl ;Head +mov ch, al ;Cylinder + +;Load the drive number +mov dl, byte [drive] + +;Load BX and AX from the stack pop bx pop ax -mov dl, byte [drive] + +;Return ret +;*** + ;Buffer buffer: diff --git a/src/LOADF.INC b/src/LOADF.INC index f7665b5..83aabe0 100644 --- a/src/LOADF.INC +++ b/src/LOADF.INC @@ -8,7 +8,7 @@ loadf: -;Store the initial registers in the stack +;Store BX, DX, SI, and DI in the stack push bx push dx push si @@ -22,24 +22,28 @@ mov byte [.drive], dl ;Change the drive if needed ;Check for a drive specification cmp byte [si + 0x1], ":" -jne .start +jne .convert +;Get the BIOS equipment list +int 0x11 +;Get the number of floppy drives +times 0x6 shr ax, 0x1 +and ax, 0x3 +inc ax +;Set the loop and drive letter counters and the drive letter and number +mov cx, ax +mov di, driveletters +mov al, [si] +mov dl, 0x0 ;Check which drive to change to -cmp byte [si], "a" -je .cha -cmp byte [si], "A" -je .cha -cmp byte [si], "b" -je .chb -cmp byte [si], "B" -je .chb -cmp byte [si], "c" -je .chc -cmp byte [si], "C" -je .chc -cmp byte [si], "d" -je .chd -cmp byte [si], "D" -je .chd +.checkdrive: +cmp al, [di] +je .contchdrive +inc di +cmp al, [di] +je .contchdrive +inc di +inc dl +loop .checkdrive ;Set AL to 0x1, CX to 0x0, and print an error message mov si, .driverrormsg mov ah, 0x2 @@ -47,57 +51,41 @@ int 0x21 mov al, 0x1 mov cx, 0x0 jmp .done -;Change -.cha: -mov dl, 0x0 -mov byte [.drive], dl -jmp .drivechanged -.chb: -mov dl, 0x1 -mov byte [.drive], dl -jmp .drivechanged -.chc: -mov dl, 0x2 -mov byte [.drive], dl -jmp .drivechanged -.chd: -mov dl, 0x3 -mov byte [.drive], dl -.drivechanged: +;Change the drive +.contchdrive: +mov [.drive], dl +;Move to the file name add si, 0x2 -.start: - ;Set DI at .file and initialise it with spaces +.convert: mov di, .file mov cx, 0xb mov al, 0x20 rep stosb sub di, 0xb -;Convert .file into FAT formatting - -;Initialise the length counter for the main part of the file name +;Convert the main part of the file name into FAT format +;Set the length counter mov bl, 0x8 - -;Convert the main part of the file name -.nameloop: ;Load a character +.nameloop: lodsb ;Check for a period cmp al, 0x2e je .initext ;Check for everything else and convert to upper case call .checkconv +;Load the next character jmp .nameloop -;Convert the extension +;Convert the extension into FAT format +;Set DI and the length counter for the extension .initext: -;Set DI and initialise the length counter for the extension mov bl, 0x3 mov di, .file+0x8 -.extloop: ;Load a character +.extloop: lodsb ;Check for a period push ax @@ -106,6 +94,7 @@ je .error pop ax ;Check for everything else and convert to upper case call .checkconv +;Load the next character jmp .extloop ;Set AL to 0x4, CX to 0x0, and print an error message .error: @@ -118,7 +107,6 @@ mov cx, 0x0 jmp .done ;Find and load the file - .load: pop ax @@ -133,7 +121,7 @@ mov si, buffer mov bx, si ;Set the size mov al, 0x1 -;Load +;Load the disk description table mov ah, 0x2 int 0x13 jnc .storevalues @@ -147,79 +135,91 @@ jmp .done ;Store the disk values used for the rest of the call .storevalues: -mov ax, word [buffer + 0xb] -mov word [.sectorsize], ax -mov al, byte [buffer + 0xd] -mov byte [.clustersize], al -mov ax, word [buffer + 0xe] -mov word [.bootsectors], ax -mov al, byte [buffer + 0x10] -mov byte [.fats], al -mov ax, word [buffer + 0x11] -mov word [.rootentries], ax -mov ax, word [buffer + 0x16] -mov word [.sectorsperfat], ax -mov ax, word [buffer + 0x18] -mov word [.sectorspertrack], ax -mov ax, word [buffer + 0x1a] -mov word [.sides], ax +mov ax, [buffer + 0xb] +mov [.sectorsize], ax +mov al, [buffer + 0xd] +mov [.clustersize], al +mov ax, [buffer + 0xe] +mov [.reservedsectors], ax +mov al, [buffer + 0x10] +mov [.fats], al +mov ax, [buffer + 0x11] +mov [.rootentries], ax +mov ax, [buffer + 0x16] +mov [.sectorsperfat], ax +mov ax, [buffer + 0x18] +mov [.sectorspertrack], ax +mov ax, [buffer + 0x1a] +mov [.heads], ax -;Load the root -;Set the source +;Calculate and store variables not found in the BPB +;Start of the root mov ah, 0x0 mov al, [.fats] mul word [.sectorsperfat] -add ax, [.bootsectors] -push ax -;Set the destination -mov si, buffer -mov bx, si -;Set the size +add ax, [.reservedsectors] +mov [.rootstart], ax +;Size of the root in sectors mov ax, [.rootentries] mov dx, 0x20 mul dx mov dx, 0x0 div word [.sectorsize] -mov cx, ax -pop ax +mov [.rootsectors], ax +;Start of data +add ax, [.rootstart] +mov [.datastart], ax + +;Load the root +;Set the source +mov ax, [.rootstart] +;Set the destination +mov si, buffer +mov bx, si +;Set the size +mov cx, [.rootsectors] +;Store the source and the loop counter in the stack +.loadrootsector: push ax push cx -.loadroot: -push cx +;Set the source call .calcsource ;Set the size -push ax mov al, 0x1 -;Load +;Load a sector mov ah, 0x2 int 0x13 +;Load the loop counter and the source from the stack +pop cx pop ax ;Set the next sector add ax, 0x1 add bx, word [.sectorsize] -pop cx -loop .loadroot +;Load the next sector +loop .loadrootsector ;Search the root for the file entry ;Set DI to the root mov di, buffer -;Initialise the search loop +;Set the number of root entries mov cx, word [.rootentries] +;Set the entry pointer mov ax, 0x0 +;Store the loop counter in the stack .search: -;Store CX in the stack push cx ;Check for the file entry mov si, .file mov cx, 0xb rep cmpsb je .checksize -;Set DI to the next entry +;Set DI at the next entry add ax, 0x20 mov di, buffer add di, ax -;Load CX from the stack +;Load the loop counter from the stack pop cx +;Search the next entry loop .search ;Set AL to 0x4, CX to 0x0, and print an error message mov si, .filerrormsg @@ -227,11 +227,11 @@ mov ah, 0x2 int 0x21 mov al, 0x4 mov cx, 0x0 -jmp .clearstack +jmp .done ;Check and store the file size -.checksize: ;Load CX from the stack +.checksize: pop cx ;Check for files larger than 64 KiB cmp word [di + 0x13], 0x0 @@ -259,61 +259,58 @@ mov ah, 0x2 int 0x21 mov al, 0x8 mov cx, 0x0 -jmp .clearstack +jmp .done ;Load the FAT .loadfat: -;Store the first cluster of the file -mov ax, word [di + 0xf] -mov word [.cluster], ax +;Store the address of the first cluster +mov ax, [di + 0xf] +mov [.cluster], ax ;Set the source -mov ax, 0x1 +mov ax, [.reservedsectors] call .calcsource ;Set the destination -mov di, buffer -mov bx, di +mov bx, buffer ;Set the size mov ax, [.sectorsperfat] -;Load +;Load the FAT mov ah, 0x2 int 0x13 -;Load the file - ;Load a cluster .loadcluster: ;Set the source -pop cx -pop bx mov ax, word [.cluster] sub ax, 0x2 mul byte [.clustersize] -add ax, bx -add ax, cx -push bx -push cx +add ax, [.datastart] ;Set the destination mov bx, word [.pointer] -;Load a sector +;Set the size mov ch, 0x0 mov cl, byte [.clustersize] +;Store the loop counter in the stack .loadsector: push cx +;Set the source call .calcsource ;Set the size push ax mov al, 0x1 -;Load +;Load a sector mov ah, 0x2 int 0x13 pop ax ;Set the next sector add ax, 0x1 add bx, word [.sectorsize] +;Load the loop counter from the stack pop cx +;Load the next sector loop .loadsector ;Calculate the next cluster +;Check if the cluster is even or odd mov ax, [.cluster] mov dx, 0x0 mov bx, 0x3 @@ -322,23 +319,26 @@ mov bx, 0x2 div bx mov si, buffer add si, ax -mov ax, word [ds:si] +mov ax, word [si] or dx, dx jz .even -shr ax, 1 -shr ax, 1 -shr ax, 1 -shr ax, 1 +;If the cluster is odd shift out the first four bits +times 0x4 shr ax, 0x1 jmp .contcalc +;If the cluster is even mask out the final four bits .even: and ax, 0xfff .contcalc: -mov word [.cluster], ax +;Check for the file end cmp ax, 0xff8 jge .success +;Store the address of the next cluster +mov word [.cluster], ax +;Set the destination of the next cluster mov ax, [.sectorsize] mul word [.clustersize] add word [.pointer], ax +;Load the next cluster jmp .loadcluster ;Set AL to 0x0 and load the file size to CX if the load was succesful @@ -347,13 +347,9 @@ mov al, 0x0 mov cx, [.size] ;Clear the stack -.clearstack: -pop bx -pop bx - .done: -;Load the initial registers from the stack +;Load DI, SI, DX, and BX from the stack pop di pop si pop dx @@ -362,18 +358,22 @@ pop bx ;Set AH to its initial value mov ah, 0x0 +;Return iret ;Data .drive db 0x0 .sectorsize dw 0x0 ;bytes .clustersize db 0x0 ;sectors -.bootsectors dw 0x0 +.reservedsectors dw 0x0 .fats db 0x0 .rootentries dw 0x0 .sectorsperfat dw 0x0 .sectorspertrack dw 0x0 -.sides dw 0x0 +.heads dw 0x0 +.rootstart dw 0x0 +.rootsectors dw 0x0 +.datastart dw 0x0 .file times 0xb db 0x20 .size dw 0x0 .cluster dw 0x0 @@ -383,8 +383,12 @@ iret .filerrormsg db "File or command not found", 0x0 .sizerrormsg db "Not enough memory", 0x0 +;*** + ;Check the file name and convert to upper case .checkconv: + +;Check for the string end, length limit, and invalid characters ;Check for the string end cmp al, 0x0 je .load @@ -416,6 +420,8 @@ jmp .error .contcheck3: cmp al, 0x7c je .error + +;Check for lower case and convert it to upper case ;Check for lower case cmp al, 0x61 jl .storech @@ -423,30 +429,50 @@ cmp al, 0x7a jg .storech ;Convert lower to upper case sub al, 0x20 -.storech: + ;Store the character +.storech: stosb + ;Decrease the counter dec bl + +;Return ret +;*** + ;Calculate the source arguments for loading data from the disk .calcsource: + +;Store AX and BX in the stack push ax push bx + +;Calculate the cylinder, head, and sector +;Store the logical sector in BX mov bx, ax +;Calculate the sector mov dx, 0x0 div word [.sectorspertrack] add dl, 0x1 mov cl, dl +;Load the logical sector from BX mov ax, bx +;Calculate the head and cylinder mov dx, 0x0 div word [.sectorspertrack] mov dx, 0x0 -div word [.sides] -mov dh, dl -mov ch, al +div word [.heads] +mov dh, dl ;Head +mov ch, al ;Cylinder + +;Load the drive number +mov dl, byte [.drive] + +;Load BX and AX from the stack pop bx pop ax -mov dl, byte [.drive] + +;Return ret diff --git a/src/PRINT.ASM b/src/PRINT.ASM index 17503fb..7e571b2 100644 --- a/src/PRINT.ASM +++ b/src/PRINT.ASM @@ -1,5 +1,5 @@ -CPU 8086 -ORG 0x3000 +cpu 8086 +org 0x3000 ;Load a file and print it @@ -11,17 +11,16 @@ sti ;Check for an empty tail ;Check cmp byte [si], 0x0 -jne start +jne extract ;Print an error message and abort if the tail is empty mov si, errormsg mov ah, 0x2 int 0x21 je done -start: - ;Find the end of the filename and add a null if needed ;Set DI at the tail +extract: mov di, si findend: ;Check for the string end @@ -32,13 +31,14 @@ cmp byte [di], 0x20 je addnull inc di jmp findend +;Add a null addnull: mov al, 0x0 stosb ;Load the file -load: ;Load +load: mov bx, stack + 0x100 mov ah, 0x0 int 0x22 @@ -52,8 +52,8 @@ mov bh, 0x0 mov bl, 0x18 mov dl, 0x50 mov si, stack + 0x100 -print: ;Decrease the character counter +print: dec dl ;Load the current character lodsb @@ -66,8 +66,8 @@ je linecount ;Check for a soft line end cmp dl, 0x0 je linecount -contprint: ;Check paging +contprint: cmp bl, 0x0 jz page ;Repeat for the next character @@ -83,15 +83,19 @@ page: push ax mov ah, 0x0 int 0x16 +cmp al, 0x1b +je done pop ax mov bl, 0x18 mov dl, 0x50 loop print +;Return to the system done: int 0x20 ;Data errormsg db "File not found", 0x0 +;Stack stack: diff --git a/src/PRINTLN.INC b/src/PRINTLN.INC index ac5dc55..35b1355 100644 --- a/src/PRINTLN.INC +++ b/src/PRINTLN.INC @@ -1,5 +1,4 @@ ;Print a string ending in a null from SI followed by a CRLF. - println: ;Print the string @@ -9,4 +8,5 @@ int 0x21 ;Print a CRLF call printcrlf +;Return iret diff --git a/src/PRINTSTR.INC b/src/PRINTSTR.INC index 57fde6b..4cf7346 100644 --- a/src/PRINTSTR.INC +++ b/src/PRINTSTR.INC @@ -1,14 +1,13 @@ ;Print a string ending in a null from SI. - printstr: -;Store the initial registers in the stack +;Store AX and SI in the stack push ax push si ;Print the string -.loop: ;Load the current character +.loop: lodsb ;Check for the string end cmp al, 0x0 @@ -16,13 +15,13 @@ je .done ;Print the character mov ah, 0xe int 0x10 -;Repeat for the next character +;Print the next character jmp .loop -.done: - ;Load the initial registers from the stack +.done: pop si pop ax +;Return iret diff --git a/src/READLN.INC b/src/READLN.INC index 59e4f44..a2db6c9 100644 --- a/src/READLN.INC +++ b/src/READLN.INC @@ -1,6 +1,5 @@ ;Read a string ending in a null of at most AL characters to DI until a ;return and print a CRLF. - readln: ;Read the string @@ -10,4 +9,5 @@ int 0x21 ;Print a CRLF call printcrlf +;Return iret diff --git a/src/READSTR.INC b/src/READSTR.INC index cd0bef8..e5aca43 100644 --- a/src/READSTR.INC +++ b/src/READSTR.INC @@ -1,9 +1,8 @@ ;Read a string ending in a null of at most AL characters to DI until a ;return. - readstr: -;Store the initial registers in the stack +;Store AX, BX, CX, DX, and DI in the stack push ax push bx push cx @@ -26,12 +25,11 @@ mov ah, 0xf int 0x10 dec ah mov [.lastcolumn], ah -;Initialise the cursor pointer in BL and clear BH +;Set the cursor pointer in BL and clear BH mov bx, 0x1 -.loop: - ;Read a keypress +.loop: mov ah, 0x0 int 0x16 @@ -87,29 +85,27 @@ jmp .loop ;Check for the input beginning cmp bl, 0x1 je .loop -;Move +;Move the cursor call .prevchar dec di dec bl jmp .loop -;Finish reading the string -.return: - ;Check for and remove trailing spaces ;Go to the end of the input +.return: pop ax mov bh, 0x0 sub ax, bx push di add di, ax +;Check for trailing spaces .findtrailing: -;Check cmp byte [di], 0x20 je .deltrailing jmp .end +;Remove trailing spaces .deltrailing: -;Remove mov al, 0x0 stosb sub di, 0x2 @@ -128,49 +124,57 @@ inc di inc bl jmp .findend +;Load DI, DX, CX, BX, and AX from the stack .done: - -;Load the initial registers from the stack pop di pop dx pop cx pop bx pop ax +;Return iret ;Data .lastcolumn db 0x0 -;Move the cursor forward within a line +;*** + +;Move the cursor forward .nextchar: + ;Get the cursor position mov ah, 0x3 int 0x10 + ;Check for the end of the line cmp dl, [.lastcolumn] je .nextln -;Move + +;Move the cursor forward within a line inc dl mov ah, 0x2 int 0x10 + +;Return ret ;Move the cursor to the beginning of the next line -.nextln: ;Check if the current line is the last on screen +.nextln: cmp dh, 0x18 je .scroll -;Move +;Move the cursor mov ah, 0x2 inc dh mov dl, 0x0 int 0x10 + +;Return ret ;Scroll the screen up by one line .scroll: -;Scroll mov ah, 0x6 mov al, 0x1 mov bh, 0x7 @@ -179,25 +183,35 @@ mov cl, 0x0 mov dh, 0x18 mov dl, [.lastcolumn] int 0x10 + ;Move to the beginning of the new line mov ah, 0x2 mov bh, 0x0 mov dl, 0x0 int 0x10 + +;Return ret -;Move the cursor backward within a line +;*** + +;Move the cursor backward .prevchar: + ;Get the cursor position mov ah, 0x3 int 0x10 + ;Check for the beginning of the line cmp dl, 0x0 je .prevln -;Move + +;Move the cursor backward within a line dec dl mov ah, 0x2 int 0x10 + +;Return ret ;Move the cursor to the end of the previous line @@ -206,4 +220,6 @@ mov ah, 0x2 dec dh mov dl, [.lastcolumn] int 0x10 + +;Return ret diff --git a/src/SYSTEM.ASM b/src/SYSTEM.ASM index 4bd125e..22079c1 100644 --- a/src/SYSTEM.ASM +++ b/src/SYSTEM.ASM @@ -1,6 +1,7 @@ -CPU 8086 -ORG 0x500 +cpu 8086 +org 0x500 +;Jump to the code jmp start ;Interrupt handler @@ -25,17 +26,16 @@ je loadf ;To do: savef iret -;System calls +;System call includes %include "PRINTSTR.INC" %include "READSTR.INC" %include "PRINTLN.INC" %include "READLN.INC" %include "LOADF.INC" -start: - ;Set up the interrupt vectors ;Interrupt 0x20 offset +start: mov ax, int0x20 mov [0x80], ax ;Interrupt 0x21 offset @@ -110,10 +110,10 @@ mov cx, 0xe mov al, 0x20 rep stosb sub di, 0xe -;Initialise the length counter +;Set the length counter mov bl, 0xa -specloop: ;Load a character +specloop: lodsb ;Check for the string end cmp al, 0x0 @@ -128,16 +128,18 @@ je cmderror stosb ;Decrease the counter dec bl +;Extract the next character jmp specloop -;Add extension to the name +;Store the start of the command tail in the stack addext: push si +;Add extension to the specification mov si, extension mov cx, 0x5 rep movsb ;Load and execute the program -;Load +;Load the program mov bx, 0x3000 mov si, program mov ah, 0x0 @@ -149,9 +151,43 @@ jne shell mov dl, [drive] pop si call ignoreleading -;Execute +;Execute the program jmp 0x3000 +;Change the drive +;Get the BIOS equipment list +changedrive: +int 0x11 +;Get the number of floppy drives +times 0x6 shr ax, 0x1 +and ax, 0x3 +inc ax +;Set the loop and drive letter counters and the drive letter and number +mov cx, ax +mov di, driveletters +mov al, [si] +mov dl, 0x0 +;Check which drive to change to +checkdrive: +cmp al, [di] +je contchdrive +inc di +cmp al, [di] +je contchdrive +inc di +inc dl +loop checkdrive +;Print a drive error message and return to the shell +mov si, driverrormsg +mov ah, 0x2 +int 0x21 +jmp shell +;Change the drive +contchdrive: +mov [drive], dl +call setdriveletter +jmp shell + ;Print a command error message and return to the shell cmderror: mov si, cmderrormsg @@ -159,56 +195,11 @@ mov ah, 0x2 int 0x21 jmp shell -;Change the drive -changedrive: -;Check which drive to change to -cmp byte [si], "a" -je cha -cmp byte [si], "A" -je cha -cmp byte [si], "b" -je chb -cmp byte [si], "B" -je chb -cmp byte [si], "c" -je chc -cmp byte [si], "C" -je chc -cmp byte [si], "d" -je chd -cmp byte [si], "D" -je chd -;Print a drive error message and return to the shell -mov si, driverrormsg -mov ah, 0x2 -int 0x21 -jmp shell -;Change -cha: -mov dl, 0x0 -mov [drive], dl -call setdriveletter -jmp shell -chb: -mov dl, 0x1 -mov [drive], dl -call setdriveletter -jmp shell -chc: -mov dl, 0x2 -mov [drive], dl -call setdriveletter -jmp shell -chd: -mov dl, 0x3 -mov [drive], dl -call setdriveletter -jmp shell - ;Data welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0 drive db 0x0 driveletter db "?:", 0x0 +driveletters db "AaBbCcDd" prompt db "> ", 0x0 input times 0x4c db 0x0 program times 0xf db 0x0 @@ -216,53 +207,70 @@ extension db ".BIN", 0x0 cmderrormsg db "File or command not found", 0x0 driverrormsg db "Drive not found", 0x0 +;*** + ;Set the drive letter setdriveletter: + +;Set the drive number and letter counters +mov dh, 0x0 +mov si, driveletters + ;Check the drive number -cmp dl, 0x0 -je .seta -cmp dl, 0x1 -je .setb -cmp dl, 0x2 -je .setc -cmp dl, 0x3 -je .setd -ret -;Set -.seta: -mov byte [driveletter], "A" -ret -.setb: -mov byte [driveletter], "B" -ret -.setc: -mov byte [driveletter], "C" -ret -.setd: -mov byte [driveletter], "D" +.checkdrive: +cmp dl, dh +je .set +add si, 0x2 +inc dh +jmp .checkdrive + +;Set the drive letter +.set: +mov al, [si] +mov byte [driveletter], al + +;Return ret +;*** + ;Ignore leading spaces in the command and its tail ignoreleading: + +;Check for a space lodsb cmp al, 0x20 je ignoreleading + +;Set SI to the first non-space character dec si + +;Return ret +;*** + ;Print a CRLF printcrlf: -;Store the initial registers in the stack + +;Store SI in the stack push si + ;Print the CRLF mov si, .crlf mov ah, 0x0 int 0x21 -;Load the initial registers from the stack + +;Load SI from the stack pop si + +;Return ret + ;Data .crlf db 0xd, 0xa, 0x0 +;*** + ;File system buffer buffer: