commit 62e1d36c38d18fbc417eb89bd4a79c8b8c4d2fee Author: Jørn Guldberg Date: Fri Sep 6 21:57:00 2019 +0200 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2e0c600 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +*.swp +*.sublime* +*.img +*.bin \ No newline at end of file diff --git a/CLI/CLI.nasm b/CLI/CLI.nasm new file mode 100644 index 0000000..d65a012 --- /dev/null +++ b/CLI/CLI.nasm @@ -0,0 +1,173 @@ +BITS 16 +;CLI + +;Command syntax: +;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 + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..23c4dba --- /dev/null +++ b/README.md @@ -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 +``` diff --git a/bootloader.nasm b/bootloader.nasm new file mode 100644 index 0000000..60b0027 --- /dev/null +++ b/bootloader.nasm @@ -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 + diff --git a/build b/build new file mode 100755 index 0000000..3652081 --- /dev/null +++ b/build @@ -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" \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..ba74090 --- /dev/null +++ b/build.sh @@ -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" + diff --git a/kernel.nasm b/kernel.nasm new file mode 100644 index 0000000..7bef9b4 --- /dev/null +++ b/kernel.nasm @@ -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. diff --git a/legacy/README.md b/legacy/README.md new file mode 100644 index 0000000..3e0b39f --- /dev/null +++ b/legacy/README.md @@ -0,0 +1 @@ +SingOs diff --git a/legacy/compile_folder/README.md b/legacy/compile_folder/README.md new file mode 100644 index 0000000..c16b22b --- /dev/null +++ b/legacy/compile_folder/README.md @@ -0,0 +1,2 @@ +Folder of compiling the OS +This folder has to be empty on the repository diff --git a/legacy/source/build.sh b/legacy/source/build.sh new file mode 100755 index 0000000..6570a4b --- /dev/null +++ b/legacy/source/build.sh @@ -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 diff --git a/legacy/source/generic_build.sh b/legacy/source/generic_build.sh new file mode 100755 index 0000000..e8b9976 --- /dev/null +++ b/legacy/source/generic_build.sh @@ -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 diff --git a/legacy/source/info.txt b/legacy/source/info.txt new file mode 100644 index 0000000..76c1921 --- /dev/null +++ b/legacy/source/info.txt @@ -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 diff --git a/legacy/source/mytest.s b/legacy/source/mytest.s new file mode 100644 index 0000000..3fed3ef --- /dev/null +++ b/legacy/source/mytest.s @@ -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 diff --git a/legacy/source/mytest2.s b/legacy/source/mytest2.s new file mode 100644 index 0000000..b20add1 --- /dev/null +++ b/legacy/source/mytest2.s @@ -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 diff --git a/legacy/source/sing_boot_alt.s b/legacy/source/sing_boot_alt.s new file mode 100644 index 0000000..c719c51 --- /dev/null +++ b/legacy/source/sing_boot_alt.s @@ -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 diff --git a/legacy/source/sing_boot_guess.s b/legacy/source/sing_boot_guess.s new file mode 100644 index 0000000..ffec9f9 --- /dev/null +++ b/legacy/source/sing_boot_guess.s @@ -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 diff --git a/lib/debug_tools.nasm b/lib/debug_tools.nasm new file mode 100644 index 0000000..8d2118b --- /dev/null +++ b/lib/debug_tools.nasm @@ -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 \ No newline at end of file diff --git a/lib/os_lib.nasm b/lib/os_lib.nasm new file mode 100644 index 0000000..46f661c --- /dev/null +++ b/lib/os_lib.nasm @@ -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 \ No newline at end of file diff --git a/lib/std_power.nasm b/lib/std_power.nasm new file mode 100644 index 0000000..5f764cf --- /dev/null +++ b/lib/std_power.nasm @@ -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 \ No newline at end of file diff --git a/lib/string.nasm b/lib/string.nasm new file mode 100644 index 0000000..50e863f --- /dev/null +++ b/lib/string.nasm @@ -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 diff --git a/lib/svim.nasm b/lib/svim.nasm new file mode 100644 index 0000000..5f1cc44 --- /dev/null +++ b/lib/svim.nasm @@ -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 diff --git a/mem_lib/mem_lib.nasm b/mem_lib/mem_lib.nasm new file mode 100644 index 0000000..204616d --- /dev/null +++ b/mem_lib/mem_lib.nasm @@ -0,0 +1,4 @@ +BITS 16 + +mem_get_zstack_buffer: + ; INPUT size of zeroed buffer ax in bytes diff --git a/vsfs/vsfs.nasm b/vsfs/vsfs.nasm new file mode 100644 index 0000000..77908a8 --- /dev/null +++ b/vsfs/vsfs.nasm @@ -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 \ No newline at end of file