@ -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 |