Compare commits

..

1 Commits
main ... main

Author SHA1 Message Date
Jonas 'Sortie' Termansen dcd9d60271 Upgrade to Sortix build environment. 2021-06-22 18:21:53 +00:00
15 changed files with 314 additions and 1261 deletions

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="79"
height="22"
viewBox="0 0 20.902084 5.8208335"
version="1.1"
id="svg5"
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
sodipodi:docname="EttinOS.svg"
inkscape:export-filename="/home/leaf/OSes/EttinOS/EttinOS.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="true"
units="px"
height="36px"
borderlayer="true"
inkscape:showpageshadow="false"
width="80px"
inkscape:zoom="4"
inkscape:cx="105.25"
inkscape:cy="31.875"
inkscape:window-width="1920"
inkscape:window-height="1200"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g4007"
transform="translate(-0.00284051)">
<g
id="g3944"
transform="translate(-2.9649416,8.6465431)">
<path
id="path19415-7"
style="color:#000000;-inkscape-font-specification:'AcPlus IBM MDA';fill:#000000;stroke:none;stroke-width:2;-inkscape-stroke:none"
d="m 12.445312,-31.673828 v 4 h 1.328126 v 11.988281 h -1.328126 v 4.001953 h 11.324219 v -8.001953 H 21.111328 V -23.6875 h 2.658203 v -7.986328 z m 15.97461,0 v 1.992187 h -1.328125 v 4.001953 h -2.658203 v 4 h 2.658203 v 8.001954 h 1.328125 v 1.99414 h 6.009766 v -1.99414 h 1.3125 v -4 h -0.988282 -3.011718 v -4.001954 h 2.6875 v -4 h -2.6875 v -5.99414 z m 11.988281,0 v 1.992187 h -1.34375 v 4.001953 H 36.40625 v 4 h 2.658203 v 8.001954 h 1.34375 v 1.99414 h 5.994141 v -1.99414 h 1.328125 v -4 h -1.003907 -2.996093 v -4.001954 h 2.671875 v -4 h -2.671875 v -5.99414 z m 11.972656,0 v 5.99414 h -1.328125 v 4 h 1.328125 v 5.994141 h -1.328125 v 4.001953 h 0.988282 6.349609 v -4.001953 h -1.34375 v -9.994141 -5.99414 z m -33.941406,4 h 0.664063 v 1.99414 h -0.664063 z m 41.929688,1.99414 v 4 h 1.003906 0.310547 v 9.996094 h 4.679687 v -9.996094 h 0.664063 v 9.996094 h 4.666015 V -12.673828 -23.6875 h -1.330078 v -1.992188 h -5.330078 -0.664062 z m -41.929688,8.001954 h 0.664063 v 1.992187 h -0.664063 z"
transform="scale(0.26458333)" />
<path
id="path14267-3-7-1"
style="font-size:4.23333px;line-height:1.25;font-family:'AcPlus IBM MDA';-inkscape-font-specification:'AcPlus IBM MDA';letter-spacing:0px;word-spacing:0px;fill:#08dd30;fill-opacity:1;stroke-width:0.529166"
d="m 3.5576229,-8.117201 v 0.5291666 h 0.3493347 v 3.7041666 H 3.5576229 v 0.5291667 h 2.4660013 v -1.5875 H 5.6742896 v 0.5291667 H 5.3197902 v 0.5291666 h -0.703834 v -1.5874999 h 0.3493347 v 0.5291666 h 0.3544993 v -1.5875 H 4.9652909 v 0.5291667 H 4.6159562 v -1.5875 h 0.703834 v 0.5291667 h 0.3544994 v 0.5291666 H 6.0236242 V -8.117201 Z m 4.2281633,0 v 0.5291666 H 7.4312869 v 1.0583333 h -0.703834 v 0.5291667 h 0.703834 v 2.1166666 h 0.3544993 v 0.5291667 h 1.0583334 v -0.5291667 h 0.3493346 v -0.5291666 h -0.703834 v 0.5291666 H 8.1351209 V -6.0005344 H 8.8441196 V -6.5297011 H 8.1351209 V -8.117201 Z m 3.1698358,0 v 0.5291666 h -0.3545 v 1.0583333 H 9.8972882 v 0.5291667 h 0.7038338 v 2.1166666 h 0.3545 v 0.5291667 h 1.058333 v -0.5291667 h 0.348297 v -0.5291666 h -0.702796 v 0.5291666 h -0.355537 v -2.1166666 h 0.710036 V -6.5297011 H 11.303919 V -8.117201 Z m 3.168798,0 v 1.0583333 h 0.703834 V -8.117201 Z m -0.3545,1.5874999 v 0.5291667 h 0.3545 v 2.1166666 h -0.3545 v 0.5291667 h 1.412833 v -0.5291667 h -0.354499 v -2.6458333 z m 2.465996,0 v 0.5291667 h 0.349335 v 2.6458333 h 0.708999 v -2.6458333 h -0.3545 v -0.5291667 z m 1.058334,0.5291667 h 0.703834 v 2.6458333 h 0.703834 V -6.0005344 H 18.352583 V -6.5297011 H 17.29425 Z" />
</g>
<g
id="g3982"
transform="translate(-14.717186,-10.650771)">
<path
id="path3745"
style="color:#000000;-inkscape-font-specification:'AcPlus IBM MDA';fill:#000000;stroke-width:3.77953;-inkscape-stroke:none"
transform="scale(0.26458333)"
d="m 120.74609,41.255859 v 2 h -1.34375 v 2 h -1.32226 v 11.996094 h 1.32226 v 2 h 1.34375 v 2.001953 h 2.65625 3.34375 5.33789 v -2.001953 h 1.32227 v -5.994141 h -1.32227 v -2 h -1.34375 v -2 h 2.66602 v -6.001953 h -1.32227 v -2 h -5.33789 -3.34375 z m 2,8.001953 h 0.65625 v 2 h 1.34375 v 2 h -2 z" />
<path
d="m 31.856628,14.8841 h -0.34925 v -2.645831 h 0.34925 v -0.529166 h 0.35454 v -0.529166 h 1.058334 v 0.529166 h 0.35454 v 0.529166 h 0.34925 V 14.8841 h -0.34925 v 0.529168 h -0.35454 v 0.529166 h -1.058334 v -0.529166 h -0.35454 z m 0.709082,0 v 0.529168 h 0.34925 V 14.8841 h 0.354542 V 12.238269 H 32.91496 v -0.529166 h -0.34925 v 0.529166 H 32.211168 V 14.8841 Z"
id="path14277-2-10-7-2-7-2"
style="font-size:4.23333px;line-height:1.25;font-family:'AcPlus IBM MDA';-inkscape-font-specification:'AcPlus IBM MDA';letter-spacing:0px;word-spacing:0px;fill:#e500e5;fill-opacity:1;stroke-width:0.529166" />
<path
id="path3358"
style="font-size:8.46667px;line-height:1.25;font-family:'AcPlus IBM MDA';-inkscape-font-specification:'AcPlus IBM MDA';letter-spacing:0px;word-spacing:0px;fill:#e5b800;fill-opacity:1;stroke-width:0.264583"
d="m 32.915046,11.179938 v 0.529166 h -0.349335 v 0.529167 0.529167 h 0.349335 v 0.529166 h 0.354499 v -0.529166 -0.529167 -0.529167 h 0.3545 0.703834 v 1.058334 h 0.703834 v -1.058334 h -0.349335 v -0.529166 h -1.412833 z m 1.058333,2.116666 v 0.529167 0.529167 h 0.3545 v 1.058333 h -0.703834 -0.3545 v -0.529166 -0.529167 h -0.703834 v 0.529167 0.529166 h 0.349335 v 0.529167 h 0.354499 1.412833 v -0.529167 h 0.349335 v -1.058333 h -0.349335 v -0.529167 h -0.354499 v -0.529167 z" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -1,7 +1,7 @@
MIT License MIT License
=========== ===========
Copyright (c) 2021 CrazyEttin and contributors Copyright (c) 2021 CrazyEttin
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the copy of this software and associated documentation files (the

View File

@ -1,11 +1,9 @@
EttinOS EttinOS
======= =======
EttinOS is a minimalist 16-bit hobbyist disk operating system for the EttinOS is a minimalist 16-bit DOS-like hobbyist operating system for
IBM Personal Computer and compatible machines. Its git repository can be the IBM PC and compatible computers. Its git repository can be found at
found at https://ahti.space/git/crazyettin/EttinOS and that of https://ahti.space/git/crazyettin/EttinOS.
EttinOS-extra, a collection of programs for the system, at
https://ahti.space/git/crazyettin/EttinOS-extra.
System requirements System requirements
------------------- -------------------
@ -13,72 +11,44 @@ System requirements
* An Intel 8086 or compatible CPU * An Intel 8086 or compatible CPU
* BIOS, or UEFI in legacy mode * BIOS, or UEFI in legacy mode
* 64 KiB of RAM * 64 KiB of RAM
* 1-4 floppy disk drives (hard disk drives are not supported) * A floppy disk drive
Building Building
-------- --------
Build dependencies: Build dependencies:
* A Unix-like operating system * A Unix-like operating system
* bash
* coreutils * coreutils
* dosfstools * dosfstools
* mtools * mtools
* nasm * nasm
* rw (optional)
Running make.sh will build EttinOS and create a bootable 360 KiB 5.25" Running make.sh will build EttinOS and create a bootable 360 KiB 5.25"
floppy disk image named EttinOS.img and a source image of the same floppy disk image named EttinOS.img. To get a 1.44 MB 3.5" one instead
format named EttinOS-src.img. To get 1440 KiB 3.5" images instead use use the argument -1440. If you want to use another floppy disk format
the argument -1440. If you want to use another format you will have to you will have to adjust the bootloader disk description tables and
build the system manually. install the system manually. Hard disk drives are not supported.
Usage Input
----- -----
The input system is inspired by typewriters. Typing a character The EttinOS input system is inspired by typewriters. Typing a character
overwrites the cursor location and the erase (=tab) key erases it. The overwrites the cursor location and the erase (=tab) key erases it. The
space and backspace keys move the cursor. space and backspace keys move the cursor.
EttinOS assigns the drives letters from A to D and uses a version of the
MS-DOS 3.0 FAT12 file system (in actual use since 2.1) without support
for file attributes and thus disk labels and subdirectories. 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
optional.
A command can be followed by arguments separated from eachother and the
command with spaces. Extra spaces are ignored. Commands other than
changing the current drive are stored as external programs: the command
for a program is its file specification without the extension.
Commands included in EttinOS:
* [A-D]:: Change the current drive.
* ECHO: Print a message. Syntax: ECHO Message to be printed
* HELLO: Print "Hello world!".
* LIST: Print a list of the files on a drive. Syntax: LIST DRIVE
* 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 other than escape to continue
printing after each screen or escape to quit the program.
Programming Programming
----------- -----------
EttinOS has a flat address space of 64 KiB. The data, stack, and extra EttinOS has a flat address space of 64 KiB. The data, stack, and
segments are set at the beginning of the RAM and the system stack at the extra segments are set at the beginning of the RAM and the system stack
end of the address space. Programs are loaded at address 0x3000, the at the end of the address space. Programs are loaded at address 0x2000.
number of the current drive is loaded in DL, and SI is pointed at the
command tail (a string ending in a null) when the program is executed.
The stack is reset back to the end of the address space after a program The stack is reset back to the end of the address space after a program
has finished running. has finished running.
System calls: System calls:
* Interrupt 0x20: Return to the shell. * Interrupt 0x20: Return to the shell.
* Interrupt 0x21: String operations: * Interrupt 0x21: Input and output:
* AH = 0x0: Print a string ending in a null from SI. * AH = 0x0: Print a string ending in a null from SI.
* AH = 0x1: Read a string ending in a null of at most AL * AH = 0x1: Read a string ending in a null of at most AL
characters to DI until a return. characters to DI until a return.
@ -86,37 +56,8 @@ System calls:
CRLF. CRLF.
* AH = 0x3: Read a string ending in a null of at most AL * AH = 0x3: Read a string ending in a null of at most AL
characters to DI until a return and print a CRLF. characters to DI until a return and print a CRLF.
* AH = 0x4: (Under construction) Convert a decimal string ending
in a null at SI to a value in AL.
* AH = 0x5: (Under construction) Convert a value in AL to a
decimal string ending in a null at DI.
* AH = 0x6: (Under construction) Convert a hexadecimal string
ending in a null at SI to a value in AL.
* AH = 0x7: (Under construction) Convert a value in AL to a
hexadecimal string ending in a null at DI.
* Interrupt 0x22: Disk operations: * Interrupt 0x22: Disk operations:
* AH = 0x0: (Under construction) Load the directory of a drive * AH = 0x0: Load a file named in SI as a string ending in a null
named at SI as a string ending in a null to the offset to the offset BX and set AL to 0x0 if the load was
BX and store the error codes in AL: succesfull and 0x1 if there was an error.
* AL = 0x0: Succesful load * AH = 0x1: Save a file (under construction).
* AL = 0x1: Drive not found
* AL = 0x2: Unable to read disk
* AH = 0x1: (Under construction) Store a directory at the offset
BX to a drive named at SI as a string ending in a
null.
* AH = 0x2: Load a file named at SI as a string ending in a null
to the offset BX and store the file size in CX and the
error codes in AL:
* AL = 0x0: Succesful load
* AL = 0x1: Drive not found
* AL = 0x2: Unable to read disk
* AL = 0x4: File or command not found
* AL = 0x8: Not enough memory
* AH = 0x3: (Under construction) Save a file.
Known bugs
----------
* Trying to access a disk of different format than the current one can
crash the system.
* Files beyond the ~40th one on the disk might not load properly.

41
make.sh
View File

@ -1,8 +1,10 @@
#!/bin/sh #!/bin/sh
rm -f EttinOS.img rm -f EttinOS.img
rm -f EttinOS-src.img if [ ! -d "bin" ]
mkdir -p bin then
mkdir bin
fi
cd src/ cd src/
if [ "$1" = "-1440" ] if [ "$1" = "-1440" ]
@ -10,42 +12,15 @@ if [ "$1" = "-1440" ]
else nasm BOOT.ASM -f bin -o ../bin/BOOT.BIN else nasm BOOT.ASM -f bin -o ../bin/BOOT.BIN
fi fi
nasm SYSTEM.ASM -f bin -o ../bin/SYSTEM.BIN nasm SYSTEM.ASM -f bin -o ../bin/SYSTEM.BIN
nasm ECHO.ASM -f bin -o ../bin/ECHO.BIN
nasm HELLO.ASM -f bin -o ../bin/HELLO.BIN nasm HELLO.ASM -f bin -o ../bin/HELLO.BIN
nasm LIST.ASM -f bin -o ../bin/LIST.BIN
nasm PRINT.ASM -f bin -o ../bin/PRINT.BIN
cd .. cd ..
if [ "$1" = "-1440" ] if [ "$1" = "-1440" ]
then then mkfs.fat -C EttinOS.img 1440
mkfs.fat -C EttinOS.img 1440 1>/dev/null else mkfs.fat -C EttinOS.img 360
mkfs.fat -C EttinOS-src.img 1440 1>/dev/null
else
mkfs.fat -C EttinOS.img 360 1>/dev/null
mkfs.fat -C EttinOS-src.img 360 1>/dev/null
fi
if which rw > /dev/null 2>&1
then rw -i bin/BOOT.BIN -o EttinOS.img -b 512 -c 1x
else dd if=bin/BOOT.BIN of=EttinOS.img conv=notrunc bs=512 count=1 1>/dev/null
fi fi
rw -i bin/BOOT.BIN -o EttinOS.img -b 512 -c 1x
mcopy -i EttinOS.img bin/SYSTEM.BIN :: mcopy -i EttinOS.img bin/SYSTEM.BIN ::
mcopy -i EttinOS.img bin/HELLO.BIN ::
mcopy -i EttinOS.img README.MD :: mcopy -i EttinOS.img README.MD ::
mcopy -i EttinOS.img LICENSE.MD :: mcopy -i EttinOS.img LICENSE.MD ::
mcopy -i EttinOS.img bin/ECHO.BIN ::
mcopy -i EttinOS.img bin/HELLO.BIN ::
mcopy -i EttinOS.img bin/LIST.BIN ::
mcopy -i EttinOS.img bin/PRINT.BIN ::
mcopy -i EttinOS-src.img src/BOOT.ASM ::
mcopy -i EttinOS-src.img src/SYSTEM.ASM ::
mcopy -i EttinOS-src.img src/PRINTSTR.INC ::
mcopy -i EttinOS-src.img src/READSTR.INC ::
mcopy -i EttinOS-src.img src/PRINTLN.INC ::
mcopy -i EttinOS-src.img src/READLN.INC ::
mcopy -i EttinOS-src.img README.MD ::
mcopy -i EttinOS-src.img LICENSE.MD ::
mcopy -i EttinOS-src.img src/ECHO.ASM ::
mcopy -i EttinOS-src.img src/HELLO.ASM ::
mcopy -i EttinOS-src.img src/LIST.ASM ::
mcopy -i EttinOS-src.img src/PRINT.ASM ::

View File

@ -1,136 +1,120 @@
cpu 8086 CPU 8086
org 0x7c00 ORG 0x7c00
;Jump to the code
jmp start jmp start
;Padding
nop nop
;OEM label ;Disk description tables
db "ETTINOS "
%ifdef F1440 %ifdef F1440
;1.44 MB 3.5" floppy disk (enable with the argument -d F1440 when building)
;1.44 MB 3.5" floppy disk BPB (enable with the argument -d F1440) oemlabel db "ETTINOS "
sectorsize dw 0x200 ;bytes sectorsize dw 0x200 ;bytes
clustersize db 0x1 ;sectors clustersize db 0x1 ;sectors
reservedsectors dw 0x1 bootsectors dw 0x1
fats db 0x2 fats db 0x2
rootentries dw 0xe0 rootentries dw 0xe0
logicalsectors dw 0xb40 logicalsectors dw 0xb40
mediadescriptor db 0xf0 mediadescriptor db 0xf0
sectorsperfat dw 0x9 sectorsperfat dw 0x9
sectorspertrack dw 0x12 sectorspertrack dw 0x12
heads dw 0x2 sides dw 0x2
hiddensectors dw 0x0 hiddensectors dd 0x0
largesectors dd 0x0
driveid dw 0x0
drivesignature db 0x29
volumeid dd 0x0
volumelabel db "ETTINOS "
filesystem db "FAT12 "
%else %else
;360 KiB 5.25" floppy disk (default)
;360 KiB 5.25" floppy disk BPB (default) oemlabel db "ETTINOS "
sectorsize dw 0x200 ;bytes sectorsize dw 0x200 ;bytes
clustersize db 0x2 ;sectors clustersize db 0x2 ;sectors
reservedsectors dw 0x1 bootsectors dw 0x1
fats db 0x2 fats db 0x2
rootentries dw 0x70 rootentries dw 0x70
logicalsectors dw 0x2d0 logicalsectors dw 0x2d0
mediadescriptor db 0xfd mediadescriptor db 0xfd
sectorsperfat dw 0x2 sectorsperfat dw 0x2
sectorspertrack dw 0x9 sectorspertrack dw 0x9
heads dw 0x2 sides dw 0x2
hiddensectors dw 0x0 hiddensectors dd 0x0
largesectors dd 0x0
driveid dw 0x0
drivesignature db 0x29
volumeid dd 0x0
volumelabel db "ETTINOS "
filesystem db "FAT12 "
%endif %endif
;Setup
;Set the segments
start: start:
;Setup
;Set up the data, stack, and extra segments
mov ax, 0x0 mov ax, 0x0
mov ds, ax mov ds, ax
mov ss, ax mov ss, ax
mov es, ax mov es, ax
;Set the stack ;Set up the stack
cli cli
mov sp, 0x0 mov sp, 0x0
sti sti
;Store the boot drive number ;Store the boot drive number
mov [drive], dl mov [bootdrive], dl
;Calculate and store variables not found in the BPB ;Load the root
;Start of the root ;Set the source
mov ah, 0x0 mov ah, 0x0
mov al, [fats] mov al, [fats]
mul word [sectorsperfat] mul word [sectorsperfat]
add ax, [reservedsectors] add ax, [bootsectors]
mov [rootstart], ax push ax
;Size of the root in sectors call calcsource
;Set the destination
mov si, buffer
mov bx, si
;Set the size
push dx
mov ax, [rootentries] mov ax, [rootentries]
mov dx, 0x20 mov dx, 0x20
mul dx mul dx
mov dx, 0x0 mov dx, 0x0
div word [sectorsize] div word [sectorsize]
mov [rootsectors], ax pop dx
;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 ax
push cx ;Load
;Set the source
call calcsource
;Set the size
mov al, 0x1
;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 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]
;Load the next sector
loop loadrootsector
;Search the root for the system entry ;Search the root for the system entry
;Set DI to the root ;Set DI to the root
mov di, buffer mov di, buffer
;Set the number of root entries ;Initialise the search loop
mov cx, word [rootentries] mov cx, word [rootentries]
;Set the entry pointer
mov ax, 0x0 mov ax, 0x0
;Store the loop counter in the stack
search: search:
;Store CX in the stack
push cx push cx
;Check for the system entry ;Check for the system entry
mov si, file mov si, sysfile
mov cx, 0xb mov cx, 0xb
rep cmpsb rep cmpsb
je loadfat je loadentry
;Set DI at the next entry ;Set DI to the next entry
add ax, 0x20 add ax, 0x20
mov di, buffer mov di, buffer
add di, ax add di, ax
;Load the loop counter from the stack ;Load CX from the stack
pop cx pop cx
;Search the next entry
loop search loop search
;Print an error message and hang if the system is not found ;Print an error message if the system is not found
;Set SI at the file error message mov si, errormsg
mov si, filerrormsg printerror:
;Load a character ;Load a character
printstr:
lodsb lodsb
;Check for the string end ;Check for the string end
cmp al, 0x0 cmp al, 0x0
@ -138,61 +122,53 @@ je $
;Print the character ;Print the character
mov ah, 0xe mov ah, 0xe
int 0x10 int 0x10
;Print the next character ;Repeat
jmp printstr jmp printerror
;Load the FAT ;Load the system entry
loadentry:
;Load CX from the stack ;Load CX from the stack
loadfat:
pop cx pop cx
;Store the address of the first cluster ;Store the first cluster
mov ax, [di + 0xf] mov ax, word [es:di+0xf]
mov [cluster], ax mov word [cluster], ax
;Set the source ;Set the source
mov ax, [reservedsectors] mov ax, 0x1
call calcsource call calcsource
;Set the destination ;Set the destination
mov bx, buffer mov di, buffer
mov bx, di
;Set the size ;Set the size
mov ax, [sectorsperfat] mov ax, [sectorsperfat]
;Load the FAT ;Load
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
;Load the system file
;Load a cluster ;Load a cluster
loadcluster: loadcluster:
;Set the source ;Set the source
pop cx
pop bx
mov ax, word [cluster] mov ax, word [cluster]
sub ax, 0x2 sub ax, 0x2
mul byte [clustersize] mul byte [clustersize]
add ax, [datastart] add ax, bx
add ax, cx
push bx
push cx
call calcsource
;Set the destination ;Set the destination
mov bx, word [pointer] mov bx, word [pointer]
;Set the size ;Set the size
mov ch, 0x0 ;mov al, 0x1
mov cl, byte [clustersize] mov al, [clustersize]
;Store the loop counter in the stack ;Load
loadclustersector:
push cx
;Set the source
call calcsource
;Set the size
push ax
mov al, 0x1
;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
pop ax
;Set the next sector
add ax, 0x1
add bx, [sectorsize]
;Load the loop counter from the stack
pop cx
;Load the next sector
loop loadclustersector
;Calculate the next cluster ;Calculate the next cluster
;Check if the cluster is even or odd
mov ax, [cluster] mov ax, [cluster]
mov dx, 0x0 mov dx, 0x0
mov bx, 0x3 mov bx, 0x3
@ -201,87 +177,65 @@ mov bx, 0x2
div bx div bx
mov si, buffer mov si, buffer
add si, ax add si, ax
mov ax, word [si] mov ax, word [ds:si]
or dx, dx or dx, dx
jz even jz even
;If the cluster is odd shift out the first four bits odd:
times 0x4 shr ax, 0x1 shr ax, 1
shr ax, 1
shr ax, 1
shr ax, 1
jmp contcalc jmp contcalc
;If the cluster is even mask out the final four bits
even: even:
and ax, 0xfff and ax, 0xfff
contcalc: contcalc:
;Check for the file end mov word [cluster], ax
cmp ax, 0xff8 cmp ax, 0xff8
jge boot jge boot
;Store the address of the next cluster
mov word [cluster], ax
;Set the destination of the next cluster
mov ax, [sectorsize] mov ax, [sectorsize]
mul word [clustersize] mul word [clustersize]
add word [pointer], ax add word [pointer], ax
;Load the next cluster
jmp loadcluster jmp loadcluster
;Boot the system ;Clear the stack and boot the system
;Pass the boot drive number to the system
boot: boot:
mov dl, byte [drive] ;Clear
;Boot the system pop cx
pop bx
;Boot
jmp 0x0:0x500 jmp 0x0:0x500
;Data ;Data
drive db 0x0 bootdrive db 0x0
rootstart dw 0x0 sysfile db "SYSTEM BIN"
rootsectors dw 0x0 errormsg db "System not found", 0xd, 0xa, 0x0
datastart dw 0x0 cluster dw 0x0
file db "SYSTEM BIN" pointer dw 0x500
filerrormsg db "System not found", 0xd, 0xa, 0x0
cluster dw 0x0
pointer dw 0x500
;***
;Calculate the source arguments for loading data from the disk ;Calculate the source arguments for loading data from the disk
calcsource: calcsource:
;Store AX and BX in the stack
push ax push ax
push bx push bx
;Calculate the cylinder, head, and sector
;Store the logical sector in BX
mov bx, ax mov bx, ax
;Calculate the sector
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [sectorspertrack]
add dl, 0x1 add dl, 0x1
mov cl, dl mov cl, dl
;Load the logical sector from BX
mov ax, bx mov ax, bx
;Calculate the head and cylinder
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [sectorspertrack]
mov dx, 0x0 mov dx, 0x0
div word [heads] div word [sides]
mov dh, dl ;Head mov dh, dl
mov ch, al ;Cylinder mov ch, al
;Load the boot drive number
mov dl, byte [drive]
;Load BX and AX from the stack
pop bx pop bx
pop ax pop ax
mov dl, byte [bootdrive]
;Return
ret ret
;*** ;Pad the binary to a full sector and make the disk bootable
;Padding ;Padding
times 0x1fe-($-$$) db 0x0 times 0x1fe-($-$$) db 0x0
;Boot signature ;Boot signature
dw 0xaa55 dw 0xaa55

View File

@ -1,14 +0,0 @@
cpu 8086
org 0x3000
;Check for an empty tail
cmp byte [si], 0x0
je done
;Print the message
mov ah, 0x2
int 0x21
;Return to the system
done:
int 0x20

View File

@ -1,13 +1,11 @@
cpu 8086 CPU 8086
org 0x3000 ORG 0x2000
;Print a hello world. ;Prints a hello world.
mov si, hello mov si, .hello
mov ah, 0x2 mov ah, 0x2
int 0x21 int 0x21
;Return to the system
int 0x20 int 0x20
;Data ;Data
hello db "Hello world!", 0x0 .hello db "Hello world!", 0x0

View File

@ -1,264 +0,0 @@
cpu 8086
org 0x3000
;Store the drive number
mov [drive], dl
;Check for an empty tail
cmp byte [si], 0x0
je loadvalues
;Change the drive if needed
;Check for a drive specification
cmp byte [si + 0x1], ":"
jne driverror
cmp byte [si + 0x2], 0x0
je changedrive
cmp byte [si + 0x2], 0x20
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
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 the drive
contchdrive:
mov [drive], dl
;Load the disk description table
;Set the source
loadvalues:
mov dl, [drive]
mov ch, 0x0
mov dh, 0x0
mov cl, 0x1
;Set the destination
mov si, buffer
mov bx, si
;Set the size
mov al, 0x1
;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, [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
;Calculate and store variables not found in the BPB
;Start of the root
mov ah, 0x0
mov al, [fats]
mul word [sectorsperfat]
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 [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
;Set the source
call calcsource
;Set the size
mov al, 0x1
;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]
loop loadrootsector
;List
;Set SI to the root
mov si, buffer
;Initialise the loop
mov cx, word [rootentries]
mov ax, 0x0
mov bl, 0x17
;Store CX in the stack
loop:
push cx
;Check for an empty entry
cmp byte [si], 0xe5
je skip
;Check for the end of entries
cmp byte [si], 0x0
je done
;store AX in the stack
push ax
;Print the main part of the name
mov cx, 0x8
push ax
printname:
mov al, [si]
mov ah, 0xe
int 0x10
inc si
loop printname
;Print a space
mov al, 0x20
mov ah, 0xe
int 0x10
;Print the extension
mov cx, 0x3
printext:
mov al, [si]
mov ah, 0xe
int 0x10
inc si
loop printext
;Print a newline
mov al, 0xd
mov ah, 0xe
int 0x10
mov al, 0xa
mov ah, 0xe
int 0x10
;Load AX from the stack
pop ax
;Check paging
cmp bl, 0x0
jz page
dec bl
;Set SI to the next entry
skip:
add ax, 0x20
mov si, buffer
add si, ax
;Load CX from the stack
pop cx
loop loop
page:
push ax
mov ah, 0x0
int 0x16
cmp al, 0x1b
je done
pop ax
mov bl, 0x17
jmp skip
done:
int 0x20
driverror:
mov si, driverrormsg
mov ah, 0x2
int 0x21
jmp done
diskerror:
mov si, diskerrormsg
mov ah, 0x2
int 0x21
jmp done
;Data
drive db 0x0
sectorsize dw 0x0 ;bytes
reservedsectors dw 0x0
fats db 0x0
rootentries dw 0x0
sectorsperfat dw 0x0
sectorspertrack 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 [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
;Return
ret
;***
;Buffer
buffer:

View File

@ -1,91 +1,48 @@
;Load a file named at SI as a string ending in a null to the offset BX ;Load a file named in SI as a string ending in a null to the offset BX and set AL to 0x0 if the load was succesful and 0x1 if there was an error.
;and store the file size in CX and the error codes in AL:
; * AL = 0x0: Succesful load
; * AL = 0x1: Drive not found
; * AL = 0x2: Unable to read disk
; * AL = 0x4: File or command not found
; * AL = 0x8: Not enough memory
loadf: loadf:
;Store BX, DX, SI, and DI in the stack ;Store the initial registers in the stack
push ax
push bx push bx
push cx
push dx push dx
push si push si
push di push di
;Store the current drive and offset ;Store the offset
mov word [.pointer], bx mov word [.pointer], bx
mov dl, byte [curdrive]
mov byte [drive], dl
;Change the drive if needed
;Check for a drive specification
cmp byte [si + 0x1], ":"
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
.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
int 0x21
mov al, 0x1
mov cx, 0x0
jmp .done
;Change the drive
.contchdrive:
mov [drive], dl
;Move to the file name
add si, 0x2
;Set DI at .file and initialise it with spaces ;Set DI at .file and initialise it with spaces
.convert:
mov di, .file mov di, .file
mov cx, 0xb mov cx, 0xb
mov al, 0x20 mov al, 0x20
rep stosb rep stosb
sub di, 0xb sub di, 0xb
;Convert the main part of the file name into FAT format ;Convert .file into FAT formatting
;Set the length counter
;Initialise the length counter for the main part of the name
mov bl, 0x8 mov bl, 0x8
;Load a character
;Convert the main part of the file name
.nameloop: .nameloop:
;Load a character
lodsb lodsb
;Check for a period ;Check for a period
cmp al, 0x2e cmp al, 0x2e
je .initext je .initext
;Check for everything else and convert to upper case ;Check for everything else and convert to upper case
call .checkconv call .checkconv
;Load the next character
jmp .nameloop jmp .nameloop
;Convert the extension into FAT format ;Convert the extension
;Set DI and the length counter for the extension
.initext: .initext:
;Set DI and initialise the length counter for the extension
mov bl, 0x3 mov bl, 0x3
mov di, .file+0x8 mov di, .file+0x8
;Load a character
.extloop: .extloop:
;Load a character
lodsb lodsb
;Check for a period ;Check for a period
push ax push ax
@ -94,223 +51,119 @@ je .error
pop ax pop ax
;Check for everything else and convert to upper case ;Check for everything else and convert to upper case
call .checkconv call .checkconv
;Load the next character
jmp .extloop jmp .extloop
;Set AL to 0x4, CX to 0x0, and print an error message
;Set the carry flag and print an error message if the file name is invalid
.error: .error:
pop ax pop ax
mov si, .filerrormsg stc
mov si, .errormsg
mov ah, 0x2 mov ah, 0x2
int 0x21 int 0x21
mov al, 0x4
mov cx, 0x0
jmp .done jmp .done
;Find and load the file ;Find and load the file
.load: .load:
pop ax pop ax
;Load the disk description table ;Load the root
;Set the source ;Set the source
mov dl, [drive] mov ah, 0x0
mov ch, 0x0 mov al, [.fats]
mov dh, 0x0 mul word [.sectorsperfat]
mov cl, 0x1 add ax, [.bootsectors]
push ax
call .calcsource
;Set the destination ;Set the destination
mov si, buffer mov si, buffer
mov bx, si mov bx, si
;Set the size ;Set the size
mov al, 0x1 push dx
;Load the disk description table mov ax, [.rootentries]
mov ah, 0x2
int 0x13
jnc .storevalues
;Set AL to 0x2, CX to 0x0, and print an error message
mov si, .diskerrormsg
mov ah, 0x2
int 0x21
mov al, 0x2
mov cx, 0x0
jmp .done
;Store the disk values used for the rest of the call
.storevalues:
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
;Calculate and store variables not found in the BPB
;Start of the root
mov ah, 0x0
mov al, [fats]
mul word [sectorsperfat]
add ax, [reservedsectors]
mov [rootstart], ax
;Size of the root in sectors
mov ax, [rootentries]
mov dx, 0x20 mov dx, 0x20
mul dx mul dx
mov dx, 0x0 mov dx, 0x0
div word [sectorsize] div word [.sectorsize]
mov [rootsectors], ax pop dx
;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 ax
push cx ;Load
;Set the source
call .calcsource
;Set the size
mov al, 0x1
;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 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]
;Load the next sector
loop .loadrootsector
;Search the root for the file entry ;Search the root for the file entry
;Set DI to the root ;Set DI to the root
mov di, buffer mov di, buffer
;Set the number of root entries ;Initialise the search loop
mov cx, word [rootentries] mov cx, word [.rootentries]
;Set the entry pointer
mov ax, 0x0 mov ax, 0x0
;Store the loop counter in the stack
.search: .search:
;Store CX in the stack
push cx push cx
;Check for the file entry ;Check for the file entry
mov si, .file mov si, .file
mov cx, 0xb mov cx, 0xb
rep cmpsb rep cmpsb
je .checksize je .loadentry
;Set DI at the next entry ;Set DI to the next entry
add ax, 0x20 add ax, 0x20
mov di, buffer mov di, buffer
add di, ax add di, ax
;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
mov ah, 0x2
int 0x21
mov al, 0x4
mov cx, 0x0
jmp .done
;Check and store the file size
;Load CX from the stack ;Load CX from the stack
.checksize:
pop cx pop cx
;Check for files larger than 64 KiB loop .search
cmp word [di + 0x13], 0x0
jne .sizerror ;Set the carry flag and print an error message if the file is not found
;Get the cluster size in bytes stc
mov ah, 0x0 mov si, .errormsg
mov al, [clustersize]
mul word [sectorsize]
mov bx, ax
;Store the file size
mov ax, [di + 0x11]
mov word [.size], ax
;Check for files smaller than 64 KiB but too large to fit into memory
jc .sizerror
dec ax
mov dx, 0x0
div bx
mul bx
add ax, [.pointer]
jnc .loadfat
;Set AL to 0x8, CX to 0x0, and print an error message
.sizerror:
mov si, .sizerrormsg
mov ah, 0x2 mov ah, 0x2
int 0x21 int 0x21
mov al, 0x8 jmp .clearstack
mov cx, 0x0
jmp .done
;Load the FAT ;Load the file entry
.loadfat: .loadentry:
;Store the address of the first cluster ;Load CX from the stack
mov ax, [di + 0xf] pop cx
mov [.cluster], ax ;Store the first cluster
mov ax, word [es:di+0xf]
mov word [.cluster], ax
;Set the source ;Set the source
mov ax, [reservedsectors] mov ax, 0x1
call .calcsource call .calcsource
;Set the destination ;Set the destination
mov bx, buffer mov di, buffer
mov bx, di
;Set the size ;Set the size
mov ax, [sectorsperfat] mov ax, [.sectorsperfat]
;Load the FAT ;Load
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
;Load the file
;Load a cluster ;Load a cluster
.loadcluster: .loadcluster:
;Set the source ;Set the source
pop cx
pop bx
mov ax, word [.cluster] mov ax, word [.cluster]
sub ax, 0x2 sub ax, 0x2
mul byte [clustersize] mul byte [.clustersize]
add ax, [datastart] add ax, bx
add ax, cx
push bx
push cx
call .calcsource
;Set the destination ;Set the destination
mov bx, word [.pointer] mov bx, word [.pointer]
;Set the size ;Set the size
mov ch, 0x0 ;mov al, 0x1
mov cl, byte [clustersize] mov al, [.clustersize]
;Store the loop counter in the stack ;Load
.loadsector:
push cx
;Set the source
call .calcsource
;Set the size
push ax
mov al, 0x1
;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 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 ;Calculate the next cluster
;Check if the cluster is even or odd
mov ax, [.cluster] mov ax, [.cluster]
mov dx, 0x0 mov dx, 0x0
mov bx, 0x3 mov bx, 0x3
@ -319,64 +172,71 @@ mov bx, 0x2
div bx div bx
mov si, buffer mov si, buffer
add si, ax add si, ax
mov ax, word [si] mov ax, word [ds:si]
or dx, dx or dx, dx
jz .even jz .even
;If the cluster is odd shift out the first four bits shr ax, 1
times 0x4 shr ax, 0x1 shr ax, 1
shr ax, 1
shr ax, 1
jmp .contcalc jmp .contcalc
;If the cluster is even mask out the final four bits
.even: .even:
and ax, 0xfff and ax, 0xfff
.contcalc: .contcalc:
;Check for the file end
cmp ax, 0xff8
jge .success
;Store the address of the next cluster
mov word [.cluster], ax mov word [.cluster], ax
;Set the destination of the next cluster cmp ax, 0xff8
mov ax, [sectorsize] jge .clearcarry
mul word [clustersize] mov ax, [.sectorsize]
mul word [.clustersize]
add word [.pointer], ax add word [.pointer], ax
;Load the next cluster
jmp .loadcluster jmp .loadcluster
;Set AL to 0x0 and load the file size to CX if the load was succesful ;Clear the carry flag if the load was succesful
.success: .clearcarry:
mov al, 0x0 clc
mov cx, [.size]
;Clear the stack ;Clear the stack
.clearstack:
pop cx
pop bx
.done: .done:
;Load DI, SI, DX, and BX from the stack ;Load the initial registers from the stack
pop di pop di
pop si pop si
pop dx pop dx
pop cx
pop bx pop bx
pop ax
;Set AH to its initial value ;Set AL to 0x1 if there was an error and to 0x0 otherwise and return
mov ah, 0x0 jc .setal
mov al, 0x0
;Return iret
.setal:
mov al, 0x1
iret iret
;Data ;Data
.file times 0xb db 0x20 .file times 0xb db 0x20
.size dw 0x0 .errormsg db "File not found", 0x0
.cluster dw 0x0 .cluster dw 0x0
.pointer dw 0x0 .pointer dw 0x0
.driverrormsg db "Drive not found", 0x0
.diskerrormsg db "Unable to read disk", 0x0
.filerrormsg db "File or command not found", 0x0
.sizerrormsg db "Not enough memory", 0x0
;*** ;These are temporary until i write something to load them from the disk itself
.bootdrive db 0x0
.sectorsize dw 0x200 ;bytes
.clustersize db 0x2 ;sectors
.bootsectors dw 0x1
.fats db 0x2
.rootentries dw 0x70
.sectorsperfat dw 0x2
.sectorspertrack dw 0x9
.sides dw 0x2
;Check the file name and convert to upper case ;Check the file name and convert to upper case
.checkconv: .checkconv:
;Check for the string end, length limit, and invalid characters
;Check for the string end ;Check for the string end
cmp al, 0x0 cmp al, 0x0
je .load je .load
@ -408,8 +268,6 @@ jmp .error
.contcheck3: .contcheck3:
cmp al, 0x7c cmp al, 0x7c
je .error je .error
;Check for lower case and convert it to upper case
;Check for lower case ;Check for lower case
cmp al, 0x61 cmp al, 0x61
jl .storech jl .storech
@ -417,50 +275,30 @@ cmp al, 0x7a
jg .storech jg .storech
;Convert lower to upper case ;Convert lower to upper case
sub al, 0x20 sub al, 0x20
;Store the character
.storech: .storech:
;Store the character
stosb stosb
;Increase the counter
;Decrease the counter
dec bl dec bl
;Return
ret ret
;***
;Calculate the source arguments for loading data from the disk ;Calculate the source arguments for loading data from the disk
.calcsource: .calcsource:
;Store AX and BX in the stack
push ax push ax
push bx push bx
;Calculate the cylinder, head, and sector
;Store the logical sector in BX
mov bx, ax mov bx, ax
;Calculate the sector
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [.sectorspertrack]
add dl, 0x1 add dl, 0x1
mov cl, dl mov cl, dl
;Load the logical sector from BX
mov ax, bx mov ax, bx
;Calculate the head and cylinder
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [.sectorspertrack]
mov dx, 0x0 mov dx, 0x0
div word [heads] div word [.sides]
mov dh, dl ;Head mov dh, dl
mov ch, al ;Cylinder mov ch, al
;Load the drive number
mov dl, byte [drive]
;Load BX and AX from the stack
pop bx pop bx
pop ax pop ax
mov dl, byte [.bootdrive]
;Return
ret ret

View File

@ -1,101 +0,0 @@
cpu 8086
org 0x3000
;Load a file and print it
;Set the stack
cli
mov sp, stack + 0x100
sti
;Check for an empty tail
;Check
cmp byte [si], 0x0
jne extract
;Print an error message and abort if the tail is empty
mov si, errormsg
mov ah, 0x2
int 0x21
je done
;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
cmp byte [di], 0x0
je load
;Check for a space
cmp byte [di], 0x20
je addnull
inc di
jmp findend
;Add a null
addnull:
mov al, 0x0
stosb
;Load the file
;Load
load:
mov bx, stack + 0x100
mov ah, 0x2
int 0x22
;Check for errors
cmp al, 0x0
jne done
;Print the file
;Setup
mov bh, 0x0
mov bl, 0x18
mov dl, 0x50
mov si, stack + 0x100
;Decrease the character counter
print:
dec dl
;Load the current character
lodsb
;Print the character
mov ah, 0xe
int 0x10
;Check for a hard line end
cmp al, 0xa
je linecount
;Check for a soft line end
cmp dl, 0x0
je linecount
;Check paging
contprint:
cmp bl, 0x0
jz page
;Repeat for the next character
loop print
jmp done
;Decrease the line counter and reset the character one
linecount:
dec bl
mov dl, 0x50
jmp contprint
;Page
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:

View File

@ -1,4 +1,5 @@
;Print a string ending in a null from SI followed by a CRLF. ;Print a string ending in a null from SI followed by a CRLF.
println: println:
;Print the string ;Print the string
@ -8,5 +9,4 @@ int 0x21
;Print a CRLF ;Print a CRLF
call printcrlf call printcrlf
;Return
iret iret

View File

@ -1,13 +1,14 @@
;Print a string ending in a null from SI. ;Print a string ending in a null from SI.
printstr: printstr:
;Store AX and SI in the stack ;Store the initial registers in the stack
push ax push ax
push si push si
;Print the string ;Print the string
;Load the current character
.loop: .loop:
;Load the current character
lodsb lodsb
;Check for the string end ;Check for the string end
cmp al, 0x0 cmp al, 0x0
@ -15,13 +16,13 @@ je .done
;Print the character ;Print the character
mov ah, 0xe mov ah, 0xe
int 0x10 int 0x10
;Print the next character ;Repeat for the next character
jmp .loop jmp .loop
;Load the initial registers from the stack
.done: .done:
;Load the initial registers from the stack
pop si pop si
pop ax pop ax
;Return
iret iret

View File

@ -1,5 +1,5 @@
;Read a string ending in a null of at most AL characters to DI until a ;Read a string ending in null of at most AL characters to DI until a return and print a CRLF.
;return and print a CRLF.
readln: readln:
;Read the string ;Read the string
@ -9,5 +9,4 @@ int 0x21
;Print a CRLF ;Print a CRLF
call printcrlf call printcrlf
;Return
iret iret

View File

@ -1,8 +1,8 @@
;Read a string ending in a null of at most AL characters to DI until a ;Read a string ending in a null of at most AL characters to DI until a return.
;return.
readstr: readstr:
;Store AX, BX, CX, DX, and DI in the stack ;Store the initial registers in the stack
push ax push ax
push bx push bx
push cx push cx
@ -20,16 +20,12 @@ rep stosb
pop ax pop ax
push ax push ax
sub di, ax sub di, ax
;Store the last column number ;Initialise the cursor pointer in BL and clear BH
mov ah, 0xf
int 0x10
dec ah
mov [.lastcolumn], ah
;Set the cursor pointer in BL and clear BH
mov bx, 0x1 mov bx, 0x1
;Read a keypress
.loop: .loop:
;Read a keypress
mov ah, 0x0 mov ah, 0x0
int 0x16 int 0x16
@ -59,9 +55,9 @@ je .loop
;Store and print a character ;Store and print a character
.character: .character:
;Store ;Store the character
stosb stosb
;Print ;Print the character
mov ah, 0xe mov ah, 0xe
int 0x10 int 0x10
;Move the cursor pointer ;Move the cursor pointer
@ -91,21 +87,23 @@ dec di
dec bl dec bl
jmp .loop jmp .loop
;Check for and remove trailing spaces ;Finish reading the string
;Go to the end of the input
.return: .return:
;Find and remove trailing spaces
;Go to the end of the input
pop ax pop ax
mov bh, 0x0 mov bh, 0x0
sub ax, bx sub ax, bx
push di push di
add di, ax add di, ax
;Check for trailing spaces
.findtrailing: .findtrailing:
;Check for a trailing space
cmp byte [di], 0x20 cmp byte [di], 0x20
je .deltrailing je .deltrailing
jmp .end jmp .end
;Remove trailing spaces
.deltrailing: .deltrailing:
;Delete a trailing space
mov al, 0x0 mov al, 0x0
stosb stosb
sub di, 0x2 sub di, 0x2
@ -124,102 +122,83 @@ inc di
inc bl inc bl
jmp .findend jmp .findend
;Load DI, DX, CX, BX, and AX from the stack
.done: .done:
;Load the initial registers from the stack
pop di pop di
pop dx pop dx
pop cx pop cx
pop bx pop bx
pop ax pop ax
;Return
iret iret
;Data
.lastcolumn db 0x0
;***
;Move the cursor forward ;Move the cursor forward
.nextchar:
;Move forward within a line
.nextchar:
;Get the cursor position ;Get the cursor position
mov ah, 0x3 mov ah, 0x3
int 0x10 int 0x10
;Check for the end of the line ;Check for the end of the line
cmp dl, [.lastcolumn] cmp dl, 0x4f
je .nextln je .nextln
;Move
;Move the cursor forward within a line
inc dl inc dl
mov ah, 0x2 mov ah, 0x2
int 0x10 int 0x10
;Return
ret ret
;Move the cursor to the beginning of the next line ;Move to the beginning of the next line
;Check if the current line is the last on screen
.nextln: .nextln:
;Check if the current line is the last on screen
cmp dh, 0x18 cmp dh, 0x18
je .scroll je .scroll
;Move the cursor ;Move
mov ah, 0x2 mov ah, 0x2
inc dh inc dh
mov dl, 0x0 mov dl, 0x0
int 0x10 int 0x10
;Return
ret ret
;Scroll the screen up by one line ;Scroll the screen up by one line
.scroll: .scroll:
;Scroll
mov ah, 0x6 mov ah, 0x6
mov al, 0x1 mov al, 0x1
mov bh, 0x7 mov bh, 0x7
mov ch, 0x0 mov ch, 0x0
mov cl, 0x0 mov cl, 0x0
mov dh, 0x18 mov dh, 0x18
mov dl, [.lastcolumn] mov dl, 0x4f
int 0x10 int 0x10
;Move to the beginning of the new line ;Move to the beginning of the new line
mov ah, 0x2 mov ah, 0x2
mov bh, 0x0 mov bh, 0x0
mov dl, 0x0 mov dl, 0x0
int 0x10 int 0x10
;Return
ret ret
;***
;Move the cursor backward ;Move the cursor backward
.prevchar:
;Move backward within a line
.prevchar:
;Get the cursor position ;Get the cursor position
mov ah, 0x3 mov ah, 0x3
int 0x10 int 0x10
;Check for the beginning of the line ;Check for the beginning of the line
cmp dl, 0x0 cmp dl, 0x0
je .prevln je .prevln
;Move
;Move the cursor backward within a line
dec dl dec dl
mov ah, 0x2 mov ah, 0x2
int 0x10 int 0x10
;Return
ret ret
;Move the cursor to the end of the previous line ;Move to the end of the previous line
.prevln: .prevln:
mov ah, 0x2 mov ah, 0x2
dec dh dec dh
mov dl, [.lastcolumn] mov dl, 0x4f
int 0x10 int 0x10
;Return
ret ret

View File

@ -1,7 +1,6 @@
cpu 8086 CPU 8086
org 0x500 ORG 0x500
;Jump to the code
jmp start jmp start
;Interrupt handler ;Interrupt handler
@ -21,21 +20,22 @@ je readln
iret iret
;Disk operations ;Disk operations
int0x22: int0x22:
cmp ah, 0x2 cmp ah, 0x0
je loadf je loadf
;To do: savef ;To do: savef
iret iret
;System call includes ;System calls
%include "PRINTSTR.INC" %include "PRINTSTR.INC"
%include "READSTR.INC" %include "READSTR.INC"
%include "PRINTLN.INC" %include "PRINTLN.INC"
%include "READLN.INC" %include "READLN.INC"
%include "LOADF.INC" %include "LOADF.INC"
start:
;Set up the interrupt vectors ;Set up the interrupt vectors
;Interrupt 0x20 offset ;Interrupt 0x20 offset
start:
mov ax, int0x20 mov ax, int0x20
mov [0x80], ax mov [0x80], ax
;Interrupt 0x21 offset ;Interrupt 0x21 offset
@ -50,11 +50,6 @@ mov [0x82], ax
mov [0x86], ax mov [0x86], ax
mov [0x8a], ax mov [0x8a], ax
;Store the boot drive number as the current drive and set the current
;drive letter
mov [curdrive], dl
call setcurdriveletter
;Print a welcome message ;Print a welcome message
mov si, welcomemsg mov si, welcomemsg
mov ah, 0x2 mov ah, 0x2
@ -68,226 +63,62 @@ mov sp, 0x0
sti sti
;Prompt for and read a command ;Prompt for and read a command
;Print the current drive letter
mov si, curdriveletter
mov ah, 0x0
int 0x21
;Print a prompt ;Print a prompt
mov si, prompt mov si, prompt
mov ah, 0x0 mov ah, 0x0
int 0x21 int 0x21
;Read ;Read
mov di, input mov di, input
mov al, 0x4c mov al, 0x4e
mov ah, 0x3 mov ah, 0x3
int 0x21 int 0x21
;Load an execute the program
;Check for an empty command ;Check for an empty command
cmp byte [input], 0x0 cmp byte [input], 0x0
jz shell jz shell
;Load
;Set SI at the command mov bx, 0x2000
;Set SI at input
mov si, input mov si, input
;Ignore leading spaces mov ah, 0x0
call ignoreleading
;Check for a current drive change command
cmp byte [si + 0x1], ":"
jne extract
cmp byte [si + 0x2], 0x0
je changecurdrive
cmp byte [si + 0x2], 0x20
je changecurdrive
;Extract the specification of the program file
extract:
;Set DI at program
mov di, program
;Initialise program with spaces
mov cx, 0xe
mov al, 0x20
rep stosb
sub di, 0xe
;Set the length counter
mov bl, 0xa
;Load a character
specloop:
lodsb
;Check for the string end
cmp al, 0x0
je addext
;Check for a space
cmp al, 0x20
je addext
;Check for the length limit
cmp bl, 0x0
je cmderror
;Store the character
stosb
;Decrease the counter
dec bl
;Extract the next character
jmp specloop
;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 the program
mov bx, 0x3000
mov si, program
mov ah, 0x2
int 0x22 int 0x22
;Check for errors ;Check for errors
cmp al, 0x0 cmp al, 0x1
jne shell je error
;Pass the current drive and command tail to the program ;Execute
mov dl, [curdrive] jmp 0x2000
pop si
call ignoreleading
;Execute the program
jmp 0x3000
;Print a command error message and return to the shell ;Print an error message and return to the shell
cmderror: error:
mov si, cmderrormsg mov bh, 0x0
mov ah, 0x3
int 0x10
dec dh
mov ah, 0x2
int 0x10
mov si, errormsg
mov ah, 0x2 mov ah, 0x2
int 0x21 int 0x21
jmp shell jmp shell
;Change the current drive ;Data
;Get the BIOS equipment list
changecurdrive:
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 [curdrive], dl
call setcurdriveletter
jmp shell
;Welcome message
welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0 welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0
prompt db "> ", 0x0
;Drive stuff errormsg db "Unknown command", 0x0
curdrive db 0x0 input times 0x4e db 0x0
driveletters db "AaBbCcDd" crlf db 0xd, 0xa, 0x0
;Shell
curdriveletter db "?:", 0x0
prompt db "> ", 0x0
input times 0x4c db 0x0
program times 0xf db 0x0
extension db ".BIN", 0x0
cmderrormsg db "File or command not found", 0x0
driverrormsg db "Drive not found", 0x0
;Disk parameters
drive db 0x0
sectorsize dw 0x0 ;bytes
clustersize db 0x0 ;sectors
reservedsectors dw 0x0
fats db 0x0
rootentries dw 0x0
sectorsperfat dw 0x0
sectorspertrack dw 0x0
heads dw 0x0
rootstart dw 0x0
rootsectors dw 0x0
datastart dw 0x0
;***
;Set the drive letter
setcurdriveletter:
;Set the drive number and letter counters
mov dh, 0x0
mov si, driveletters
;Check the drive number
.checkdrive:
cmp dl, dh
je .set
add si, 0x2
inc dh
jmp .checkdrive
;Set the drive letter
.set:
mov al, [si]
mov byte [curdriveletter], 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 ;Print a CRLF
printcrlf: printcrlf:
;Store the initial registers in the stack
;Store SI in the stack
push si push si
;Print the CRLF ;Print the CRLF
mov si, .crlf mov si, crlf
mov ah, 0x0 mov ah, 0x0
int 0x21 int 0x21
;Load the initial registers from the stack
;Load SI from the stack
pop si pop si
;Return
ret ret
;Data
.crlf db 0xd, 0xa, 0x0
;***
;File system buffer ;File system buffer
buffer: buffer: