commit
62e1d36c38
23 changed files with 2501 additions and 0 deletions
@ -0,0 +1,5 @@ |
|||
.DS_Store |
|||
*.swp |
|||
*.sublime* |
|||
*.img |
|||
*.bin |
@ -0,0 +1,173 @@ |
|||
BITS 16 |
|||
;CLI |
|||
|
|||
;Command syntax: <command name> <arg1> |
|||
;Argument must not contain spaces. |
|||
|
|||
; Data |
|||
CLI_Command_Buffer times 256 db 0 |
|||
CLI_Command_Length dw 0 |
|||
|
|||
; API |
|||
; args: |
|||
; ax: keyboard keycode. |
|||
CLI_ASCII_INPUT: |
|||
pusha |
|||
|
|||
; Fetch command buffer offset. |
|||
; If there is no room in the buffer, then just bail on the key press. |
|||
mov bx, [CLI_Command_Length] |
|||
cmp bx, 255 |
|||
je .end |
|||
|
|||
inc bx ; The new last element will be located at this offset. |
|||
mov [CLI_Command_Length], bx ; Save the new counter. |
|||
dec bx ; Go back to the index the character should be written to. |
|||
|
|||
; Move new ascii character into command buffer. |
|||
add bx, CLI_Command_Buffer ; address+offset = destination |
|||
mov [bx], al |
|||
|
|||
inc bx |
|||
mov byte [bx], 0 |
|||
|
|||
; Print out the input character |
|||
mov ah, 0xe ; Teletype output |
|||
mov bl, 0x02 ; color (green) |
|||
int 0x10 |
|||
|
|||
.end: |
|||
popa |
|||
ret |
|||
|
|||
; args: |
|||
CLI_DELETE: |
|||
pusha |
|||
|
|||
; Check if at the beginning of the line. |
|||
mov bx, [CLI_Command_Length] |
|||
cmp bx, 0x00 |
|||
je .end |
|||
|
|||
; Move the counter one back |
|||
sub bx, 0x01 |
|||
mov [CLI_Command_Length], bx |
|||
|
|||
;Move NULL into the last character of the line (delete) |
|||
mov al, 0x0 |
|||
add bx, CLI_Command_Buffer ; address+offset = destination |
|||
mov [bx], al |
|||
|
|||
; Go back one space |
|||
mov ax, 0x0e08 ; ah=0x0e means teletype output. al=0x08 means backspace character. |
|||
int 0x10 |
|||
|
|||
; Place a NULL |
|||
mov al, 0x0 ; NULL |
|||
int 0x10 |
|||
|
|||
; Go back one space again as the above print of NULL pushes the cursor forward again. |
|||
mov ax, 0x0e08 |
|||
int 0x10 |
|||
|
|||
.end: |
|||
popa |
|||
ret |
|||
|
|||
; Probably activated with the 'Enter' button. |
|||
CLI_CONFIRM_INPUT: |
|||
|
|||
call CLI_EXECUTE |
|||
|
|||
mov bx, 0 |
|||
mov [CLI_Command_Length], bx |
|||
mov [CLI_Command_Buffer], bx |
|||
ret |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
print_help_message: |
|||
; Prints a list of available commands |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
push si |
|||
mov si, .command_list_string |
|||
call print |
|||
pop si |
|||
ret |
|||
.command_list_string: |
|||
db 13, 10 |
|||
db "Available commands:", 13, 10 |
|||
db " help: Prints this screen", 13, 10 |
|||
db " dumpmem: Prints the contents of a memory region (At the moment hardcoded)", 13, 10 |
|||
db " keyprint: Prints the character and keycode for a key presssd", 13, 10 |
|||
db " clear: Clears the screen", 13, 10 |
|||
db " formatdisk: Initialize the file system", 13, 10 |
|||
db " createfile: Name a file, in the file system", 13, 10 |
|||
db " fsinfo: Displays info about the file system", 13, 10 |
|||
db " ls: Lists the named files", 13, 10 |
|||
db " svim: SingOS' text editor", 13, 10, 0 |
|||
|
|||
; Executes the command. |
|||
CLI_EXECUTE: |
|||
pusha |
|||
|
|||
mov bx, [CLI_Command_Length] |
|||
cmp bx, 0 |
|||
je near .end ; If there are not bytes in the buffer then there is no command. |
|||
|
|||
mov ax, [.Num_Commands] ; The number of commands available. |
|||
|
|||
lea si, [CLI_Command_Buffer] |
|||
mov cx, 0 ; Index into the list of commands. |
|||
|
|||
.Interpreter_Search_Commands_Loop: |
|||
;cmp cx, ax ; Start by comparing. |
|||
;je .end |
|||
|
|||
mov bx, cx ; Move Index into bx to offset into the array of commands. |
|||
add bx, bx ; The pointers are two bytes long. This compensates for that. |
|||
|
|||
mov bx, [.Command_Name_List + bx] ; Fetch the pointer for the string. |
|||
|
|||
lea di, [bx] |
|||
call stringcompare |
|||
|
|||
je .Interpreter_Command_Execute |
|||
|
|||
inc cx ; Prepare for next iteration. |
|||
cmp ax, cx |
|||
je .end |
|||
jmp .Interpreter_Search_Commands_Loop |
|||
|
|||
|
|||
.Interpreter_Command_Execute: |
|||
mov bx, cx ; Move Index into bx to offset into the array of commands. |
|||
add bx, bx ; The pointers are two bytes long. This compensates for that. |
|||
|
|||
pusha |
|||
call printCRLF |
|||
popa |
|||
|
|||
mov dx, [.Command_Function_Pointers + bx] ; Program pointer |
|||
|
|||
; Execute program. |
|||
call dx |
|||
|
|||
.end: |
|||
popa |
|||
ret |
|||
|
|||
.tmp dw 0 |
|||
.Num_Commands dw 9 |
|||
.Command_Name_List dw .CMD1, .CMD2, .CMD3, .CMD4, .CMD5, .CMD6, .CMD7, .CMD8, .CMD9 |
|||
.Command_Function_Pointers dw dumpmem_hardcoded_args, keyprint, svim, vsfs_list_files_command, vsfs_create_file, vsfs_format_disk, vsfs_get_fs_info, os_clear_screen, print_help_message |
|||
.CMD1 db 'dumpmem', 0 |
|||
.CMD2 db 'keyprint', 0 |
|||
.CMD3 db 'svim', 0 |
|||
.CMD4 db 'ls', 0 |
|||
.CMD5 db 'createfile', 0 |
|||
.CMD6 db 'formatdisk', 0 |
|||
.CMD7 db 'fsinfo', 0 |
|||
.CMD8 db 'clear', 0 |
|||
.CMD9 db 'help', 0 |
|||
|
|||
|
@ -0,0 +1,39 @@ |
|||
SingOS is a single task operating system. |
|||
|
|||
Current version 0.0.3 |
|||
|
|||
The goal for this project is to create a Operating System |
|||
which tries to find new better ways to handle memory adressing |
|||
|
|||
It will also be posible to switch between 16, 32 and 64-bit mode |
|||
such that anything on very low level can be tested. |
|||
|
|||
You can build and run the OS with following command |
|||
(Require nasm and qemu installed) |
|||
|
|||
```sh |
|||
|
|||
sh build.sh |
|||
|
|||
``` |
|||
|
|||
If you only want to run SingOS: |
|||
|
|||
```sh |
|||
|
|||
sh build.sh run |
|||
|
|||
``` |
|||
|
|||
If you only want to compile the binary: |
|||
|
|||
```sh |
|||
|
|||
sh build.sh make |
|||
|
|||
``` |
|||
|
|||
If you want to write it to a usb device |
|||
```sh |
|||
sudo dd if=/some_dir/SingOS.img of=/dev/name_device status=progress oflag=sync |
|||
``` |
@ -0,0 +1,235 @@ |
|||
BITS 16 |
|||
;http://www.ousob.com/ng/bios/ng1223.php |
|||
start: |
|||
; Set up 4K stack after this bootloader |
|||
; [Remember: Effective Address = Segment*16 + Offset] |
|||
mov ax, 0x7C0 ; Set 'ax' equal to the location of this bootloader divided by 16 |
|||
add ax, 0x20 ; Skip over the size of the bootloader divided by 16 |
|||
mov ss, ax ; Set 'ss' to this location (the beginning of our stack region) |
|||
mov sp, 8192 ; Set 'ss:sp' to the top of our 8K stack |
|||
|
|||
; Set data segment to where we're loaded so we can implicitly access all 64K from here |
|||
mov ax, 0x7C0 ; Set 'ax' equal to the location of this bootloader divided by 16 |
|||
mov ds, ax ; Set 'ds' to the this location |
|||
|
|||
mov [disk_identifier], dl |
|||
; Print our message and stop execution |
|||
mov si, message ; Put address of the null-terminated string to output into 'si' |
|||
call print ; Call our string-printing routine |
|||
mov si, enter_debug_mode |
|||
call print |
|||
call printCRLF |
|||
; here goes wait call, for the user to enter debug mode. |
|||
; Wating for 2 seconds: |
|||
mov ah, 0x86 ; code for waiting interupt call |
|||
mov cx, 0x001e ; high count of microseconds |
|||
mov dx, 0x8480 ; low count |
|||
int 0x15 |
|||
|
|||
.busy_wait_for_key: |
|||
xor ax, ax |
|||
mov ah, 0x01 ; BIOS call to wait for key |
|||
int 0x16 |
|||
jnz debug_mode |
|||
|
|||
; entering system check: |
|||
mov si, enter_system_check |
|||
|
|||
mov si, sys_check_ok ; Put address of the null-terminated string to output into 'si' |
|||
call print ; Call our string-printing routine |
|||
|
|||
mov si, boot_system ; Put address of the null-terminated string to output into 'si' |
|||
call print ; Call our string-printing routine |
|||
|
|||
;This goes first as to now overwrite %ah and %al. |
|||
mov ax, 0x0 |
|||
mov es, ax ;Section to write into |
|||
mov ah, 0x2 ;Read sectors from drive |
|||
mov al, 0xf ;Number of sectors to read (15 * 512 = 7680 bytes) |
|||
mov ch, 0x0 ;Low 8 bits of cylinder |
|||
mov cl, 0x11 ;First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov dh, 0x0 ;Head number |
|||
mov dl, [disk_identifier] ;0x0 ;Drive number |
|||
mov bx, 0x7e00 ;Offset into section |
|||
int 0x13 ;Low level disk services |
|||
;mov [0x7000], es ; saving retult of read |
|||
; |
|||
;Debug dump of loaded memory |
|||
;mov si, 500 |
|||
;mov cx, 512 |
|||
;call b_dumpmem |
|||
|
|||
jnc notcarry |
|||
mov si, error_str |
|||
call print |
|||
jmp endcarrycheck |
|||
; |
|||
notcarry: |
|||
mov si, success_str |
|||
call print |
|||
call printCRLF |
|||
call printCRLF |
|||
|
|||
; xor ax, ax |
|||
; mov al, [disk_identifier] |
|||
; call dumpax |
|||
mov dl, [disk_identifier] |
|||
|
|||
mov ax, 0x7e0 |
|||
mov ds, ax |
|||
jmp 0x7e0:0x00 |
|||
|
|||
endcarrycheck: |
|||
cli ; Clear the Interrupt Flag (disable external interrupts) |
|||
hlt ; Halt the CPU (until the next external interrupt) |
|||
|
|||
debug_mode: |
|||
mov si, .welcome_debug |
|||
call print |
|||
cli ; Clear the Interrupt Flag (disable external interrupts) |
|||
hlt |
|||
|
|||
.welcome_debug db 'This is debug mode', 0 |
|||
data: |
|||
message db 'Bootloader for SingOS! v0.0.3',13,10,0 |
|||
enter_debug_mode db 'Press d to enter bootloader debug mode',13,10,0 |
|||
enter_system_check db 'Performing system check:',13,10,0 |
|||
sys_check_ok db 'System check ok', 13, 10, 0 |
|||
boot_system db 'Read SingOS from disk', 13, 10, 0 |
|||
error_str db 'Error', 0 |
|||
success_str db 'Success', 0 |
|||
disk_identifier db 0 |
|||
|
|||
; Routine for printing a 'ax' as hex |
|||
dumpax: |
|||
pusha ; save registers |
|||
mov bx, ax |
|||
mov ah, 0xE ; Teletype output |
|||
|
|||
mov cx, 4 ; 4 nipples in a 16 bit word |
|||
.loop: |
|||
rol bx, 4 ; rotate to next nipple |
|||
mov al, bl ; we copy to al because we need to mask only the low 4 bits |
|||
and al, 1111b ; Do the masking |
|||
add al, '0' ; convert to ASCII |
|||
cmp al, '9' ; If we are greater than 9 ascii, we add 7 to make digit 10 be represented as 'A' |
|||
jbe .skip ; -|- |
|||
add al, 7 ; -|- |
|||
.skip: ; -|- |
|||
int 0x10 ; BIOS call 'output' |
|||
loop .loop |
|||
|
|||
popa ; restore registers |
|||
ret |
|||
|
|||
dumpax10: ; Prints ax as 16-bit decimal number |
|||
pusha |
|||
|
|||
mov bx, 10 ; Divisor |
|||
|
|||
mov cx, 5 ; Loop 5 times |
|||
.loop1: ; finds digits and pushes them to stack |
|||
xor dx, dx |
|||
div bx |
|||
add dl, '0' |
|||
push dx |
|||
loop .loop1 |
|||
|
|||
|
|||
mov ah, 0xE |
|||
mov cx, 5 ; Loop 5 times |
|||
mov bl, '0' |
|||
|
|||
.loop2: ; Pops from stack until it hits a non-'0' value. It then jumps to nonzero_nopop to print it. |
|||
pop dx |
|||
mov al, dl |
|||
cmp al, bl |
|||
jne .nonzero_nopop |
|||
loop .loop2 |
|||
|
|||
.nonzero_loop: ; Pops values from the stack and prints them. |
|||
pop dx |
|||
mov al, dl |
|||
.nonzero_nopop: ; Part of the loop that prints the value. Jump to here to print without popping on first iteration. |
|||
int 0x10 |
|||
loop .nonzero_loop |
|||
|
|||
popa |
|||
ret |
|||
|
|||
dumpax10_rev: ; Prints ax as 16-bit decimal number in reverse |
|||
pusha |
|||
|
|||
mov cx, 10 ; Divisor |
|||
.loop: |
|||
xor dx, dx ; zero dx |
|||
div cx ; Divide dx:ax by 10 -> quotient in ax, remainder in dx |
|||
|
|||
mov bx, ax ; save quotient in bx |
|||
|
|||
mov al, dl ; put remainder in al |
|||
add al, '0' ; Make ASCII |
|||
|
|||
mov ah, 0xE ; Set teletype output |
|||
int 0x10 ; BIOS: write one char |
|||
|
|||
mov ax, bx |
|||
;test ax, ax |
|||
cmp ax, 0 |
|||
jnz .loop |
|||
|
|||
popa |
|||
ret |
|||
|
|||
printCRLF: |
|||
mov ah, 0xE |
|||
mov al, 13 |
|||
int 0x10 |
|||
mov al, 10 |
|||
int 0x10 |
|||
ret |
|||
|
|||
; Routine for outputting string in 'si' register to screen |
|||
print: |
|||
mov ah, 0xE ; Specify 'int 0x10' 'teletype output' function |
|||
; [AL = Character, BH = Page Number, BL = Colour (in graphics mode)] |
|||
.printchar: |
|||
lodsb ; Load byte at address SI into AL, and increment SI |
|||
cmp al, 0 |
|||
je .done ; If the character is zero (NUL), stop writing the string |
|||
int 0x10 ; Otherwise, print the character via 'int 0x10' |
|||
jmp .printchar ; Repeat for the next character |
|||
.done: |
|||
ret |
|||
|
|||
; b_dumpmem: |
|||
; push ax |
|||
; push dx |
|||
; call printCRLF |
|||
; shr cx, 1 |
|||
; xor dx, dx ; zero dx |
|||
; .loop: |
|||
; cmp dx, cx |
|||
; jae .end |
|||
; mov ax, word [esi + 2*edx] |
|||
; call dumpax |
|||
; mov ax, 0xe20 |
|||
; int 0x10 |
|||
; inc dx |
|||
; jmp .loop |
|||
; .end: |
|||
; pop dx |
|||
; pop ax |
|||
; ret |
|||
; Pad to 510 bytes (boot sector size minus 2) with 0s, and finish with the two-byte standard boot signature |
|||
times 510-($-$$) db 0 |
|||
dw 0xAA55 ; => 0x55 0xAA (little endian byte order) |
|||
; bootloder debug_mode goes here |
|||
|
|||
times 8192-($-$$) db 0 |
|||
|
|||
; From Version 0.0.3 we are concatinate the bootloader and the kernel after compile time |
|||
;%include "kernel.nasm" |
|||
|
|||
;times 8192-($-$$) db 0 |
|||
|
@ -0,0 +1,17 @@ |
|||
#!/usr/bin/bash |
|||
|
|||
if [ "$1" == "build" ] || [ "$1" == "run" ]; then |
|||
nasm -fbin bootloader.nasm -o bootloader.bin |
|||
nasm -fbin kernel.nasm -o kernel.bin |
|||
cat bootloader.bin kernel.bin > SingOS.img |
|||
|
|||
if [ $1 == "run" ]; then |
|||
#qemu-system-x86_64 -drive format=raw,file=SingOS.img |
|||
#qemu-system-x86_64 -hda SingOS.img |
|||
qemu-system-x86_64 -drive index=0,if=floppy,format=raw,file=SingOS.img |
|||
else |
|||
bash -c "echo;echo;echo 'Press [ENTER] to exit'; read line" |
|||
fi |
|||
fi |
|||
|
|||
echo "Done" |
@ -0,0 +1,16 @@ |
|||
#!/bin/bash |
|||
|
|||
if [ "$1" != "run" ]; then |
|||
nasm -fbin bootloader.nasm -o bootloader.bin |
|||
nasm -fbin kernel.nasm -o kernel.bin |
|||
cat bootloader.bin kernel.bin > SingOS.img |
|||
fi |
|||
|
|||
if [ "$1" != "make" ]; then |
|||
#qemu-system-x86_64 -drive format=raw,file=SingOS.img |
|||
#qemu-system-x86_64 -hda SingOS.img |
|||
qemu-system-x86_64 -drive index=0,if=floppy,format=raw,file=SingOS.img |
|||
fi |
|||
|
|||
echo "Done" |
|||
|
@ -0,0 +1,305 @@ |
|||
BITS 16 |
|||
|
|||
start_sing: |
|||
; loading essentials for SingOS to run |
|||
|
|||
; VSFS is loaded: |
|||
mov [global_disk_identifier], dl ; saving disk_identifier, this is the number the disk that we are booting from. |
|||
; This number is set by the bios |
|||
|
|||
jmp sing_ready |
|||
%include "mem_lib/mem_lib.nasm" |
|||
%include "lib/os_lib.nasm" |
|||
%include "lib/string.nasm" |
|||
%include "lib/debug_tools.nasm" |
|||
%include "lib/std_power.nasm" |
|||
%include "lib/svim.nasm" |
|||
%include "vsfs/vsfs.nasm" |
|||
%include "CLI/CLI.nasm" |
|||
|
|||
sing_ready: ; SingOS is ready for the user: |
|||
|
|||
call os_clear_screen |
|||
|
|||
mov si, welcome ; Put address of the null-terminated string to output into 'si' |
|||
call print ; Call our string-printing routine |
|||
|
|||
print_format example_format_string, 0xdead, 0xbeef, 0xbabe, 420 |
|||
|
|||
call printCRLF |
|||
|
|||
call dump_general_registers |
|||
call printCRLF |
|||
|
|||
call dump_segment_registers |
|||
call printCRLF |
|||
|
|||
call dump_stack_registers |
|||
call printCRLF |
|||
|
|||
call dump_status_flags |
|||
call printCRLF |
|||
|
|||
call print_help_message |
|||
|
|||
; call dump_status_flags |
|||
; call printCRLF |
|||
|
|||
mov si, command_line |
|||
call print |
|||
jmp terminal |
|||
terminal: |
|||
call wait_for_key |
|||
jmp terminal |
|||
|
|||
wait_for_key: |
|||
pusha |
|||
|
|||
mov ax, 0 |
|||
mov ah, 0x10 ; BIOS call to wait for key |
|||
int 0x16 |
|||
|
|||
cmp ax, 0x11b; ESC key |
|||
je near .end |
|||
cmp ax, 0x3b00 ; f1 key |
|||
je .change_one |
|||
cmp ax, 0x3c00 ; f2 key |
|||
je .change_two |
|||
cmp ax, 0x1c0d ; enter key |
|||
je .enter_hit |
|||
mov [.tmp_buf], ax ; save the key pressed befor printing it |
|||
|
|||
mov cx, [.tmp_buf] |
|||
cmp cx, 0x0e08 ; backspace key |
|||
;je .backspace_handler |
|||
jne .dont_backspace |
|||
call CLI_DELETE |
|||
popa |
|||
ret |
|||
|
|||
.dont_backspace: |
|||
call CLI_ASCII_INPUT |
|||
|
|||
;mov ah, 0xE ; This destroy the high part of the key pressed |
|||
;mov bl, 0x02 |
|||
;int 0x10 |
|||
;mov bx, [.os_command_buffer_counter] |
|||
;cmp bx, 254 |
|||
;je .os_buffer_full |
|||
;mov ax, bx |
|||
;add ax, .os_command_buffer |
|||
;add bx, 0x01 |
|||
;mov [.os_command_buffer_counter], bx |
|||
;mov bx, ax |
|||
;mov ax, [.tmp_buf] |
|||
;mov [bx], ax |
|||
.return_enter: |
|||
mov ax, [.tmp_buf] |
|||
popa ; But restore all other regs |
|||
ret |
|||
|
|||
.os_buffer_full: |
|||
mov si, .os_str_full |
|||
call print |
|||
popa |
|||
ret |
|||
|
|||
.backspace_handler: |
|||
; bx already set to the current buffer count |
|||
mov bx, [.os_command_buffer_counter] |
|||
cmp bx, 0x00 |
|||
je .backspace_stop |
|||
sub bx, 0x01 |
|||
mov [.os_command_buffer_counter], bx |
|||
add bx, .os_command_buffer |
|||
mov ax, 0x00 |
|||
mov [bx], ax |
|||
mov ax, [.tmp_buf] ; load the backpace |
|||
mov ah, 0xE ; print the backspace |
|||
int 0x10 |
|||
mov al, 0 |
|||
int 0x10 |
|||
mov al, 0x08 |
|||
int 0x10 |
|||
;mov al, 0x20 ; now the curser is one back |
|||
;int 0x10 ; print null charecter |
|||
.backspace_stop: |
|||
popa ; But restore all other regs |
|||
ret |
|||
|
|||
.change_one: |
|||
|
|||
mov al, 0x00 ; arg: index 0 |
|||
call os_change_screen |
|||
jmp terminal |
|||
|
|||
.change_two: |
|||
|
|||
mov al, 0x01 ; arg: index 0 |
|||
call os_change_screen |
|||
jmp terminal |
|||
|
|||
|
|||
.enter_hit: |
|||
call CLI_CONFIRM_INPUT |
|||
jmp .command_interpreter |
|||
|
|||
.no_str: |
|||
mov si, command_line |
|||
call print |
|||
jmp .return_enter |
|||
|
|||
.compare_with_LIST_searchindex dw 0 |
|||
.compare_with_LIST_NAMES dw .compare_with_dumpmem, .compare_with_keyprint, .compare_with_display, .compare_with_svim, .compare_with_clear, .compare_with_ls, 0 |
|||
.compare_with_LIST_POINTERS dw dumpmem, keyprint, .change_display, svim, .clearcommand, vsfs_list_files_command, 0 |
|||
.compare_with_dumpmem db 'dumpmem', 0 |
|||
.compare_with_keyprint db 'keyprint', 0 |
|||
.compare_with_display db 'display', 0 ; original this is the display command for better grapichs |
|||
.compare_with_svim db 'svim', 0 ; SingOS vim edition 'svim' |
|||
.compare_with_clear db 'clear', 0 ; Clear the screen |
|||
.compare_with_ls db 'ls', 0 ; List file table |
|||
|
|||
.end: |
|||
mov si, exit_message |
|||
call print |
|||
|
|||
call power_off |
|||
|
|||
cli |
|||
hlt |
|||
|
|||
.change_display: |
|||
mov ax, 0x4F02 ; set VBE mode |
|||
mov bx, 0x4118 ; VBE mode number; notice that bits 0-13 contain the mode number and bit 14 (LFB) is set and bit 15 (DM) is clear. |
|||
;xor bx, bx |
|||
;xor cx, cx |
|||
;xor dx, dx |
|||
;mov ah, 0x06 |
|||
;mov al, 0xff |
|||
int 0x10 |
|||
ret |
|||
|
|||
.clearcommand: |
|||
xor bx, bx |
|||
xor cx, cx ; Upper and left coordinate |
|||
mov bh, 0x0f ; color for new screen 0 = black f = white |
|||
mov dh, 0xff ; Select all screen |
|||
mov dl, 0xff ; Select all screen |
|||
mov ah, 0x07 ; scrool down |
|||
mov al, 0x00 ; scrool 0 lines (means blank screen ) |
|||
int 0x10 |
|||
|
|||
; move curser back to the top of the screen |
|||
mov ah, 0x02 |
|||
mov bh, 0x00 ; page number 0 |
|||
mov dh, 0x00 ; row zero |
|||
mov dl, 0x00 ; coloumn zero |
|||
int 0x10 |
|||
ret |
|||
|
|||
.tmp_buf dw 0 |
|||
.os_command_buffer times 255 dw 0 |
|||
.os_command_buffer_counter dw 0 |
|||
.os_str_full db 13, 10, 'Buffer is full', 13, 10, 0 |
|||
|
|||
.command_interpreter: |
|||
|
|||
mov bx, [.os_command_buffer_counter] |
|||
cmp bx, 0x00 |
|||
je near .no_str ; First byte is 0 => No command |
|||
call printCRLF |
|||
add bx, .os_command_buffer ; Note addition. Sets bx to the end of the string, which should be guaranteed to be 0 |
|||
mov ax, 0x00 |
|||
mov [bx], ax ; Ensure that the command is null-terminated |
|||
xor bx, bx |
|||
mov [.os_command_buffer_counter], bx |
|||
mov si, .os_command_buffer |
|||
call print ; Echo the command |
|||
|
|||
lea si, [.os_command_buffer] |
|||
;mov dword [.compare_with_LIST_searchindex], 0 ; Next time, start at 0 |
|||
mov cx, 0 ; Index |
|||
|
|||
.command_interpreter_searchloop: |
|||
;call printCRLF |
|||
;mov ax, cx |
|||
;call dumpax |
|||
;mov bx, [.compare_with_LIST_searchindex] |
|||
mov bx, cx |
|||
add bx, bx ; The pointers are 2 bytes long. Compensate here |
|||
|
|||
;call printCRLF |
|||
;mov ax, cx |
|||
;call dumpax |
|||
|
|||
mov dx, [.compare_with_LIST_NAMES+bx] ; Here it HAS to be bx. Otherwise it is invalid for some reason |
|||
mov bx, dx |
|||
|
|||
lea di, [bx] |
|||
|
|||
call stringcompare |
|||
|
|||
je .command_interpreter_foundcommand |
|||
|
|||
; I don't assume here that the registers contain the same values they used to after the calls |
|||
;mov bx, [.compare_with_LIST_searchindex] |
|||
;inc bx |
|||
;mov [.compare_with_LIST_searchindex], bx |
|||
inc cx |
|||
|
|||
mov bx, cx |
|||
add bx, bx |
|||
mov dx, [.compare_with_LIST_NAMES+bx] |
|||
|
|||
cmp dx, 0 ;Is it at the null terminator? |
|||
|
|||
jne .command_interpreter_searchloop ; There is another command to check |
|||
|
|||
jmp .no_str |
|||
|
|||
.command_interpreter_foundcommand: |
|||
call printCRLF |
|||
|
|||
;mov bx, [.compare_with_LIST_searchindex] ; Remember this thing |
|||
mov bx, cx |
|||
add bx, bx ;The pointers are 2 bytes long. Compensate here |
|||
|
|||
;call printCRLF |
|||
;mov ax, cx |
|||
;call dumpax |
|||
|
|||
mov dx, [.compare_with_LIST_POINTERS+bx] ; This is where the program is. |
|||
|
|||
;mov ax, dx |
|||
;call printCRLF |
|||
;call dumpax |
|||
|
|||
call dx |
|||
|
|||
jmp .no_str |
|||
; |
|||
|
|||
|
|||
global_vars: |
|||
global_vsfs_master_record dw 8 ; this is the index of the start of the master table for the filesystem |
|||
; This should maby contain more information. |
|||
; and somehow be setted in a fix sector, which holds all the variabels for SingOS |
|||
; 8 is currently the magic number where the file system starts on our disk. |
|||
|
|||
global_vsfs_next_index dw 0 ; This is the next index to the next file created. |
|||
; this var is set durling load of SingOS |
|||
; Changed my mind, the index is currently loaded and written back to disk under |
|||
; creation of a new file. |
|||
global_disk_identifier db 0 ; set by the bios passed by the bootloader, |
|||
; this is the bios ID |
|||
|
|||
data: |
|||
welcome db "###############################################################################", 13, 10, "# Welcome to SingOS anniversary edition. #", 13, 10, "# This build marks 1 year of SingOS! #", 13, 10, "###############################################################################", 13, 10, 'Press ESC to halt.', 13, 10, 13, 10, 0 |
|||
exit_message db 13, 10, 'Goodbye from SingOS',13,10,'The system has halted.', 0 |
|||
command_line db 13, 10, 'groot@SingOS $ ', 0 |
|||
number_one_zstring db '71', 0 |
|||
example_format_string db "(%x-%x-%x){%d%%}",0 |
|||
|
|||
;times 131072-($-$$) db 0 ; 256 sectos |
|||
;GLOBAL_VSFS_START db 'VSFS v0.1' ; sector 257 reserved for file system information |
|||
times (1<<20)-($-$$) db 0 ; sector 258 to sector 2048 should be avaliable to the filesystem. |
@ -0,0 +1 @@ |
|||
SingOs |
@ -0,0 +1,2 @@ |
|||
Folder of compiling the OS |
|||
This folder has to be empty on the repository |
@ -0,0 +1,3 @@ |
|||
as sing_boot_alt.s -o ../compile_folder/alt.o |
|||
ld -Ttext 0x7c00 --oformat=binary ../compile_folder/alt.o -o ../compile_folder/sing.bin |
|||
dd if=../compile_folder/sing.bin of=../compile_folder/sing.img |
@ -0,0 +1,3 @@ |
|||
as $1.s -o ../compile_folder/$2.o |
|||
ld -Ttext 0x7c00 --oformat=binary ../compile_folder/$2.o -o ../compile_folder/$2.bin |
|||
dd if=../compile_folder/$2.bin of=../compile_folder/$2.img |
@ -0,0 +1,3 @@ |
|||
https://www.codeproject.com/Articles/664165/Writing-a-boot-loader-in-Assembly-and-C-Part |
|||
|
|||
http://www.computer-engineering.org/index.html // keyboard and mouse programming |
@ -0,0 +1,76 @@ |
|||
#generate 16-bit code |
|||
.code16 |
|||
|
|||
#hint the assembler that here is the executable code located |
|||
.text |
|||
.globl _start; |
|||
#boot code entry |
|||
_start: |
|||
jmp _boot |
|||
start: .asciz "Start.\n\r" |
|||
error: .asciz "Error.\n\r" |
|||
succes: .asciz "Succes.\n\r" |
|||
ffs: .asciz "F.\n\r" |
|||
end: .asciz "End.\n\r" |
|||
|
|||
.macro mWriteString str #macro which calls a function to print a string |
|||
leaw \str, %si |
|||
call .writeStringIn |
|||
.endm |
|||
|
|||
# function to print the string |
|||
.writeStringIn: |
|||
lodsb |
|||
orb %al, %al |
|||
jz .writeStringOut |
|||
movb $0x0e, %ah |
|||
int $0x10 |
|||
jmp .writeStringIn |
|||
.writeStringOut: |
|||
ret |
|||
|
|||
|
|||
_boot: |
|||
mWriteString start |
|||
|
|||
#This goes first as to now overwrite %ah and %al. |
|||
mov $0x00, %ax |
|||
mov %ax, %es #Section to write into |
|||
|
|||
mov $0x02, %ah # Read sectors from drive |
|||
mov $0x01, %al # Number of sectors to read |
|||
mov $0x00, %ch # Low 8 bits of cylinder |
|||
mov $0x02, %cl # First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov $0x00, %dh # Head number |
|||
mov $0x00, %dl # Drive number |
|||
# mov $0x00, %es |
|||
mov $0xFF, %bx #Offset into section |
|||
int $0x13 # Low level disk services |
|||
|
|||
jnc notcarry |
|||
mWriteString error |
|||
jmp endcarrycheck |
|||
|
|||
notcarry: |
|||
mWriteString succes |
|||
#fallthrough |
|||
|
|||
endcarrycheck: |
|||
|
|||
mWriteString mystr |
|||
|
|||
mWriteString end |
|||
|
|||
# |
|||
|
|||
|
|||
|
|||
#move to 510th byte from the start and append boot signature |
|||
. = _start + 510 |
|||
.byte 0x55 |
|||
.byte 0xaa |
|||
|
|||
mystr: .asciz "asdf" |
|||
|
|||
. = _start + 1023 |
|||
.byte 0x00 |
@ -0,0 +1,227 @@ |
|||
#generate 16-bit code |
|||
.code16 |
|||
|
|||
#hint the assembler that here is the executable code located |
|||
.text |
|||
.globl _start; |
|||
#boot code entry |
|||
_start: |
|||
jmp _boot |
|||
start: .asciz "Start.\n\r" |
|||
error: .asciz "Error.\n\r" |
|||
succes: .asciz "Succes.\n\r" |
|||
ffs: .asciz "F.\n\r" |
|||
end: .asciz "End.\n\r" |
|||
derpy2str: .asciz "This is from derpy2.\n\r" |
|||
cookies: .word derpy2 |
|||
|
|||
.macro mWriteString str #macro which calls a function to print a string |
|||
leaw \str, %si |
|||
call .writeStringIn |
|||
.endm |
|||
|
|||
# function to print the string |
|||
.writeStringIn: |
|||
lodsb |
|||
orb %al, %al |
|||
jz .writeStringOut |
|||
movb $0x0e, %ah |
|||
int $0x10 |
|||
jmp .writeStringIn |
|||
.writeStringOut: |
|||
ret |
|||
|
|||
|
|||
_boot: |
|||
mWriteString start |
|||
|
|||
movb $0x0e, %ah |
|||
movb $'X', %al |
|||
int $0x10 |
|||
|
|||
movb $'\n', %al |
|||
int $0x10 |
|||
|
|||
movb $'\r', %al |
|||
int $0x10 |
|||
|
|||
lgdt gdtdesc |
|||
|
|||
#movb $42, %bl #NOT 'A' |
|||
#movb %bl, 0x512 |
|||
|
|||
#This goes first as to now overwrite %ah and %al. |
|||
mov $0x00, %ax |
|||
#mov $0x08, %ax |
|||
mov %ax, %es #Section to write into |
|||
|
|||
mov $0x02, %ah # Read sectors from drive |
|||
mov $0x01, %al # Number of sectors to read |
|||
mov $0x00, %ch # Low 8 bits of cylinder |
|||
mov $0x02, %cl # First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov $0x00, %dh # Head number |
|||
mov $0x00, %dl # Drive number |
|||
# mov $0x00, %es |
|||
#mov $0x7e00, %bx #Offset into section |
|||
mov $(_start+0x200), %bx #Offset into section |
|||
#mov $0x0, %bx #Offset into section |
|||
int $0x13 # Low level disk services |
|||
|
|||
jnc notcarry |
|||
#mWriteString error |
|||
jmp endcarrycheck |
|||
|
|||
notcarry: |
|||
#mWriteString succes |
|||
|
|||
#mov $0x7000, %ax |
|||
#movb (%ax), %bl |
|||
#movb %bl, ffs |
|||
#movb 0x7000, %bl |
|||
#movb %bl, ffs |
|||
#mWriteString ffs |
|||
#fallthrough |
|||
|
|||
endcarrycheck: |
|||
|
|||
#mWriteString mystr-block2_offset |
|||
#mWriteString 0x513 |
|||
#mWriteString mystr |
|||
|
|||
#ljmp $0x0, $derpy |
|||
#.byte 0, 0, 0, 0, 0, 0, 0, 0 |
|||
#ljmp $0x00, $0x7e00 |
|||
#ljmp $0x00, $derpy2 |
|||
ljmp $0x00, $code |
|||
|
|||
# movw $derpy, %ax |
|||
# |
|||
# cmp $0x7e00, %ax |
|||
# je equal |
|||
# mWriteString error |
|||
# jmp after |
|||
# |
|||
# equal: |
|||
# mWriteString succes |
|||
# |
|||
# after: |
|||
/* |
|||
movb $0x0e, %ah |
|||
|
|||
movw $derpy, %cx |
|||
|
|||
movb 0x0e, %ah |
|||
movb $'I', %al |
|||
int $0x10 |
|||
movb 0x0e, %ah |
|||
movb $'J', %al |
|||
int $0x10 |
|||
*/ |
|||
|
|||
#movw $0x7E00, %cx |
|||
movw $derpy2, %cx |
|||
|
|||
movb $0x0e, %ah |
|||
#movb $'Y', %al |
|||
movb %ch, %al |
|||
#movb $'H', %al |
|||
#movb $0x7E, %al |
|||
int $0x10 |
|||
|
|||
movb $0x0e, %ah |
|||
#movb $'Z', %al |
|||
movb %cl, %al |
|||
#add $0x7E, %al |
|||
#sub $0x50, %al |
|||
#movb $0x3C, %al |
|||
int $0x10 |
|||
|
|||
movb $0x0e, %ah |
|||
movb $'\n', %al |
|||
int $0x10 |
|||
|
|||
movb $0x0e, %ah |
|||
movb $'\r', %al |
|||
int $0x10 |
|||
|
|||
|
|||
#mWriteString mystr |
|||
|
|||
#jmp derpy |
|||
derpyret: |
|||
|
|||
mWriteString end |
|||
|
|||
#jmp 0x7008 |
|||
#endend: |
|||
#mWriteString end |
|||
|
|||
cli |
|||
hlt |
|||
|
|||
# |
|||
|
|||
derpy: |
|||
mWriteString ffs |
|||
ljmp $0x00, $derpyret |
|||
#jmp derpyret |
|||
|
|||
.p2align 2 /* force 4-byte alignment */ |
|||
gdt: |
|||
.word 0, 0 |
|||
.byte 0, 0, 0, 0 |
|||
|
|||
/* code segment */ |
|||
.word 0xFFFF, 0 |
|||
.byte 0, 0x9A, 0xCF, 0 |
|||
|
|||
/* data segment */ |
|||
.word 0xFFFF, 0 |
|||
.byte 0, 0x92, 0xCF, 0 |
|||
|
|||
/* 16 bit real mode CS */ |
|||
.word 0xFFFF, 0 |
|||
.byte 0, 0x9E, 0, 0 |
|||
|
|||
/* 16 bit real mode DS */ |
|||
.word 0xFFFF, 0 |
|||
.byte 0, 0x92, 0, 0 |
|||
|
|||
/* this is the GDT descriptor */ |
|||
gdtdesc: |
|||
.word 0x27 /* limit */ |
|||
.long gdt /* addr */ |
|||
|
|||
#move to 510th byte from the start and append boot signature |
|||
. = _start + 510 |
|||
.byte 0x55 |
|||
.byte 0xaa |
|||
#block2_offset: |
|||
.byte 'A' #Byte 513 |
|||
#mystr: .asciz "asdf\n\r" |
|||
|
|||
#derpderp: |
|||
# mwriteString 0x7001 |
|||
# jmp endend |
|||
|
|||
derpy2: |
|||
mWriteString derpy2str |
|||
ljmp $0x00, $derpyret |
|||
|
|||
code: |
|||
mWriteString derpy2str |
|||
movb $0x0e, %ah |
|||
movb $'C', %al |
|||
int $0x10 |
|||
movb $0x0e, %ah |
|||
movb $'\n', %al |
|||
int $0x10 |
|||
movb $0x0e, %ah |
|||
movb $'\r', %al |
|||
int $0x10 |
|||
ljmp $0x00, $derpyret |
|||
|
|||
. = _start + 1021 |
|||
.byte 0x00 |
|||
|
|||
.word derpy2 |
@ -0,0 +1,120 @@ |
|||
#generate 16-bit code |
|||
.code16 |
|||
|
|||
#hint the assembler that here is the executable code located |
|||
.text |
|||
.globl _start; |
|||
#boot code entry |
|||
_start: |
|||
jmp _boot #jump to boot code |
|||
welcome: .asciz "Hello, new World\n\r" #here we define the string |
|||
enter_number: .asciz "Enter a number: \n\r" |
|||
lower_msg: .asciz "\nYour number is to low :( \n\r" # 26 |
|||
higher_msg: .asciz "\nYour number is to high :( \n\r" # 27 |
|||
winner_msg: .asciz "\nYour are the CAMPION, :D \n\r" # 26 |
|||
|
|||
.macro mWriteString str #macro which calls a function to print a string |
|||
leaw \str, %si |
|||
call .writeStringIn |
|||
.endm |
|||
|
|||
# function to print the string |
|||
.writeStringIn: |
|||
lodsb |
|||
orb %al, %al |
|||
jz .writeStringOut |
|||
movb $0x0e, %ah |
|||
int $0x10 |
|||
jmp .writeStringIn |
|||
.writeStringOut: |
|||
ret |
|||
|
|||
.type get_number, @function |
|||
get_number: |
|||
|
|||
# save state before function |
|||
push %bp |
|||
mov %sp, %bp |
|||
|
|||
push %bx |
|||
push %cx |
|||
# Start of function |
|||
mWriteString enter_number |
|||
|
|||
mov $0, %ah |
|||
mov $0, %al |
|||
int $0x16 |
|||
|
|||
mov $0x0E, %ah |
|||
int $0x10 |
|||
|
|||
pop %cx |
|||
pop %bx |
|||
|
|||
mov %bp, %sp |
|||
pop %bp |
|||
ret |
|||
|
|||
.type string_to_int, @function |
|||
string_to_int: |
|||
/* Converts a string to an integer. Returns the integer in %rax. |
|||
* %rax: Address of string to convert. |
|||
*/ |
|||
push %bp |
|||
mov %sp, %bp |
|||
|
|||
push %bx |
|||
push %cx |
|||
|
|||
mov %ax, %dx |
|||
|
|||
cmp $47, %dx |
|||
jl not_a_num |
|||
cmp $57, %dx |
|||
jg not_a_num |
|||
# I multiply by 10 to shift the number one placement to the right to add the newest integer. |
|||
sub $48, %dx |
|||
jmp convertdone # In ascii, numbers start at 0 = 48, 1 = 49, 2 = 50 and so on. So I subtract 48 to get the digit. |
|||
|
|||
not_a_num: |
|||
xor %dx, %dx |
|||
|
|||
convertdone: |
|||
|
|||
pop %cx |
|||
pop %bx |
|||
|
|||
mov %bp, %sp |
|||
pop %bp |
|||
ret |
|||
|
|||
|
|||
_boot: |
|||
mWriteString welcome |
|||
|
|||
guess: |
|||
call get_number |
|||
xor %ah, %ah |
|||
call string_to_int |
|||
|
|||
cmp $5, %dx |
|||
|
|||
jl if_lower |
|||
je if_eg |
|||
jg if_higher |
|||
|
|||
if_lower: |
|||
mWriteString lower_msg |
|||
jmp guess |
|||
|
|||
if_higher: |
|||
mWriteString higher_msg |
|||
jmp guess |
|||
|
|||
if_eg: |
|||
mWriteString winner_msg |
|||
|
|||
#move to 510th byte from the start and append boot signature |
|||
. = _start + 510 |
|||
.byte 0x55 |
|||
.byte 0xaa |
@ -0,0 +1,135 @@ |
|||
#generate 16-bit code |
|||
.code16 |
|||
|
|||
#hint the assembler that here is the executable code located |
|||
.text |
|||
.globl _start; |
|||
#boot code entry |
|||
_start: |
|||
welcome: .asciz "Welcome to this very fine Guessing game \n\r" #here we define the string |
|||
enter_number: .asciz "Enter a number: \n" |
|||
lower_msg: .asciz "Your number is to low :( \n" # 26 |
|||
higher_msg: .asciz "Your number is to high :( \n" # 27 |
|||
winner_msg: .asciz "Your are the CAMPION, :D \n" # 26 |
|||
.macro mWriteString str #macro which calls a function to print a string |
|||
leaw \str, %si |
|||
call .writeStringIn |
|||
.endm |
|||
#jmp _boot |
|||
|
|||
# function to print the string |
|||
.writeStringIn: |
|||
lodsb |
|||
orb %al, %al |
|||
jz .writeStringOut |
|||
movb $0x0e, %ah |
|||
int $0x10 |
|||
jmp .writeStringIn |
|||
.writeStringOut: |
|||
ret #jump to boot code |
|||
|
|||
mWriteString welcome |
|||
|
|||
/* |
|||
guess: |
|||
call get_number |
|||
xor %ah, %ah |
|||
call string_to_int |
|||
|
|||
cmp $5, %dx |
|||
|
|||
jl if_lower # rax less then 50 |
|||
je if_eg |
|||
jg if_higher |
|||
if_lower: |
|||
mWriteString lower_msg |
|||
jmp guess |
|||
|
|||
if_higher: |
|||
mWriteString higher_msg |
|||
jmp guess |
|||
|
|||
if_eg: |
|||
mWriteString winner_msg #message length |
|||
|
|||
hlt |
|||
*/ |
|||
#_boot: |
|||
# mWriteString welcome |
|||
|
|||
|
|||
|
|||
#.type string_to_int, @function |
|||
#string_to_int: |
|||
/* Converts a string to an integer. Returns the integer in %rax. |
|||
* %rax: Address of string to convert. |
|||
*/ |
|||
/* |
|||
push %bp |
|||
mov %sp, %bp |
|||
|
|||
push %bx |
|||
push %cx |
|||
|
|||
mov %ax, %dx |
|||
|
|||
xor %ax, %ax |
|||
|
|||
cmp $47, %dx |
|||
jl not_a_num |
|||
cmp $57, %dx |
|||
jg not_a_num |
|||
# I multiply by 10 to shift the number one placement to the right to add the newest integer. |
|||
sub $48, %dx # In ascii, numbers start at 0 = 48, 1 = 49, 2 = 50 and so on. So I subtract 48 to get the digit. |
|||
|
|||
not_a_num: |
|||
xor %dx, %dx |
|||
|
|||
convertdone: |
|||
|
|||
pop %cx |
|||
pop %bx |
|||
|
|||
mov %bp, %sp |
|||
pop %bp |
|||
ret |
|||
|
|||
.type get_number, @function |
|||
get_number: |
|||
# .enter_char: |
|||
# mov $0, %ah |
|||
# mov $0, %al |
|||
# int $0x16 |
|||
|
|||
# mov $0x0E, %ah |
|||
# int $0x10 |
|||
|
|||
# jmp .enter_char |
|||
|
|||
# save state before function |
|||
push %bp |
|||
mov %sp, %bp |
|||
|
|||
push %bx |
|||
push %cx |
|||
# Start of function |
|||
mWriteString enter_number |
|||
|
|||
mov $0, %ah |
|||
mov $0, %al |
|||
int $0x16 |
|||
|
|||
mov $0x0E, %ah |
|||
int $0x10 |
|||
|
|||
pop %cx |
|||
pop %bx |
|||
|
|||
mov %bp, %sp |
|||
pop %bp |
|||
ret |
|||
*/ |
|||
#move to 510th byte from the start and append boot signature |
|||
. = _start + 510 |
|||
.byte 0x55 |
|||
.byte 0xaa |
@ -0,0 +1,337 @@ |
|||
%macro print_format 1 |
|||
lea si, [%1] |
|||
call _print_format |
|||
%endmacro |
|||
%macro print_format 2 |
|||
lea si, [%1] |
|||
push %2 |
|||
call _print_format |
|||
add sp, 2 |
|||
%endmacro |
|||
%macro print_format 3 |
|||
lea si, [%1] |
|||
push %3 |
|||
push %2 |
|||
call _print_format |
|||
add sp, 4 |
|||
%endmacro |
|||
%macro print_format 4 |
|||
lea si, [%1] |
|||
push %4 |
|||
push %3 |
|||
push %2 |
|||
call _print_format |
|||
add sp, 6 |
|||
%endmacro |
|||
%macro print_format 5 |
|||
lea si, [%1] |
|||
push %5 |
|||
push %4 |
|||
push %3 |
|||
push %2 |
|||
call _print_format |
|||
add sp, 8 |
|||
%endmacro |
|||
%macro print_format 6 |
|||
lea si, [%1] |
|||
push %6 |
|||
push %5 |
|||
push %4 |
|||
push %3 |
|||
push %2 |
|||
call _print_format |
|||
add sp, 10 |
|||
%endmacro |
|||
%macro print_format 7 |
|||
lea si, [%1] |
|||
push %7 |
|||
push %6 |
|||
push %5 |
|||
push %4 |
|||
push %3 |
|||
push %2 |
|||
call _print_format |
|||
add sp, 12 |
|||
%endmacro |
|||
|
|||
|
|||
BITS 16 |
|||
|
|||
dumpmem_hardcoded_args: |
|||
mov si, sp |
|||
mov si, [si] |
|||
mov cx, 400 |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dumpmem: |
|||
; Dumps memory |
|||
; IN 'si': Start address to dump from |
|||
; IN 'cx': Number of bytes do dump |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
pusha |
|||
|
|||
xor edx, edx |
|||
|
|||
.loop: |
|||
mov ax, word [esi + 2*edx] |
|||
inc edx |
|||
call dumpax |
|||
mov ax, (0xE<<8)|' ' ; print space |
|||
int 0x10 |
|||
loop .loop |
|||
.end: |
|||
|
|||
popa |
|||
ret |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dumpax: |
|||
; Prints the contens of ax as a hexadecimal number |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
pusha ; save registers |
|||
mov dx, ax |
|||
mov ah, 0xE ; Teletype output |
|||
|
|||
mov cx, 4 ; 4 nibbles in a 16 bit word |
|||
.print_loop: |
|||
rol dx, 4 ; rotate to next nibble |
|||
mov al, dl ; we copy to al because we need to mask only the low 4 bits |
|||
and al, 0xF ; Do the masking |
|||
add al, '0' ; convert to ASCII |
|||
|
|||
; If we are greater than 9 ascii... |
|||
cmp al, '9' |
|||
jbe .skip_diff_to_ascii_A |
|||
add al, 'A'-('9'+1) ; ...add 7 to make digits 10 to 15 be represented as 'A' to 'F' |
|||
.skip_diff_to_ascii_A: |
|||
|
|||
int 0x10 ; BIOS call 'output' |
|||
loop .print_loop |
|||
|
|||
popa ; restore registers |
|||
ret |
|||
|
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dumpax10: |
|||
; Prints the contens of ax as a decimal number |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
pusha |
|||
|
|||
mov bx, 10 ; Divisor |
|||
|
|||
xor cx, cx ; Digit count starts at 0 |
|||
|
|||
.loop_divide: ; finds digits and pushes them to stack |
|||
test ax, ax |
|||
jz .break_loop_divide |
|||
xor dx, dx |
|||
div bx ; dx = (dx:ax)%bx, ax = (dx:ax)/bx |
|||
push dx |
|||
inc cx ; Increase digit count |
|||
jmp .loop_divide |
|||
.break_loop_divide: |
|||
|
|||
.loop_print: |
|||
pop ax |
|||
add al, '0' ; Convert to ascii |
|||
mov ah, 0xE |
|||
int 0x10 |
|||
loop .loop_print |
|||
|
|||
popa |
|||
ret |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dumpax_char: |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
mov ah, 0xE |
|||
int 0x10 |
|||
ret |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
keyprint: |
|||
; Enters a loop where the keycode of each pressed key is printed |
|||
; [ESC] exits the loop |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
pusha |
|||
|
|||
mov si, .f_info |
|||
call print |
|||
|
|||
.keyprint_loop: |
|||
mov ax, 0x1000 ; BIOS call to wait for key |
|||
int 0x16 |
|||
|
|||
mov bx, ax ; Save KeyCode in bx |
|||
|
|||
print_format .f, ax, ax |
|||
|
|||
cmp bx, 0x011B ; ESC key |
|||
je .break_keyprint_loop |
|||
|
|||
jmp .keyprint_loop |
|||
.break_keyprint_loop: |
|||
|
|||
popa |
|||
ret |
|||
.f_info: db 13, 10, "Press keys to see their keycodes.",13,10,"Press [ESC] to exit.", 13, 10, 0 |
|||
.f: db "(%c: %x)", 13, 10, 0 |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dump_stack_registers: |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
push si |
|||
print_format .format_string, sp, bp |
|||
pop si |
|||
ret |
|||
.format_string: db "StackRegisters(SP:%x BP:%x)", 0 |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dump_general_registers: |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
push si |
|||
print_format .format_string, ax, cx, dx, bx, si, di |
|||
pop si |
|||
ret |
|||
.format_string: db "GeneralRegisters(ax:%x cx:%x dx:%x bx:%x si:%x di:%x)", 0 |
|||
|
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dump_segment_registers: |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
push si |
|||
print_format .format_string, ss, cs, ds, es, fs, gs |
|||
pop si |
|||
ret |
|||
.format_string: db "SegmentRegisters(Stack:%x Code:%x Data:%x Extra:%x F:%x G:%x)", 0 |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
_print_format: |
|||
; IN: variable number of 16-bit numbers on stack |
|||
; IN: 'si' points to beginning of format string with the following format: |
|||
; %x in string replaced with hexadecimal representation |
|||
; %d in string replaced with decimal representation |
|||
; %% in string replaced with literal % sign |
|||
; |
|||
; EXAMPLE call: |
|||
; push word 1337 |
|||
; push word 0xbeef |
|||
; push word 0xdead |
|||
; lea si, [.FORMAT] |
|||
; call print_format ; output: "(DEAD-BEEF){1337} 100%" |
|||
; add sp, 6 |
|||
; (...) |
|||
; .FORMAT: db "(%x-%x){%d} 100%%",0 |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
push bp |
|||
mov bp, sp |
|||
pushf |
|||
pusha |
|||
|
|||
lea bp, [bp+4] |
|||
|
|||
.outer_loop: |
|||
mov ah, 0xE ; Specify 'int 0x10' 'teletype output' function |
|||
|
|||
.print_loop: |
|||
lodsb ; al = *si++ |
|||
cmp al, '%' |
|||
je .break_print |
|||
test al, al |
|||
jz .break_outer |
|||
int 0x10 |
|||
jmp .print_loop |
|||
.break_print: |
|||
|
|||
lodsb |
|||
cmp al, 'x' |
|||
je .format_hex |
|||
cmp al, 'd' |
|||
je .format_dec |
|||
cmp al, 'c' |
|||
je .format_char |
|||
cmp al, '%' |
|||
je .print_literal_percent |
|||
|
|||
.format_hex: |
|||
lea cx, [dumpax] |
|||
jmp .print_ax |
|||
.format_dec: |
|||
lea cx, [dumpax10] |
|||
jmp .print_ax |
|||
.format_char: |
|||
lea cx, [dumpax_char] |
|||
|
|||
.print_ax: |
|||
mov ax, [bp] |
|||
lea bp, [bp+2] |
|||
call cx |
|||
jmp .outer_loop |
|||
|
|||
.print_literal_percent: |
|||
mov ax, (0xE<<8)|'%' |
|||
int 0x10 |
|||
jmp .outer_loop |
|||
.break_outer: |
|||
|
|||
popa |
|||
popf |
|||
pop bp |
|||
ret |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dump_dx_as_two_chars: |
|||
; IN dh: first char |
|||
; IN dl: second char |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
push ax |
|||
mov ah, 0xE |
|||
mov al, dh |
|||
int 0x10 |
|||
mov al, dl |
|||
int 0x10 |
|||
pop ax |
|||
ret |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
dump_status_flags: |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
pushf |
|||
push si |
|||
push ax |
|||
push bx |
|||
|
|||
lahf |
|||
mov bl, ah |
|||
|
|||
lea si, [.flags_string] |
|||
|
|||
mov ah, 0xE ; Specify 'int 0x10' 'teletype output' function |
|||
|
|||
.outer_loop: |
|||
; [AL = Character, BH = Page Number, BL = Colour (in graphics mode)] |
|||
.print_loop: |
|||
lodsb ; Load byte at address SI into AL, and increment SI |
|||
cmp al, '%' |
|||
je .break_print_loop ; If the character is zero (NUL), stop writing the string |
|||
test al, al |
|||
jz .break_outer_loop |
|||
int 0x10 ; Otherwise, print the character via 'int 0x10' |
|||
jmp .print_loop ; Repeat for the next character |
|||
.break_print_loop: |
|||
|
|||
ror bl, 1 |
|||
mov al, bl |
|||
and al, 1 |
|||
add al, '0' |
|||
int 0x10 |
|||
jmp .outer_loop |
|||
|
|||
.break_outer_loop: |
|||
|
|||
pop bx |
|||
pop ax |
|||
pop si |
|||
popf |
|||
ret |
|||
.flags_string: db "Flags(Sign:% Zero:% ?:% Adjust:% ?:% Parity:% ?:% Carry:%)", 0 |
@ -0,0 +1,72 @@ |
|||
BITS 16 |
|||
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
print: |
|||
; Prints string in si |
|||
; IN si: zero terminated string to print |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
mov ah, 0xE ; Specify 'int 0x10' 'teletype output' function |
|||
; [AL = Character, BH = Page Number, BL = Colour (in graphics mode)] |
|||
.printchar: |
|||
lodsb ; Load byte at address SI into AL, and increment SI |
|||
test al, al |
|||
jz .done ; If the character is zero (NUL), stop writing the string |
|||
int 0x10 ; Otherwise, print the character via 'int 0x10' |
|||
jmp .printchar ; Repeat for the next character |
|||
.done: |
|||
ret |
|||
|
|||
printCRLF: |
|||
mov ah, 0xE |
|||
mov al, 13 |
|||
int 0x10 |
|||
mov al, 10 |
|||
int 0x10 |
|||
ret |
|||
|
|||
printSpace: |
|||
mov ax, 0xE20 |
|||
int 0x10 |
|||
ret |
|||
|
|||
printALChar: |
|||
mov ah, 0xE |
|||
mov bl, 0x02 ;color |
|||
int 0x10 |
|||
ret |
|||
|
|||
; Changing the screen the user i looking at. |
|||
; value in 'al' is the screen we want to switch to. |
|||
; starting from 0x00 |
|||
os_change_screen: |
|||
; Here the addresses for the screens stack |
|||
; and base pointer has to be set. |
|||
mov ah, 0x05 |
|||
int 0x10 |
|||
ret |
|||
|
|||
os_clear_screen: |
|||
pusha |
|||
; move cursor to the bootom |
|||
xor ax, ax |
|||
xor bx, bx |
|||
mov ah, 0x02 |
|||
mov bh, 0x00 ; page number 0 |
|||
mov dh, 0x18 ; row zero |
|||
mov dl, 0x00 ; coloumn zero |
|||
int 0x10 |
|||
xor cx, cx |
|||
.loop: |
|||
call printCRLF |
|||
add cx, 1 |
|||
cmp cx, 0x19 ; until blank screen |
|||
jne .loop |
|||
; Move curser back to the top of the screen |
|||
mov ah, 0x02 |
|||
mov bh, 0x00 ; page number 0 |
|||
mov dh, 0x00 ; row zero |
|||
mov dl, 0x00 ; coloumn zero |
|||
int 0x10 |
|||
|
|||
popa |
|||
ret |
@ -0,0 +1,39 @@ |
|||
BITS 16 |
|||
; THIS LIBARY IS IN REALLY BAD SHAPE |
|||
; Power_off is okay to use |
|||
|
|||
power_check: |
|||
;perform an installation check |
|||
mov ah,53h ;this is an APM command |
|||
mov al,00h ;installation check command |
|||
xor bx,bx ;device id (0 = APM BIOS) |
|||
int 15h ;call the BIOS function through interrupt 15h |
|||
call printCRLF |
|||
call dumpax |
|||
;jc APM_error ;if the carry flag is set there was an error |
|||
;the function was successful |
|||
;AX = APM version number |
|||
;AH = Major revision number (in BCD format) |
|||
;AL = Minor revision number (also BCD format) |
|||
;BX = ASCII characters "P" (in BH) and "M" (in BL) |
|||
;CX = APM flags (see the official documentation for more details) |
|||
ret |
|||
|
|||
power_enable: |
|||
;Enable power management for all devices |
|||
mov ah,53h ;this is an APM command |
|||
mov al,08h ;Change the state of power management... |
|||
mov bx,0001h ;...on all devices to... |
|||
mov cx,0001h ;...power management on. |
|||
int 15h ;call the BIOS function through interrupt 15h |
|||
;jc APM_error ;if the carry flag is set there was an error |
|||
ret |
|||
|
|||
power_off: |
|||
;actual shutdown command |
|||
mov ah, 0x53 |
|||
mov al, 0x07 |
|||
mov bx, 0x1 |
|||
mov cx, 0x3 |
|||
int 0x15 |
|||
ret |
@ -0,0 +1,57 @@ |
|||
BITS 16 |
|||
; Compares two strings |
|||
; IN si: the first (zero terminated) string |
|||
; IN di: the second (zero terminated) string |
|||
; OUT SF and ZF (same semantics as cmp) |
|||
stringcompare: |
|||
push bx |
|||
push si |
|||
push di |
|||
.loop: |
|||
mov bl, [si] |
|||
mov bh, [di] |
|||
cmp bl, bh |
|||
jne .end |
|||
test bl, bl ; bl and bh are the same, so bl = 0 => dl = 0 |
|||
jz .end |
|||
inc si |
|||
inc di |
|||
jmp .loop |
|||
.end: |
|||
pop di |
|||
pop si |
|||
pop bx |
|||
|
|||
ret |
|||
|
|||
zstring_to_integer: |
|||
;IN: si Pointer to string |
|||
;OUT: ax result in binary |
|||
push bx |
|||
push si |
|||
push cx |
|||
push dx |
|||
xor ax, ax |
|||
xor bx, bx |
|||
xor cx, cx |
|||
xor dx, dx |
|||
mov bx, 10 |
|||
.loop: |
|||
mov cl, [si] |
|||
cmp cl, 0 |
|||
je .end |
|||
sub cl,'0' |
|||
cmp cl, 9 |
|||
ja .end ; next number is not a number, or its a zero, and then we are done |
|||
; multiply by 10, and add the new number. |
|||
mul bx |
|||
add ax, cx |
|||
inc si |
|||
jmp .loop |
|||
|
|||
.end: |
|||
pop dx |
|||
pop cx |
|||
pop si |
|||
pop bx |
|||
ret |
@ -0,0 +1,290 @@ |
|||
BITS 16 |
|||
svim: |
|||
pusha ; save state before program |
|||
;mov si, .os_clear_screen_str |
|||
;call print |
|||
xor bx, bx |
|||
call os_clear_screen |
|||
;xor cx, cx ; Upper and left coordinate |
|||
;mov bh, 0x0a ; color for new screen 0 = black a = light green |
|||
;mov dh, 0xff ; Select all screen |
|||
;mov dl, 0xff ; Select all screen |
|||
;mov ah, 0x07 ; scrool down |
|||
;mov al, 0x00 ; scrool 0 lines (means blank screen ) |
|||
;int 0x10 |
|||
|
|||
mov ah, 0x02 |
|||
mov bh, 0x00 ; page number 0 |
|||
mov dh, 0x00 ; row zero |
|||
mov dl, 0x17 ; coloumn zero |
|||
int 0x10 |
|||
mov si, .welcome_svim_select_file |
|||
call print |
|||
call printCRLF |
|||
mov si, .seperate_line |
|||
call print |
|||
call vsfs_list_files_command |
|||
|
|||
; move cursor to the bootom |
|||
xor ax, ax |
|||
xor bx, bx |
|||
mov ah, 0x02 |
|||
mov bh, 0x00 ; page number 0 |
|||
mov dh, 0x17 ; row zero |
|||
mov dl, 0x00 ; coloumn zero |
|||
int 0x10 |
|||
|
|||
mov si, .welcome_svim |
|||
call print |
|||
call printCRLF |
|||
mov si, .welcome_svim_enter_fileindex |
|||
call print |
|||
|
|||
; Ask the user for the filename |
|||
xor bx, bx |
|||
xor cx, cx ; are going to be the counter |
|||
xor dx, dx |
|||
.enter_fileindex_loop: |
|||
push cx |
|||
.loop_no_push: |
|||
mov ax, 0x10 ; BIOS call to wait for key |
|||
int 0x16 |
|||
cmp ax, 0x1c0d ; enter key |
|||
je .fileindex_done |
|||
cmp ax, 0x0e08 ; backspace |
|||
jne .no_enter_fileindex |
|||
cmp cx, 0 |
|||
je .loop_no_push |
|||
pop cx |
|||
sub cx, 1 |
|||
mov bx, .buffer_for_svim |
|||
add bx, cx |
|||
mov BYTE [bx], 0 |
|||
; Go back one space |
|||
mov ax, 0x0e08 ; ah=0x0e means teletype output. al=0x08 means backspace character. |
|||
int 0x10 |
|||
|
|||
; Place a NULL |
|||
mov al, 0x0 ; NULL |
|||
int 0x10 |
|||
|
|||
; Go back one space again as the above print of NULL pushes the cursor forward again. |
|||
mov ax, 0x0e08 |
|||
int 0x10 |
|||
jmp .enter_fileindex_loop |
|||
|
|||
.no_enter_fileindex: |
|||
mov bh, 0x00 |
|||
mov bl, 0x02 |
|||
mov ah, 0x0E |
|||
int 0x10 ; print char |
|||
pop cx |
|||
mov bx, .buffer_for_svim |
|||
add bx, cx |
|||
mov [bx], al |
|||
add cx, 1 |
|||
; fileindex must only be 120 chars |
|||
cmp cx, 120 |
|||
jae .fileindex_done |
|||
|
|||
jmp .enter_fileindex_loop |
|||
|
|||
.fileindex_done: |
|||
pop cx ; Cleanup, and now contain filename size |
|||
mov ax, cx |
|||
add ax, .buffer_for_svim |
|||
mov bx, ax |
|||
mov BYTE [bx], 0 |
|||
mov si, .buffer_for_svim |
|||
call zstring_to_integer ; ax now contain the interger index for the file |
|||
mov [.fileindex_for_open_file], ax ; save the file index |
|||
|
|||
call os_clear_screen |
|||
|
|||
; move cursor to the bootom |
|||
xor ax, ax |
|||
xor bx, bx |
|||
mov ah, 0x02 |
|||
mov bh, 0x00 ; page number 0 |
|||
mov dh, 0x17 ; row zero |
|||
mov dl, 0x00 ; coloumn zero |
|||
int 0x10 |
|||
|
|||
mov si, .seperate_line |
|||
call print |
|||
mov si, .welcome_svim |
|||
call print |
|||
|
|||
; move cursor to the top |
|||
xor ax, ax |
|||
xor bx, bx |
|||
mov ah, 0x02 |
|||
mov bh, 0x00 ; page number 0 |
|||
mov dh, 0x00 ; row zero |
|||
mov dl, 0x00 ; coloumn zero |
|||
int 0x10 |
|||
; Load from disk and, enter it, into the buffer |
|||
|
|||
mov si, .welcome_svim_select_file |
|||
call print |
|||
|
|||
mov ax, [.fileindex_for_open_file] |
|||
|
|||
call dumpax10 |
|||
call printCRLF |
|||
|
|||
mov si, .seperate_line |
|||
call print |
|||
|
|||
mov ax, [.fileindex_for_open_file] |
|||
|
|||
mov ch, al ; move the fileindex in the ch |
|||
mov bx, ds |
|||
mov es, bx |
|||
xor bx, bx |
|||
mov bx, .buffer_for_svim |
|||
xor ax, ax |
|||
mov ah, 0x02 ;Read sectors from drive |
|||
mov al, 0x04 ;Number of sectors to read (8 * 512 = 4096 bytes) |
|||
mov cl, 0x01 ;First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov dh, 0x00 ;Head number |
|||
mov dl, [global_disk_identifier] ;Drive number |
|||
int 0x13 |
|||
|
|||
mov bx, .buffer_for_svim |
|||
add bx, 2046 |
|||
mov ax, [bx] |
|||
mov [.buffer_counter_svim], ax |
|||
; print buffer |
|||
mov si, .buffer_for_svim |
|||
mov es, si |
|||
call print |
|||
|
|||
.svim_loop: |
|||
xor bx, bx |
|||
xor cx, cx |
|||
xor dx, dx |
|||
mov ax, 0x1000 ; BIOS call to wait for key |
|||
int 0x16 |
|||
cmp ax, 0x1c0d ; enter key |
|||
jne .no_enter |
|||
mov bx, .buffer_for_svim |
|||
add bx, [.buffer_counter_svim] |
|||
mov BYTE [bx], 13 ; put char in the buffer |
|||
mov BYTE [bx + 1], 10 ; put char in the buffer |
|||
mov bx, [.buffer_counter_svim] |
|||
add bx, 0x02 |
|||
mov [.buffer_counter_svim], bx |
|||
|
|||
xor bx, bx |
|||
xor cx, cx |
|||
xor dx, dx |
|||
mov ax, 0x0e0d |
|||
int 0x10 |
|||
|
|||
mov ax, 0x0e0a |
|||
int 0x10 |
|||
|
|||
jmp .svim_loop |
|||
|
|||
.no_enter: |
|||
cmp ax, 0x11b ; ESC key |
|||
je .end_svim |
|||
;cmp ax, 0x3c00 ; f2 key |
|||
;je .f_key_pushed |
|||
cmp ax, 0x0e08 ; backspace |
|||
je .backspace_pushed |
|||
mov bx, ax |
|||
mov ax, 0xe20 |
|||
mov al, bl |
|||
mov bx, .buffer_for_svim |
|||
add bx, [.buffer_counter_svim] |
|||
mov [bx], al ; put char in the buffer |
|||
mov bx, [.buffer_counter_svim] |
|||
add bx, 0x01 |
|||
mov [.buffer_counter_svim], bx |
|||
|
|||
int 0x10 ; print char |
|||
jmp .svim_loop |
|||
.end_svim: |
|||
; save the written buffer |
|||
;AH 03h |
|||
;AL Sectors To Write Count |
|||
;CH Track |
|||
;CL Sector |
|||
;DH Head |
|||
;DL Drive |
|||
;ES:BX Buffer Address Pointer |
|||
mov ax, [.buffer_counter_svim] |
|||
mov bx, .buffer_for_svim |
|||
add bx, 2046 |
|||
mov [bx], ax |
|||
|
|||
mov bx, ds |
|||
mov es, bx |
|||
mov bx, .buffer_for_svim |
|||
|
|||
mov ax, [.fileindex_for_open_file] |
|||
mov ch, al ; move the fileindex in the ch |
|||
|
|||
mov ah, 0x03 ;Write sectors to drive |
|||
mov al, 0x04 ;Number of sectors to write (8 * 512 = 4096 bytes) |
|||
mov cl, 0x01 ;First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov dh, 0x00 ;Head number |
|||
mov dl, [global_disk_identifier] ;Drive number |
|||
int 0x13 ;Low level disk services |
|||
|
|||
; clean up swim |
|||
;xor bx, bx |
|||
;xor cx, cx ; Upper and left coordinate |
|||
;mov bh, 0x0f ; color for new screen 0 = black f = white |
|||
;mov dh, 0xff ; Select all screen |
|||
;mov dl, 0xff ; Select all screen |
|||
;mov ah, 0x07 ; scrool down |
|||
;mov al, 0x00 ; scrool 0 lines (means blank screen ) |
|||
;int 0x10 |
|||
call os_clear_screen |
|||
popa |
|||
ret |
|||
|
|||
.backspace_pushed: |
|||
mov bx, [.buffer_counter_svim] |
|||
cmp bx, 0 |
|||
je .svim_loop |
|||
;print_format .debug_buffer_counter, bx |
|||
mov cx, bx |
|||
sub cx, 1 |
|||
mov bx, .buffer_for_svim |
|||
add bx, cx |
|||
mov BYTE [bx], 0 |
|||
mov [.buffer_counter_svim], cx |
|||
;print_format .debug_buffer_counter, cx |
|||
; Go back one space |
|||
mov ax, 0x0e08 ; ah=0x0e means teletype output. al=0x08 means backspace character. |
|||
int 0x10 |
|||
|
|||
; Place a NULL |
|||
mov al, 0x0 ; NULL |
|||
int 0x10 |
|||
|
|||
; Go back one space again as the above print of NULL pushes the cursor forward again. |
|||
mov ax, 0x0e08 |
|||
int 0x10 |
|||
jmp .svim_loop |
|||
|
|||
|
|||
;.f_key_pushed: |
|||
;mov al, 0x01 ;arg: index 1 |
|||
;call os_change_screen |
|||
;jmp .svim_loop |
|||
|
|||
;.load_buffer_svim: |
|||
|
|||
.debug_buffer_counter db 'Buffer count: %d', 13, 10, 0 |
|||
.welcome_svim db 'Vim like text editor for SingOS, ESC to exit', 0 |
|||
.welcome_svim_select_file db 'svim - Open file: ', 0 |
|||
.welcome_svim_enter_fileindex db 'Enter fileindex: ', 0 |
|||
.seperate_line db '________________________________________________________________________________', 0 |
|||
.fileindex_for_open_file dw 0 |
|||
.buffer_for_svim times 2048 db 0 ; db 'this is the buffer', 0, times 32 db 0 |
|||
.buffer_counter_svim dw 0 |
@ -0,0 +1,4 @@ |
|||
BITS 16 |
|||
|
|||
mem_get_zstack_buffer: |
|||
; INPUT size of zeroed buffer ax in bytes |
@ -0,0 +1,342 @@ |
|||
BITS 16 |
|||
vsfs_format_disk: |
|||
; When SingOS it booted for the first time, |
|||
; we have to format the disk to create the global structure |
|||
; of the VSFS. |
|||
pusha |
|||
;AH 03h |
|||
;AL Sectors To Write Count |
|||
;CH Track |
|||
;CL Sector |
|||
;DH Head |
|||
;DL Drive |
|||
|
|||
; Set the es to point to the data segment, |
|||
; this is the global segment, where we calculate all |
|||
; our adresses from |
|||
; ES:BX Buffer Address Pointer |
|||
mov bx, ds |
|||
mov es, bx |
|||
|
|||
; Set the bx to point to the pointer of the sector we have to write |
|||
; to the disk. |
|||
mov bx, .vsfs_format_disk_buffer |
|||
mov ah, 0x03 ;Write sectors to drive |
|||
mov al, 0x01 ;Number of sectors to write (8 * 512 = 4096 bytes) |
|||
mov cl, 0x01 ;First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov ch, 0x08 |
|||
mov dh, 0x00 ;Head number |
|||
mov dl, [global_disk_identifier] ;Drive number |
|||
int 0x13 ;Low level disk services |
|||
|
|||
popa |
|||
ret |
|||
|
|||
.vsfs_format_disk_buffer db 'VSFS v0.1', 13, 10, '(VerySimpelFileSystem)', 13, 10, 'Developed to SingOS', 13, 10, 'by Jorn Guldberg', 13, 10, 0 ; 66 chars + 8 bytes |
|||
times 431 db 0 |
|||
dw 8, 0, 9 ; Start index, number of files, next free index |
|||
|
|||
vsfs_get_fs_info: |
|||
pusha |
|||
mov bx, ds |
|||
mov es, bx |
|||
mov bx, vsfs_loading_buffer |
|||
|
|||
mov ah, 0x02 ; Read sectors from drive |
|||
mov al, 0x01 ; Number of sectors to read (8 * 512 = 4096 bytes) |
|||
mov ch, 0x08 ; cylinder |
|||
mov cl, 0x01 ; First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov dh, 0x00 ; Head number |
|||
mov dl, [global_disk_identifier] ; Drive number |
|||
int 0x13 |
|||
|
|||
mov si, vsfs_loading_buffer |
|||
call print |
|||
popa |
|||
ret |
|||
|
|||
vsfs_read_file_index_in_ax: |
|||
; INPUT ax = file index |
|||
; INPUT bx = filebuffer |
|||
pusha ; save all register state |
|||
;call vsfs_convert_index_into_regs |
|||
;mov bx, .buffer_for_svim |
|||
push bx |
|||
mov bx, ds |
|||
mov es, bx |
|||
pop bx |
|||
|
|||
mov ch, al ; Low 8 bits of cylinder |
|||
; the file index into ch, we need to calculatet this, if the number is larger than 16-bits |
|||
mov ah, 0x02 ; Read sectors from drive |
|||
mov al, 0x01 ; Number of sectors to read (8 * 512 = 4096 bytes) |
|||
mov cl, 0x01 ; First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov dh, 0x00 ; Head number |
|||
mov dl, [global_disk_identifier] ; Drive number |
|||
int 0x13 |
|||
popa |
|||
ret |
|||
|
|||
|
|||
vsfs_write_file_to_index_in_ax: |
|||
pusha ; save all register state |
|||
;AH 03h |
|||
;AL Sectors To Write Count |
|||
;CH Track |
|||
;CL Sector |
|||
;DH Head |
|||
;DL Drive |
|||
;ES:BX Buffer Address Pointer |
|||
mov bx, ds |
|||
mov es, bx |
|||
xor bx, bx |
|||
;mov bx, .buffer_for_svim |
|||
xor cx, cx |
|||
xor ax, ax |
|||
mov ah, 0x03 ;Write sectors to drive |
|||
mov al, 0x01 ;Number of sectors to write (8 * 512 = 4096 bytes) |
|||
mov cl, 0x03 ;First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov ch, 0x02 |
|||
mov dh, 0x01 ;Head number |
|||
mov dl, [global_disk_identifier] ;Drive number |
|||
int 0x13 ;Low level disk services |
|||
popa |
|||
ret |
|||
|
|||
vsfs_convert_index_into_regs: |
|||
; This function takes a file index in ax, do the calculations |
|||
; to set the registers to the right place at the disk |
|||
; CH Track |
|||
; CL Sector |
|||
; DH Head |
|||
; The rest of the parameters is set in the read and write function. |
|||
|
|||
ret |
|||
|
|||
vsfs_create_file: |
|||
; ax pointer to filename |
|||
; bx size |
|||
; cx fileIndex |
|||
|
|||
pusha ; save all register state |
|||
|
|||
mov si, .vsfs_create_file_type_filename |
|||
call print |
|||
|
|||
; Ask the user for the filename |
|||
xor bx, bx |
|||
xor cx, cx ; are going to be the counter |
|||
xor dx, dx |
|||
.enter_filename_loop: |
|||
push cx |
|||
mov ax, 0x10 ; BIOS call to wait for key |
|||
int 0x16 |
|||
cmp ax, 0x1c0d ; enter key |
|||
je .filename_done |
|||
|
|||
cmp ax, 0x0e08 ; backspace |
|||
jne .no_enter |
|||
pop cx |
|||
cmp cx, 0 |
|||
je .enter_filename_loop |
|||
|
|||
sub cx, 1 |
|||
mov bx, .new_filename_buffer |
|||
add bx, cx |
|||
mov BYTE [bx], 0 |
|||
; Go back one space |
|||
mov ax, 0x0e08 ; ah=0x0e means teletype output. al=0x08 means backspace character. |
|||
int 0x10 |
|||
|
|||
; Place a NULL |
|||
mov al, 0x0 ; NULL |
|||
int 0x10 |
|||
|
|||
; Go back one space again as the above print of NULL pushes the cursor forward again. |
|||
mov ax, 0x0e08 |
|||
int 0x10 |
|||
jmp .enter_filename_loop |
|||
|
|||
.no_enter: |
|||
mov bh, 0x00 |
|||
mov bl, 0x02 |
|||
mov ah, 0x0E |
|||
int 0x10 ; print char |
|||
pop cx |
|||
mov bx, .new_filename_buffer |
|||
add bx, cx |
|||
mov [bx], al |
|||
add cx, 1 |
|||
; filename must only be 120 chars |
|||
cmp cx, 120 |
|||
jae .filename_done |
|||
|
|||
jmp .enter_filename_loop |
|||
|
|||
.filename_done: |
|||
pop cx ; Cleanup, and now contain filename size |
|||
mov bx, .new_filename_buffer |
|||
add bx, cx |
|||
mov BYTE [bx], 0 |
|||
call printCRLF |
|||
|
|||
|
|||
; We first need to know the index for the file. |
|||
; The next avaliable index are we going to get from the |
|||
; FSinfo sctor of the disk: |
|||
mov bx, ds |
|||
mov es, bx |
|||
|
|||
mov bx, vsfs_loading_buffer |
|||
mov ch, 0x08 ; Low 8 bits of cylinder |
|||
; the file index into ch, we need to calculatet this, if the number is larger than 16-bits |
|||
mov ah, 0x02 ; Read sectors from drive |
|||
mov al, 0x01 ; Number of sectors to read (8 * 512 = 4096 bytes) |
|||
mov cl, 0x01 ; First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov dh, 0x00 ; Head number |
|||
mov dl, [global_disk_identifier] ; Drive number |
|||
int 0x13 |
|||
|
|||
mov ax, [vsfs_loading_buffer + 510] |
|||
mov [.to_write_fileindex], ax |
|||
|
|||
; We have to do modulo 4, to know where in the sector the |
|||
; file entry has to be written |
|||
add DWORD [vsfs_loading_buffer + 510], 1 |
|||
add DWORD [vsfs_loading_buffer + 508], 1 |
|||
|
|||
mov bx, vsfs_loading_buffer |
|||
mov ah, 0x03 ;Write sectors to drive |
|||
mov al, 0x01 ;Number of sectors to write (8 * 512 = 4096 bytes) |
|||
mov cl, 0x01 ;First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov ch, 0x08 |
|||
mov dh, 0x00 ;Head number |
|||
mov dl, [global_disk_identifier] ;Drive number |
|||
int 0x13 ;Low level disk services |
|||
|
|||
; Now we have the index in ax. |
|||
|
|||
;AH 03h |
|||
;AL Sectors To Write Count |
|||
;CH Track |
|||
;CL Sector |
|||
;DH Head |
|||
;DL Drive |
|||
|
|||
; Set the es to point to the data segment, |
|||
; this is the global segment, where we calculate all |
|||
; our adresses from |
|||
; ES:BX Buffer Address Pointer |
|||
mov bx, ds |
|||
mov es, bx |
|||
|
|||
mov bx, [.to_write_fileindex] |
|||
sub bx, 0x07 ; Det skal den bare |
|||
mov cl, bl ; First sector to write (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
; Set the bx to point to the pointer of the sector we have to write |
|||
; to the disk. |
|||
mov bx, .new_filename_buffer |
|||
mov ah, 0x03 ;Write sectors to drive |
|||
mov al, 0x01 ;Number of sectors to write (8 * 512 = 4096 bytes) |
|||
mov ch, 0x08 |
|||
mov dh, 0x00 ;Head number |
|||
mov dl, [global_disk_identifier] ;Drive number |
|||
int 0x13 ;Low level disk services |
|||
popa |
|||
ret |
|||
|
|||
.vsfs_create_file_type_filename db 'Enter filename: ', 0 |
|||
.new_filename_buffer times 122 db 0 |
|||
.new_file_size dw 0, 0 |
|||
.to_write_fileindex dw 0 |
|||
|
|||
vsfs_list_files_command: |
|||
; This function takes the adress of the first sector of the disk |
|||
; which the OS has to know |
|||
; the adress is given by ax |
|||
|
|||
; Check which registers to save |
|||
pusha |
|||
|
|||
; Load the master table into memory |
|||
;mov ax, 8 ; file index for master record |
|||
;mov bx, vsfs_loading_buffer ; pointer to the input buffer |
|||
;call vsfs_read_file_index_in_ax ; call the fucntion which read the master record |
|||
; TODO we might want this to be in memory at all times |
|||
; loaded already from boot |
|||
|
|||
mov bx, ds |
|||
mov es, bx |
|||
|
|||
mov si, .ls_header |
|||
call print |
|||
|
|||
mov si, .seperate_line |
|||
call print |
|||
|
|||
mov BYTE [.ls_counter], 1 |
|||
.load_next_fileinfo: |
|||
add BYTE [.ls_counter], 1 |
|||
mov bl, [.ls_counter] |
|||
mov cl, bl ; First sector to read (bits 0-5), upper bits of cylinder (bits 6-7) |
|||
mov bx, vsfs_loading_buffer |
|||
;mov ch, al ; Low 8 bits of cylinder |
|||
; the file index into ch, we need to calculatet this, if the number is larger than 16-bits |
|||
mov ah, 0x02 ; Read sectors from drive |
|||
mov al, 0x01 ; Number of sectors to read (8 * 512 = 4096 bytes) |
|||
mov ch, 0x08 ; cylinder |
|||
mov dh, 0x00 ; Head number |
|||
mov dl, [global_disk_identifier] ; Drive number |
|||
int 0x13 |
|||
|
|||
mov ax, [vsfs_loading_buffer + 126] |
|||
mov bx, ax |
|||
mov cx, ' ' |
|||
mov dx, 'X' |
|||
|
|||
cmp ax, 0 |
|||
je .end_ls |
|||
cmp ax, 10 |
|||
ja .index_over_10 |
|||
mov [.fileentry_line + 3 ], cx |
|||
mov [.fileentry_line + 4 ], cx |
|||
add bx, 48 ; get ascii value |
|||
mov [.fileentry_line + 5 ], bl |
|||
jmp .stop_index |
|||
.index_over_10: |
|||
cmp ax, 10 |
|||
ja .index_over_100 |
|||
mov [.fileentry_line + 3 ], cx |
|||
mov [.fileentry_line + 4 ], dx |
|||
mov [.fileentry_line + 5 ], dx |
|||
jmp .stop_index |
|||
|
|||
.index_over_100: |
|||
mov [.fileentry_line + 3 ], dx |
|||
mov [.fileentry_line + 4 ], dx |
|||
mov [.fileentry_line + 5 ], dx |
|||
|
|||
|
|||
.stop_index: |
|||
|
|||
mov si, .fileentry_line ; printing the buffer |
|||
call print |
|||
mov si, vsfs_loading_buffer ; printing the buffer |
|||
call print |
|||
|
|||
call printCRLF |
|||
mov si, .seperate_line |
|||
|
|||
call print |
|||
jmp .load_next_fileinfo |
|||
|
|||
.end_ls: |
|||
popa |
|||
ret |
|||
|
|||
.ls_counter db 0 |
|||
.ls_header db 'List of files:', 13, 10, 'Index | Filename ', 13, 10, 0 |
|||
.seperate_line db '- - - - - - - - - - - - - - - - ', 13, 10, 0 |
|||
.fileentry_line db ' 456 | ', 0 |
|||
|
|||
vsfs_loading_buffer times 512 db 0 |
Loading…
Reference in new issue