From 75ac016823ba718656413ebc87ff16a87b6a265c Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 17 Apr 2012 09:23:55 +0300 Subject: [PATCH] * remove "\r" nonsense --- amd64/bareMetalOS-0.5.2/baremetal-libc/crt0.s | 22 +- amd64/bareMetalOS-0.5.2/baremetal0.5.2/README.TXT | 60 +- .../baremetal0.5.2/docs/CREDITS.TXT | 36 +- .../baremetal0.5.2/docs/LICENSE.TXT | 70 +- amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/cli.asm | 814 ++-- .../baremetal0.5.2/os/drivers.asm | 180 +- .../baremetal0.5.2/os/drivers/fat16.asm | 1598 +++---- .../baremetal0.5.2/os/drivers/hdd.asm | 430 +- .../baremetal0.5.2/os/drivers/net/bcm57xx.asm | 244 +- .../baremetal0.5.2/os/drivers/net/i8254x.asm | 904 ++-- .../baremetal0.5.2/os/drivers/net/rtl8169.asm | 656 +-- .../baremetal0.5.2/os/drivers/pci.asm | 314 +- .../baremetal0.5.2/os/init_64.asm | 556 +-- .../baremetal0.5.2/os/init_hdd.asm | 168 +- .../baremetal0.5.2/os/init_net.asm | 142 +- .../baremetal0.5.2/os/init_pci.asm | 58 +- .../baremetal0.5.2/os/interrupt.asm | 1168 ++--- amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4.asm | 34 +- .../baremetal0.5.2/os/ipv4/arp.asm | 296 +- .../baremetal0.5.2/os/ipv4/icmp.asm | 48 +- .../baremetal0.5.2/os/ipv4/tcp.asm | 32 +- .../baremetal0.5.2/os/ipv4/udp.asm | 32 +- .../baremetal0.5.2/os/ipv6/ndp.asm | 28 +- .../baremetal0.5.2/os/kernel64.asm | 1074 ++--- .../baremetal0.5.2/os/syscalls.asm | 54 +- .../baremetal0.5.2/os/syscalls/debug.asm | 532 +-- .../baremetal0.5.2/os/syscalls/ethernet.asm | 588 +-- .../baremetal0.5.2/os/syscalls/file.asm | 172 +- .../baremetal0.5.2/os/syscalls/input.asm | 214 +- .../baremetal0.5.2/os/syscalls/math.asm | 52 +- .../baremetal0.5.2/os/syscalls/memory.asm | 284 +- .../baremetal0.5.2/os/syscalls/misc.asm | 1008 ++-- .../baremetal0.5.2/os/syscalls/screen.asm | 1054 ++--- .../baremetal0.5.2/os/syscalls/serial.asm | 116 +- .../baremetal0.5.2/os/syscalls/smp.asm | 614 +-- .../baremetal0.5.2/os/syscalls/sound.asm | 154 +- .../baremetal0.5.2/os/syscalls/string.asm | 1490 +++--- .../bareMetalOS-0.5.2/baremetal0.5.2/os/sysvar.asm | 362 +- .../baremetal0.5.2/programs/argtest.asm | 70 +- .../baremetal0.5.2/programs/basic.asm | 3474 +++++++------- .../baremetal0.5.2/programs/bf.asm | 228 +- .../baremetal0.5.2/programs/bmdev.asm | 172 +- .../baremetal0.5.2/programs/ethtool.asm | 142 +- .../baremetal0.5.2/programs/filetest.asm | 120 +- .../baremetal0.5.2/programs/hello.asm | 40 +- .../baremetal0.5.2/programs/keyboard.asm | 220 +- .../baremetal0.5.2/programs/libBareMetal.h | 150 +- .../baremetal0.5.2/programs/mbasic.asm | 4872 ++++++++++---------- .../baremetal0.5.2/programs/nibbles.asm | 232 +- .../baremetal0.5.2/programs/primeasm.asm | 86 +- .../baremetal0.5.2/programs/smptest.asm | 128 +- .../baremetal0.5.2/programs/sysinfo.asm | 468 +- .../baremetal0.5.2/programs/test.asm | 124 +- amd64/bareMetalOS-0.5.2/pure64.boot0/README.TXT | 36 +- .../pure64.boot0/bootsector/boot16b.asm | 502 +- .../pure64.boot0/bootsector/fat16mbr.asm | 262 +- .../pure64.boot0/bootsector/pxestart.asm | 132 +- .../pure64.boot0/docs/CREDITS.TXT | 34 +- .../pure64.boot0/docs/LICENSE.TXT | 70 +- .../pure64.boot0/kernel_asm/kernel64.asm | 40 +- amd64/bareMetalOS-0.5.2/pure64.boot0/src/fat16.asm | 288 +- .../pure64.boot0/src/init_cpu.asm | 288 +- .../pure64.boot0/src/init_hdd.asm | 356 +- .../pure64.boot0/src/init_isa.asm | 356 +- .../pure64.boot0/src/init_smp.asm | 464 +- .../pure64.boot0/src/init_smp_acpi.asm | 334 +- .../pure64.boot0/src/init_smp_ap.asm | 356 +- .../pure64.boot0/src/interrupt.asm | 328 +- .../bareMetalOS-0.5.2/pure64.boot0/src/pure64.asm | 1370 +++--- .../pure64.boot0/src/syscalls.asm | 936 ++-- .../bareMetalOS-0.5.2/pure64.boot0/src/sysvar.asm | 320 +- amd64/bareMetalOS-0.5.3/docs/CREDITS.TXT | 36 +- amd64/bareMetalOS-0.5.3/docs/LICENSE.TXT | 70 +- amd64/bareMetalOS-0.5.3/newlib/baremetal/crt0.s | 22 +- amd64/bareMetalOS-0.5.3/os/cli.asm | 1004 ++-- amd64/bareMetalOS-0.5.3/os/drivers.asm | 190 +- amd64/bareMetalOS-0.5.3/os/drivers/achi.asm | 92 +- amd64/bareMetalOS-0.5.3/os/drivers/fat16.asm | 1598 +++---- amd64/bareMetalOS-0.5.3/os/drivers/hdd.asm | 430 +- amd64/bareMetalOS-0.5.3/os/drivers/net/bcm57xx.asm | 244 +- amd64/bareMetalOS-0.5.3/os/drivers/net/i8254x.asm | 922 ++-- amd64/bareMetalOS-0.5.3/os/drivers/net/rtl8169.asm | 686 +-- amd64/bareMetalOS-0.5.3/os/drivers/pci.asm | 314 +- amd64/bareMetalOS-0.5.3/os/drivers/storage.asm | 92 +- amd64/bareMetalOS-0.5.3/os/init_64.asm | 604 +-- amd64/bareMetalOS-0.5.3/os/init_hdd.asm | 168 +- amd64/bareMetalOS-0.5.3/os/init_net.asm | 168 +- amd64/bareMetalOS-0.5.3/os/init_pci.asm | 58 +- amd64/bareMetalOS-0.5.3/os/interrupt.asm | 1066 ++--- amd64/bareMetalOS-0.5.3/os/ipv4.asm | 58 +- amd64/bareMetalOS-0.5.3/os/ipv4/arp.asm | 274 +- amd64/bareMetalOS-0.5.3/os/ipv4/icmp.asm | 118 +- amd64/bareMetalOS-0.5.3/os/ipv4/tcp.asm | 68 +- amd64/bareMetalOS-0.5.3/os/ipv4/udp.asm | 68 +- amd64/bareMetalOS-0.5.3/os/ipv6/ndp.asm | 28 +- amd64/bareMetalOS-0.5.3/os/kernel64.asm | 1136 ++--- amd64/bareMetalOS-0.5.3/os/syscalls.asm | 54 +- amd64/bareMetalOS-0.5.3/os/syscalls/debug.asm | 532 +-- amd64/bareMetalOS-0.5.3/os/syscalls/ethernet.asm | 588 +-- amd64/bareMetalOS-0.5.3/os/syscalls/file.asm | 172 +- amd64/bareMetalOS-0.5.3/os/syscalls/input.asm | 214 +- amd64/bareMetalOS-0.5.3/os/syscalls/math.asm | 52 +- amd64/bareMetalOS-0.5.3/os/syscalls/memory.asm | 284 +- amd64/bareMetalOS-0.5.3/os/syscalls/misc.asm | 858 ++-- amd64/bareMetalOS-0.5.3/os/syscalls/screen.asm | 1078 ++--- amd64/bareMetalOS-0.5.3/os/syscalls/serial.asm | 116 +- amd64/bareMetalOS-0.5.3/os/syscalls/smp.asm | 616 +-- amd64/bareMetalOS-0.5.3/os/syscalls/sound.asm | 154 +- amd64/bareMetalOS-0.5.3/os/syscalls/string.asm | 1490 +++--- amd64/bareMetalOS-0.5.3/os/sysvar.asm | 364 +- amd64/bareMetalOS-0.5.3/programs/argtest.asm | 70 +- amd64/bareMetalOS-0.5.3/programs/bf.asm | 228 +- amd64/bareMetalOS-0.5.3/programs/bmdev.asm | 172 +- amd64/bareMetalOS-0.5.3/programs/ethtool.asm | 142 +- amd64/bareMetalOS-0.5.3/programs/hello.asm | 40 +- amd64/bareMetalOS-0.5.3/programs/keyboard.asm | 220 +- amd64/bareMetalOS-0.5.3/programs/libBareMetal.h | 160 +- amd64/bareMetalOS-0.5.3/programs/mbasic.asm | 4872 ++++++++++---------- amd64/bareMetalOS-0.5.3/programs/nibbles.asm | 232 +- amd64/bareMetalOS-0.5.3/programs/smptest.asm | 128 +- amd64/bareMetalOS-0.5.3/programs/sysinfo.asm | 468 +- amd64/pure64-0.5.0/README.TXT | 36 +- amd64/pure64-0.5.0/bootsector/boot16b.asm | 504 +- amd64/pure64-0.5.0/bootsector/fat16mbr.asm | 262 +- amd64/pure64-0.5.0/bootsector/pxestart.asm | 136 +- amd64/pure64-0.5.0/docs/CREDITS.TXT | 34 +- amd64/pure64-0.5.0/docs/LICENSE.TXT | 70 +- amd64/pure64-0.5.0/kernel_asm/kernel64.asm | 40 +- amd64/pure64-0.5.0/src/fat16.asm | 324 +- amd64/pure64-0.5.0/src/init_acpi.asm | 516 +-- amd64/pure64-0.5.0/src/init_cpu.asm | 384 +- amd64/pure64-0.5.0/src/init_hdd.asm | 542 +-- amd64/pure64-0.5.0/src/init_ioapic.asm | 308 +- amd64/pure64-0.5.0/src/init_isa.asm | 306 +- amd64/pure64-0.5.0/src/init_smp.asm | 312 +- amd64/pure64-0.5.0/src/init_smp_ap.asm | 356 +- amd64/pure64-0.5.0/src/interrupt.asm | 476 +- amd64/pure64-0.5.0/src/pci.asm | 130 +- amd64/pure64-0.5.0/src/pure64.asm | 1666 +++---- amd64/pure64-0.5.0/src/syscalls.asm | 1030 ++--- amd64/pure64-0.5.0/src/sysvar.asm | 332 +- 141 files changed, 31619 insertions(+), 31619 deletions(-) diff --git a/amd64/bareMetalOS-0.5.2/baremetal-libc/crt0.s b/amd64/bareMetalOS-0.5.2/baremetal-libc/crt0.s index 875cded6..2eb82cc6 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal-libc/crt0.s +++ b/amd64/bareMetalOS-0.5.2/baremetal-libc/crt0.s @@ -1,12 +1,12 @@ -.global _start -.extern main -_start: - -## here you might want to get the argc/argv pairs somehow and then push -## them onto the stack... - -# call the user's function -call main - -# return to the OS +.global _start +.extern main +_start: + +## here you might want to get the argc/argv pairs somehow and then push +## them onto the stack... + +# call the user's function +call main + +# return to the OS ret \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/README.TXT b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/README.TXT index 4dd4cd2b..8ec92cad 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/README.TXT +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/README.TXT @@ -1,30 +1,30 @@ -=============================================================================== -BareMetal OS -- a 64-bit OS written in Assembly for x86-64 systems -Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -=============================================================================== - - -BareMetal is a 64-bit protected mode operating system for x86-64 compatible -PCs, written entirely in assembly language, which boots from a hard drive. It -features a command-line, support for FAT16 hard drives and sound via the PC -speaker. It can load external programs and has over 60 system calls. BareMetal -can also utilize all available CPU's in the computer it is run on. - -At the moment there is no plan to BareMetal into a general-purpose operating -system like Windows, Mac OS X, or Linux; it is designed as a learning tool, -to demonstrate how a simple OS works. One idea for BareMetal is to be used as -a base for raw number crunching applications, perhaps even in a cluster -enviroment. You can use it as the basis of your own OS project, or to learn -about x86-64 assembly language. The complete documentation for BareMetal, -including instructions on running it, building it and writing your own -programs for it can be found in the docs/ directory. - -See LICENSE.TXT for redistribution/modification rights, and CREDITS.TXT for -a list of people involved. - -Have fun and happy hacking! - - -- Ian Seyler (ian.seyler@returninfinity.com) - - -=============================================================================== +=============================================================================== +BareMetal OS -- a 64-bit OS written in Assembly for x86-64 systems +Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +=============================================================================== + + +BareMetal is a 64-bit protected mode operating system for x86-64 compatible +PCs, written entirely in assembly language, which boots from a hard drive. It +features a command-line, support for FAT16 hard drives and sound via the PC +speaker. It can load external programs and has over 60 system calls. BareMetal +can also utilize all available CPU's in the computer it is run on. + +At the moment there is no plan to BareMetal into a general-purpose operating +system like Windows, Mac OS X, or Linux; it is designed as a learning tool, +to demonstrate how a simple OS works. One idea for BareMetal is to be used as +a base for raw number crunching applications, perhaps even in a cluster +enviroment. You can use it as the basis of your own OS project, or to learn +about x86-64 assembly language. The complete documentation for BareMetal, +including instructions on running it, building it and writing your own +programs for it can be found in the docs/ directory. + +See LICENSE.TXT for redistribution/modification rights, and CREDITS.TXT for +a list of people involved. + +Have fun and happy hacking! + + -- Ian Seyler (ian.seyler@returninfinity.com) + + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/CREDITS.TXT b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/CREDITS.TXT index c79a38d4..184580ad 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/CREDITS.TXT +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/CREDITS.TXT @@ -1,18 +1,18 @@ -=============================================================================== -BareMetal OS -- a 64-bit OS written in Assembly for x86-64 systems -Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -=============================================================================== - - -PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) - - * Ian Seyler -- ian.seyler@returninfinity.com - - -DEVELOPMENT AND TESTING - - * Mike Saunders (and the MikeOS team) - * Members of OSDev.org - - -=============================================================================== +=============================================================================== +BareMetal OS -- a 64-bit OS written in Assembly for x86-64 systems +Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +=============================================================================== + + +PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) + + * Ian Seyler -- ian.seyler@returninfinity.com + + +DEVELOPMENT AND TESTING + + * Mike Saunders (and the MikeOS team) + * Members of OSDev.org + + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/LICENSE.TXT b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/LICENSE.TXT index 3c98a3bd..9440e631 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/LICENSE.TXT +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/docs/LICENSE.TXT @@ -1,35 +1,35 @@ -=============================================================================== -BareMetal OS -- License -=============================================================================== - -Copyright (C) 2008-2011 Return Infinity -- http://www.returninfinity.com - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name BareMetal nor the names of any BareMetal contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -=============================================================================== +=============================================================================== +BareMetal OS -- License +=============================================================================== + +Copyright (C) 2008-2011 Return Infinity -- http://www.returninfinity.com + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name BareMetal nor the names of any BareMetal contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/cli.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/cli.asm index ee9dd9ee..90704984 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/cli.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/cli.asm @@ -1,407 +1,407 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; COMMAND LINE INTERFACE -; ============================================================================= - -align 16 -db 'DEBUG: CLI ' -align 16 - - -os_command_line: - mov rsi, prompt ; Prompt for input - mov bl, 0x09 ; Black background, Light Red text - call os_print_string_with_color - - mov rdi, cli_temp_string - mov rcx, 250 ; Limit the input to 250 characters - call os_input_string - call os_print_newline ; The user hit enter so print a new line - jrcxz os_command_line ; os_input_string stores the number of charaters received in RCX - - mov rsi, rdi - call os_string_parse ; Remove extra spaces - jrcxz os_command_line ; os_string_parse stores the number of words in RCX - mov byte [cli_args], cl ; Store the number of words in the string - -; Copy the first word in the string to a new string. This is the command/application to run - xor rcx, rcx - mov rsi, cli_temp_string - mov rdi, cli_command_string - push rdi ; Push the command string -nextbyte: - add rcx, 1 - lodsb - cmp al, ' ' ; End of the word - je endofcommand - cmp al, 0x00 ; End of the string - je endofcommand - cmp rcx, 13 ; More than 12 bytes - je endofcommand - stosb - jmp nextbyte -endofcommand: - mov al, 0x00 - stosb ; Terminate the string - -; At this point cli_command_string holds at least "a" and at most "abcdefgh.ijk" - - ; Break the contents of cli_temp_string into individual strings - mov rsi, cli_temp_string - mov al, 0x20 - mov bl, 0x00 - call os_string_change_char - - pop rsi ; Pop the command string - call os_string_uppercase ; Convert to uppercase for comparison - - mov rdi, cls_string ; 'CLS' entered? - call os_string_compare - jc near clear_screen - - mov rdi, dir_string ; 'DIR' entered? - call os_string_compare - jc near dir - - mov rdi, ver_string ; 'VER' entered? - call os_string_compare - jc near print_ver - - mov rdi, date_string ; 'DATE' entered? - call os_string_compare - jc near date - - mov rdi, exit_string ; 'EXIT' entered? - call os_string_compare - jc near exit - - mov rdi, help_string ; 'HELP' entered? - call os_string_compare - jc near print_help - - mov rdi, node_string ; 'NODE' entered? - call os_string_compare - jc near node - - mov rdi, time_string ; 'TIME' entered? - call os_string_compare - jc near time - - mov rdi, debug_string ; 'DEBUG' entered? - call os_string_compare - jc near debug - - mov rdi, reboot_string ; 'REBOOT' entered? - call os_string_compare - jc near reboot - - mov rdi, testzone_string ; 'TESTZONE' entered? - call os_string_compare - jc near testzone - -; At this point it is not one of the built-in CLI functions. Prepare to check the filesystem. - mov al, '.' - call os_string_find_char ; Check for a '.' in the string - cmp rax, 0 - jne full_name ; If there was a '.' then a suffix is present - -; No suffix was present so we add the default application suffix of ".APP" -add_suffix: - call os_string_length - cmp rcx, 8 - jg fail ; If the string is longer than 8 chars we can't add a suffix - - mov rdi, cli_command_string - mov rsi, appextension ; '.APP' - call os_string_append ; Append the extension to the command string - -; cli_command_string now contains a full filename -full_name: - mov rsi, cli_command_string - mov rdi, programlocation ; We load the program to this location in memory (currently 0x00100000 : at the 2MB mark) - call os_file_read ; Read the file into memory - jc fail ; If carry is set then the file was not found - - mov rax, programlocation ; 0x00100000 : at the 2MB mark - xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) - call os_smp_enqueue ; Queue the application to run on the next available core - jmp exit ; The CLI can quit now. IRQ 8 will restart it when the program is finished - -fail: ; We didn't get a valid command or program name - mov rsi, not_found_msg - call os_print_string - jmp os_command_line - -print_help: - mov rsi, help_text - call os_print_string - jmp os_command_line - -clear_screen: - call os_screen_clear - mov ax, 0x0018 - call os_move_cursor - jmp os_command_line - -print_ver: - mov rsi, version_msg - call os_print_string - jmp os_command_line - -dir: - mov rdi, cli_temp_string - mov rsi, rdi - call os_file_get_list - call os_print_string - jmp os_command_line - -date: - mov rdi, cli_temp_string - mov rsi, rdi - call os_get_date_string - call os_print_string - call os_print_newline - jmp os_command_line - -time: - mov rdi, cli_temp_string - mov rsi, rdi - call os_get_time_string - call os_print_string - call os_print_newline - jmp os_command_line - -node: - jmp os_command_line ; Nothing here yet... - -align 16 -testzone: - xchg bx, bx ; Bochs Magic Breakpoint - -; call os_ethernet_avail -; call os_debug_dump_rax - -; mov rdi, cli_temp_string -; mov rsi, rdi -; mov rcx, 12 -; call os_input_string -; call os_file_get_size -; mov rax, rcx -; call os_print_newline -; call os_debug_dump_rax - -; cli -; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected -; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue -; rdtsc -; mov r15d, eax - ; Benchmark code start - -; sub rsp, 0x28 -; mov [rsp + 0x20], rax -; mov [rsp + 0x18], rax -; mov [rsp + 0x10], rax -; mov [rsp + 0x8], rax -; mov [rsp], rax -; mov rax, [rsp] -; mov rax, [rsp + 0x8] -; mov rax, [rsp + 0x10] -; mov rax, [rsp + 0x18] -; mov rax, [rsp + 0x20] -; add rsp, 0x28 - -; push rax -; push rax -; push rax -; push rax -; push rax -; pop rax -; pop rax -; pop rax -; pop rax -; pop rax - - ; Benchmark code finish -; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected -; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue -; rdtsc -; sti -; sub eax, r15d -; call os_debug_dump_eax -; call os_print_newline - - mov bl, 0x0F - mov al, '0' - call os_print_char_with_color - mov al, '0' - call os_print_char_with_color - mov bl, 0x10 - mov al, '0' - call os_print_char_with_color - mov al, '1' - call os_print_char_with_color - mov bl, 0x20 - mov al, '0' - call os_print_char_with_color - mov al, '2' - call os_print_char_with_color - mov bl, 0x30 - mov al, '0' - call os_print_char_with_color - mov al, '3' - call os_print_char_with_color - mov bl, 0x40 - mov al, '0' - call os_print_char_with_color - mov al, '4' - call os_print_char_with_color - mov bl, 0x50 - mov al, '0' - call os_print_char_with_color - mov al, '5' - call os_print_char_with_color - mov bl, 0x60 - mov al, '0' - call os_print_char_with_color - mov al, '6' - call os_print_char_with_color - mov bl, 0x70 - mov al, '0' - call os_print_char_with_color - mov al, '7' - call os_print_char_with_color - call os_print_newline - mov bl, 0x80 - mov al, '0' - call os_print_char_with_color - mov al, '8' - call os_print_char_with_color - mov bl, 0x90 - mov al, '0' - call os_print_char_with_color - mov al, '9' - call os_print_char_with_color - mov bl, 0xA0 - mov al, '0' - call os_print_char_with_color - mov al, 'A' - call os_print_char_with_color - mov bl, 0xB0 - mov al, '0' - call os_print_char_with_color - mov al, 'B' - call os_print_char_with_color - mov bl, 0xC0 - mov al, '0' - call os_print_char_with_color - mov al, 'C' - call os_print_char_with_color - mov bl, 0xD0 - mov al, '0' - call os_print_char_with_color - mov al, 'D' - call os_print_char_with_color - mov bl, 0xE0 - mov al, '0' - call os_print_char_with_color - mov al, 'E' - call os_print_char_with_color - mov bl, 0xF0 - mov al, '0' - call os_print_char_with_color - mov al, 'F' - call os_print_char_with_color - call os_print_newline -; mov al, ' ' -; call os_print_char -; mov rax, rcx -; call os_debug_dump_rax - -; call os_mem_get_free -; mov rax, rcx -; call os_debug_dump_rax -; mov al, ' ' -; call os_print_char -; xor eax, eax -; mov ax, word [os_MemAmount] -; shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) -; call os_debug_dump_rax -; call os_print_newline -; mov rcx, 2 ; 2 pages = 4 MiB -; call os_mem_allocate -; call os_debug_dump_rax -; call os_print_newline - -; mov rax, 0x400000 -; call os_get_time_data - - -; ud2 - -; xor rax, rax -; xor rbx, rcx -; xor rcx, rcx -; xor rdx, rdx -; div rax - - jmp os_command_line - -reboot: - in al, 0x64 - test al, 00000010b ; Wait for an empty Input Buffer - jne reboot - mov al, 0xFE - out 0x64, al ; Send the reboot call to the keyboard controller - jmp reboot - -debug: - call os_get_argc ; Check the argument number - cmp al, 1 - je debug_dump_reg ; If it is only one then do a register dump - mov rcx, 16 - cmp al, 3 ; Did we get at least 3? - jl noamount ; If not no amount was specified - mov al, 2 - call os_get_argv ; Get the amount of bytes to display - call os_string_to_int ; Convert to an integer - mov rcx, rax -noamount: - mov al, 1 - call os_get_argv ; Get the starting memory address - call os_hex_string_to_int - mov rsi, rax -debug_default: - call os_debug_dump_mem - call os_print_newline - - jmp os_command_line - -debug_dump_reg: - call os_debug_dump_reg - jmp os_command_line - -exit: - ret - -; Strings - help_text db 'Built-in commands: CLS, DATE, DEBUG, DIR, HELP, REBOOT, TIME, VER', 13, 0 - not_found_msg db 'Command or program not found', 13, 0 - version_msg db 'BareMetal OS ', BAREMETALOS_VER, 13, 0 - - cls_string db 'CLS', 0 - dir_string db 'DIR', 0 - ver_string db 'VER', 0 - date_string db 'DATE', 0 - exit_string db 'EXIT', 0 - help_string db 'HELP', 0 - node_string db 'NODE', 0 - time_string db 'TIME', 0 - debug_string db 'DEBUG', 0 - reboot_string db 'REBOOT', 0 - testzone_string db 'TESTZONE', 0 - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; COMMAND LINE INTERFACE +; ============================================================================= + +align 16 +db 'DEBUG: CLI ' +align 16 + + +os_command_line: + mov rsi, prompt ; Prompt for input + mov bl, 0x09 ; Black background, Light Red text + call os_print_string_with_color + + mov rdi, cli_temp_string + mov rcx, 250 ; Limit the input to 250 characters + call os_input_string + call os_print_newline ; The user hit enter so print a new line + jrcxz os_command_line ; os_input_string stores the number of charaters received in RCX + + mov rsi, rdi + call os_string_parse ; Remove extra spaces + jrcxz os_command_line ; os_string_parse stores the number of words in RCX + mov byte [cli_args], cl ; Store the number of words in the string + +; Copy the first word in the string to a new string. This is the command/application to run + xor rcx, rcx + mov rsi, cli_temp_string + mov rdi, cli_command_string + push rdi ; Push the command string +nextbyte: + add rcx, 1 + lodsb + cmp al, ' ' ; End of the word + je endofcommand + cmp al, 0x00 ; End of the string + je endofcommand + cmp rcx, 13 ; More than 12 bytes + je endofcommand + stosb + jmp nextbyte +endofcommand: + mov al, 0x00 + stosb ; Terminate the string + +; At this point cli_command_string holds at least "a" and at most "abcdefgh.ijk" + + ; Break the contents of cli_temp_string into individual strings + mov rsi, cli_temp_string + mov al, 0x20 + mov bl, 0x00 + call os_string_change_char + + pop rsi ; Pop the command string + call os_string_uppercase ; Convert to uppercase for comparison + + mov rdi, cls_string ; 'CLS' entered? + call os_string_compare + jc near clear_screen + + mov rdi, dir_string ; 'DIR' entered? + call os_string_compare + jc near dir + + mov rdi, ver_string ; 'VER' entered? + call os_string_compare + jc near print_ver + + mov rdi, date_string ; 'DATE' entered? + call os_string_compare + jc near date + + mov rdi, exit_string ; 'EXIT' entered? + call os_string_compare + jc near exit + + mov rdi, help_string ; 'HELP' entered? + call os_string_compare + jc near print_help + + mov rdi, node_string ; 'NODE' entered? + call os_string_compare + jc near node + + mov rdi, time_string ; 'TIME' entered? + call os_string_compare + jc near time + + mov rdi, debug_string ; 'DEBUG' entered? + call os_string_compare + jc near debug + + mov rdi, reboot_string ; 'REBOOT' entered? + call os_string_compare + jc near reboot + + mov rdi, testzone_string ; 'TESTZONE' entered? + call os_string_compare + jc near testzone + +; At this point it is not one of the built-in CLI functions. Prepare to check the filesystem. + mov al, '.' + call os_string_find_char ; Check for a '.' in the string + cmp rax, 0 + jne full_name ; If there was a '.' then a suffix is present + +; No suffix was present so we add the default application suffix of ".APP" +add_suffix: + call os_string_length + cmp rcx, 8 + jg fail ; If the string is longer than 8 chars we can't add a suffix + + mov rdi, cli_command_string + mov rsi, appextension ; '.APP' + call os_string_append ; Append the extension to the command string + +; cli_command_string now contains a full filename +full_name: + mov rsi, cli_command_string + mov rdi, programlocation ; We load the program to this location in memory (currently 0x00100000 : at the 2MB mark) + call os_file_read ; Read the file into memory + jc fail ; If carry is set then the file was not found + + mov rax, programlocation ; 0x00100000 : at the 2MB mark + xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) + call os_smp_enqueue ; Queue the application to run on the next available core + jmp exit ; The CLI can quit now. IRQ 8 will restart it when the program is finished + +fail: ; We didn't get a valid command or program name + mov rsi, not_found_msg + call os_print_string + jmp os_command_line + +print_help: + mov rsi, help_text + call os_print_string + jmp os_command_line + +clear_screen: + call os_screen_clear + mov ax, 0x0018 + call os_move_cursor + jmp os_command_line + +print_ver: + mov rsi, version_msg + call os_print_string + jmp os_command_line + +dir: + mov rdi, cli_temp_string + mov rsi, rdi + call os_file_get_list + call os_print_string + jmp os_command_line + +date: + mov rdi, cli_temp_string + mov rsi, rdi + call os_get_date_string + call os_print_string + call os_print_newline + jmp os_command_line + +time: + mov rdi, cli_temp_string + mov rsi, rdi + call os_get_time_string + call os_print_string + call os_print_newline + jmp os_command_line + +node: + jmp os_command_line ; Nothing here yet... + +align 16 +testzone: + xchg bx, bx ; Bochs Magic Breakpoint + +; call os_ethernet_avail +; call os_debug_dump_rax + +; mov rdi, cli_temp_string +; mov rsi, rdi +; mov rcx, 12 +; call os_input_string +; call os_file_get_size +; mov rax, rcx +; call os_print_newline +; call os_debug_dump_rax + +; cli +; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected +; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue +; rdtsc +; mov r15d, eax + ; Benchmark code start + +; sub rsp, 0x28 +; mov [rsp + 0x20], rax +; mov [rsp + 0x18], rax +; mov [rsp + 0x10], rax +; mov [rsp + 0x8], rax +; mov [rsp], rax +; mov rax, [rsp] +; mov rax, [rsp + 0x8] +; mov rax, [rsp + 0x10] +; mov rax, [rsp + 0x18] +; mov rax, [rsp + 0x20] +; add rsp, 0x28 + +; push rax +; push rax +; push rax +; push rax +; push rax +; pop rax +; pop rax +; pop rax +; pop rax +; pop rax + + ; Benchmark code finish +; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected +; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue +; rdtsc +; sti +; sub eax, r15d +; call os_debug_dump_eax +; call os_print_newline + + mov bl, 0x0F + mov al, '0' + call os_print_char_with_color + mov al, '0' + call os_print_char_with_color + mov bl, 0x10 + mov al, '0' + call os_print_char_with_color + mov al, '1' + call os_print_char_with_color + mov bl, 0x20 + mov al, '0' + call os_print_char_with_color + mov al, '2' + call os_print_char_with_color + mov bl, 0x30 + mov al, '0' + call os_print_char_with_color + mov al, '3' + call os_print_char_with_color + mov bl, 0x40 + mov al, '0' + call os_print_char_with_color + mov al, '4' + call os_print_char_with_color + mov bl, 0x50 + mov al, '0' + call os_print_char_with_color + mov al, '5' + call os_print_char_with_color + mov bl, 0x60 + mov al, '0' + call os_print_char_with_color + mov al, '6' + call os_print_char_with_color + mov bl, 0x70 + mov al, '0' + call os_print_char_with_color + mov al, '7' + call os_print_char_with_color + call os_print_newline + mov bl, 0x80 + mov al, '0' + call os_print_char_with_color + mov al, '8' + call os_print_char_with_color + mov bl, 0x90 + mov al, '0' + call os_print_char_with_color + mov al, '9' + call os_print_char_with_color + mov bl, 0xA0 + mov al, '0' + call os_print_char_with_color + mov al, 'A' + call os_print_char_with_color + mov bl, 0xB0 + mov al, '0' + call os_print_char_with_color + mov al, 'B' + call os_print_char_with_color + mov bl, 0xC0 + mov al, '0' + call os_print_char_with_color + mov al, 'C' + call os_print_char_with_color + mov bl, 0xD0 + mov al, '0' + call os_print_char_with_color + mov al, 'D' + call os_print_char_with_color + mov bl, 0xE0 + mov al, '0' + call os_print_char_with_color + mov al, 'E' + call os_print_char_with_color + mov bl, 0xF0 + mov al, '0' + call os_print_char_with_color + mov al, 'F' + call os_print_char_with_color + call os_print_newline +; mov al, ' ' +; call os_print_char +; mov rax, rcx +; call os_debug_dump_rax + +; call os_mem_get_free +; mov rax, rcx +; call os_debug_dump_rax +; mov al, ' ' +; call os_print_char +; xor eax, eax +; mov ax, word [os_MemAmount] +; shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) +; call os_debug_dump_rax +; call os_print_newline +; mov rcx, 2 ; 2 pages = 4 MiB +; call os_mem_allocate +; call os_debug_dump_rax +; call os_print_newline + +; mov rax, 0x400000 +; call os_get_time_data + + +; ud2 + +; xor rax, rax +; xor rbx, rcx +; xor rcx, rcx +; xor rdx, rdx +; div rax + + jmp os_command_line + +reboot: + in al, 0x64 + test al, 00000010b ; Wait for an empty Input Buffer + jne reboot + mov al, 0xFE + out 0x64, al ; Send the reboot call to the keyboard controller + jmp reboot + +debug: + call os_get_argc ; Check the argument number + cmp al, 1 + je debug_dump_reg ; If it is only one then do a register dump + mov rcx, 16 + cmp al, 3 ; Did we get at least 3? + jl noamount ; If not no amount was specified + mov al, 2 + call os_get_argv ; Get the amount of bytes to display + call os_string_to_int ; Convert to an integer + mov rcx, rax +noamount: + mov al, 1 + call os_get_argv ; Get the starting memory address + call os_hex_string_to_int + mov rsi, rax +debug_default: + call os_debug_dump_mem + call os_print_newline + + jmp os_command_line + +debug_dump_reg: + call os_debug_dump_reg + jmp os_command_line + +exit: + ret + +; Strings + help_text db 'Built-in commands: CLS, DATE, DEBUG, DIR, HELP, REBOOT, TIME, VER', 13, 0 + not_found_msg db 'Command or program not found', 13, 0 + version_msg db 'BareMetal OS ', BAREMETALOS_VER, 13, 0 + + cls_string db 'CLS', 0 + dir_string db 'DIR', 0 + ver_string db 'VER', 0 + date_string db 'DATE', 0 + exit_string db 'EXIT', 0 + help_string db 'HELP', 0 + node_string db 'NODE', 0 + time_string db 'TIME', 0 + debug_string db 'DEBUG', 0 + reboot_string db 'REBOOT', 0 + testzone_string db 'TESTZONE', 0 + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers.asm index bf30a872..2a758368 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers.asm @@ -1,90 +1,90 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Driver Includes -; ============================================================================= - -align 16 -db 'DEBUG: DRIVERS ' -align 16 - - -%include "drivers/hdd.asm" -%include "drivers/fat16.asm" -%include "drivers/pci.asm" -%include "drivers/net/rtl8169.asm" -%include "drivers/net/i8254x.asm" -;%include "drivers/net/bcm57xx.asm" - - -NIC_DeviceVendor_ID: ; The supported list of NICs -; Realtek 816x/811x Gigabit Ethernet -dd 0x816710EC, 0x00008169 ; 8110SC/8169SC -dd 0x816810EC, 0x00008169 ; 8111/8168B -dd 0x816910EC, 0x00008169 ; 8169 - -; Intel 8254x Gigabit Ethernet -dd 0x10008086, 0x00008254 ; 82542 (Fiber) -dd 0x10018086, 0x00008254 ; 82543GC (Fiber) -dd 0x10048086, 0x00008254 ; 82543GC (Copper) -dd 0x10088086, 0x00008254 ; 82544EI (Copper) -dd 0x10098086, 0x00008254 ; 82544EI (Fiber) -dd 0x100A8086, 0x00008254 ; 82540EM -dd 0x100C8086, 0x00008254 ; 82544GC (Copper) -dd 0x100D8086, 0x00008254 ; 82544GC (LOM) -dd 0x100E8086, 0x00008254 ; 82540EM -dd 0x100F8086, 0x00008254 ; 82545EM (Copper) -dd 0x10108086, 0x00008254 ; 82546EB (Copper) -dd 0x10118086, 0x00008254 ; 82545EM (Fiber) -dd 0x10128086, 0x00008254 ; 82546EB (Fiber) -dd 0x10138086, 0x00008254 ; 82541EI -dd 0x10148086, 0x00008254 ; 82541ER -dd 0x10158086, 0x00008254 ; 82540EM (LOM) -dd 0x10168086, 0x00008254 ; 82540EP (Mobile) -dd 0x10178086, 0x00008254 ; 82540EP -dd 0x10188086, 0x00008254 ; 82541EI -dd 0x10198086, 0x00008254 ; 82547EI -dd 0x101a8086, 0x00008254 ; 82547EI (Mobile) -dd 0x101d8086, 0x00008254 ; 82546EB -dd 0x101e8086, 0x00008254 ; 82540EP (Mobile) -dd 0x10268086, 0x00008254 ; 82545GM -dd 0x10278086, 0x00008254 ; 82545GM -dd 0x10288086, 0x00008254 ; 82545GM -dd 0x105b8086, 0x00008254 ; 82546GB (Copper) -dd 0x10758086, 0x00008254 ; 82547GI -dd 0x10768086, 0x00008254 ; 82541GI -dd 0x10778086, 0x00008254 ; 82541GI -dd 0x10788086, 0x00008254 ; 82541ER -dd 0x10798086, 0x00008254 ; 82546GB -dd 0x107a8086, 0x00008254 ; 82546GB -dd 0x107b8086, 0x00008254 ; 82546GB -dd 0x107c8086, 0x00008254 ; 82541PI -dd 0x10b58086, 0x00008254 ; 82546GB (Copper) -dd 0x11078086, 0x00008254 ; 82544EI -dd 0x11128086, 0x00008254 ; 82544GC - -; Broadcom BCM57xx Gigabit Ethernet -dd 0x000312AE, 0x00005700 ; 5700, Broadcom -dd 0x164514E4, 0x00005700 ; 5701 -dd 0x16A614E4, 0x00005700 ; 5702 -dd 0x16A714E4, 0x00005700 ; 5703C, 5703S -dd 0x164814E4, 0x00005700 ; 5704C -dd 0x164914E4, 0x00005700 ; 5704S -dd 0x165D14E4, 0x00005700 ; 5705M -dd 0x165314E4, 0x00005700 ; 5705 -dd 0x03ED173B, 0x00005700 ; 5788 -dd 0x167714E4, 0x00005700 ; 5721, 5751 -dd 0x167D14E4, 0x00005700 ; 5751M -dd 0x160014E4, 0x00005700 ; 5752 -dd 0x160114E4, 0x00005700 ; 5752M -dd 0x166814E4, 0x00005700 ; 5714C -dd 0x166914E4, 0x00005700 ; 5714S -dd 0x167814E4, 0x00005700 ; 5715C -dd 0x167914E4, 0x00005700 ; 5715S - -dd 0x00000000, 0x00000000 ; End of list - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Driver Includes +; ============================================================================= + +align 16 +db 'DEBUG: DRIVERS ' +align 16 + + +%include "drivers/hdd.asm" +%include "drivers/fat16.asm" +%include "drivers/pci.asm" +%include "drivers/net/rtl8169.asm" +%include "drivers/net/i8254x.asm" +;%include "drivers/net/bcm57xx.asm" + + +NIC_DeviceVendor_ID: ; The supported list of NICs +; Realtek 816x/811x Gigabit Ethernet +dd 0x816710EC, 0x00008169 ; 8110SC/8169SC +dd 0x816810EC, 0x00008169 ; 8111/8168B +dd 0x816910EC, 0x00008169 ; 8169 + +; Intel 8254x Gigabit Ethernet +dd 0x10008086, 0x00008254 ; 82542 (Fiber) +dd 0x10018086, 0x00008254 ; 82543GC (Fiber) +dd 0x10048086, 0x00008254 ; 82543GC (Copper) +dd 0x10088086, 0x00008254 ; 82544EI (Copper) +dd 0x10098086, 0x00008254 ; 82544EI (Fiber) +dd 0x100A8086, 0x00008254 ; 82540EM +dd 0x100C8086, 0x00008254 ; 82544GC (Copper) +dd 0x100D8086, 0x00008254 ; 82544GC (LOM) +dd 0x100E8086, 0x00008254 ; 82540EM +dd 0x100F8086, 0x00008254 ; 82545EM (Copper) +dd 0x10108086, 0x00008254 ; 82546EB (Copper) +dd 0x10118086, 0x00008254 ; 82545EM (Fiber) +dd 0x10128086, 0x00008254 ; 82546EB (Fiber) +dd 0x10138086, 0x00008254 ; 82541EI +dd 0x10148086, 0x00008254 ; 82541ER +dd 0x10158086, 0x00008254 ; 82540EM (LOM) +dd 0x10168086, 0x00008254 ; 82540EP (Mobile) +dd 0x10178086, 0x00008254 ; 82540EP +dd 0x10188086, 0x00008254 ; 82541EI +dd 0x10198086, 0x00008254 ; 82547EI +dd 0x101a8086, 0x00008254 ; 82547EI (Mobile) +dd 0x101d8086, 0x00008254 ; 82546EB +dd 0x101e8086, 0x00008254 ; 82540EP (Mobile) +dd 0x10268086, 0x00008254 ; 82545GM +dd 0x10278086, 0x00008254 ; 82545GM +dd 0x10288086, 0x00008254 ; 82545GM +dd 0x105b8086, 0x00008254 ; 82546GB (Copper) +dd 0x10758086, 0x00008254 ; 82547GI +dd 0x10768086, 0x00008254 ; 82541GI +dd 0x10778086, 0x00008254 ; 82541GI +dd 0x10788086, 0x00008254 ; 82541ER +dd 0x10798086, 0x00008254 ; 82546GB +dd 0x107a8086, 0x00008254 ; 82546GB +dd 0x107b8086, 0x00008254 ; 82546GB +dd 0x107c8086, 0x00008254 ; 82541PI +dd 0x10b58086, 0x00008254 ; 82546GB (Copper) +dd 0x11078086, 0x00008254 ; 82544EI +dd 0x11128086, 0x00008254 ; 82544GC + +; Broadcom BCM57xx Gigabit Ethernet +dd 0x000312AE, 0x00005700 ; 5700, Broadcom +dd 0x164514E4, 0x00005700 ; 5701 +dd 0x16A614E4, 0x00005700 ; 5702 +dd 0x16A714E4, 0x00005700 ; 5703C, 5703S +dd 0x164814E4, 0x00005700 ; 5704C +dd 0x164914E4, 0x00005700 ; 5704S +dd 0x165D14E4, 0x00005700 ; 5705M +dd 0x165314E4, 0x00005700 ; 5705 +dd 0x03ED173B, 0x00005700 ; 5788 +dd 0x167714E4, 0x00005700 ; 5721, 5751 +dd 0x167D14E4, 0x00005700 ; 5751M +dd 0x160014E4, 0x00005700 ; 5752 +dd 0x160114E4, 0x00005700 ; 5752M +dd 0x166814E4, 0x00005700 ; 5714C +dd 0x166914E4, 0x00005700 ; 5714S +dd 0x167814E4, 0x00005700 ; 5715C +dd 0x167914E4, 0x00005700 ; 5715S + +dd 0x00000000, 0x00000000 ; End of list + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/fat16.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/fat16.asm index e4d25ad6..d09bc1c6 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/fat16.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/fat16.asm @@ -1,799 +1,799 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; FAT16 Functions -; ============================================================================= - -align 16 -db 'DEBUG: FAT16 ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_fat16_read_cluster -- Read a cluster from the FAT16 partition -; IN: AX = Cluster # to read -; RDI = Memory location to store at least 32KB -; OUT: AX = Next cluster in chain (0xFFFF if this was the last) -; RDI = Points one byte after the last byte read -os_fat16_read_cluster: - push rsi - push rdx - push rcx - push rbx - - and rax, 0x000000000000FFFF ; Clear the top 48 bits - mov rbx, rax ; Save the cluster number to be used later - - cmp ax, 2 ; If less than 2 then bail out... - jl near os_fat16_read_cluster_bailout ; as clusters start at 2 - -; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start - xor rcx, rcx - mov cl, byte [fat16_SectorsPerCluster] - push rcx ; Save the number of sectors per cluster - sub ax, 2 - imul cx ; EAX now holds starting sector - add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - - pop rcx ; Restore the number of sectors per cluster - call readsectors ; Read one cluster of sectors - -; Calculate the next cluster -; Psuedo-code -; tint1 = Cluster / 256 <- Dump the remainder -; sector_to_read = tint1 + ReservedSectors -; tint2 = (Cluster - (tint1 * 256)) * 2 - push rdi - mov rdi, secbuffer1 ; Read to this temporary buffer - mov rsi, rdi ; Copy buffer address to RSI - push rbx ; Save the original cluster value - shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - add rax, rbx ; Add the sector offset - mov rcx, 1 - call readsectors - pop rax ; Get our original cluster value back - shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) - sub rax, rbx ; RAX is now pointed to the offset within the sector - shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) - add rsi, rax - lodsw ; AX now holds the next cluster - pop rdi - - jmp os_fat16_read_cluster_end - -os_fat16_read_cluster_bailout: - xor ax, ax - -os_fat16_read_cluster_end: - pop rbx - pop rcx - pop rdx - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_write_cluster -- Write a cluster to the FAT16 partition -; IN: AX = Cluster # to write to -; RSI = Memory location of data to write -; OUT: AX = Next cluster in the chain (set to 0xFFFF if this was the last cluster of the chain) -; RSI = Points one byte after the last byte written -os_fat16_write_cluster: - push rdi - push rdx - push rcx - push rbx - - and rax, 0x000000000000FFFF ; Clear the top 48 bits - mov rbx, rax ; Save the cluster number to be used later - - cmp ax, 2 ; If less than 2 then bail out... - jl near os_fat16_write_cluster_bailout ; as clusters start at 2 - -; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start - xor rcx, rcx - mov cl, byte [fat16_SectorsPerCluster] - push rcx ; Save the number of sectors per cluster - sub ax, 2 - imul cx ; EAX now holds starting sector - add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - - pop rcx ; Restore the number of sectors per cluster - call writesectors - -; Calculate the next cluster - push rsi - mov rdi, secbuffer1 ; Read to this temporary buffer - mov rsi, rdi ; Copy buffer address to RSI - push rbx ; Save the original cluster value - shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - add rax, rbx ; Add the sector offset - mov rcx, 1 - call readsectors - pop rax ; Get our original cluster value back - shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) - sub rax, rbx ; RAX is now pointed to the offset within the sector - shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) - add rsi, rax - lodsw ; AX now holds the next cluster - pop rsi - - jmp os_fat16_write_cluster_done - -os_fat16_write_cluster_bailout: - xor ax, ax - -os_fat16_write_cluster_done: - pop rbx - pop rcx - pop rdx - pop rdi -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_find_file -- Search for a file name and return the starting cluster -; IN: RSI = Pointer to file name, must be in 'FILENAMEEXT' format -; OUT: AX = Staring cluster -; ECX = File size -; Carry set if not found. If carry is set then ignore value in AX -os_fat16_find_file: - push rsi - push rdi - push rdx - push rbx - - clc ; Clear carry - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - -os_fat16_find_file_read_sector: - mov rdi, hdbuffer1 - push rdi - mov rcx, 1 - call readsectors - pop rdi - mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 - -os_fat16_find_file_next_entry: - cmp byte [rdi], 0x00 ; end of records - je os_fat16_find_file_notfound - - mov rcx, 11 - push rsi - repe cmpsb - pop rsi - mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at - mov ecx, [rdi+17] ; ECX now holds the size of the file in bytes - jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 - - add rdi, byte 0x20 - and rdi, byte -0x20 - dec rbx - cmp rbx, 0 - jne os_fat16_find_file_next_entry - -; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. - - add rdx, 1 - mov rax, rdx - jmp os_fat16_find_file_read_sector - -os_fat16_find_file_notfound: - stc ; Set carry - xor rax, rax - -os_fat16_find_file_done: - cmp ax, 0x0000 ; BUG HERE - jne wut ; Carry is not being set properly in this function - stc -wut: - pop rbx - pop rdx - pop rdi - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_get_file_list -- Generate a list of files on disk -; IN: RDI = location to store list -; OUT: RDI = pointer to end of list -os_fat16_get_file_list: - push rsi - push rdi - push rcx - push rbx - push rax - - push rsi - mov rsi, dir_title_string - call os_string_length - call os_string_copy ; Copy the header - add rdi, rcx - pop rsi - - xor rbx, rbx - mov ebx, [fat16_RootStart] ; ebx points to the first sector of the root - add ebx, [fat16_PartitionOffset] ; Add the offset to the partition - - jmp os_fat16_get_file_list_read_sector - -os_fat16_get_file_list_next_sector: - add rbx, 1 - -os_fat16_get_file_list_read_sector: - push rdi - mov rdi, hdbuffer1 - mov rsi, rdi - mov rcx, 1 - mov rax, rbx - call readsectors - pop rdi - - ; RDI = location of string - ; RSI = buffer that contains the cluster - - ; start reading -os_fat16_get_file_list_read: - cmp rsi, hdbuffer1+512 - je os_fat16_get_file_list_next_sector - cmp byte [rsi], 0x00 ; end of records - je os_fat16_get_file_list_done - cmp byte [rsi], 0xE5 ; unused record - je os_fat16_get_file_list_skip - - mov al, [rsi + 8] ; Grab the attribute byte - bt ax, 5 ; check if bit 3 is set (volume label) - jc os_fat16_get_file_list_skip ; if so skip the entry - mov al, [rsi + 11] ; Grab the attribute byte - cmp al, 0x0F ; Check if it is a LFN entry - je os_fat16_get_file_list_skip ; if so skip the entry - - ; copy the string - xor rcx, rcx - xor rax, rax -os_fat16_get_file_list_copy: - mov al, [rsi+rcx] - stosb ; Store to RDI - inc rcx - cmp rcx, 8 - jne os_fat16_get_file_list_copy - - mov al, ' ' ; Store a space as the separtator - stosb - - mov al, [rsi+8] - stosb - mov al, [rsi+9] - stosb - mov al, [rsi+10] - stosb - - mov al, ' ' ; Store a space as the separtator - stosb - - mov eax, [rsi+0x1C] - call os_int_to_string - dec rdi - mov al, 13 - stosb - -os_fat16_get_file_list_skip: - add rsi, 32 - jmp os_fat16_get_file_list_read - -os_fat16_get_file_list_done: - mov al, 0x00 - stosb - - pop rax - pop rbx - pop rcx - pop rdi - pop rsi -ret - -dir_title_string: db "Name Ext Size", 13, "====================", 13, 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_read -- Read a file from disk into memory -; IN: RSI = Address of filename string -; RDI = Memory location where file will be loaded to -; OUT: Carry clear on success, set if file was not found or error occured -os_fat16_file_read: - push rsi - push rdi - push rcx ; Used by os_fat16_find_file - push rax - -; Convert the file name to FAT format - push rdi ; Save the memory address - mov rdi, os_fat16_file_read_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - xchg rsi, rdi - pop rdi ; Grab the memory address - jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted - -; Check to see if the file exists - call os_fat16_find_file ; Fuction will return the starting cluster value in AX or carry set if not found - jc os_fat16_file_read_done ; If Carry is clear then the file exists. AX is set to the starting cluster - -os_fat16_file_read_read: - call os_fat16_read_cluster ; Store cluster in memory. AX is set to the next cluster - cmp ax, 0xFFFF ; 0xFFFF is the FAT end of file marker - jne os_fat16_file_read_read ; Are there more clusters? If so then read again.. if not fall through - clc ; Clear Carry - -os_fat16_file_read_done: - pop rax - pop rcx - pop rdi - pop rsi -ret - - os_fat16_file_read_string times 13 db 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_write -- Write a file to the hard disk -; IN: RSI = Address of data in memory -; RDI = File name to write -; RCX = number of bytes to write -; OUT: Carry clear on success, set on failure -os_fat16_file_write: - push rsi - push rdi - push rcx - push rax - - mov [memory_address], rsi ; Save the memory address - -; Convert the file name to FAT format - mov rsi, rdi ; Move the file name address into RSI - mov rdi, os_fat16_file_write_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - jc os_fat16_file_write_done ; Fail (Invalid file name) - -; Check to see if a file already exists with the same name - mov rsi, os_fat16_file_write_string - push rcx - call os_fat16_find_file ; Returns the starting cluster in AX or carry set if it doesn't exist - pop rcx - jc os_fat16_file_write_create ; Jump if the file doesn't exist (No need to delete it) - jmp os_fat16_file_write_done ; call os_fat16_file_delete - -; At this point the file doesn't exist so create it. -os_fat16_file_write_create: -xchg bx, bx - call os_fat16_file_create - jc os_fat16_file_write_done ; Fail (Couldn't create the file) - call os_fat16_find_file ; Call this to get the starting cluster - jc os_fat16_file_write_done ; Fail (File was supposed to be created but wasn't) - -; We are ready to start writing. First cluster is in AX - mov rsi, [memory_address] -os_fat16_file_write_write: - call os_fat16_write_cluster - cmp ax, 0xFFFF - jne os_fat16_file_write_write - clc - -os_fat16_file_write_done: - pop rax - pop rcx - pop rdi - pop rsi -ret - - os_fat16_file_write_string times 13 db 0 - memory_address dq 0x0000000000000000 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_create -- Create a file on the hard disk -; IN: RSI = Pointer to file name, must be in FAT 'FILENAMEEXT' format -; RCX = File size -; OUT: Carry clear on success, set on failure -; Note: This function pre-allocates all clusters required for the size of the file -os_fat16_file_create: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - clc ; Clear the carry flag. It will be set if there is an error - - mov [filesize], ecx ; Save file size for later - mov [filename], rsi - -; Check to see if a file already exists with the same name -; call os_fat16_find_file -; jc os_fat16_file_create_fail ; Fail (File already exists) - -; How many clusters will we need? - mov rax, rcx - xor rdx, rdx - xor rbx, rbx - mov bl, byte [fat16_SectorsPerCluster] - shl rbx, 9 ; Multiply by 512 to get bytes per cluster - div rbx - cmp rdx, 0 - jg add_a_bit ; If there's a remainder, we need another cluster - jmp carry_on -add_a_bit: - add rax, 1 -carry_on: - mov rcx, rax ; RCX holds number of clusters that are needed - -; Allocate all of the clusters required for the amount of bytes we are writting. - xor rax, rax - mov ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdi, hdbuffer0 - mov rsi, rdi - push rcx - mov rcx, 64 - call readsectors - pop rcx - xor rdx, rdx ; cluster we are currently at - xor rbx, rbx ; cluster marker -findfirstfreeclust: - mov rdi, rsi - lodsw - inc dx ; counter - cmp ax, 0x0000 - jne findfirstfreeclust ; Continue until we find a free cluster - dec dx - mov [startcluster], dx ; Save the starting cluster ID - inc dx - mov bx, dx - cmp rcx, 0 - je clusterdone - cmp rcx, 1 - je clusterdone - -findnextfreecluster: - lodsw - inc dx - cmp ax, 0x0000 - jne findnextfreecluster - mov ax, bx - mov bx, dx - stosw - mov rdi, rsi - sub rdi, 2 - dec rcx - cmp rcx, 1 - jne findnextfreecluster - -clusterdone: - mov ax, 0xFFFF - stosw -; push dx ; save the free cluster number -; inc rbx -; cmp rbx, rcx ; Have we found enough free clusters? -; jne nextclust ; If not keep going, if yes fall through -; At this point we have free cluster ID's on the stack - -; mov ax, 0xFFFF - - - -; At this point we have a sector of FAT in hdbuffer0. A cluster has been marked in use but the sector is not written back to disk yet! -; Save the sector # as we will write this to disk later - -; Load the first sector of the file info table - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdi, hdbuffer1 - push rdi - mov rcx, 1 - call readsectors - pop rdi - mov rcx, 16 ; records / sector - mov rsi, rdi -nextrecord: - sub rcx, 1 - cmp byte [rsi], 0x00 ; Empty record - je foundfree - cmp byte [rsi], 0xE5 ; Unused record - je foundfree - add rsi, 32 ; Each record is 32 bytes - cmp rcx, 0 - je os_fat16_file_create_fail - jmp nextrecord - -foundfree: - ; At this point RSI points to the start of the record - mov rdi, rsi - mov rsi, [filename] - mov rcx, 11 -nextchar: - lodsb - stosb - sub rcx, 1 - cmp rcx, 0 - jne nextchar - xor rax, rax - stosb ; LFN Attrib - stosb ; NT Reserved - stosw ; Create time - stosb ; Create time - stosw ; Create date - stosw ; Access date - stosw ; Access time - stosw ; Modified time - stosw ; Modified date - mov ax, [startcluster] - stosw - mov eax, [filesize] - stosd ; File size - -; At this point the updated file record is in memory at hdbuffer1 - - xor rax, rax - - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rsi, hdbuffer0 - mov rcx, 64 - call writesectors - - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rsi, hdbuffer1 - mov rcx, 1 - call writesectors - - jmp os_fat16_file_create_done - -os_fat16_file_create_fail: - stc - call os_speaker_beep - -os_fat16_file_create_done: - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret - -; newfile_string times 13 db 0 - startcluster dw 0x0000 - filesize dd 0x00000000 - filename dq 0x0000000000000000 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_delete -- Delete a file from the hard disk -; IN: RSI = File name to delete -; OUT: Carry clear on success, set on failure -os_fat16_file_delete: - push rsi - push rdi - push rdx - push rcx - push rbx - - clc ; Clear carry - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - -; Convert the file name to FAT format - mov rdi, os_fat16_file_delete_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - jc os_fat16_file_delete_error ; Fail (Invalid file name) - mov rsi, rdi - -; Read through the root cluster (if file not found bail out) -os_fat16_file_delete_read_sector: - mov rdi, hdbuffer0 - push rdi - mov rcx, 1 - call readsectors - pop rdi - mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 - -os_fat16_file_delete_next_entry: - cmp byte [rdi], 0x00 ; end of records - je os_fat16_file_delete_error - - mov rcx, 11 - push rsi - repe cmpsb - pop rsi - mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at - jz os_fat16_file_delete_found ; The file was found. Note that rdi now is at dirent+11 - - add rdi, byte 0x20 ; Great little trick here. Add 32 ... - and rdi, byte -0x20 ; ... and then round backwards to a 32-byte barrier. Sets RDI to the start of the next record - dec rbx - cmp rbx, 0 - jne os_fat16_file_delete_next_entry - -; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. - add rdx, 1 ; We are about to read the next sector so increment the counter - mov rax, rdx - jmp os_fat16_file_delete_read_sector - -; Mark the file as deleted (set first byte of file name to 0xE5) and write the sector back to the drive -os_fat16_file_delete_found: - xor rbx, rbx - mov bx, ax ; Save the starting cluster value - and rdi, byte -0x20 ; Round backward to get to the start of the record - mov al, 0xE5 ; Set the first character of the filename to this - stosb - mov rsi, hdbuffer0 - mov rax, rdx ; Retrieve the sector number - mov rcx, 1 - call writesectors - -; Follow cluster chain and set any cluster in the chain to 0x0000 (mark as free) - xor rax, rax - mov ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - mov rdi, hdbuffer1 - mov rsi, rdi - mov rcx, 1 - call readsectors - xor rax, rax -os_fat16_file_delete_next_cluster: - shl rbx, 1 - mov ax, word [rsi+rbx] - mov [rsi+rbx], word 0x0000 - mov bx, ax - cmp ax, 0xFFFF - jne os_fat16_file_delete_next_cluster - mov rax, rdx ; Get the sector back. RSI already points to what we need - mov rcx, 1 - call writesectors - jmp os_fat16_file_delete_done - -os_fat16_file_delete_error: - xor rax, rax - stc ; Set carry - -os_fat16_file_delete_done: - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret - - os_fat16_file_delete_string times 13 db 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_get_file_size -- Read a file from disk into memory -; IN: RSI = Address of filename string -; OUT: RCX = Size of file in bytes -; Carry clear on success, set if file was not found or error occured -os_fat16_get_file_size: - push rsi - push rdi - push rax - xor ecx, ecx - -; Convert the file name to FAT format - mov rdi, os_fat16_get_file_size_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - mov rsi, rdi - jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted - -; Check to see if the file exists - call os_fat16_find_file ; Fuction will return the starting cluster value in AX and size in ECX or carry set if not found - -os_fat16_get_file_size_done: - pop rax - pop rdi - pop rsi -ret - - os_fat16_get_file_size_string times 13 db 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_filename_convert -- Change 'test.er' into 'TEST ER ' as per FAT16 -; IN: RSI = filename string -; RDI = location to store converted string (carry set if invalid) -; OUT: All registers preserved -; NOTE: Must have room for 12 bytes. 11 for the name and 1 for the NULL -; Need fix for short extensions! -os_fat16_filename_convert: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - mov rbx, rdi ; Save the string destination address - call os_string_length - cmp rcx, 12 ; Bigger than name + dot + extension? - jg os_fat16_filename_convert_failure ; Fail if so - cmp rcx, 0 - je os_fat16_filename_convert_failure ; Similarly, fail if zero-char string - - mov rdx, rcx ; Store string length for now - xor rcx, rcx -os_fat16_filename_convert_copy_loop: - lodsb - cmp al, '.' - je os_fat16_filename_convert_extension_found - stosb - inc rcx - cmp rcx, rdx - jg os_fat16_filename_convert_failure ; No extension found = wrong - jmp os_fat16_filename_convert_copy_loop - -os_fat16_filename_convert_failure: - stc ; Set carry for failure - jmp os_fat16_filename_convert_done - -os_fat16_filename_convert_extension_found: - cmp rcx, 0 - je os_fat16_filename_convert_failure ; Fail if extension dot is first char - cmp rcx, 8 - je os_fat16_filename_convert_do_extension ; Skip spaces if first bit is 8 chars - - mov al, ' ' -os_fat16_filename_convert_add_spaces: - stosb - inc rcx - cmp rcx, 8 - jl os_fat16_filename_convert_add_spaces - -os_fat16_filename_convert_do_extension: ; FIX THIS for cases where ext is less than 3 chars - lodsb - stosb - lodsb - stosb - lodsb - stosb - mov byte [rdi], 0 ; Zero-terminate filename - clc ; Clear carry for success - mov rsi, rbx ; Get the start address of the desitination string - call os_string_uppercase ; Set it all to uppercase - -os_fat16_filename_convert_done: - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; FAT16 Functions +; ============================================================================= + +align 16 +db 'DEBUG: FAT16 ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_fat16_read_cluster -- Read a cluster from the FAT16 partition +; IN: AX = Cluster # to read +; RDI = Memory location to store at least 32KB +; OUT: AX = Next cluster in chain (0xFFFF if this was the last) +; RDI = Points one byte after the last byte read +os_fat16_read_cluster: + push rsi + push rdx + push rcx + push rbx + + and rax, 0x000000000000FFFF ; Clear the top 48 bits + mov rbx, rax ; Save the cluster number to be used later + + cmp ax, 2 ; If less than 2 then bail out... + jl near os_fat16_read_cluster_bailout ; as clusters start at 2 + +; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start + xor rcx, rcx + mov cl, byte [fat16_SectorsPerCluster] + push rcx ; Save the number of sectors per cluster + sub ax, 2 + imul cx ; EAX now holds starting sector + add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + + pop rcx ; Restore the number of sectors per cluster + call readsectors ; Read one cluster of sectors + +; Calculate the next cluster +; Psuedo-code +; tint1 = Cluster / 256 <- Dump the remainder +; sector_to_read = tint1 + ReservedSectors +; tint2 = (Cluster - (tint1 * 256)) * 2 + push rdi + mov rdi, secbuffer1 ; Read to this temporary buffer + mov rsi, rdi ; Copy buffer address to RSI + push rbx ; Save the original cluster value + shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + add rax, rbx ; Add the sector offset + mov rcx, 1 + call readsectors + pop rax ; Get our original cluster value back + shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) + sub rax, rbx ; RAX is now pointed to the offset within the sector + shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) + add rsi, rax + lodsw ; AX now holds the next cluster + pop rdi + + jmp os_fat16_read_cluster_end + +os_fat16_read_cluster_bailout: + xor ax, ax + +os_fat16_read_cluster_end: + pop rbx + pop rcx + pop rdx + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_write_cluster -- Write a cluster to the FAT16 partition +; IN: AX = Cluster # to write to +; RSI = Memory location of data to write +; OUT: AX = Next cluster in the chain (set to 0xFFFF if this was the last cluster of the chain) +; RSI = Points one byte after the last byte written +os_fat16_write_cluster: + push rdi + push rdx + push rcx + push rbx + + and rax, 0x000000000000FFFF ; Clear the top 48 bits + mov rbx, rax ; Save the cluster number to be used later + + cmp ax, 2 ; If less than 2 then bail out... + jl near os_fat16_write_cluster_bailout ; as clusters start at 2 + +; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start + xor rcx, rcx + mov cl, byte [fat16_SectorsPerCluster] + push rcx ; Save the number of sectors per cluster + sub ax, 2 + imul cx ; EAX now holds starting sector + add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + + pop rcx ; Restore the number of sectors per cluster + call writesectors + +; Calculate the next cluster + push rsi + mov rdi, secbuffer1 ; Read to this temporary buffer + mov rsi, rdi ; Copy buffer address to RSI + push rbx ; Save the original cluster value + shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + add rax, rbx ; Add the sector offset + mov rcx, 1 + call readsectors + pop rax ; Get our original cluster value back + shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) + sub rax, rbx ; RAX is now pointed to the offset within the sector + shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) + add rsi, rax + lodsw ; AX now holds the next cluster + pop rsi + + jmp os_fat16_write_cluster_done + +os_fat16_write_cluster_bailout: + xor ax, ax + +os_fat16_write_cluster_done: + pop rbx + pop rcx + pop rdx + pop rdi +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_find_file -- Search for a file name and return the starting cluster +; IN: RSI = Pointer to file name, must be in 'FILENAMEEXT' format +; OUT: AX = Staring cluster +; ECX = File size +; Carry set if not found. If carry is set then ignore value in AX +os_fat16_find_file: + push rsi + push rdi + push rdx + push rbx + + clc ; Clear carry + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + +os_fat16_find_file_read_sector: + mov rdi, hdbuffer1 + push rdi + mov rcx, 1 + call readsectors + pop rdi + mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 + +os_fat16_find_file_next_entry: + cmp byte [rdi], 0x00 ; end of records + je os_fat16_find_file_notfound + + mov rcx, 11 + push rsi + repe cmpsb + pop rsi + mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at + mov ecx, [rdi+17] ; ECX now holds the size of the file in bytes + jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 + + add rdi, byte 0x20 + and rdi, byte -0x20 + dec rbx + cmp rbx, 0 + jne os_fat16_find_file_next_entry + +; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. + + add rdx, 1 + mov rax, rdx + jmp os_fat16_find_file_read_sector + +os_fat16_find_file_notfound: + stc ; Set carry + xor rax, rax + +os_fat16_find_file_done: + cmp ax, 0x0000 ; BUG HERE + jne wut ; Carry is not being set properly in this function + stc +wut: + pop rbx + pop rdx + pop rdi + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_get_file_list -- Generate a list of files on disk +; IN: RDI = location to store list +; OUT: RDI = pointer to end of list +os_fat16_get_file_list: + push rsi + push rdi + push rcx + push rbx + push rax + + push rsi + mov rsi, dir_title_string + call os_string_length + call os_string_copy ; Copy the header + add rdi, rcx + pop rsi + + xor rbx, rbx + mov ebx, [fat16_RootStart] ; ebx points to the first sector of the root + add ebx, [fat16_PartitionOffset] ; Add the offset to the partition + + jmp os_fat16_get_file_list_read_sector + +os_fat16_get_file_list_next_sector: + add rbx, 1 + +os_fat16_get_file_list_read_sector: + push rdi + mov rdi, hdbuffer1 + mov rsi, rdi + mov rcx, 1 + mov rax, rbx + call readsectors + pop rdi + + ; RDI = location of string + ; RSI = buffer that contains the cluster + + ; start reading +os_fat16_get_file_list_read: + cmp rsi, hdbuffer1+512 + je os_fat16_get_file_list_next_sector + cmp byte [rsi], 0x00 ; end of records + je os_fat16_get_file_list_done + cmp byte [rsi], 0xE5 ; unused record + je os_fat16_get_file_list_skip + + mov al, [rsi + 8] ; Grab the attribute byte + bt ax, 5 ; check if bit 3 is set (volume label) + jc os_fat16_get_file_list_skip ; if so skip the entry + mov al, [rsi + 11] ; Grab the attribute byte + cmp al, 0x0F ; Check if it is a LFN entry + je os_fat16_get_file_list_skip ; if so skip the entry + + ; copy the string + xor rcx, rcx + xor rax, rax +os_fat16_get_file_list_copy: + mov al, [rsi+rcx] + stosb ; Store to RDI + inc rcx + cmp rcx, 8 + jne os_fat16_get_file_list_copy + + mov al, ' ' ; Store a space as the separtator + stosb + + mov al, [rsi+8] + stosb + mov al, [rsi+9] + stosb + mov al, [rsi+10] + stosb + + mov al, ' ' ; Store a space as the separtator + stosb + + mov eax, [rsi+0x1C] + call os_int_to_string + dec rdi + mov al, 13 + stosb + +os_fat16_get_file_list_skip: + add rsi, 32 + jmp os_fat16_get_file_list_read + +os_fat16_get_file_list_done: + mov al, 0x00 + stosb + + pop rax + pop rbx + pop rcx + pop rdi + pop rsi +ret + +dir_title_string: db "Name Ext Size", 13, "====================", 13, 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_read -- Read a file from disk into memory +; IN: RSI = Address of filename string +; RDI = Memory location where file will be loaded to +; OUT: Carry clear on success, set if file was not found or error occured +os_fat16_file_read: + push rsi + push rdi + push rcx ; Used by os_fat16_find_file + push rax + +; Convert the file name to FAT format + push rdi ; Save the memory address + mov rdi, os_fat16_file_read_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + xchg rsi, rdi + pop rdi ; Grab the memory address + jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted + +; Check to see if the file exists + call os_fat16_find_file ; Fuction will return the starting cluster value in AX or carry set if not found + jc os_fat16_file_read_done ; If Carry is clear then the file exists. AX is set to the starting cluster + +os_fat16_file_read_read: + call os_fat16_read_cluster ; Store cluster in memory. AX is set to the next cluster + cmp ax, 0xFFFF ; 0xFFFF is the FAT end of file marker + jne os_fat16_file_read_read ; Are there more clusters? If so then read again.. if not fall through + clc ; Clear Carry + +os_fat16_file_read_done: + pop rax + pop rcx + pop rdi + pop rsi +ret + + os_fat16_file_read_string times 13 db 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_write -- Write a file to the hard disk +; IN: RSI = Address of data in memory +; RDI = File name to write +; RCX = number of bytes to write +; OUT: Carry clear on success, set on failure +os_fat16_file_write: + push rsi + push rdi + push rcx + push rax + + mov [memory_address], rsi ; Save the memory address + +; Convert the file name to FAT format + mov rsi, rdi ; Move the file name address into RSI + mov rdi, os_fat16_file_write_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + jc os_fat16_file_write_done ; Fail (Invalid file name) + +; Check to see if a file already exists with the same name + mov rsi, os_fat16_file_write_string + push rcx + call os_fat16_find_file ; Returns the starting cluster in AX or carry set if it doesn't exist + pop rcx + jc os_fat16_file_write_create ; Jump if the file doesn't exist (No need to delete it) + jmp os_fat16_file_write_done ; call os_fat16_file_delete + +; At this point the file doesn't exist so create it. +os_fat16_file_write_create: +xchg bx, bx + call os_fat16_file_create + jc os_fat16_file_write_done ; Fail (Couldn't create the file) + call os_fat16_find_file ; Call this to get the starting cluster + jc os_fat16_file_write_done ; Fail (File was supposed to be created but wasn't) + +; We are ready to start writing. First cluster is in AX + mov rsi, [memory_address] +os_fat16_file_write_write: + call os_fat16_write_cluster + cmp ax, 0xFFFF + jne os_fat16_file_write_write + clc + +os_fat16_file_write_done: + pop rax + pop rcx + pop rdi + pop rsi +ret + + os_fat16_file_write_string times 13 db 0 + memory_address dq 0x0000000000000000 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_create -- Create a file on the hard disk +; IN: RSI = Pointer to file name, must be in FAT 'FILENAMEEXT' format +; RCX = File size +; OUT: Carry clear on success, set on failure +; Note: This function pre-allocates all clusters required for the size of the file +os_fat16_file_create: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + clc ; Clear the carry flag. It will be set if there is an error + + mov [filesize], ecx ; Save file size for later + mov [filename], rsi + +; Check to see if a file already exists with the same name +; call os_fat16_find_file +; jc os_fat16_file_create_fail ; Fail (File already exists) + +; How many clusters will we need? + mov rax, rcx + xor rdx, rdx + xor rbx, rbx + mov bl, byte [fat16_SectorsPerCluster] + shl rbx, 9 ; Multiply by 512 to get bytes per cluster + div rbx + cmp rdx, 0 + jg add_a_bit ; If there's a remainder, we need another cluster + jmp carry_on +add_a_bit: + add rax, 1 +carry_on: + mov rcx, rax ; RCX holds number of clusters that are needed + +; Allocate all of the clusters required for the amount of bytes we are writting. + xor rax, rax + mov ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdi, hdbuffer0 + mov rsi, rdi + push rcx + mov rcx, 64 + call readsectors + pop rcx + xor rdx, rdx ; cluster we are currently at + xor rbx, rbx ; cluster marker +findfirstfreeclust: + mov rdi, rsi + lodsw + inc dx ; counter + cmp ax, 0x0000 + jne findfirstfreeclust ; Continue until we find a free cluster + dec dx + mov [startcluster], dx ; Save the starting cluster ID + inc dx + mov bx, dx + cmp rcx, 0 + je clusterdone + cmp rcx, 1 + je clusterdone + +findnextfreecluster: + lodsw + inc dx + cmp ax, 0x0000 + jne findnextfreecluster + mov ax, bx + mov bx, dx + stosw + mov rdi, rsi + sub rdi, 2 + dec rcx + cmp rcx, 1 + jne findnextfreecluster + +clusterdone: + mov ax, 0xFFFF + stosw +; push dx ; save the free cluster number +; inc rbx +; cmp rbx, rcx ; Have we found enough free clusters? +; jne nextclust ; If not keep going, if yes fall through +; At this point we have free cluster ID's on the stack + +; mov ax, 0xFFFF + + + +; At this point we have a sector of FAT in hdbuffer0. A cluster has been marked in use but the sector is not written back to disk yet! +; Save the sector # as we will write this to disk later + +; Load the first sector of the file info table + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdi, hdbuffer1 + push rdi + mov rcx, 1 + call readsectors + pop rdi + mov rcx, 16 ; records / sector + mov rsi, rdi +nextrecord: + sub rcx, 1 + cmp byte [rsi], 0x00 ; Empty record + je foundfree + cmp byte [rsi], 0xE5 ; Unused record + je foundfree + add rsi, 32 ; Each record is 32 bytes + cmp rcx, 0 + je os_fat16_file_create_fail + jmp nextrecord + +foundfree: + ; At this point RSI points to the start of the record + mov rdi, rsi + mov rsi, [filename] + mov rcx, 11 +nextchar: + lodsb + stosb + sub rcx, 1 + cmp rcx, 0 + jne nextchar + xor rax, rax + stosb ; LFN Attrib + stosb ; NT Reserved + stosw ; Create time + stosb ; Create time + stosw ; Create date + stosw ; Access date + stosw ; Access time + stosw ; Modified time + stosw ; Modified date + mov ax, [startcluster] + stosw + mov eax, [filesize] + stosd ; File size + +; At this point the updated file record is in memory at hdbuffer1 + + xor rax, rax + + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rsi, hdbuffer0 + mov rcx, 64 + call writesectors + + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rsi, hdbuffer1 + mov rcx, 1 + call writesectors + + jmp os_fat16_file_create_done + +os_fat16_file_create_fail: + stc + call os_speaker_beep + +os_fat16_file_create_done: + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret + +; newfile_string times 13 db 0 + startcluster dw 0x0000 + filesize dd 0x00000000 + filename dq 0x0000000000000000 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_delete -- Delete a file from the hard disk +; IN: RSI = File name to delete +; OUT: Carry clear on success, set on failure +os_fat16_file_delete: + push rsi + push rdi + push rdx + push rcx + push rbx + + clc ; Clear carry + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + +; Convert the file name to FAT format + mov rdi, os_fat16_file_delete_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + jc os_fat16_file_delete_error ; Fail (Invalid file name) + mov rsi, rdi + +; Read through the root cluster (if file not found bail out) +os_fat16_file_delete_read_sector: + mov rdi, hdbuffer0 + push rdi + mov rcx, 1 + call readsectors + pop rdi + mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 + +os_fat16_file_delete_next_entry: + cmp byte [rdi], 0x00 ; end of records + je os_fat16_file_delete_error + + mov rcx, 11 + push rsi + repe cmpsb + pop rsi + mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at + jz os_fat16_file_delete_found ; The file was found. Note that rdi now is at dirent+11 + + add rdi, byte 0x20 ; Great little trick here. Add 32 ... + and rdi, byte -0x20 ; ... and then round backwards to a 32-byte barrier. Sets RDI to the start of the next record + dec rbx + cmp rbx, 0 + jne os_fat16_file_delete_next_entry + +; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. + add rdx, 1 ; We are about to read the next sector so increment the counter + mov rax, rdx + jmp os_fat16_file_delete_read_sector + +; Mark the file as deleted (set first byte of file name to 0xE5) and write the sector back to the drive +os_fat16_file_delete_found: + xor rbx, rbx + mov bx, ax ; Save the starting cluster value + and rdi, byte -0x20 ; Round backward to get to the start of the record + mov al, 0xE5 ; Set the first character of the filename to this + stosb + mov rsi, hdbuffer0 + mov rax, rdx ; Retrieve the sector number + mov rcx, 1 + call writesectors + +; Follow cluster chain and set any cluster in the chain to 0x0000 (mark as free) + xor rax, rax + mov ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + mov rdi, hdbuffer1 + mov rsi, rdi + mov rcx, 1 + call readsectors + xor rax, rax +os_fat16_file_delete_next_cluster: + shl rbx, 1 + mov ax, word [rsi+rbx] + mov [rsi+rbx], word 0x0000 + mov bx, ax + cmp ax, 0xFFFF + jne os_fat16_file_delete_next_cluster + mov rax, rdx ; Get the sector back. RSI already points to what we need + mov rcx, 1 + call writesectors + jmp os_fat16_file_delete_done + +os_fat16_file_delete_error: + xor rax, rax + stc ; Set carry + +os_fat16_file_delete_done: + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret + + os_fat16_file_delete_string times 13 db 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_get_file_size -- Read a file from disk into memory +; IN: RSI = Address of filename string +; OUT: RCX = Size of file in bytes +; Carry clear on success, set if file was not found or error occured +os_fat16_get_file_size: + push rsi + push rdi + push rax + xor ecx, ecx + +; Convert the file name to FAT format + mov rdi, os_fat16_get_file_size_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + mov rsi, rdi + jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted + +; Check to see if the file exists + call os_fat16_find_file ; Fuction will return the starting cluster value in AX and size in ECX or carry set if not found + +os_fat16_get_file_size_done: + pop rax + pop rdi + pop rsi +ret + + os_fat16_get_file_size_string times 13 db 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_filename_convert -- Change 'test.er' into 'TEST ER ' as per FAT16 +; IN: RSI = filename string +; RDI = location to store converted string (carry set if invalid) +; OUT: All registers preserved +; NOTE: Must have room for 12 bytes. 11 for the name and 1 for the NULL +; Need fix for short extensions! +os_fat16_filename_convert: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + mov rbx, rdi ; Save the string destination address + call os_string_length + cmp rcx, 12 ; Bigger than name + dot + extension? + jg os_fat16_filename_convert_failure ; Fail if so + cmp rcx, 0 + je os_fat16_filename_convert_failure ; Similarly, fail if zero-char string + + mov rdx, rcx ; Store string length for now + xor rcx, rcx +os_fat16_filename_convert_copy_loop: + lodsb + cmp al, '.' + je os_fat16_filename_convert_extension_found + stosb + inc rcx + cmp rcx, rdx + jg os_fat16_filename_convert_failure ; No extension found = wrong + jmp os_fat16_filename_convert_copy_loop + +os_fat16_filename_convert_failure: + stc ; Set carry for failure + jmp os_fat16_filename_convert_done + +os_fat16_filename_convert_extension_found: + cmp rcx, 0 + je os_fat16_filename_convert_failure ; Fail if extension dot is first char + cmp rcx, 8 + je os_fat16_filename_convert_do_extension ; Skip spaces if first bit is 8 chars + + mov al, ' ' +os_fat16_filename_convert_add_spaces: + stosb + inc rcx + cmp rcx, 8 + jl os_fat16_filename_convert_add_spaces + +os_fat16_filename_convert_do_extension: ; FIX THIS for cases where ext is less than 3 chars + lodsb + stosb + lodsb + stosb + lodsb + stosb + mov byte [rdi], 0 ; Zero-terminate filename + clc ; Clear carry for success + mov rsi, rbx ; Get the start address of the desitination string + call os_string_uppercase ; Set it all to uppercase + +os_fat16_filename_convert_done: + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/hdd.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/hdd.asm index 9e7878b6..07ee75ff 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/hdd.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/hdd.asm @@ -1,215 +1,215 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Hard Drive Functions -; ============================================================================= - -align 16 -db 'DEBUG: HDD ' -align 16 - - -; NOTE: These functions use LBA28. Maximum visible drive size is 128GiB -; LBA48 would be needed to access sectors over 128GiB (up to 128PiB) -; These functions are hard coded to access the Primary Master HDD - - -; ----------------------------------------------------------------------------- -; readsectors -- Read sectors on the hard drive -; IN: RAX = starting sector to read -; RCX = number of sectors to read (1 - 256) -; RDI = memory location to store sectors -; OUT: RAX = RAX + number of sectors that were read -; RCX = number of sectors that were read (0 on error) -; RDI = RDI + (number of sectors * 512) -; All other registers preserved -readsectors: - push rdx - push rcx - push rbx - push rax - - push rcx ; Save RCX for use in the read loop - mov rbx, rcx ; Store number of sectors to read - cmp rcx, 256 - jg readsectors_fail ; Over 256? Fail! - jne readsectors_skip ; Not 256? No need to modify CL - xor rcx, rcx ; 0 translates to 256 -readsectors_skip: - - push rax ; Save RAX since we are about to overwrite it - mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 - mov al, cl ; Read CL sectors - out dx, al - pop rax ; Restore RAX which is our sector number - inc dx ; 0x01F3 - LBA Low Port 7:0 - out dx, al - inc dx ; 0x01F4 - LBA Mid Port 15:8 - shr rax, 8 - out dx, al - inc dx ; 0x01F5 - LBA High Port 23:16 - shr rax, 8 - out dx, al - inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) - shr rax, 8 - and al, 00001111b ; Clear bits 4-7 just to be safe - or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) - out dx, al - inc dx ; 0x01F7 - Command Port - mov al, 0x20 ; Read sector(s). 0x24 if LBA48 - out dx, al - - mov rcx, 4 -readsectors_wait: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_retry - test al, 0x08 ; DRQ set? - jne readsectors_dataready -readsectors_retry: - dec rcx - jg readsectors_wait -readsectors_nextsector: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_nextsector - test al, 0x21 ; ERR or DF set? - jne readsectors_fail - -readsectors_dataready: - sub dx, 7 ; Data port (0x1F0) - mov rcx, 256 ; Read - rep insw ; Copy a 512 byte sector to RDI - add dx, 7 ; Set DX back to status register (0x01F7) - in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ - in al, dx - in al, dx - in al, dx - - dec rbx ; RBX is the "sectors to read" counter - cmp rbx, 0 - jne readsectors_nextsector - - pop rcx - pop rax - pop rbx - add rax, rcx - pop rcx - pop rdx -ret - -readsectors_fail: - pop rcx - pop rax - pop rbx - pop rcx - pop rdx - xor rcx, rcx ; Set RCX to 0 since nothing was read -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; writesectors -- Write sectors on the hard drive -; IN: RAX = starting sector to write -; RCX = number of sectors to write (1 - 256) -; RSI = memory location of sectors -; OUT: RAX = RAX + number of sectors that were written -; RCX = number of sectors that were written (0 on error) -; RSI = RSI + (number of sectors * 512) -; All other registers preserved -writesectors: - push rdx - push rcx - push rbx - push rax - - push rcx ; Save RCX for use in the write loop - mov rbx, rcx ; Store number of sectors to write - cmp rcx, 256 - jg writesectors_fail ; Over 256? Fail! - jne writesectors_skip ; Not 256? No need to modify CL - xor rcx, rcx ; 0 translates to 256 -writesectors_skip: - - push rax ; Save RAX since we are about to overwrite it - mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 - mov al, cl ; Write CL sectors - out dx, al - pop rax ; Restore RAX which is our sector number - inc dx ; 0x01F3 - LBA Low Port 7:0 - out dx, al - inc dx ; 0x01F4 - LBA Mid Port 15:8 - shr rax, 8 - out dx, al - inc dx ; 0x01F5 - LBA High Port 23:16 - shr rax, 8 - out dx, al - inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) - shr rax, 8 ; Bits 7 and 5 are obsolete in LBA mode so set to 0 - and al, 00001111b ; Clear bits 4-7 just to be safe - or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) - out dx, al - inc dx ; 0x01F7 - Command Port - mov al, 0x30 ; Write sector(s). 0x34 if LBA48 - out dx, al - - mov rcx, 4 -writesectors_wait: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne writesectors_retry - test al, 0x08 ; DRQ set? - jne writesectors_dataready -writesectors_retry: - dec rcx - jg writesectors_wait -writesectors_nextsector: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne writesectors_nextsector - test al, 0x21 ; ERR or DF set? - jne writesectors_fail - -writesectors_dataready: - sub dx, 7 ; Data port (0x01F0) - mov rcx, 256 ; Write 256 words (512 bytes) -writesectors_nextword: - outsw ; Cannot use rep as a small delay is needed between each out - sub rcx, 1 - cmp rcx, 0 - jne writesectors_nextword - add dx, 7 ; Set DX back to Command / Status Register (0x01F7) - mov al, 0xE7 ; Cache Flush command - out dx, al - in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ - in al, dx - in al, dx - in al, dx - - dec rbx ; RBX is the "sectors to write" counter - cmp rbx, 0 - jne writesectors_nextsector - - pop rcx - pop rax - pop rbx - add rax, rcx - pop rcx - pop rdx -ret - -writesectors_fail: - pop rcx - pop rax - pop rbx - pop rcx - pop rdx - xor rcx, rcx ; Set RCX to 0 since nothing was written -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Hard Drive Functions +; ============================================================================= + +align 16 +db 'DEBUG: HDD ' +align 16 + + +; NOTE: These functions use LBA28. Maximum visible drive size is 128GiB +; LBA48 would be needed to access sectors over 128GiB (up to 128PiB) +; These functions are hard coded to access the Primary Master HDD + + +; ----------------------------------------------------------------------------- +; readsectors -- Read sectors on the hard drive +; IN: RAX = starting sector to read +; RCX = number of sectors to read (1 - 256) +; RDI = memory location to store sectors +; OUT: RAX = RAX + number of sectors that were read +; RCX = number of sectors that were read (0 on error) +; RDI = RDI + (number of sectors * 512) +; All other registers preserved +readsectors: + push rdx + push rcx + push rbx + push rax + + push rcx ; Save RCX for use in the read loop + mov rbx, rcx ; Store number of sectors to read + cmp rcx, 256 + jg readsectors_fail ; Over 256? Fail! + jne readsectors_skip ; Not 256? No need to modify CL + xor rcx, rcx ; 0 translates to 256 +readsectors_skip: + + push rax ; Save RAX since we are about to overwrite it + mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 + mov al, cl ; Read CL sectors + out dx, al + pop rax ; Restore RAX which is our sector number + inc dx ; 0x01F3 - LBA Low Port 7:0 + out dx, al + inc dx ; 0x01F4 - LBA Mid Port 15:8 + shr rax, 8 + out dx, al + inc dx ; 0x01F5 - LBA High Port 23:16 + shr rax, 8 + out dx, al + inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) + shr rax, 8 + and al, 00001111b ; Clear bits 4-7 just to be safe + or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) + out dx, al + inc dx ; 0x01F7 - Command Port + mov al, 0x20 ; Read sector(s). 0x24 if LBA48 + out dx, al + + mov rcx, 4 +readsectors_wait: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_retry + test al, 0x08 ; DRQ set? + jne readsectors_dataready +readsectors_retry: + dec rcx + jg readsectors_wait +readsectors_nextsector: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_nextsector + test al, 0x21 ; ERR or DF set? + jne readsectors_fail + +readsectors_dataready: + sub dx, 7 ; Data port (0x1F0) + mov rcx, 256 ; Read + rep insw ; Copy a 512 byte sector to RDI + add dx, 7 ; Set DX back to status register (0x01F7) + in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ + in al, dx + in al, dx + in al, dx + + dec rbx ; RBX is the "sectors to read" counter + cmp rbx, 0 + jne readsectors_nextsector + + pop rcx + pop rax + pop rbx + add rax, rcx + pop rcx + pop rdx +ret + +readsectors_fail: + pop rcx + pop rax + pop rbx + pop rcx + pop rdx + xor rcx, rcx ; Set RCX to 0 since nothing was read +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; writesectors -- Write sectors on the hard drive +; IN: RAX = starting sector to write +; RCX = number of sectors to write (1 - 256) +; RSI = memory location of sectors +; OUT: RAX = RAX + number of sectors that were written +; RCX = number of sectors that were written (0 on error) +; RSI = RSI + (number of sectors * 512) +; All other registers preserved +writesectors: + push rdx + push rcx + push rbx + push rax + + push rcx ; Save RCX for use in the write loop + mov rbx, rcx ; Store number of sectors to write + cmp rcx, 256 + jg writesectors_fail ; Over 256? Fail! + jne writesectors_skip ; Not 256? No need to modify CL + xor rcx, rcx ; 0 translates to 256 +writesectors_skip: + + push rax ; Save RAX since we are about to overwrite it + mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 + mov al, cl ; Write CL sectors + out dx, al + pop rax ; Restore RAX which is our sector number + inc dx ; 0x01F3 - LBA Low Port 7:0 + out dx, al + inc dx ; 0x01F4 - LBA Mid Port 15:8 + shr rax, 8 + out dx, al + inc dx ; 0x01F5 - LBA High Port 23:16 + shr rax, 8 + out dx, al + inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) + shr rax, 8 ; Bits 7 and 5 are obsolete in LBA mode so set to 0 + and al, 00001111b ; Clear bits 4-7 just to be safe + or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) + out dx, al + inc dx ; 0x01F7 - Command Port + mov al, 0x30 ; Write sector(s). 0x34 if LBA48 + out dx, al + + mov rcx, 4 +writesectors_wait: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne writesectors_retry + test al, 0x08 ; DRQ set? + jne writesectors_dataready +writesectors_retry: + dec rcx + jg writesectors_wait +writesectors_nextsector: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne writesectors_nextsector + test al, 0x21 ; ERR or DF set? + jne writesectors_fail + +writesectors_dataready: + sub dx, 7 ; Data port (0x01F0) + mov rcx, 256 ; Write 256 words (512 bytes) +writesectors_nextword: + outsw ; Cannot use rep as a small delay is needed between each out + sub rcx, 1 + cmp rcx, 0 + jne writesectors_nextword + add dx, 7 ; Set DX back to Command / Status Register (0x01F7) + mov al, 0xE7 ; Cache Flush command + out dx, al + in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ + in al, dx + in al, dx + in al, dx + + dec rbx ; RBX is the "sectors to write" counter + cmp rbx, 0 + jne writesectors_nextsector + + pop rcx + pop rax + pop rbx + add rax, rcx + pop rcx + pop rdx +ret + +writesectors_fail: + pop rcx + pop rax + pop rbx + pop rcx + pop rdx + xor rcx, rcx ; Set RCX to 0 since nothing was written +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/bcm57xx.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/bcm57xx.asm index 1cc94dc9..7bdf91ef 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/bcm57xx.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/bcm57xx.asm @@ -1,122 +1,122 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Broadcom 57XX NIC. -; ============================================================================= - -align 16 -db 'DEBUG: BCM57xx ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_init - Initialize a Broadcom 57XX NIC -; IN: AL = Bus number of the Realtek device -; BL = Device/Slot number of the Realtek device -os_net_bcm57xx_init: - push rsi - push rdx - push rcx - push rax - - ; Grab the Base I/O Address of the device - push ax - mov cl, 0x04 ; BAR0 - Lower 32 bits of memory address - call os_pci_read_reg -; mov dword [os_NetIOAddress], eax - pop ax - - ; Grab the IRQ of the device - mov cl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) - call os_pci_read_reg - mov [os_NetIRQ], al ; AL holds the IRQ - - ; Grab the MAC address - mov rsi, [os_NetIOBaseMem] - mov eax, [rsi+0x410] ; Mac_Address_0 Part 1 - ror eax, 8 - mov [os_NetMAC], al - rol eax, 8 - mov [os_NetMAC+1], al - mov eax, [rsi+0x414] ; Mac_Address_0 Part 2 - rol eax, 8 - mov [os_NetMAC+2], al - rol eax, 8 - mov [os_NetMAC+3], al - rol eax, 8 - mov [os_NetMAC+4], al - rol eax, 8 - mov [os_NetMAC+5], al - - ; Enable the Network IRQ in the PIC - ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 - in al, 0x21 ; low byte target 0x21 - mov bl, al - mov al, [os_NetIRQ] - mov dx, 0x21 ; Use the low byte pic - cmp al, 8 - jl os_net_bcm57xx_init_low - sub al, 8 ; IRQ 8-16 - push ax - in al, 0xA1 ; High byte target 0xA1 - mov bl, al - pop ax - mov dx, 0xA1 ; Use the high byte pic -os_net_bcm57xx_init_low: - mov cl, al - mov al, 1 - shl al, cl - not al - and al, bl - out dx, al - - ; Reset the device - call os_net_bcm57xx_reset - - pop rax - pop rcx - pop rdx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_reset - Reset a Broadcom 57XX NIC -; IN: Nothing -; OUT: Nothing, all registers preserved -os_net_bcm57xx_reset: - - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_transmit - Transmit a packet via a Broadcom 57XX NIC -; IN: RSI = Location of packet -; RCX = Length of packet -; OUT: Nothing -; Uses RAX, RCX, RDX, RSI, RDI -; ToDo: Check for proper timeout instead of calling os_delay -os_net_bcm57xx_transmit: - - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_poll - Polls the Broadcom 57XX NIC for a received packet -; IN: RDI = Location to store packet -; OUT: RCX = Length of packet -; Uses RAX, RCX, RDX, RSI, RDI -os_net_bcm57xx_poll: - -os_net_bcm57xx_ack_int: - - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Broadcom 57XX NIC. +; ============================================================================= + +align 16 +db 'DEBUG: BCM57xx ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_init - Initialize a Broadcom 57XX NIC +; IN: AL = Bus number of the Realtek device +; BL = Device/Slot number of the Realtek device +os_net_bcm57xx_init: + push rsi + push rdx + push rcx + push rax + + ; Grab the Base I/O Address of the device + push ax + mov cl, 0x04 ; BAR0 - Lower 32 bits of memory address + call os_pci_read_reg +; mov dword [os_NetIOAddress], eax + pop ax + + ; Grab the IRQ of the device + mov cl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) + call os_pci_read_reg + mov [os_NetIRQ], al ; AL holds the IRQ + + ; Grab the MAC address + mov rsi, [os_NetIOBaseMem] + mov eax, [rsi+0x410] ; Mac_Address_0 Part 1 + ror eax, 8 + mov [os_NetMAC], al + rol eax, 8 + mov [os_NetMAC+1], al + mov eax, [rsi+0x414] ; Mac_Address_0 Part 2 + rol eax, 8 + mov [os_NetMAC+2], al + rol eax, 8 + mov [os_NetMAC+3], al + rol eax, 8 + mov [os_NetMAC+4], al + rol eax, 8 + mov [os_NetMAC+5], al + + ; Enable the Network IRQ in the PIC + ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 + in al, 0x21 ; low byte target 0x21 + mov bl, al + mov al, [os_NetIRQ] + mov dx, 0x21 ; Use the low byte pic + cmp al, 8 + jl os_net_bcm57xx_init_low + sub al, 8 ; IRQ 8-16 + push ax + in al, 0xA1 ; High byte target 0xA1 + mov bl, al + pop ax + mov dx, 0xA1 ; Use the high byte pic +os_net_bcm57xx_init_low: + mov cl, al + mov al, 1 + shl al, cl + not al + and al, bl + out dx, al + + ; Reset the device + call os_net_bcm57xx_reset + + pop rax + pop rcx + pop rdx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_reset - Reset a Broadcom 57XX NIC +; IN: Nothing +; OUT: Nothing, all registers preserved +os_net_bcm57xx_reset: + + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_transmit - Transmit a packet via a Broadcom 57XX NIC +; IN: RSI = Location of packet +; RCX = Length of packet +; OUT: Nothing +; Uses RAX, RCX, RDX, RSI, RDI +; ToDo: Check for proper timeout instead of calling os_delay +os_net_bcm57xx_transmit: + + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_poll - Polls the Broadcom 57XX NIC for a received packet +; IN: RDI = Location to store packet +; OUT: RCX = Length of packet +; Uses RAX, RCX, RDX, RSI, RDI +os_net_bcm57xx_poll: + +os_net_bcm57xx_ack_int: + + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/i8254x.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/i8254x.asm index beeefba2..6b0ac597 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/i8254x.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/i8254x.asm @@ -1,452 +1,452 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Intel i8254x NIC. -; ============================================================================= - -align 16 -db 'DEBUG: I8254X ' -align 16 - - -; ----------------------------------------------------------------------------- -; Initialize an Intel 8254x NIC -; IN: BL = Bus number of the Intel device -; CL = Device/Slot number of the Intel device -os_net_i8254x_init: - push rsi - push rdx - push rcx - push rax - - ; Read BAR4, If BAR4 is all 0'z then we are using 32-bit addresses - - ; Grab the Base I/O Address of the device - mov dl, 0x04 ; BAR0 - call os_pci_read_reg -; bt eax, 0 -; jc os_net_i8254x_init_pio -; bt eax, 2 -; jc os_net_i8253x_init_64_bit - and eax, 0xFFFFFFF0 ; EAX now holds the Base Memory IO Address (clear the low 4 bits) - - mov dword [os_NetIOBaseMem], eax - - ; Grab the IRQ of the device - mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) - call os_pci_read_reg - mov [os_NetIRQ], al ; AL holds the IRQ - - ; Grab the MAC address - mov rsi, [os_NetIOBaseMem] - mov eax, [rsi+0x5400] ; RAL - cmp eax, 0x00000000 - je os_net_i8254x_init_get_MAC_via_EPROM - mov [os_NetMAC], al - shr eax, 8 - mov [os_NetMAC+1], al - shr eax, 8 - mov [os_NetMAC+2], al - shr eax, 8 - mov [os_NetMAC+3], al - mov eax, [rsi+0x5404] ; RAH - mov [os_NetMAC+4], al - shr eax, 8 - mov [os_NetMAC+5], al - jmp os_net_i8254x_init_done_MAC - -os_net_i8254x_init_get_MAC_via_EPROM: - mov rsi, [os_NetIOBaseMem] - mov eax, 0x00000001 - mov [rsi+0x14], eax - mov eax, [rsi+0x14] - shr eax, 16 - mov [os_NetMAC], al - shr eax, 8 - mov [os_NetMAC+1], al - mov eax, 0x00000101 - mov [rsi+0x14], eax - mov eax, [rsi+0x14] - shr eax, 16 - mov [os_NetMAC+2], al - shr eax, 8 - mov [os_NetMAC+3], al - mov eax, 0x00000201 - mov [rsi+0x14], eax - mov eax, [rsi+0x14] - shr eax, 16 - mov [os_NetMAC+4], al - shr eax, 8 - mov [os_NetMAC+5], al -os_net_i8254x_init_done_MAC: - - ; Enable the Network IRQ in the PIC - mov al, [os_NetIRQ] - call interrupt_enable - - ; Reset the device - call os_net_i8254x_reset - - pop rax - pop rcx - pop rdx - pop rsi - ret - -;os_net_i8254x_init_pio: -; jmp $ -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_reset - Reset an Intel 8254x NIC -; IN: Nothing -; OUT: Nothing, all registers preserved -os_net_i8254x_reset: - mov rsi, [os_NetIOBaseMem] - mov rdi, rsi - - mov eax, 0xFFFFFFFF - mov [rsi+I8254X_REG_IMC], eax ; Disable all interrupt causes - mov eax, [rsi+I8254X_REG_ICR] ; Clear any pending interrupts - xor eax, eax - mov [rsi+I8254X_REG_ITR], eax ; Disable interrupt throttling logic - - mov eax, 0x00000030 - mov [rsi+I8254X_REG_PBA], eax ; PBA: set the RX buffer size to 48KB (TX buffer is calculated as 64-RX buffer) - - mov eax, 0x08008060 - mov [rsi+I8254X_REG_TXCW], eax ; TXCW: set ANE, TxConfigWord (Half/Full duplex, Next Page Request) - - mov eax, [rsi+I8254X_REG_CTRL] - btr eax, 3 - bts eax, 6 - bts eax, 5 - btr eax, 31 - btr eax, 30 - btr eax, 7 - mov [rsi+I8254X_REG_CTRL], eax ; CTRL: clear LRST, set SLU and ASDE, clear RSTPHY, VME, and ILOS - - push rdi - add rdi, 0x5200 ; MTA: reset - mov eax, 0xFFFFFFFF - stosd - stosd - stosd - stosd - pop rdi - - mov rax, os_eth_rx_buffer - mov [rsi+I8254X_REG_RDBAL], eax ; Receive Descriptor Base Address Low - shr rax, 32 - mov [rsi+I8254X_REG_RDBAH], eax ; Receive Descriptor Base Address High - mov eax, (32 * 16) - mov [rsi+I8254X_REG_RDLEN], eax ; Receive Descriptor Length - xor eax, eax - mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head - mov eax, 1 - mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail - mov eax, 0x04008006 ; Receiver Enable, Store Bad Packets, Broadcast Accept Mode, Strip Ethernet CRC from incoming packet - mov [rsi+I8254X_REG_RCTL], eax ; Receive Control Register - - push rdi - mov rdi, os_eth_rx_buffer - mov rax, 0x1c9000 - stosd - pop rdi - - mov rax, os_eth_tx_buffer - mov [rsi+I8254X_REG_TDBAL], eax ; Transmit Descriptor Base Address Low - shr rax, 32 - mov [rsi+I8254X_REG_TDBAH], eax ; Transmit Descriptor Base Address High - mov eax, (32 * 16) - mov [rsi+I8254X_REG_TDLEN], eax ; Transmit Descriptor Length - xor eax, eax - mov [rsi+I8254X_REG_TDH], eax ; Transmit Descriptor Head - mov [rsi+I8254X_REG_TDT], eax ; Transmit Descriptor Tail - mov eax, 0x010400FA ; Enabled, Pad Short Packets, 15 retrys, 64-byte COLD, Re-transmit on Late Collision - mov [rsi+I8254X_REG_TCTL], eax ; Transmit Control Register - mov eax, 0x0060200A ; IPGT 10, IPGR1 8, IPGR2 6 - mov [rsi+I8254X_REG_TIPG], eax ; Transmit IPG Register - - xor eax, eax - mov [rsi+I8254X_REG_RDTR], eax ; Clear the Receive Delay Timer Register - mov [rsi+I8254X_REG_RADV], eax ; Clear the Receive Interrupt Absolute Delay Timer - mov [rsi+I8254X_REG_RSRPD], eax ; Clear the Receive Small Packet Detect Interrupt - bts eax, 0 ; TXDW - bts eax, 7 ; RXT0 -; mov eax, 0x1FFFF ; Temp enable all interrupt types - mov [rsi+I8254X_REG_IMS], eax ; Enable interrupt types - - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_transmit - Transmit a packet via an Intel 8254x NIC -; IN: RSI = Location of packet -; RCX = Length of packet -; OUT: Nothing -; Uses RAX, RCX, RSI, RDI -os_net_i8254x_transmit: - mov rdi, os_eth_tx_buffer ; Transmit Descriptor Base Address - mov rax, rsi - stosq ; Store the data location - mov rax, rcx ; The packet size is in CL - bts rax, 24 ; EOP - bts rax, 25 ; IFCS - bts rax, 27 ; RS - stosq - mov rdi, [os_NetIOBaseMem] - xor eax, eax - mov [rdi+I8254X_REG_TDH], eax ; TDH - Transmit Descriptor Head - add eax, 1 - mov [rdi+I8254X_REG_TDT], eax ; TDL - Transmit Descriptor Tail - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_poll - Polls the Intel 8254x NIC for a received packet -; IN: RDI = Location to store packet -; OUT: RCX = Length of packet -; Uses RAX, RCX, RDX, RSI, RDI -os_net_i8254x_poll: - xor ecx, ecx - mov cx, [os_eth_rx_buffer+8] ; Get the packet length - mov rsi, 0x1c9000 - push rcx - rep movsb - pop rcx - mov rsi, [os_NetIOBaseMem] - xor eax, eax - mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head - mov eax, 1 - mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_ack_int - Acknowledge an internal interrupt of the Intel 8254x NIC -os_net_i8254x_ack_int: - mov rdi, [os_NetIOBaseMem] - mov eax, [rdi+I8254X_REG_ICR] - ret -; ----------------------------------------------------------------------------- - - -; Maximum packet size -I8254X_MAX_PKT_SIZE equ 16384 - -; Register list -I8254X_REG_CTRL equ 0x0000 ; Control Register -I8254X_REG_STATUS equ 0x0008 ; Device Status Register -I8254X_REG_CTRLEXT equ 0x0018 ; Extended Control Register -I8254X_REG_MDIC equ 0x0020 ; MDI Control Register -I8254X_REG_FCAL equ 0x0028 ; Flow Control Address Low -I8254X_REG_FCAH equ 0x002C ; Flow Control Address High -I8254X_REG_FCT equ 0x0030 ; Flow Control Type -I8254X_REG_VET equ 0x0038 ; VLAN Ether Type -I8254X_REG_ICR equ 0x00C0 ; Interrupt Cause Read -I8254X_REG_ITR equ 0x00C4 ; Interrupt Throttling Register -I8254X_REG_ICS equ 0x00C8 ; Interrupt Cause Set Register -I8254X_REG_IMS equ 0x00D0 ; Interrupt Mask Set/Read Register -I8254X_REG_IMC equ 0x00D8 ; Interrupt Mask Clear Register -I8254X_REG_RCTL equ 0x0100 ; Receive Control Register -I8254X_REG_FCTTV equ 0x0170 ; Flow Control Transmit Timer Value -I8254X_REG_TXCW equ 0x0178 ; Transmit Configuration Word -I8254X_REG_RXCW equ 0x0180 ; Receive Configuration Word -I8254X_REG_TCTL equ 0x0400 ; Transmit Control Register -I8254X_REG_TIPG equ 0x0410 ; Transmit Inter Packet Gap - -I8254X_REG_LEDCTL equ 0x0E00 ; LED Control -I8254X_REG_PBA equ 0x1000 ; Packet Buffer Allocation - -I8254X_REG_RDBAL equ 0x2800 ; RX Descriptor Base Address Low -I8254X_REG_RDBAH equ 0x2804 ; RX Descriptor Base Address High -I8254X_REG_RDLEN equ 0x2808 ; RX Descriptor Length -I8254X_REG_RDH equ 0x2810 ; RX Descriptor Head -I8254X_REG_RDT equ 0x2818 ; RX Descriptor Tail -I8254X_REG_RDTR equ 0x2820 ; RX Delay Timer Register -I8254X_REG_RXDCTL equ 0x3828 ; RX Descriptor Control -I8254X_REG_RADV equ 0x282C ; RX Int. Absolute Delay Timer -I8254X_REG_RSRPD equ 0x2C00 ; RX Small Packet Detect Interrupt - -I8254X_REG_TXDMAC equ 0x3000 ; TX DMA Control -I8254X_REG_TDBAL equ 0x3800 ; TX Descriptor Base Address Low -I8254X_REG_TDBAH equ 0x3804 ; TX Descriptor Base Address High -I8254X_REG_TDLEN equ 0x3808 ; TX Descriptor Length -I8254X_REG_TDH equ 0x3810 ; TX Descriptor Head -I8254X_REG_TDT equ 0x3818 ; TX Descriptor Tail -I8254X_REG_TIDV equ 0x3820 ; TX Interrupt Delay Value -I8254X_REG_TXDCTL equ 0x3828 ; TX Descriptor Control -I8254X_REG_TADV equ 0x382C ; TX Absolute Interrupt Delay Value -I8254X_REG_TSPMT equ 0x3830 ; TCP Segmentation Pad & Min Threshold - -I8254X_REG_RXCSUM equ 0x5000 ; RX Checksum Control - -; Register list for i8254x -I82542_REG_RDTR equ 0x0108 ; RX Delay Timer Register -I82542_REG_RDBAL equ 0x0110 ; RX Descriptor Base Address Low -I82542_REG_RDBAH equ 0x0114 ; RX Descriptor Base Address High -I82542_REG_RDLEN equ 0x0118 ; RX Descriptor Length -I82542_REG_RDH equ 0x0120 ; RDH for i82542 -I82542_REG_RDT equ 0x0128 ; RDT for i82542 -I82542_REG_TDBAL equ 0x0420 ; TX Descriptor Base Address Low -I82542_REG_TDBAH equ 0x0424 ; TX Descriptor Base Address Low -I82542_REG_TDLEN equ 0x0428 ; TX Descriptor Length -I82542_REG_TDH equ 0x0430 ; TDH for i82542 -I82542_REG_TDT equ 0x0438 ; TDT for i82542 - -; CTRL - Control Register (0x0000) -I8254X_CTRL_FD equ 0x00000001 ; Full Duplex -I8254X_CTRL_LRST equ 0x00000008 ; Link Reset -I8254X_CTRL_ASDE equ 0x00000020 ; Auto-speed detection -I8254X_CTRL_SLU equ 0x00000040 ; Set Link Up -I8254X_CTRL_ILOS equ 0x00000080 ; Invert Loss of Signal -I8254X_CTRL_SPEED_MASK equ 0x00000300 ; Speed selection -I8254X_CTRL_SPEED_SHIFT equ 8 -I8254X_CTRL_FRCSPD equ 0x00000800 ; Force Speed -I8254X_CTRL_FRCDPLX equ 0x00001000 ; Force Duplex -I8254X_CTRL_SDP0_DATA equ 0x00040000 ; SDP0 data -I8254X_CTRL_SDP1_DATA equ 0x00080000 ; SDP1 data -I8254X_CTRL_SDP0_IODIR equ 0x00400000 ; SDP0 direction -I8254X_CTRL_SDP1_IODIR equ 0x00800000 ; SDP1 direction -I8254X_CTRL_RST equ 0x04000000 ; Device Reset -I8254X_CTRL_RFCE equ 0x08000000 ; RX Flow Ctrl Enable -I8254X_CTRL_TFCE equ 0x10000000 ; TX Flow Ctrl Enable -I8254X_CTRL_VME equ 0x40000000 ; VLAN Mode Enable -I8254X_CTRL_PHY_RST equ 0x80000000 ; PHY reset - -; STATUS - Device Status Register (0x0008) -I8254X_STATUS_FD equ 0x00000001 ; Full Duplex -I8254X_STATUS_LU equ 0x00000002 ; Link Up -I8254X_STATUS_TXOFF equ 0x00000010 ; Transmit paused -I8254X_STATUS_TBIMODE equ 0x00000020 ; TBI Mode -I8254X_STATUS_SPEED_MASK equ 0x000000C0 ; Link Speed setting -I8254X_STATUS_SPEED_SHIFT equ 6 -I8254X_STATUS_ASDV_MASK equ 0x00000300 ; Auto Speed Detection -I8254X_STATUS_ASDV_SHIFT equ 8 -I8254X_STATUS_PCI66 equ 0x00000800 ; PCI bus speed -I8254X_STATUS_BUS64 equ 0x00001000 ; PCI bus width -I8254X_STATUS_PCIX_MODE equ 0x00002000 ; PCI-X mode -I8254X_STATUS_PCIXSPD_MASK equ 0x0000C000 ; PCI-X speed -I8254X_STATUS_PCIXSPD_SHIFT equ 14 - -; CTRL_EXT - Extended Device Control Register (0x0018) -I8254X_CTRLEXT_PHY_INT equ 0x00000020 ; PHY interrupt -I8254X_CTRLEXT_SDP6_DATA equ 0x00000040 ; SDP6 data -I8254X_CTRLEXT_SDP7_DATA equ 0x00000080 ; SDP7 data -I8254X_CTRLEXT_SDP6_IODIR equ 0x00000400 ; SDP6 direction -I8254X_CTRLEXT_SDP7_IODIR equ 0x00000800 ; SDP7 direction -I8254X_CTRLEXT_ASDCHK equ 0x00001000 ; Auto-Speed Detect Chk -I8254X_CTRLEXT_EE_RST equ 0x00002000 ; EEPROM reset -I8254X_CTRLEXT_SPD_BYPS equ 0x00008000 ; Speed Select Bypass -I8254X_CTRLEXT_RO_DIS equ 0x00020000 ; Relaxed Ordering Dis. -I8254X_CTRLEXT_LNKMOD_MASK equ 0x00C00000 ; Link Mode -I8254X_CTRLEXT_LNKMOD_SHIFT equ 22 - -; MDIC - MDI Control Register (0x0020) -I8254X_MDIC_DATA_MASK equ 0x0000FFFF ; Data -I8254X_MDIC_REG_MASK equ 0x001F0000 ; PHY Register -I8254X_MDIC_REG_SHIFT equ 16 -I8254X_MDIC_PHY_MASK equ 0x03E00000 ; PHY Address -I8254X_MDIC_PHY_SHIFT equ 21 -I8254X_MDIC_OP_MASK equ 0x0C000000 ; Opcode -I8254X_MDIC_OP_SHIFT equ 26 -I8254X_MDIC_R equ 0x10000000 ; Ready -I8254X_MDIC_I equ 0x20000000 ; Interrupt Enable -I8254X_MDIC_E equ 0x40000000 ; Error - -; ICR - Interrupt Cause Read (0x00c0) -I8254X_ICR_TXDW equ 0x00000001 ; TX Desc Written back -I8254X_ICR_TXQE equ 0x00000002 ; TX Queue Empty -I8254X_ICR_LSC equ 0x00000004 ; Link Status Change -I8254X_ICR_RXSEQ equ 0x00000008 ; RX Sequence Error -I8254X_ICR_RXDMT0 equ 0x00000010 ; RX Desc min threshold reached -I8254X_ICR_RXO equ 0x00000040 ; RX Overrun -I8254X_ICR_RXT0 equ 0x00000080 ; RX Timer Interrupt -I8254X_ICR_MDAC equ 0x00000200 ; MDIO Access Complete -I8254X_ICR_RXCFG equ 0x00000400 -I8254X_ICR_PHY_INT equ 0x00001000 ; PHY Interrupt -I8254X_ICR_GPI_SDP6 equ 0x00002000 ; GPI on SDP6 -I8254X_ICR_GPI_SDP7 equ 0x00004000 ; GPI on SDP7 -I8254X_ICR_TXD_LOW equ 0x00008000 ; TX Desc low threshold hit -I8254X_ICR_SRPD equ 0x00010000 ; Small RX packet detected - -; RCTL - Receive Control Register (0x0100) -I8254X_RCTL_EN equ 0x00000002 ; Receiver Enable -I8254X_RCTL_SBP equ 0x00000004 ; Store Bad Packets -I8254X_RCTL_UPE equ 0x00000008 ; Unicast Promiscuous Enabled -I8254X_RCTL_MPE equ 0x00000010 ; Xcast Promiscuous Enabled -I8254X_RCTL_LPE equ 0x00000020 ; Long Packet Reception Enable -I8254X_RCTL_LBM_MASK equ 0x000000C0 ; Loopback Mode -I8254X_RCTL_LBM_SHIFT equ 6 -I8254X_RCTL_RDMTS_MASK equ 0x00000300 ; RX Desc Min Threshold Size -I8254X_RCTL_RDMTS_SHIFT equ 8 -I8254X_RCTL_MO_MASK equ 0x00003000 ; Multicast Offset -I8254X_RCTL_MO_SHIFT equ 12 -I8254X_RCTL_BAM equ 0x00008000 ; Broadcast Accept Mode -I8254X_RCTL_BSIZE_MASK equ 0x00030000 ; RX Buffer Size -I8254X_RCTL_BSIZE_SHIFT equ 16 -I8254X_RCTL_VFE equ 0x00040000 ; VLAN Filter Enable -I8254X_RCTL_CFIEN equ 0x00080000 ; CFI Enable -I8254X_RCTL_CFI equ 0x00100000 ; Canonical Form Indicator Bit -I8254X_RCTL_DPF equ 0x00400000 ; Discard Pause Frames -I8254X_RCTL_PMCF equ 0x00800000 ; Pass MAC Control Frames -I8254X_RCTL_BSEX equ 0x02000000 ; Buffer Size Extension -I8254X_RCTL_SECRC equ 0x04000000 ; Strip Ethernet CRC - -; TCTL - Transmit Control Register (0x0400) -I8254X_TCTL_EN equ 0x00000002 ; Transmit Enable -I8254X_TCTL_PSP equ 0x00000008 ; Pad short packets -I8254X_TCTL_SWXOFF equ 0x00400000 ; Software XOFF Transmission - -; PBA - Packet Buffer Allocation (0x1000) -I8254X_PBA_RXA_MASK equ 0x0000FFFF ; RX Packet Buffer -I8254X_PBA_RXA_SHIFT equ 0 -I8254X_PBA_TXA_MASK equ 0xFFFF0000 ; TX Packet Buffer -I8254X_PBA_TXA_SHIFT equ 16 - -; Flow Control Type -I8254X_FCT_TYPE_DEFAULT equ 0x8808 - -; === TX Descriptor fields === - -; TX Packet Length (word 2) -I8254X_TXDESC_LEN_MASK equ 0x0000ffff - -; TX Descriptor CMD field (word 2) -I8254X_TXDESC_IDE equ 0x80000000 ; Interrupt Delay Enable -I8254X_TXDESC_VLE equ 0x40000000 ; VLAN Packet Enable -I8254X_TXDESC_DEXT equ 0x20000000 ; Extension -I8254X_TXDESC_RPS equ 0x10000000 ; Report Packet Sent -I8254X_TXDESC_RS equ 0x08000000 ; Report Status -I8254X_TXDESC_IC equ 0x04000000 ; Insert Checksum -I8254X_TXDESC_IFCS equ 0x02000000 ; Insert FCS -I8254X_TXDESC_EOP equ 0x01000000 ; End Of Packet - -; TX Descriptor STA field (word 3) -I8254X_TXDESC_TU equ 0x00000008 ; Transmit Underrun -I8254X_TXDESC_LC equ 0x00000004 ; Late Collision -I8254X_TXDESC_EC equ 0x00000002 ; Excess Collisions -I8254X_TXDESC_DD equ 0x00000001 ; Descriptor Done - -; === RX Descriptor fields === - -; RX Packet Length (word 2) -I8254X_RXDESC_LEN_MASK equ 0x0000ffff - -; RX Descriptor STA field (word 3) -I8254X_RXDESC_PIF equ 0x00000080 ; Passed In-exact Filter -I8254X_RXDESC_IPCS equ 0x00000040 ; IP cksum calculated -I8254X_RXDESC_TCPCS equ 0x00000020 ; TCP cksum calculated -I8254X_RXDESC_VP equ 0x00000008 ; Packet is 802.1Q -I8254X_RXDESC_IXSM equ 0x00000004 ; Ignore cksum indication -I8254X_RXDESC_EOP equ 0x00000002 ; End Of Packet -I8254X_RXDESC_DD equ 0x00000001 ; Descriptor Done - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Intel i8254x NIC. +; ============================================================================= + +align 16 +db 'DEBUG: I8254X ' +align 16 + + +; ----------------------------------------------------------------------------- +; Initialize an Intel 8254x NIC +; IN: BL = Bus number of the Intel device +; CL = Device/Slot number of the Intel device +os_net_i8254x_init: + push rsi + push rdx + push rcx + push rax + + ; Read BAR4, If BAR4 is all 0'z then we are using 32-bit addresses + + ; Grab the Base I/O Address of the device + mov dl, 0x04 ; BAR0 + call os_pci_read_reg +; bt eax, 0 +; jc os_net_i8254x_init_pio +; bt eax, 2 +; jc os_net_i8253x_init_64_bit + and eax, 0xFFFFFFF0 ; EAX now holds the Base Memory IO Address (clear the low 4 bits) + + mov dword [os_NetIOBaseMem], eax + + ; Grab the IRQ of the device + mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) + call os_pci_read_reg + mov [os_NetIRQ], al ; AL holds the IRQ + + ; Grab the MAC address + mov rsi, [os_NetIOBaseMem] + mov eax, [rsi+0x5400] ; RAL + cmp eax, 0x00000000 + je os_net_i8254x_init_get_MAC_via_EPROM + mov [os_NetMAC], al + shr eax, 8 + mov [os_NetMAC+1], al + shr eax, 8 + mov [os_NetMAC+2], al + shr eax, 8 + mov [os_NetMAC+3], al + mov eax, [rsi+0x5404] ; RAH + mov [os_NetMAC+4], al + shr eax, 8 + mov [os_NetMAC+5], al + jmp os_net_i8254x_init_done_MAC + +os_net_i8254x_init_get_MAC_via_EPROM: + mov rsi, [os_NetIOBaseMem] + mov eax, 0x00000001 + mov [rsi+0x14], eax + mov eax, [rsi+0x14] + shr eax, 16 + mov [os_NetMAC], al + shr eax, 8 + mov [os_NetMAC+1], al + mov eax, 0x00000101 + mov [rsi+0x14], eax + mov eax, [rsi+0x14] + shr eax, 16 + mov [os_NetMAC+2], al + shr eax, 8 + mov [os_NetMAC+3], al + mov eax, 0x00000201 + mov [rsi+0x14], eax + mov eax, [rsi+0x14] + shr eax, 16 + mov [os_NetMAC+4], al + shr eax, 8 + mov [os_NetMAC+5], al +os_net_i8254x_init_done_MAC: + + ; Enable the Network IRQ in the PIC + mov al, [os_NetIRQ] + call interrupt_enable + + ; Reset the device + call os_net_i8254x_reset + + pop rax + pop rcx + pop rdx + pop rsi + ret + +;os_net_i8254x_init_pio: +; jmp $ +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_reset - Reset an Intel 8254x NIC +; IN: Nothing +; OUT: Nothing, all registers preserved +os_net_i8254x_reset: + mov rsi, [os_NetIOBaseMem] + mov rdi, rsi + + mov eax, 0xFFFFFFFF + mov [rsi+I8254X_REG_IMC], eax ; Disable all interrupt causes + mov eax, [rsi+I8254X_REG_ICR] ; Clear any pending interrupts + xor eax, eax + mov [rsi+I8254X_REG_ITR], eax ; Disable interrupt throttling logic + + mov eax, 0x00000030 + mov [rsi+I8254X_REG_PBA], eax ; PBA: set the RX buffer size to 48KB (TX buffer is calculated as 64-RX buffer) + + mov eax, 0x08008060 + mov [rsi+I8254X_REG_TXCW], eax ; TXCW: set ANE, TxConfigWord (Half/Full duplex, Next Page Request) + + mov eax, [rsi+I8254X_REG_CTRL] + btr eax, 3 + bts eax, 6 + bts eax, 5 + btr eax, 31 + btr eax, 30 + btr eax, 7 + mov [rsi+I8254X_REG_CTRL], eax ; CTRL: clear LRST, set SLU and ASDE, clear RSTPHY, VME, and ILOS + + push rdi + add rdi, 0x5200 ; MTA: reset + mov eax, 0xFFFFFFFF + stosd + stosd + stosd + stosd + pop rdi + + mov rax, os_eth_rx_buffer + mov [rsi+I8254X_REG_RDBAL], eax ; Receive Descriptor Base Address Low + shr rax, 32 + mov [rsi+I8254X_REG_RDBAH], eax ; Receive Descriptor Base Address High + mov eax, (32 * 16) + mov [rsi+I8254X_REG_RDLEN], eax ; Receive Descriptor Length + xor eax, eax + mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head + mov eax, 1 + mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail + mov eax, 0x04008006 ; Receiver Enable, Store Bad Packets, Broadcast Accept Mode, Strip Ethernet CRC from incoming packet + mov [rsi+I8254X_REG_RCTL], eax ; Receive Control Register + + push rdi + mov rdi, os_eth_rx_buffer + mov rax, 0x1c9000 + stosd + pop rdi + + mov rax, os_eth_tx_buffer + mov [rsi+I8254X_REG_TDBAL], eax ; Transmit Descriptor Base Address Low + shr rax, 32 + mov [rsi+I8254X_REG_TDBAH], eax ; Transmit Descriptor Base Address High + mov eax, (32 * 16) + mov [rsi+I8254X_REG_TDLEN], eax ; Transmit Descriptor Length + xor eax, eax + mov [rsi+I8254X_REG_TDH], eax ; Transmit Descriptor Head + mov [rsi+I8254X_REG_TDT], eax ; Transmit Descriptor Tail + mov eax, 0x010400FA ; Enabled, Pad Short Packets, 15 retrys, 64-byte COLD, Re-transmit on Late Collision + mov [rsi+I8254X_REG_TCTL], eax ; Transmit Control Register + mov eax, 0x0060200A ; IPGT 10, IPGR1 8, IPGR2 6 + mov [rsi+I8254X_REG_TIPG], eax ; Transmit IPG Register + + xor eax, eax + mov [rsi+I8254X_REG_RDTR], eax ; Clear the Receive Delay Timer Register + mov [rsi+I8254X_REG_RADV], eax ; Clear the Receive Interrupt Absolute Delay Timer + mov [rsi+I8254X_REG_RSRPD], eax ; Clear the Receive Small Packet Detect Interrupt + bts eax, 0 ; TXDW + bts eax, 7 ; RXT0 +; mov eax, 0x1FFFF ; Temp enable all interrupt types + mov [rsi+I8254X_REG_IMS], eax ; Enable interrupt types + + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_transmit - Transmit a packet via an Intel 8254x NIC +; IN: RSI = Location of packet +; RCX = Length of packet +; OUT: Nothing +; Uses RAX, RCX, RSI, RDI +os_net_i8254x_transmit: + mov rdi, os_eth_tx_buffer ; Transmit Descriptor Base Address + mov rax, rsi + stosq ; Store the data location + mov rax, rcx ; The packet size is in CL + bts rax, 24 ; EOP + bts rax, 25 ; IFCS + bts rax, 27 ; RS + stosq + mov rdi, [os_NetIOBaseMem] + xor eax, eax + mov [rdi+I8254X_REG_TDH], eax ; TDH - Transmit Descriptor Head + add eax, 1 + mov [rdi+I8254X_REG_TDT], eax ; TDL - Transmit Descriptor Tail + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_poll - Polls the Intel 8254x NIC for a received packet +; IN: RDI = Location to store packet +; OUT: RCX = Length of packet +; Uses RAX, RCX, RDX, RSI, RDI +os_net_i8254x_poll: + xor ecx, ecx + mov cx, [os_eth_rx_buffer+8] ; Get the packet length + mov rsi, 0x1c9000 + push rcx + rep movsb + pop rcx + mov rsi, [os_NetIOBaseMem] + xor eax, eax + mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head + mov eax, 1 + mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_ack_int - Acknowledge an internal interrupt of the Intel 8254x NIC +os_net_i8254x_ack_int: + mov rdi, [os_NetIOBaseMem] + mov eax, [rdi+I8254X_REG_ICR] + ret +; ----------------------------------------------------------------------------- + + +; Maximum packet size +I8254X_MAX_PKT_SIZE equ 16384 + +; Register list +I8254X_REG_CTRL equ 0x0000 ; Control Register +I8254X_REG_STATUS equ 0x0008 ; Device Status Register +I8254X_REG_CTRLEXT equ 0x0018 ; Extended Control Register +I8254X_REG_MDIC equ 0x0020 ; MDI Control Register +I8254X_REG_FCAL equ 0x0028 ; Flow Control Address Low +I8254X_REG_FCAH equ 0x002C ; Flow Control Address High +I8254X_REG_FCT equ 0x0030 ; Flow Control Type +I8254X_REG_VET equ 0x0038 ; VLAN Ether Type +I8254X_REG_ICR equ 0x00C0 ; Interrupt Cause Read +I8254X_REG_ITR equ 0x00C4 ; Interrupt Throttling Register +I8254X_REG_ICS equ 0x00C8 ; Interrupt Cause Set Register +I8254X_REG_IMS equ 0x00D0 ; Interrupt Mask Set/Read Register +I8254X_REG_IMC equ 0x00D8 ; Interrupt Mask Clear Register +I8254X_REG_RCTL equ 0x0100 ; Receive Control Register +I8254X_REG_FCTTV equ 0x0170 ; Flow Control Transmit Timer Value +I8254X_REG_TXCW equ 0x0178 ; Transmit Configuration Word +I8254X_REG_RXCW equ 0x0180 ; Receive Configuration Word +I8254X_REG_TCTL equ 0x0400 ; Transmit Control Register +I8254X_REG_TIPG equ 0x0410 ; Transmit Inter Packet Gap + +I8254X_REG_LEDCTL equ 0x0E00 ; LED Control +I8254X_REG_PBA equ 0x1000 ; Packet Buffer Allocation + +I8254X_REG_RDBAL equ 0x2800 ; RX Descriptor Base Address Low +I8254X_REG_RDBAH equ 0x2804 ; RX Descriptor Base Address High +I8254X_REG_RDLEN equ 0x2808 ; RX Descriptor Length +I8254X_REG_RDH equ 0x2810 ; RX Descriptor Head +I8254X_REG_RDT equ 0x2818 ; RX Descriptor Tail +I8254X_REG_RDTR equ 0x2820 ; RX Delay Timer Register +I8254X_REG_RXDCTL equ 0x3828 ; RX Descriptor Control +I8254X_REG_RADV equ 0x282C ; RX Int. Absolute Delay Timer +I8254X_REG_RSRPD equ 0x2C00 ; RX Small Packet Detect Interrupt + +I8254X_REG_TXDMAC equ 0x3000 ; TX DMA Control +I8254X_REG_TDBAL equ 0x3800 ; TX Descriptor Base Address Low +I8254X_REG_TDBAH equ 0x3804 ; TX Descriptor Base Address High +I8254X_REG_TDLEN equ 0x3808 ; TX Descriptor Length +I8254X_REG_TDH equ 0x3810 ; TX Descriptor Head +I8254X_REG_TDT equ 0x3818 ; TX Descriptor Tail +I8254X_REG_TIDV equ 0x3820 ; TX Interrupt Delay Value +I8254X_REG_TXDCTL equ 0x3828 ; TX Descriptor Control +I8254X_REG_TADV equ 0x382C ; TX Absolute Interrupt Delay Value +I8254X_REG_TSPMT equ 0x3830 ; TCP Segmentation Pad & Min Threshold + +I8254X_REG_RXCSUM equ 0x5000 ; RX Checksum Control + +; Register list for i8254x +I82542_REG_RDTR equ 0x0108 ; RX Delay Timer Register +I82542_REG_RDBAL equ 0x0110 ; RX Descriptor Base Address Low +I82542_REG_RDBAH equ 0x0114 ; RX Descriptor Base Address High +I82542_REG_RDLEN equ 0x0118 ; RX Descriptor Length +I82542_REG_RDH equ 0x0120 ; RDH for i82542 +I82542_REG_RDT equ 0x0128 ; RDT for i82542 +I82542_REG_TDBAL equ 0x0420 ; TX Descriptor Base Address Low +I82542_REG_TDBAH equ 0x0424 ; TX Descriptor Base Address Low +I82542_REG_TDLEN equ 0x0428 ; TX Descriptor Length +I82542_REG_TDH equ 0x0430 ; TDH for i82542 +I82542_REG_TDT equ 0x0438 ; TDT for i82542 + +; CTRL - Control Register (0x0000) +I8254X_CTRL_FD equ 0x00000001 ; Full Duplex +I8254X_CTRL_LRST equ 0x00000008 ; Link Reset +I8254X_CTRL_ASDE equ 0x00000020 ; Auto-speed detection +I8254X_CTRL_SLU equ 0x00000040 ; Set Link Up +I8254X_CTRL_ILOS equ 0x00000080 ; Invert Loss of Signal +I8254X_CTRL_SPEED_MASK equ 0x00000300 ; Speed selection +I8254X_CTRL_SPEED_SHIFT equ 8 +I8254X_CTRL_FRCSPD equ 0x00000800 ; Force Speed +I8254X_CTRL_FRCDPLX equ 0x00001000 ; Force Duplex +I8254X_CTRL_SDP0_DATA equ 0x00040000 ; SDP0 data +I8254X_CTRL_SDP1_DATA equ 0x00080000 ; SDP1 data +I8254X_CTRL_SDP0_IODIR equ 0x00400000 ; SDP0 direction +I8254X_CTRL_SDP1_IODIR equ 0x00800000 ; SDP1 direction +I8254X_CTRL_RST equ 0x04000000 ; Device Reset +I8254X_CTRL_RFCE equ 0x08000000 ; RX Flow Ctrl Enable +I8254X_CTRL_TFCE equ 0x10000000 ; TX Flow Ctrl Enable +I8254X_CTRL_VME equ 0x40000000 ; VLAN Mode Enable +I8254X_CTRL_PHY_RST equ 0x80000000 ; PHY reset + +; STATUS - Device Status Register (0x0008) +I8254X_STATUS_FD equ 0x00000001 ; Full Duplex +I8254X_STATUS_LU equ 0x00000002 ; Link Up +I8254X_STATUS_TXOFF equ 0x00000010 ; Transmit paused +I8254X_STATUS_TBIMODE equ 0x00000020 ; TBI Mode +I8254X_STATUS_SPEED_MASK equ 0x000000C0 ; Link Speed setting +I8254X_STATUS_SPEED_SHIFT equ 6 +I8254X_STATUS_ASDV_MASK equ 0x00000300 ; Auto Speed Detection +I8254X_STATUS_ASDV_SHIFT equ 8 +I8254X_STATUS_PCI66 equ 0x00000800 ; PCI bus speed +I8254X_STATUS_BUS64 equ 0x00001000 ; PCI bus width +I8254X_STATUS_PCIX_MODE equ 0x00002000 ; PCI-X mode +I8254X_STATUS_PCIXSPD_MASK equ 0x0000C000 ; PCI-X speed +I8254X_STATUS_PCIXSPD_SHIFT equ 14 + +; CTRL_EXT - Extended Device Control Register (0x0018) +I8254X_CTRLEXT_PHY_INT equ 0x00000020 ; PHY interrupt +I8254X_CTRLEXT_SDP6_DATA equ 0x00000040 ; SDP6 data +I8254X_CTRLEXT_SDP7_DATA equ 0x00000080 ; SDP7 data +I8254X_CTRLEXT_SDP6_IODIR equ 0x00000400 ; SDP6 direction +I8254X_CTRLEXT_SDP7_IODIR equ 0x00000800 ; SDP7 direction +I8254X_CTRLEXT_ASDCHK equ 0x00001000 ; Auto-Speed Detect Chk +I8254X_CTRLEXT_EE_RST equ 0x00002000 ; EEPROM reset +I8254X_CTRLEXT_SPD_BYPS equ 0x00008000 ; Speed Select Bypass +I8254X_CTRLEXT_RO_DIS equ 0x00020000 ; Relaxed Ordering Dis. +I8254X_CTRLEXT_LNKMOD_MASK equ 0x00C00000 ; Link Mode +I8254X_CTRLEXT_LNKMOD_SHIFT equ 22 + +; MDIC - MDI Control Register (0x0020) +I8254X_MDIC_DATA_MASK equ 0x0000FFFF ; Data +I8254X_MDIC_REG_MASK equ 0x001F0000 ; PHY Register +I8254X_MDIC_REG_SHIFT equ 16 +I8254X_MDIC_PHY_MASK equ 0x03E00000 ; PHY Address +I8254X_MDIC_PHY_SHIFT equ 21 +I8254X_MDIC_OP_MASK equ 0x0C000000 ; Opcode +I8254X_MDIC_OP_SHIFT equ 26 +I8254X_MDIC_R equ 0x10000000 ; Ready +I8254X_MDIC_I equ 0x20000000 ; Interrupt Enable +I8254X_MDIC_E equ 0x40000000 ; Error + +; ICR - Interrupt Cause Read (0x00c0) +I8254X_ICR_TXDW equ 0x00000001 ; TX Desc Written back +I8254X_ICR_TXQE equ 0x00000002 ; TX Queue Empty +I8254X_ICR_LSC equ 0x00000004 ; Link Status Change +I8254X_ICR_RXSEQ equ 0x00000008 ; RX Sequence Error +I8254X_ICR_RXDMT0 equ 0x00000010 ; RX Desc min threshold reached +I8254X_ICR_RXO equ 0x00000040 ; RX Overrun +I8254X_ICR_RXT0 equ 0x00000080 ; RX Timer Interrupt +I8254X_ICR_MDAC equ 0x00000200 ; MDIO Access Complete +I8254X_ICR_RXCFG equ 0x00000400 +I8254X_ICR_PHY_INT equ 0x00001000 ; PHY Interrupt +I8254X_ICR_GPI_SDP6 equ 0x00002000 ; GPI on SDP6 +I8254X_ICR_GPI_SDP7 equ 0x00004000 ; GPI on SDP7 +I8254X_ICR_TXD_LOW equ 0x00008000 ; TX Desc low threshold hit +I8254X_ICR_SRPD equ 0x00010000 ; Small RX packet detected + +; RCTL - Receive Control Register (0x0100) +I8254X_RCTL_EN equ 0x00000002 ; Receiver Enable +I8254X_RCTL_SBP equ 0x00000004 ; Store Bad Packets +I8254X_RCTL_UPE equ 0x00000008 ; Unicast Promiscuous Enabled +I8254X_RCTL_MPE equ 0x00000010 ; Xcast Promiscuous Enabled +I8254X_RCTL_LPE equ 0x00000020 ; Long Packet Reception Enable +I8254X_RCTL_LBM_MASK equ 0x000000C0 ; Loopback Mode +I8254X_RCTL_LBM_SHIFT equ 6 +I8254X_RCTL_RDMTS_MASK equ 0x00000300 ; RX Desc Min Threshold Size +I8254X_RCTL_RDMTS_SHIFT equ 8 +I8254X_RCTL_MO_MASK equ 0x00003000 ; Multicast Offset +I8254X_RCTL_MO_SHIFT equ 12 +I8254X_RCTL_BAM equ 0x00008000 ; Broadcast Accept Mode +I8254X_RCTL_BSIZE_MASK equ 0x00030000 ; RX Buffer Size +I8254X_RCTL_BSIZE_SHIFT equ 16 +I8254X_RCTL_VFE equ 0x00040000 ; VLAN Filter Enable +I8254X_RCTL_CFIEN equ 0x00080000 ; CFI Enable +I8254X_RCTL_CFI equ 0x00100000 ; Canonical Form Indicator Bit +I8254X_RCTL_DPF equ 0x00400000 ; Discard Pause Frames +I8254X_RCTL_PMCF equ 0x00800000 ; Pass MAC Control Frames +I8254X_RCTL_BSEX equ 0x02000000 ; Buffer Size Extension +I8254X_RCTL_SECRC equ 0x04000000 ; Strip Ethernet CRC + +; TCTL - Transmit Control Register (0x0400) +I8254X_TCTL_EN equ 0x00000002 ; Transmit Enable +I8254X_TCTL_PSP equ 0x00000008 ; Pad short packets +I8254X_TCTL_SWXOFF equ 0x00400000 ; Software XOFF Transmission + +; PBA - Packet Buffer Allocation (0x1000) +I8254X_PBA_RXA_MASK equ 0x0000FFFF ; RX Packet Buffer +I8254X_PBA_RXA_SHIFT equ 0 +I8254X_PBA_TXA_MASK equ 0xFFFF0000 ; TX Packet Buffer +I8254X_PBA_TXA_SHIFT equ 16 + +; Flow Control Type +I8254X_FCT_TYPE_DEFAULT equ 0x8808 + +; === TX Descriptor fields === + +; TX Packet Length (word 2) +I8254X_TXDESC_LEN_MASK equ 0x0000ffff + +; TX Descriptor CMD field (word 2) +I8254X_TXDESC_IDE equ 0x80000000 ; Interrupt Delay Enable +I8254X_TXDESC_VLE equ 0x40000000 ; VLAN Packet Enable +I8254X_TXDESC_DEXT equ 0x20000000 ; Extension +I8254X_TXDESC_RPS equ 0x10000000 ; Report Packet Sent +I8254X_TXDESC_RS equ 0x08000000 ; Report Status +I8254X_TXDESC_IC equ 0x04000000 ; Insert Checksum +I8254X_TXDESC_IFCS equ 0x02000000 ; Insert FCS +I8254X_TXDESC_EOP equ 0x01000000 ; End Of Packet + +; TX Descriptor STA field (word 3) +I8254X_TXDESC_TU equ 0x00000008 ; Transmit Underrun +I8254X_TXDESC_LC equ 0x00000004 ; Late Collision +I8254X_TXDESC_EC equ 0x00000002 ; Excess Collisions +I8254X_TXDESC_DD equ 0x00000001 ; Descriptor Done + +; === RX Descriptor fields === + +; RX Packet Length (word 2) +I8254X_RXDESC_LEN_MASK equ 0x0000ffff + +; RX Descriptor STA field (word 3) +I8254X_RXDESC_PIF equ 0x00000080 ; Passed In-exact Filter +I8254X_RXDESC_IPCS equ 0x00000040 ; IP cksum calculated +I8254X_RXDESC_TCPCS equ 0x00000020 ; TCP cksum calculated +I8254X_RXDESC_VP equ 0x00000008 ; Packet is 802.1Q +I8254X_RXDESC_IXSM equ 0x00000004 ; Ignore cksum indication +I8254X_RXDESC_EOP equ 0x00000002 ; End Of Packet +I8254X_RXDESC_DD equ 0x00000001 ; Descriptor Done + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/rtl8169.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/rtl8169.asm index fe60ddf3..2ca0bad1 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/rtl8169.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/net/rtl8169.asm @@ -1,328 +1,328 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Realtek 8169 NIC. http://wiki.osdev.org/RTL8169 -; ============================================================================= - -align 16 -db 'DEBUG: RTL8169 ' -align 16 - - -; ----------------------------------------------------------------------------- -; Initialize a Realtek 8169 NIC -; IN: BL = Bus number of the Realtek device -; CL = Device/Slot number of the Realtek device -os_net_rtl8169_init: - push rsi - push rdx - push rcx - push rax - - ; Grab the Base I/O Address of the device - mov dl, 0x04 ; BAR0 - call os_pci_read_reg - and eax, 0xFFFFFFFC ; EAX now holds the Base IO Address (clear the low 2 bits) - mov word [os_NetIOAddress], ax - - ; Grab the IRQ of the device - mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) - call os_pci_read_reg - mov [os_NetIRQ], al ; AL holds the IRQ - - ; Grab the MAC address - mov dx, word [os_NetIOAddress] - in al, dx - mov [os_NetMAC], al - add dx, 1 - in al, dx - mov [os_NetMAC+1], al - add dx, 1 - in al, dx - mov [os_NetMAC+2], al - add dx, 1 - in al, dx - mov [os_NetMAC+3], al - add dx, 1 - in al, dx - mov [os_NetMAC+4], al - add dx, 1 - in al, dx - mov [os_NetMAC+5], al - - ; Enable the Network IRQ in the PIC - ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 - in al, 0x21 ; low byte target 0x21 - mov bl, al - mov al, [os_NetIRQ] - mov dx, 0x21 ; Use the low byte pic - cmp al, 8 - jl os_net_rtl8169_init_low - sub al, 8 ; IRQ 8-16 - push ax - in al, 0xA1 ; High byte target 0xA1 - mov bl, al - pop ax - mov dx, 0xA1 ; Use the high byte pic -os_net_rtl8169_init_low: - mov cl, al - mov al, 1 - shl al, cl - not al - and al, bl - out dx, al - - ; Reset the device - call os_net_rtl8169_reset - - pop rax - pop rcx - pop rdx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8136_reset - Reset a Realtek 8169 NIC -; IN: Nothing -; OUT: Nothing, all registers preserved -os_net_rtl8169_reset: - push rdx - push rcx - push rax - - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_COMMAND - mov al, 0x10 ; Bit 4 set for Reset - out dx, al - mov cx, 1000 ; Wait no longer for the reset to complete -wait_for_8169_reset: - in al, dx - test al, 0x10 - jz reset_8169_completed ; RST remains 1 during reset, Reset complete when 0 - dec cx - jns wait_for_8169_reset -reset_8169_completed: - - ; Unlock config registers - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_9346CR - mov al, 0xC0 ; Unlock - out dx, al - - ; Set the C+ Command - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_CCR - in ax, dx - bts ax, 3 ; Enable PCI Multiple Read/Write - btc ax, 9 ; Little-endian mode - out dx, ax - - ; Power management? - - ; Recieve configuration - mov dx, word [os_NetIOAddress] - add edx, RTL8169_REG_RCR - mov eax, 0x0000E70A ; Set bits 1 (APM), 3 (AB), 8-10 (Unlimited), 13-15 (No limit) - out dx, eax - - ; Set up TCR - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_TCR - mov eax, 0x03000700 - out dx, eax - - ; Setup max RX size - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_MAXRX - mov ax, 0x3FFF ; 16384 - 1 - out dx, ax - - ; Setup max TX size - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_MAXTX - mov al, 0x3B - out dx, al - - ; Set the Transmit Normal Priority Descriptor Start Address - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_TNPDS - mov rax, os_eth_tx_buffer - out dx, eax ; Write the low bits - shr rax, 32 - add dx, 4 - out dx, eax ; Write the high bits - mov eax, 0x40000000 ; Set bit 30 (End of Descriptor Ring) - mov [os_eth_tx_buffer], eax - - ; Set the Receive Descriptor Start Address - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_RDSAR - mov rax, os_eth_rx_buffer - out dx, eax ; Write the low bits - shr rax, 32 - add dx, 4 - out dx, eax ; Write the high bits - mov eax, 0xC0001FF8 ; Set bits 30 (End of Descriptor Ring) and 31 (Ownership), also buffer size - mov [os_eth_rx_buffer], eax - mov rax, os_ethernet_rx_buffer - mov [os_eth_rx_buffer+16], rax - - ; Initialize multicast registers (no filtering) - mov eax, 0xFFFFFFFF - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_MAR0 - out dx, eax - add dx, 4 ; MAR4 - out dx, eax - - ; Enable Rx/Tx in the Command register - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_COMMAND - mov al, (1 << RTL8169_BIT_RE) | (1 << RTL8169_BIT_TE) ;0x0C ; Set bits 2 (TE) and 3 (RE) - out dx, al - - ; Enable Receive and Transmit interrupts - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_IMR - mov ax, 0xFF ;0x5 ; Set bits 0 (RX OK) and 2 (TX OK) - out dx, ax - - ; Lock config register - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_9346CR - mov al, 0x00 ; Lock - out dx, al - - pop rax - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8169_transmit - Transmit a packet via a Realtek 8169 NIC -; IN: RSI = Location of packet -; RCX = Length of packet -; OUT: Nothing -; Uses RAX, RCX, RDX, RSI, RDI -; ToDo: Check for proper timeout -os_net_rtl8169_transmit: - mov rdi, os_eth_tx_buffer - mov rax, rcx - stosw ; Store the frame length - add rdi, 6 ; Should the other data be cleared here? - mov rax, rsi - stosq ; Store the packet location - or dword [os_eth_tx_buffer], 0xF0000000 ; Set bit 31 (OWN), 30 (EOR), 29 (FS), and 28 (LS) - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_TPPOLL - mov al, 0x40 - out dx, al ; Set up TX Polling -os_net_rtl8169_transmit_sendloop: - mov eax, [os_eth_tx_buffer] - and eax, 0x80000000 ; Check the ownership bit (BT command instead?) - cmp eax, 0x80000000 ; If the ownership bit is clear then the NIC sent the packet - je os_net_rtl8169_transmit_sendloop - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8169_poll - Polls the Realtek 8169 NIC for a received packet -; IN: RDI = Location to store packet -; OUT: RCX = Length of packet -; Uses RAX, RCX, RDX, RSI, RDI -os_net_rtl8169_poll: - xor ecx, ecx - mov cx, [os_eth_rx_buffer] - and cx, 0x3FFF ; Clear the two high bits as length is bits 13-0 - mov rsi, os_ethernet_rx_buffer - push rcx - rep movsb ; Copy the packet to the lacation stored in RDI - pop rcx - mov eax, 0xC0001FF8 ; Set bit 31 (Ownership) and 30 (End of Descriptor Ring), also buffer size - mov [os_eth_rx_buffer], eax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8169_ack_int - Acknowledge an internal interrupt of the Realtek 8169 NIC -os_net_rtl8169_ack_int: - mov dx, word [os_NetIOAddress] ; Clear active interrupt sources - add dx, RTL8169_REG_ISR - in ax, dx - call os_debug_dump_ax - out dx, ax - shr eax, 2 - ret -; ----------------------------------------------------------------------------- - - -; Register Descriptors - RTL8169_REG_IDR0 equ 0x00 ; ID Register 0 - RTL8169_REG_IDR1 equ 0x01 ; ID Register 1 - RTL8169_REG_IDR2 equ 0x02 ; ID Register 2 - RTL8169_REG_IDR3 equ 0x03 ; ID Register 3 - RTL8169_REG_IDR4 equ 0x04 ; ID Register 4 - RTL8169_REG_IDR5 equ 0x05 ; ID Register 5 - RTL8169_REG_MAR0 equ 0x08 ; Multicast Register 0 - RTL8169_REG_MAR1 equ 0x09 ; Multicast Register 1 - RTL8169_REG_MAR2 equ 0x0A ; Multicast Register 2 - RTL8169_REG_MAR3 equ 0x0B ; Multicast Register 3 - RTL8169_REG_MAR4 equ 0x0C ; Multicast Register 4 - RTL8169_REG_MAR5 equ 0x0D ; Multicast Register 5 - RTL8169_REG_MAR6 equ 0x0E ; Multicast Register 6 - RTL8169_REG_MAR7 equ 0x0F ; Multicast Register 7 - RTL8169_REG_TNPDS equ 0x20 ; Transmit Normal Priority Descriptors: Start address (64-bit). (256-byte alignment) - RTL8169_REG_COMMAND equ 0x37 ; Command Register - RTL8169_REG_TPPOLL equ 0x38 ; Transmit Priority Polling Register - RTL8169_REG_IMR equ 0x3C ; Interrupt Mask Register - RTL8169_REG_ISR equ 0x3E ; Interrupt Status Register - RTL8169_REG_TCR equ 0x40 ; Transmit (Tx) Configuration Register - RTL8169_REG_RCR equ 0x44 ; Receive (Rx) Configuration Register - RTL8169_REG_9346CR equ 0x50 ; 93C46 (93C56) Command Register - RTL8169_REG_CONFIG0 equ 0x51 ; Configuration Register 0 - RTL8169_REG_CONFIG1 equ 0x52 ; Configuration Register 1 - RTL8169_REG_CONFIG2 equ 0x53 ; Configuration Register 2 - RTL8169_REG_CONFIG3 equ 0x54 ; Configuration Register 3 - RTL8169_REG_CONFIG4 equ 0x55 ; Configuration Register 4 - RTL8169_REG_CONFIG5 equ 0x56 ; Configuration Register 5 - RTL8169_REG_PHYAR equ 0x60 ; PHY Access Register - RTL8169_REG_PHYStatus equ 0x6C ; PHY(GMII, MII, or TBI) Status Register - RTL8169_REG_MAXRX equ 0xDA ; Mac Receive Packet Size Register - RTL8169_REG_CCR equ 0xE0 ; C+ Command Register - RTL8169_REG_RDSAR equ 0xE4 ; Receive Descriptor Start Address Register (256-byte alignment) - RTL8169_REG_MAXTX equ 0xEC ; Max Transmit Packet Size Register - -; Command Register (Offset 0037h, R/W) - RTL8169_BIT_RST equ 4 ; Reset - RTL8169_BIT_RE equ 3 ; Receiver Enable - RTL8169_BIT_TE equ 2 ; Transmitter Enable - -; Receive Configuration (Offset 0044h-0047h, R/W) - RTL8169_BIT_AER equ 5 ; Accept Error - RTL8169_BIT_AR equ 4 ; Accept Runt - RTL8169_BIT_AB equ 3 ; Accept Broadcast Packets - RTL8169_BIT_AM equ 2 ; Accept Multicast Packets - RTL8169_BIT_APM equ 1 ; Accept Physical Match Packets - RTL8169_BIT_AAP equ 0 ; Accept All Packets with Destination Address - -; PHY Register Table -; BMCR (address 0x00) - RTL8169_BIT_ANE equ 12 ; Auto-Negotiation Enable - -PHYConfig: -dd 0x801f0001, 0x80151000, 0x801865c7, 0x80040000, 0x800300a1, 0x80020008, 0x80011020, 0x80001000 -dd 0x80040800, 0x80040000, 0x80047000, 0x8003ff41, 0x8002de60, 0x80010140, 0x80000077, 0x80047800 -dd 0x80047000, 0x8004a000, 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000fa00, 0x8004a800, 0x8004a000 -dd 0x8004b000, 0x8003ff41, 0x8002de20, 0x80010140, 0x800000bb, 0x8004b800, 0x8004b000, 0x8004f000 -dd 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000bf00, 0x8004f800, 0x8004f000, 0x80040000, 0x801f0000 -dd 0x800b0000 - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Realtek 8169 NIC. http://wiki.osdev.org/RTL8169 +; ============================================================================= + +align 16 +db 'DEBUG: RTL8169 ' +align 16 + + +; ----------------------------------------------------------------------------- +; Initialize a Realtek 8169 NIC +; IN: BL = Bus number of the Realtek device +; CL = Device/Slot number of the Realtek device +os_net_rtl8169_init: + push rsi + push rdx + push rcx + push rax + + ; Grab the Base I/O Address of the device + mov dl, 0x04 ; BAR0 + call os_pci_read_reg + and eax, 0xFFFFFFFC ; EAX now holds the Base IO Address (clear the low 2 bits) + mov word [os_NetIOAddress], ax + + ; Grab the IRQ of the device + mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) + call os_pci_read_reg + mov [os_NetIRQ], al ; AL holds the IRQ + + ; Grab the MAC address + mov dx, word [os_NetIOAddress] + in al, dx + mov [os_NetMAC], al + add dx, 1 + in al, dx + mov [os_NetMAC+1], al + add dx, 1 + in al, dx + mov [os_NetMAC+2], al + add dx, 1 + in al, dx + mov [os_NetMAC+3], al + add dx, 1 + in al, dx + mov [os_NetMAC+4], al + add dx, 1 + in al, dx + mov [os_NetMAC+5], al + + ; Enable the Network IRQ in the PIC + ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 + in al, 0x21 ; low byte target 0x21 + mov bl, al + mov al, [os_NetIRQ] + mov dx, 0x21 ; Use the low byte pic + cmp al, 8 + jl os_net_rtl8169_init_low + sub al, 8 ; IRQ 8-16 + push ax + in al, 0xA1 ; High byte target 0xA1 + mov bl, al + pop ax + mov dx, 0xA1 ; Use the high byte pic +os_net_rtl8169_init_low: + mov cl, al + mov al, 1 + shl al, cl + not al + and al, bl + out dx, al + + ; Reset the device + call os_net_rtl8169_reset + + pop rax + pop rcx + pop rdx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8136_reset - Reset a Realtek 8169 NIC +; IN: Nothing +; OUT: Nothing, all registers preserved +os_net_rtl8169_reset: + push rdx + push rcx + push rax + + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_COMMAND + mov al, 0x10 ; Bit 4 set for Reset + out dx, al + mov cx, 1000 ; Wait no longer for the reset to complete +wait_for_8169_reset: + in al, dx + test al, 0x10 + jz reset_8169_completed ; RST remains 1 during reset, Reset complete when 0 + dec cx + jns wait_for_8169_reset +reset_8169_completed: + + ; Unlock config registers + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_9346CR + mov al, 0xC0 ; Unlock + out dx, al + + ; Set the C+ Command + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_CCR + in ax, dx + bts ax, 3 ; Enable PCI Multiple Read/Write + btc ax, 9 ; Little-endian mode + out dx, ax + + ; Power management? + + ; Recieve configuration + mov dx, word [os_NetIOAddress] + add edx, RTL8169_REG_RCR + mov eax, 0x0000E70A ; Set bits 1 (APM), 3 (AB), 8-10 (Unlimited), 13-15 (No limit) + out dx, eax + + ; Set up TCR + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_TCR + mov eax, 0x03000700 + out dx, eax + + ; Setup max RX size + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_MAXRX + mov ax, 0x3FFF ; 16384 - 1 + out dx, ax + + ; Setup max TX size + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_MAXTX + mov al, 0x3B + out dx, al + + ; Set the Transmit Normal Priority Descriptor Start Address + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_TNPDS + mov rax, os_eth_tx_buffer + out dx, eax ; Write the low bits + shr rax, 32 + add dx, 4 + out dx, eax ; Write the high bits + mov eax, 0x40000000 ; Set bit 30 (End of Descriptor Ring) + mov [os_eth_tx_buffer], eax + + ; Set the Receive Descriptor Start Address + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_RDSAR + mov rax, os_eth_rx_buffer + out dx, eax ; Write the low bits + shr rax, 32 + add dx, 4 + out dx, eax ; Write the high bits + mov eax, 0xC0001FF8 ; Set bits 30 (End of Descriptor Ring) and 31 (Ownership), also buffer size + mov [os_eth_rx_buffer], eax + mov rax, os_ethernet_rx_buffer + mov [os_eth_rx_buffer+16], rax + + ; Initialize multicast registers (no filtering) + mov eax, 0xFFFFFFFF + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_MAR0 + out dx, eax + add dx, 4 ; MAR4 + out dx, eax + + ; Enable Rx/Tx in the Command register + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_COMMAND + mov al, (1 << RTL8169_BIT_RE) | (1 << RTL8169_BIT_TE) ;0x0C ; Set bits 2 (TE) and 3 (RE) + out dx, al + + ; Enable Receive and Transmit interrupts + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_IMR + mov ax, 0xFF ;0x5 ; Set bits 0 (RX OK) and 2 (TX OK) + out dx, ax + + ; Lock config register + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_9346CR + mov al, 0x00 ; Lock + out dx, al + + pop rax + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8169_transmit - Transmit a packet via a Realtek 8169 NIC +; IN: RSI = Location of packet +; RCX = Length of packet +; OUT: Nothing +; Uses RAX, RCX, RDX, RSI, RDI +; ToDo: Check for proper timeout +os_net_rtl8169_transmit: + mov rdi, os_eth_tx_buffer + mov rax, rcx + stosw ; Store the frame length + add rdi, 6 ; Should the other data be cleared here? + mov rax, rsi + stosq ; Store the packet location + or dword [os_eth_tx_buffer], 0xF0000000 ; Set bit 31 (OWN), 30 (EOR), 29 (FS), and 28 (LS) + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_TPPOLL + mov al, 0x40 + out dx, al ; Set up TX Polling +os_net_rtl8169_transmit_sendloop: + mov eax, [os_eth_tx_buffer] + and eax, 0x80000000 ; Check the ownership bit (BT command instead?) + cmp eax, 0x80000000 ; If the ownership bit is clear then the NIC sent the packet + je os_net_rtl8169_transmit_sendloop + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8169_poll - Polls the Realtek 8169 NIC for a received packet +; IN: RDI = Location to store packet +; OUT: RCX = Length of packet +; Uses RAX, RCX, RDX, RSI, RDI +os_net_rtl8169_poll: + xor ecx, ecx + mov cx, [os_eth_rx_buffer] + and cx, 0x3FFF ; Clear the two high bits as length is bits 13-0 + mov rsi, os_ethernet_rx_buffer + push rcx + rep movsb ; Copy the packet to the lacation stored in RDI + pop rcx + mov eax, 0xC0001FF8 ; Set bit 31 (Ownership) and 30 (End of Descriptor Ring), also buffer size + mov [os_eth_rx_buffer], eax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8169_ack_int - Acknowledge an internal interrupt of the Realtek 8169 NIC +os_net_rtl8169_ack_int: + mov dx, word [os_NetIOAddress] ; Clear active interrupt sources + add dx, RTL8169_REG_ISR + in ax, dx + call os_debug_dump_ax + out dx, ax + shr eax, 2 + ret +; ----------------------------------------------------------------------------- + + +; Register Descriptors + RTL8169_REG_IDR0 equ 0x00 ; ID Register 0 + RTL8169_REG_IDR1 equ 0x01 ; ID Register 1 + RTL8169_REG_IDR2 equ 0x02 ; ID Register 2 + RTL8169_REG_IDR3 equ 0x03 ; ID Register 3 + RTL8169_REG_IDR4 equ 0x04 ; ID Register 4 + RTL8169_REG_IDR5 equ 0x05 ; ID Register 5 + RTL8169_REG_MAR0 equ 0x08 ; Multicast Register 0 + RTL8169_REG_MAR1 equ 0x09 ; Multicast Register 1 + RTL8169_REG_MAR2 equ 0x0A ; Multicast Register 2 + RTL8169_REG_MAR3 equ 0x0B ; Multicast Register 3 + RTL8169_REG_MAR4 equ 0x0C ; Multicast Register 4 + RTL8169_REG_MAR5 equ 0x0D ; Multicast Register 5 + RTL8169_REG_MAR6 equ 0x0E ; Multicast Register 6 + RTL8169_REG_MAR7 equ 0x0F ; Multicast Register 7 + RTL8169_REG_TNPDS equ 0x20 ; Transmit Normal Priority Descriptors: Start address (64-bit). (256-byte alignment) + RTL8169_REG_COMMAND equ 0x37 ; Command Register + RTL8169_REG_TPPOLL equ 0x38 ; Transmit Priority Polling Register + RTL8169_REG_IMR equ 0x3C ; Interrupt Mask Register + RTL8169_REG_ISR equ 0x3E ; Interrupt Status Register + RTL8169_REG_TCR equ 0x40 ; Transmit (Tx) Configuration Register + RTL8169_REG_RCR equ 0x44 ; Receive (Rx) Configuration Register + RTL8169_REG_9346CR equ 0x50 ; 93C46 (93C56) Command Register + RTL8169_REG_CONFIG0 equ 0x51 ; Configuration Register 0 + RTL8169_REG_CONFIG1 equ 0x52 ; Configuration Register 1 + RTL8169_REG_CONFIG2 equ 0x53 ; Configuration Register 2 + RTL8169_REG_CONFIG3 equ 0x54 ; Configuration Register 3 + RTL8169_REG_CONFIG4 equ 0x55 ; Configuration Register 4 + RTL8169_REG_CONFIG5 equ 0x56 ; Configuration Register 5 + RTL8169_REG_PHYAR equ 0x60 ; PHY Access Register + RTL8169_REG_PHYStatus equ 0x6C ; PHY(GMII, MII, or TBI) Status Register + RTL8169_REG_MAXRX equ 0xDA ; Mac Receive Packet Size Register + RTL8169_REG_CCR equ 0xE0 ; C+ Command Register + RTL8169_REG_RDSAR equ 0xE4 ; Receive Descriptor Start Address Register (256-byte alignment) + RTL8169_REG_MAXTX equ 0xEC ; Max Transmit Packet Size Register + +; Command Register (Offset 0037h, R/W) + RTL8169_BIT_RST equ 4 ; Reset + RTL8169_BIT_RE equ 3 ; Receiver Enable + RTL8169_BIT_TE equ 2 ; Transmitter Enable + +; Receive Configuration (Offset 0044h-0047h, R/W) + RTL8169_BIT_AER equ 5 ; Accept Error + RTL8169_BIT_AR equ 4 ; Accept Runt + RTL8169_BIT_AB equ 3 ; Accept Broadcast Packets + RTL8169_BIT_AM equ 2 ; Accept Multicast Packets + RTL8169_BIT_APM equ 1 ; Accept Physical Match Packets + RTL8169_BIT_AAP equ 0 ; Accept All Packets with Destination Address + +; PHY Register Table +; BMCR (address 0x00) + RTL8169_BIT_ANE equ 12 ; Auto-Negotiation Enable + +PHYConfig: +dd 0x801f0001, 0x80151000, 0x801865c7, 0x80040000, 0x800300a1, 0x80020008, 0x80011020, 0x80001000 +dd 0x80040800, 0x80040000, 0x80047000, 0x8003ff41, 0x8002de60, 0x80010140, 0x80000077, 0x80047800 +dd 0x80047000, 0x8004a000, 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000fa00, 0x8004a800, 0x8004a000 +dd 0x8004b000, 0x8003ff41, 0x8002de20, 0x80010140, 0x800000bb, 0x8004b800, 0x8004b000, 0x8004f000 +dd 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000bf00, 0x8004f800, 0x8004f000, 0x80040000, 0x801f0000 +dd 0x800b0000 + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/pci.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/pci.asm index 43aacfac..c628fd9b 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/pci.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/drivers/pci.asm @@ -1,157 +1,157 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; PCI Functions. http://wiki.osdev.org/PCI -; ============================================================================= - -align 16 -db 'DEBUG: PCI ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_pci_read_reg -- Read a register from a PCI device -; IN: BL = Bus number -; CL = Device/Slot number -; DL = Register number -; OUT: EAX = Register information -; All other registers preserved -os_pci_read_reg: - push rdx - push rcx - push rbx - - shl ebx, 16 ; Move Bus number to bits 23 - 16 - shl ecx, 11 ; Move Device number to bits 15 - 11 - mov bx, cx - shl edx, 2 - mov bl, dl - and ebx, 0x00ffffff ; Clear bits 31 - 24 - or ebx, 0x80000000 ; Set bit 31 - mov eax, ebx - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - mov dx, PCI_CONFIG_DATA - in eax, dx - - pop rbx - pop rcx - pop rdx -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_pci_find_device -- Finds a PCI device based on the Device and Vendor ID provided -; IN: EAX = Device and Vendor ID (ie: 0x70008086) -; OUT: BL = Bus number (8-bit value) -; CL = Device/Slot number (5-bit value) -; Carry set if no matching device was found -; All other registers preserved -os_pci_find_device: - push rdx - - mov rbx, rax ; Save device and vendor IDs to RBX - xor rcx, rcx - xor rax, rax - - mov ecx, 0x80000000 ; Bit 31 must be set - -os_pci_find_device_check_next: - mov eax, ecx - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - mov dx, PCI_CONFIG_DATA - in eax, dx ; EAX now holds the Device and Vendor ID - cmp eax, ebx - je os_pci_find_device_found - add ecx, 0x800 - cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) - jne os_pci_find_device_check_next - -os_pci_find_device_not_found: - stc ; Set carry (failure) - jmp os_pci_find_device_end - -os_pci_find_device_found: ; ECX bits 23 - 16 is the Bus # and bits 15 - 11 is the Device/Slot # - xor rax, rax - xor rbx, rbx - shr ecx, 11 ; Device/Slot number is now bits 4 - 0 - mov bl, cl ; BL contains Device/Slot number - and bl, 00011111b ; Clear the top 3 bits, BL contains the Device/Slot number - shr ecx, 5 ; Bus number is now bits 7 - 0 - mov al, cl ; AL contains the Bus number - xor ecx, ecx - mov cl, bl - mov bl, al - clc ; Clear carry (success) - -os_pci_find_device_end: - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_pci_dump_devices -- Dump all Device and Vendor ID's to the screen -; IN: Nothing -; OUT: Nothing, All registers preserved -; http://pci-ids.ucw.cz/read/PC/ - Online list of Device and Vendor ID's -os_pci_dump_devices: - push rdx - push rcx - push rbx - push rax - - xor rcx, rcx - xor rax, rax - - mov ecx, 0x80000000 ; Bit 31 must be set - -os_pci_dump_devices_check_next: - mov eax, ecx - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - mov dx, PCI_CONFIG_DATA - in eax, dx ; EAX now holds the Device and Vendor ID - cmp eax, 0xffffffff ; 0xFFFFFFFF means no device present on that Bus and Slot - je os_pci_dump_devices_nothing_there - call os_debug_dump_eax ; Print the Device and Vendor ID (DDDDVVVV) - call os_print_newline -os_pci_dump_devices_nothing_there: - add ecx, 0x800 - cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) - jne os_pci_dump_devices_check_next - -os_pci_dump_devices_end: - pop rax - pop rbx - pop rcx - pop rdx -ret -; ----------------------------------------------------------------------------- - - -;Configuration Mechanism One has two IO port rages associated with it. -;The address port (0xcf8-0xcfb) and the data port (0xcfc-0xcff). -;A configuration cycle consists of writing to the address port to specify which device and register you want to access and then reading or writing the data to the data port. - -PCI_CONFIG_ADDRESS EQU 0x0CF8 -PCI_CONFIG_DATA EQU 0x0CFC - -;ddress dd 10000000000000000000000000000000b -; /\ /\ /\ /\ /\ /\ -; E Res Bus Dev F Reg 0 -; Bits -; 31 Enable bit = set to 1 -; 30 - 24 Reserved = set to 0 -; 23 - 16 Bus number = 256 options -; 15 - 11 Device/Slot number = 32 options -; 10 - 8 Function number = will leave at 0 (8 options) -; 7 - 2 Register number = will leave at 0 (64 options) 64 x 4 bytes = 256 bytes worth of accessible registers -; 1 - 0 Set to 0 - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; PCI Functions. http://wiki.osdev.org/PCI +; ============================================================================= + +align 16 +db 'DEBUG: PCI ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_pci_read_reg -- Read a register from a PCI device +; IN: BL = Bus number +; CL = Device/Slot number +; DL = Register number +; OUT: EAX = Register information +; All other registers preserved +os_pci_read_reg: + push rdx + push rcx + push rbx + + shl ebx, 16 ; Move Bus number to bits 23 - 16 + shl ecx, 11 ; Move Device number to bits 15 - 11 + mov bx, cx + shl edx, 2 + mov bl, dl + and ebx, 0x00ffffff ; Clear bits 31 - 24 + or ebx, 0x80000000 ; Set bit 31 + mov eax, ebx + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + mov dx, PCI_CONFIG_DATA + in eax, dx + + pop rbx + pop rcx + pop rdx +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_pci_find_device -- Finds a PCI device based on the Device and Vendor ID provided +; IN: EAX = Device and Vendor ID (ie: 0x70008086) +; OUT: BL = Bus number (8-bit value) +; CL = Device/Slot number (5-bit value) +; Carry set if no matching device was found +; All other registers preserved +os_pci_find_device: + push rdx + + mov rbx, rax ; Save device and vendor IDs to RBX + xor rcx, rcx + xor rax, rax + + mov ecx, 0x80000000 ; Bit 31 must be set + +os_pci_find_device_check_next: + mov eax, ecx + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + mov dx, PCI_CONFIG_DATA + in eax, dx ; EAX now holds the Device and Vendor ID + cmp eax, ebx + je os_pci_find_device_found + add ecx, 0x800 + cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) + jne os_pci_find_device_check_next + +os_pci_find_device_not_found: + stc ; Set carry (failure) + jmp os_pci_find_device_end + +os_pci_find_device_found: ; ECX bits 23 - 16 is the Bus # and bits 15 - 11 is the Device/Slot # + xor rax, rax + xor rbx, rbx + shr ecx, 11 ; Device/Slot number is now bits 4 - 0 + mov bl, cl ; BL contains Device/Slot number + and bl, 00011111b ; Clear the top 3 bits, BL contains the Device/Slot number + shr ecx, 5 ; Bus number is now bits 7 - 0 + mov al, cl ; AL contains the Bus number + xor ecx, ecx + mov cl, bl + mov bl, al + clc ; Clear carry (success) + +os_pci_find_device_end: + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_pci_dump_devices -- Dump all Device and Vendor ID's to the screen +; IN: Nothing +; OUT: Nothing, All registers preserved +; http://pci-ids.ucw.cz/read/PC/ - Online list of Device and Vendor ID's +os_pci_dump_devices: + push rdx + push rcx + push rbx + push rax + + xor rcx, rcx + xor rax, rax + + mov ecx, 0x80000000 ; Bit 31 must be set + +os_pci_dump_devices_check_next: + mov eax, ecx + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + mov dx, PCI_CONFIG_DATA + in eax, dx ; EAX now holds the Device and Vendor ID + cmp eax, 0xffffffff ; 0xFFFFFFFF means no device present on that Bus and Slot + je os_pci_dump_devices_nothing_there + call os_debug_dump_eax ; Print the Device and Vendor ID (DDDDVVVV) + call os_print_newline +os_pci_dump_devices_nothing_there: + add ecx, 0x800 + cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) + jne os_pci_dump_devices_check_next + +os_pci_dump_devices_end: + pop rax + pop rbx + pop rcx + pop rdx +ret +; ----------------------------------------------------------------------------- + + +;Configuration Mechanism One has two IO port rages associated with it. +;The address port (0xcf8-0xcfb) and the data port (0xcfc-0xcff). +;A configuration cycle consists of writing to the address port to specify which device and register you want to access and then reading or writing the data to the data port. + +PCI_CONFIG_ADDRESS EQU 0x0CF8 +PCI_CONFIG_DATA EQU 0x0CFC + +;ddress dd 10000000000000000000000000000000b +; /\ /\ /\ /\ /\ /\ +; E Res Bus Dev F Reg 0 +; Bits +; 31 Enable bit = set to 1 +; 30 - 24 Reserved = set to 0 +; 23 - 16 Bus number = 256 options +; 15 - 11 Device/Slot number = 32 options +; 10 - 8 Function number = will leave at 0 (8 options) +; 7 - 2 Register number = will leave at 0 (64 options) 64 x 4 bytes = 256 bytes worth of accessible registers +; 1 - 0 Set to 0 + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_64.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_64.asm index 8977e85a..d1a379bc 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_64.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_64.asm @@ -1,278 +1,278 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT_64 -; ============================================================================= - -align 16 -db 'DEBUG: INIT_64 ' -align 16 - - -init_64: - ; Make sure that memory range 0x110000 - 0x200000 is cleared - mov rdi, os_SystemVariables - xor rcx, rcx - xor rax, rax -clearmem: - stosq - add rcx, 1 - cmp rcx, 122880 ; Clear 960 KiB - jne clearmem - - mov ax, 0x000A ; Set the cursor to 0,10 and clear the screen (needs to happen before anything is printed to the screen) - call os_move_cursor - - xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) as defined by Pure64 - - ; Create exception gate stubs (Pure64 has already set the correct gate markers) - mov rcx, 32 - mov rax, exception_gate -make_exception_gate_stubs: - call create_gate - add rdi, 1 - sub rcx, 1 - jnz make_exception_gate_stubs - - ; Create interrupt gate stubs (Pure64 has already set the correct gate markers) - mov rcx, 256-32 - mov rax, interrupt_gate -make_interrupt_gate_stubs: - call create_gate - add rdi, 1 - sub rcx, 1 - jnz make_interrupt_gate_stubs - - ; Set up the exception gates for all of the CPU exceptions - mov rcx, 20 - xor rdi, rdi - mov rax, exception_gate_00 -make_exception_gates: - call create_gate - add rdi, 1 - add rax, 16 ; The exception gates are aligned at 16 bytes - sub rcx, 1 - jnz make_exception_gates - - ; Set up the IRQ handlers - mov rdi, 0x21 - mov rax, keyboard - call create_gate - mov rdi, 0x22 - mov rax, cascade - call create_gate - mov rdi, 0x28 - mov rax, rtc - call create_gate - mov rdi, 0x80 - mov rax, ap_wakeup - call create_gate - mov rdi, 0x81 - mov rax, ap_reset - call create_gate - - ; Set up RTC - ; Rate defines how often the RTC interrupt is triggered - ; Rate is a 4-bit value from 1 to 15. 1 = 32768Hz, 6 = 1024Hz, 15 = 2Hz - ; RTC value must stay at 32.768KHz or the computer will not keep the correct time - ; http://wiki.osdev.org/RTC - mov al, 0x0a - out 0x70, al - mov al, 00101101b ; RTC@32.768KHz (0010), Rate@8Hz (1101) - out 0x71, al - mov al, 0x0b - out 0x70, al - mov al, 01000010b ; Periodic(6), 24H clock(2) - out 0x71, al - mov al, 0x0C ; Acknowledge the RTC - out 0x70, al - in al, 0x71 - - mov al, 0x0B ; Set RTC to binary mode - out 0x70, al - in al, 0x71 - bts ax, 2 - mov bl, al - mov al, 0x0B - out 0x70, al - mov al, bl - out 0x71, al - - ; Disable blink - mov dx, 0x3DA - in al, dx - mov dx, 0x3C0 - mov al, 0x30 - out dx, al - add dx, 1 - in al, dx - and al, 0xF7 - sub dx, 1 - out dx, al - - ; Set color palette - xor eax, eax - mov dx, 0x03C8 ; DAC Address Write Mode Register - out dx, al - mov dx, 0x03C9 ; DAC Data Register - mov rbx, 16 ; 16 lines -nextline: - mov rcx, 16 ; 16 colors - mov rsi, palette -nexttritone: - lodsb - out dx, al - lodsb - out dx, al - lodsb - out dx, al - dec rcx - cmp rcx, 0 - jne nexttritone - dec rbx - cmp rbx, 0 - jne nextline ; Set the next 16 colors to the same - mov eax, 0x14 ; Fix for color 6 - mov dx, 0x03c8 ; DAC Address Write Mode Register - out dx, al - mov dx, 0x03c9 ; DAC Data Register - mov rsi, palette - add rsi, 18 - lodsb - out dx, al - lodsb - out dx, al - lodsb - out dx, al - - ; Grab data from Pure64's infomap - mov rsi, 0x5000 - lodsq - mov [os_LocalAPICAddress], rax - lodsq - mov [os_IOAPICAddress], rax - - mov rsi, 0x5012 - lodsw - mov [os_NumCores], ax - - mov rsi, 0x5020 - lodsw - mov [os_MemAmount], ax ; In MiB's - - ; Build the OS memory table - call init_memory_map - - ; Initialize all AP's to run our reset code. Skip the BSP - xor rax, rax - xor rcx, rcx - mov rsi, 0x0000000000005700 ; Location in memory of the Pure64 CPU data - -next_ap: - cmp rsi, 0x0000000000005800 ; Enable up to 256 CPU Cores - je no_more_aps - lodsb ; Load the CPU parameters - bt rax, 0 ; Check if the CPU is enabled - jnc skip_ap - bt rax, 1 ; Test to see if this is the BSP (Do not init!) - jc skip_ap - mov rax, rcx - call os_smp_reset ; Reset the CPU -skip_ap: - add rcx, 1 - jmp next_ap - -no_more_aps: - - ; Enable specific interrupts - in al, 0x21 - mov al, 11111001b ; Enable Cascade, Keyboard - out 0x21, al - in al, 0xA1 - mov al, 11111110b ; Enable RTC - out 0xA1, al - - call os_seed_random ; Seed the RNG - - ; Reset keyboard and empty the buffer - mov al, 0x20 ; Command to read byte of keyboard controller RAM - out 0x64, al ; Send command - in al, 0x60 ; Grab the keyboard controller command byte - or al, 00000001b ; Enable interrupts - and al, 11101111b ; Enable keyboard - push rax - mov al, 0x60 ; Command to write byte of keyboard controller RAM - out 0x64, al ; Send command - pop rax - out 0x60, al ; Send new keyboard controller command byte - -ret - -; create_gate -; rax = address of handler -; rdi = gate # to configure -create_gate: - push rdi - push rax - - shl rdi, 4 ; quickly multiply rdi by 16 - stosw ; store the low word (15..0) - shr rax, 16 - add rdi, 4 ; skip the gate marker - stosw ; store the high word (31..16) - shr rax, 16 - stosd ; store the high dword (63..32) - - pop rax - pop rdi -ret - - -init_memory_map: ; Build the OS memory table - push rax - push rcx - push rdi - - ; Build a fresh memory map for the system - mov rdi, os_MemoryMap - push rdi - xor rcx, rcx - mov cx, [os_MemAmount] - shr cx, 1 ; Divide actual memory by 2 - mov al, 1 - rep stosb - pop rdi - mov al, 2 - stosb ; Mark the first 2 MiB as in use (by Kernel and system buffers) - stosb ; As well as the second 2 MiB (by loaded application) - ; The CLI should take care of the Application memory - - ; Allocate memory for CPU stacks (2 MiB's for each core) - xor rcx, rcx - mov cx, [os_NumCores] ; Get the amount of cores in the system - call os_mem_allocate ; Allocate a page for each core - cmp rcx, 0 ; os_mem_allocate returns 0 on failure - je system_failure - add rax, 2097152 - mov [os_StackBase], rax ; Store the Stack base address - - pop rdi - pop rcx - pop rax -ret - - -system_failure: - mov ax, 0x0016 - call os_move_cursor - mov rsi, memory_message - mov bl, 0xF0 - call os_print_string_with_color -system_failure_hang: - hlt - jmp system_failure_hang -ret - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT_64 +; ============================================================================= + +align 16 +db 'DEBUG: INIT_64 ' +align 16 + + +init_64: + ; Make sure that memory range 0x110000 - 0x200000 is cleared + mov rdi, os_SystemVariables + xor rcx, rcx + xor rax, rax +clearmem: + stosq + add rcx, 1 + cmp rcx, 122880 ; Clear 960 KiB + jne clearmem + + mov ax, 0x000A ; Set the cursor to 0,10 and clear the screen (needs to happen before anything is printed to the screen) + call os_move_cursor + + xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) as defined by Pure64 + + ; Create exception gate stubs (Pure64 has already set the correct gate markers) + mov rcx, 32 + mov rax, exception_gate +make_exception_gate_stubs: + call create_gate + add rdi, 1 + sub rcx, 1 + jnz make_exception_gate_stubs + + ; Create interrupt gate stubs (Pure64 has already set the correct gate markers) + mov rcx, 256-32 + mov rax, interrupt_gate +make_interrupt_gate_stubs: + call create_gate + add rdi, 1 + sub rcx, 1 + jnz make_interrupt_gate_stubs + + ; Set up the exception gates for all of the CPU exceptions + mov rcx, 20 + xor rdi, rdi + mov rax, exception_gate_00 +make_exception_gates: + call create_gate + add rdi, 1 + add rax, 16 ; The exception gates are aligned at 16 bytes + sub rcx, 1 + jnz make_exception_gates + + ; Set up the IRQ handlers + mov rdi, 0x21 + mov rax, keyboard + call create_gate + mov rdi, 0x22 + mov rax, cascade + call create_gate + mov rdi, 0x28 + mov rax, rtc + call create_gate + mov rdi, 0x80 + mov rax, ap_wakeup + call create_gate + mov rdi, 0x81 + mov rax, ap_reset + call create_gate + + ; Set up RTC + ; Rate defines how often the RTC interrupt is triggered + ; Rate is a 4-bit value from 1 to 15. 1 = 32768Hz, 6 = 1024Hz, 15 = 2Hz + ; RTC value must stay at 32.768KHz or the computer will not keep the correct time + ; http://wiki.osdev.org/RTC + mov al, 0x0a + out 0x70, al + mov al, 00101101b ; RTC@32.768KHz (0010), Rate@8Hz (1101) + out 0x71, al + mov al, 0x0b + out 0x70, al + mov al, 01000010b ; Periodic(6), 24H clock(2) + out 0x71, al + mov al, 0x0C ; Acknowledge the RTC + out 0x70, al + in al, 0x71 + + mov al, 0x0B ; Set RTC to binary mode + out 0x70, al + in al, 0x71 + bts ax, 2 + mov bl, al + mov al, 0x0B + out 0x70, al + mov al, bl + out 0x71, al + + ; Disable blink + mov dx, 0x3DA + in al, dx + mov dx, 0x3C0 + mov al, 0x30 + out dx, al + add dx, 1 + in al, dx + and al, 0xF7 + sub dx, 1 + out dx, al + + ; Set color palette + xor eax, eax + mov dx, 0x03C8 ; DAC Address Write Mode Register + out dx, al + mov dx, 0x03C9 ; DAC Data Register + mov rbx, 16 ; 16 lines +nextline: + mov rcx, 16 ; 16 colors + mov rsi, palette +nexttritone: + lodsb + out dx, al + lodsb + out dx, al + lodsb + out dx, al + dec rcx + cmp rcx, 0 + jne nexttritone + dec rbx + cmp rbx, 0 + jne nextline ; Set the next 16 colors to the same + mov eax, 0x14 ; Fix for color 6 + mov dx, 0x03c8 ; DAC Address Write Mode Register + out dx, al + mov dx, 0x03c9 ; DAC Data Register + mov rsi, palette + add rsi, 18 + lodsb + out dx, al + lodsb + out dx, al + lodsb + out dx, al + + ; Grab data from Pure64's infomap + mov rsi, 0x5000 + lodsq + mov [os_LocalAPICAddress], rax + lodsq + mov [os_IOAPICAddress], rax + + mov rsi, 0x5012 + lodsw + mov [os_NumCores], ax + + mov rsi, 0x5020 + lodsw + mov [os_MemAmount], ax ; In MiB's + + ; Build the OS memory table + call init_memory_map + + ; Initialize all AP's to run our reset code. Skip the BSP + xor rax, rax + xor rcx, rcx + mov rsi, 0x0000000000005700 ; Location in memory of the Pure64 CPU data + +next_ap: + cmp rsi, 0x0000000000005800 ; Enable up to 256 CPU Cores + je no_more_aps + lodsb ; Load the CPU parameters + bt rax, 0 ; Check if the CPU is enabled + jnc skip_ap + bt rax, 1 ; Test to see if this is the BSP (Do not init!) + jc skip_ap + mov rax, rcx + call os_smp_reset ; Reset the CPU +skip_ap: + add rcx, 1 + jmp next_ap + +no_more_aps: + + ; Enable specific interrupts + in al, 0x21 + mov al, 11111001b ; Enable Cascade, Keyboard + out 0x21, al + in al, 0xA1 + mov al, 11111110b ; Enable RTC + out 0xA1, al + + call os_seed_random ; Seed the RNG + + ; Reset keyboard and empty the buffer + mov al, 0x20 ; Command to read byte of keyboard controller RAM + out 0x64, al ; Send command + in al, 0x60 ; Grab the keyboard controller command byte + or al, 00000001b ; Enable interrupts + and al, 11101111b ; Enable keyboard + push rax + mov al, 0x60 ; Command to write byte of keyboard controller RAM + out 0x64, al ; Send command + pop rax + out 0x60, al ; Send new keyboard controller command byte + +ret + +; create_gate +; rax = address of handler +; rdi = gate # to configure +create_gate: + push rdi + push rax + + shl rdi, 4 ; quickly multiply rdi by 16 + stosw ; store the low word (15..0) + shr rax, 16 + add rdi, 4 ; skip the gate marker + stosw ; store the high word (31..16) + shr rax, 16 + stosd ; store the high dword (63..32) + + pop rax + pop rdi +ret + + +init_memory_map: ; Build the OS memory table + push rax + push rcx + push rdi + + ; Build a fresh memory map for the system + mov rdi, os_MemoryMap + push rdi + xor rcx, rcx + mov cx, [os_MemAmount] + shr cx, 1 ; Divide actual memory by 2 + mov al, 1 + rep stosb + pop rdi + mov al, 2 + stosb ; Mark the first 2 MiB as in use (by Kernel and system buffers) + stosb ; As well as the second 2 MiB (by loaded application) + ; The CLI should take care of the Application memory + + ; Allocate memory for CPU stacks (2 MiB's for each core) + xor rcx, rcx + mov cx, [os_NumCores] ; Get the amount of cores in the system + call os_mem_allocate ; Allocate a page for each core + cmp rcx, 0 ; os_mem_allocate returns 0 on failure + je system_failure + add rax, 2097152 + mov [os_StackBase], rax ; Store the Stack base address + + pop rdi + pop rcx + pop rax +ret + + +system_failure: + mov ax, 0x0016 + call os_move_cursor + mov rsi, memory_message + mov bl, 0xF0 + call os_print_string_with_color +system_failure_hang: + hlt + jmp system_failure_hang +ret + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_hdd.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_hdd.asm index 94c271be..4270b404 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_hdd.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_hdd.asm @@ -1,84 +1,84 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT HDD -; ============================================================================= - -align 16 -db 'DEBUG: INIT_HDD ' -align 16 - - -hdd_setup: -; Read first sector (MBR) into memory - xor rax, rax - mov rdi, secbuffer0 - push rdi - mov rcx, 1 - call readsectors - pop rdi - - cmp byte [0x0000000000005030], 0x01 ; Did we boot from a MBR drive - jne hdd_setup_no_mbr ; If not then we already have the correct sector - -; Grab the partition offset value for the first partition - mov eax, [rdi+0x01C6] - mov [fat16_PartitionOffset], eax - -; Read the first sector of the first partition - mov rdi, secbuffer0 - push rdi - mov rcx, 1 - call readsectors - pop rdi - -hdd_setup_no_mbr: -; Get the values we need to start using fat16 - mov ax, [rdi+0x0b] - mov [fat16_BytesPerSector], ax ; This will probably be 512 - mov al, [rdi+0x0d] - mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) - mov ax, [rdi+0x0e] - mov [fat16_ReservedSectors], ax - mov [fat16_FatStart], eax - mov al, [rdi+0x10] - mov [fat16_Fats], al ; This will probably be 2 - mov ax, [rdi+0x11] - mov [fat16_RootDirEnts], ax - mov ax, [rdi+0x16] - mov [fat16_SectorsPerFat], ax - -; Find out how many sectors are on the disk - xor eax, eax - mov ax, [rdi+0x13] - cmp ax, 0x0000 - jne lessthan65536sectors - mov eax, [rdi+0x20] -lessthan65536sectors: - mov [fat16_TotalSectors], eax - -; Calculate the size of the drive in MiB - xor rax, rax - mov eax, [fat16_TotalSectors] - mov [hd1_maxlba], rax - shr rax, 11 ; rax = rax * 512 / 1048576 - mov [hd1_size], eax ; in mebibytes - -; Calculate FAT16 info - xor rax, rax - xor rbx, rbx - mov ax, [fat16_SectorsPerFat] - shl ax, 1 ; quick multiply by two - add ax, [fat16_ReservedSectors] - mov [fat16_RootStart], eax - mov bx, [fat16_RootDirEnts] - shr ebx, 4 ; bx = (bx * 32) / 512 - add ebx, eax ; BX now holds the datastart sector number - mov [fat16_DataStart], ebx - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT HDD +; ============================================================================= + +align 16 +db 'DEBUG: INIT_HDD ' +align 16 + + +hdd_setup: +; Read first sector (MBR) into memory + xor rax, rax + mov rdi, secbuffer0 + push rdi + mov rcx, 1 + call readsectors + pop rdi + + cmp byte [0x0000000000005030], 0x01 ; Did we boot from a MBR drive + jne hdd_setup_no_mbr ; If not then we already have the correct sector + +; Grab the partition offset value for the first partition + mov eax, [rdi+0x01C6] + mov [fat16_PartitionOffset], eax + +; Read the first sector of the first partition + mov rdi, secbuffer0 + push rdi + mov rcx, 1 + call readsectors + pop rdi + +hdd_setup_no_mbr: +; Get the values we need to start using fat16 + mov ax, [rdi+0x0b] + mov [fat16_BytesPerSector], ax ; This will probably be 512 + mov al, [rdi+0x0d] + mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) + mov ax, [rdi+0x0e] + mov [fat16_ReservedSectors], ax + mov [fat16_FatStart], eax + mov al, [rdi+0x10] + mov [fat16_Fats], al ; This will probably be 2 + mov ax, [rdi+0x11] + mov [fat16_RootDirEnts], ax + mov ax, [rdi+0x16] + mov [fat16_SectorsPerFat], ax + +; Find out how many sectors are on the disk + xor eax, eax + mov ax, [rdi+0x13] + cmp ax, 0x0000 + jne lessthan65536sectors + mov eax, [rdi+0x20] +lessthan65536sectors: + mov [fat16_TotalSectors], eax + +; Calculate the size of the drive in MiB + xor rax, rax + mov eax, [fat16_TotalSectors] + mov [hd1_maxlba], rax + shr rax, 11 ; rax = rax * 512 / 1048576 + mov [hd1_size], eax ; in mebibytes + +; Calculate FAT16 info + xor rax, rax + xor rbx, rbx + mov ax, [fat16_SectorsPerFat] + shl ax, 1 ; quick multiply by two + add ax, [fat16_ReservedSectors] + mov [fat16_RootStart], eax + mov bx, [fat16_RootDirEnts] + shr ebx, 4 ; bx = (bx * 32) / 512 + add ebx, eax ; BX now holds the datastart sector number + mov [fat16_DataStart], ebx + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_net.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_net.asm index ca32c489..eed7d5e5 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_net.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_net.asm @@ -1,71 +1,71 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT_NET -; ============================================================================= - -align 16 -db 'DEBUG: INIT_NET ' -align 16 - - -init_net: - ; Search for a supported NIC - mov rsi, NIC_DeviceVendor_ID - -init_net_probe_next: - lodsd ; Load a device and vendor ID from our list of supported NICs - cmp eax, 0x00000000 ; 0x00000000 means we have reached the end of the list - je init_net_probe_not_found ; No suported NIC found - call os_pci_find_device ; Returns BL = Bus number (8-bit value) and CL = Device/Slot number (5-bit value) if NIC was found - jnc init_net_probe_found ; If Carry is clear then we found a supported NIC - add rsi, 4 ; Skip the device type - jmp init_net_probe_next - -init_net_probe_found: - lodsd ; Load the device type - cmp eax, 0x00008169 - je init_net_probe_found_rtl8169 - cmp eax, 0x00008254 - je init_net_probe_found_i8254x - jmp init_net_probe_not_found - -init_net_probe_found_rtl8169: - call os_net_rtl8169_init - mov rdi, os_net_transmit - mov rax, os_net_rtl8169_transmit - stosq - mov rax, os_net_rtl8169_poll - stosq - mov rax, os_net_rtl8169_ack_int - stosq - jmp init_net_probe_found_finish - -init_net_probe_found_i8254x: - call os_net_i8254x_init - mov rdi, os_net_transmit - mov rax, os_net_i8254x_transmit - stosq - mov rax, os_net_i8254x_poll - stosq - mov rax, os_net_i8254x_ack_int - stosq - jmp init_net_probe_found_finish - -init_net_probe_found_finish: - xor rax, rax - mov al, [os_NetIRQ] - add al, 0x20 - mov rdi, rax - mov rax, network - call create_gate - mov byte [os_NetEnabled], 1 ; A supported NIC was found. Signal to the OS that networking is enabled - -init_net_probe_not_found: - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT_NET +; ============================================================================= + +align 16 +db 'DEBUG: INIT_NET ' +align 16 + + +init_net: + ; Search for a supported NIC + mov rsi, NIC_DeviceVendor_ID + +init_net_probe_next: + lodsd ; Load a device and vendor ID from our list of supported NICs + cmp eax, 0x00000000 ; 0x00000000 means we have reached the end of the list + je init_net_probe_not_found ; No suported NIC found + call os_pci_find_device ; Returns BL = Bus number (8-bit value) and CL = Device/Slot number (5-bit value) if NIC was found + jnc init_net_probe_found ; If Carry is clear then we found a supported NIC + add rsi, 4 ; Skip the device type + jmp init_net_probe_next + +init_net_probe_found: + lodsd ; Load the device type + cmp eax, 0x00008169 + je init_net_probe_found_rtl8169 + cmp eax, 0x00008254 + je init_net_probe_found_i8254x + jmp init_net_probe_not_found + +init_net_probe_found_rtl8169: + call os_net_rtl8169_init + mov rdi, os_net_transmit + mov rax, os_net_rtl8169_transmit + stosq + mov rax, os_net_rtl8169_poll + stosq + mov rax, os_net_rtl8169_ack_int + stosq + jmp init_net_probe_found_finish + +init_net_probe_found_i8254x: + call os_net_i8254x_init + mov rdi, os_net_transmit + mov rax, os_net_i8254x_transmit + stosq + mov rax, os_net_i8254x_poll + stosq + mov rax, os_net_i8254x_ack_int + stosq + jmp init_net_probe_found_finish + +init_net_probe_found_finish: + xor rax, rax + mov al, [os_NetIRQ] + add al, 0x20 + mov rdi, rax + mov rax, network + call create_gate + mov byte [os_NetEnabled], 1 ; A supported NIC was found. Signal to the OS that networking is enabled + +init_net_probe_not_found: + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_pci.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_pci.asm index 271f103a..15d8d53f 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_pci.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/init_pci.asm @@ -1,29 +1,29 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT_PCI -; ============================================================================= - -align 16 -db 'DEBUG: INIT_PCI ' -align 16 - - -init_pci: - ; - mov eax, 0x80000000 - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - in eax, dx - cmp eax, 0x80000000 - jne init_pci_not_found - mov byte [os_PCIEnabled], 1 - -init_pci_not_found: - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT_PCI +; ============================================================================= + +align 16 +db 'DEBUG: INIT_PCI ' +align 16 + + +init_pci: + ; + mov eax, 0x80000000 + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + in eax, dx + cmp eax, 0x80000000 + jne init_pci_not_found + mov byte [os_PCIEnabled], 1 + +init_pci_not_found: + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/interrupt.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/interrupt.asm index a940b65e..ad870299 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/interrupt.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/interrupt.asm @@ -1,584 +1,584 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Interrupts -; ============================================================================= - -align 16 -db 'DEBUG: INTERRUPT' -align 16 - - -; ----------------------------------------------------------------------------- -; Default exception handler -exception_gate: - mov rsi, int_string00 - call os_print_string - mov rsi, exc_string - call os_print_string - jmp $ ; Hang -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Default interrupt handler -align 16 -interrupt_gate: ; handler for all other interrupts - iretq ; It was an undefined interrupt so return to caller -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Keyboard interrupt. IRQ 0x01, INT 0x21 -; This IRQ runs whenever there is input on the keyboard -align 16 -keyboard: - push rax - push rbx - - xor rax, rax - -;keyboard_wait: -; in al, 0x64 -; and al, 0x01 -; jz keyboard_wait - - in al, 0x60 ; Get the scancode from the keyboard - cmp al, 0x01 - je keyboard_escape - cmp al, 0x2A ; Left Shift Make - je keyboard_shift - cmp al, 0x36 ; Right Shift Make - je keyboard_shift - cmp al, 0xAA ; Left Shift Break - je keyboard_noshift - cmp al, 0xB6 ; Right Shift Break - je keyboard_noshift - test al, 0x80 - jz keydown - jmp keyup - -keydown: - cmp byte [key_shift], 0x00 - jne keyboard_lowercase - jmp keyboard_uppercase - -keyboard_lowercase: - mov rbx, keylayoutupper - jmp keyboard_processkey - -keyboard_uppercase: - mov rbx, keylayoutlower - -keyboard_processkey: ; Convert the scancode - add rbx, rax - mov bl, [rbx] - mov [key], bl - mov al, [key] - jmp keyboard_done - -keyboard_escape: - jmp reboot - -keyup: - jmp keyboard_done - -keyboard_shift: - mov byte [key_shift], 0x01 - jmp keyboard_done - -keyboard_noshift: - mov byte [key_shift], 0x00 - jmp keyboard_done - -keyboard_done: - mov al, 0x20 ; Acknowledge the IRQ - out 0x20, al - call os_smp_wakeup_all ; A terrible hack - - pop rbx - pop rax - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Cascade interrupt. IRQ 0x02, INT 0x22 -align 16 -cascade: - push rax - - mov al, 0x20 ; Acknowledge the IRQ - out 0x20, al - - pop rax - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Real-time clock interrupt. IRQ 0x08, INT 0x28 -; Currently this IRQ runs 8 times per second (As defined in init_64.asm) -; The supervisor lives here -align 16 -rtc: - push rax - push rcx - push rsi - push rdi - - cld ; Clear direction flag - add qword [os_ClockCounter], 1 ; 64-bit counter started at bootup - - cmp byte [os_show_sysstatus], 0 - je rtc_no_sysstatus - call system_status ; Show System Status information on screen -rtc_no_sysstatus: - -; Check to make sure that at least one core is running something - cmp word [os_QueueLen], 0 ; Check the length of the Queue - jne rtc_end ; If it is greater than 0 then skip to the end - mov rcx, 256 - mov rsi, cpustatus -nextcpu: - lodsb - dec rcx - bt ax, 1 ; Is bit 1 set? If so then the CPU is running a job - jc rtc_end - cmp rcx, 0 - jne nextcpu - mov rax, os_command_line ; If nothing is running then restart the CLI - call os_smp_enqueue - -rtc_end: - mov al, 0x0C ; Select RTC register C - out 0x70, al ; Port 0x70 is the RTC index, and 0x71 is the RTC data - in al, 0x71 ; Read the value in register C - mov al, 0x20 ; Acknowledge the IRQ on the PICs - out 0xA0, al - out 0x20, al - - pop rdi - pop rsi - pop rcx - pop rax - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Network interrupt. -align 16 -network: - push rdi - push rsi - push rcx - push rax - - cld ; Clear direction flag - call os_ethernet_ack_int ; Call the driver function to acknowledge the interrupt internally - - bt ax, 0 ; TX bit set (caused the IRQ?) - jc network_tx ; If so then jump past RX section - mov byte [os_NetActivity_RX], 1 - - ; Max size of Ethernet packet: 1518 - ; + size: 2 = 1520 = 0x5F0 - ; Set each element size to 0x800 (2048). 262144 byte buffer / 2048 = room for 128 packets - ; Deal with the received packet - ; Get current offset in the ring buffer - mov rdi, os_EthernetBuffer - xor rax, rax - mov al, byte [os_EthernetBuffer_C2] - push rax ; Save the ring element value - shl rax, 11 ; Quickly multiply RAX by 2048 - add rdi, rax - push rdi - add rdi, 2 - call os_ethernet_rx_from_interrupt - pop rdi - mov rax, rcx - stosw ; Store the size of the packet - ; increment the offset in the ring buffer - pop rax ; Restore the ring element value - add al, 1 - cmp al, 128 ; Max element number is 127 - jne network_rx_buffer_nowrap - xor al, al -network_rx_buffer_nowrap: - mov byte [os_EthernetBuffer_C2], al - - ; Check the packet type - mov ax, [rdi+12] ; Grab the EtherType/Length - xchg al, ah ; Convert big endian to little endian - cmp ax, 0x0800 ; IPv4 - je network_IPv4_handler - cmp ax, 0x0806 ; ARP - je network_ARP_handler - cmp ax, 0x86DD ; IPv6 - je network_IPv6_handler - - jmp network_end - -network_tx: - mov byte [os_NetActivity_TX], 1 - -network_end: - mov al, 0x20 ; Acknowledge the IRQ on the PIC(s) - cmp byte [os_NetIRQ], 8 - jl network_ack_only_low ; If the network IRQ is less than 8 then the other PIC does not need to be ack'ed - out 0xA0, al -network_ack_only_low: - out 0x20, al - - pop rax - pop rcx - pop rsi - pop rdi - iretq - -network_ARP_handler: ; Copy the packet and call the handler - mov rsi, rdi ; Copy the packet location - mov rdi, os_eth_temp_buffer ; and copy it here - push rsi - push rcx - rep movsb - pop rcx - pop rsi - - ; Remove the ARP packet from the ring buffer -; mov al, byte [os_EthernetBuffer_C2] - - call os_arp_handler ; Handle the packet - jmp network_end - -network_IPv4_handler: - mov rsi, rdi ; Copy the packet location - mov rdi, os_eth_temp_buffer ; and copy it here - push rsi - push rcx - rep movsb - pop rcx - pop rsi - - mov al, [rsi+0x17] - cmp al, 0x01 ; ICMP - je network_IPv4_ICMP_handler - cmp al, 0x06 ; TCP - je network_end - cmp al, 0x11 ; UDP - je network_end - jmp network_end - -network_IPv4_ICMP_handler: - push rsi - mov rsi, network_string02 - call os_print_string - pop rsi - call os_icmp_handler - jmp network_end - -network_IPv6_handler: - jmp network_end - -network_string01 db 'ARP!', 0 -network_string02 db 'ICMP!', 0 -network_string03 db 'TCP!', 0 -network_string04 db 'UDP!', 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; A simple interrupt that just acknowledges an IPI. Useful for getting an AP past a 'hlt' in the code. -align 16 -ap_wakeup: - push rdi - push rax - - cld ; Clear direction flag - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI - add rdi, 0xB0 - xor rax, rax - stosd - - pop rax - pop rdi - iretq ; Return from the IPI. -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Resets a CPU to execute ap_clear -align 16 -ap_reset: - cld ; Clear direction flag - mov rax, ap_clear ; Set RAX to the address of ap_clear - mov [rsp], rax ; Overwrite the return address on the CPU's stack - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI - add rdi, 0xB0 - xor rax, rax - stosd - iretq ; Return from the IPI. CPU will execute code at ap_clear -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Enable an interrupt line -; Expects the interrupt line # in AL -align 16 -interrupt_enable: - push rdx - push rcx - push rbx - push rax - push rax - - in al, 0x21 ; low byte target 0x21 - mov bl, al - pop rax - mov dx, 0x21 ; Use the low byte pic - cmp al, 8 - jl interrupt_enable_low - sub al, 8 ; IRQ 8-16 - push rax - in al, 0xA1 ; High byte target 0xA1 - mov bl, al - pop rax - mov dx, 0xA1 ; Use the high byte pic -interrupt_enable_low: - mov cl, al - mov al, 1 - shl al, cl - not al - and al, bl - out dx, al - - pop rax - pop rbx - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; CPU Exception Gates -align 16 -exception_gate_00: - push rax - mov al, 0x00 - jmp exception_gate_main - -align 16 -exception_gate_01: - push rax - mov al, 0x01 - jmp exception_gate_main - -align 16 -exception_gate_02: - push rax - mov al, 0x02 - jmp exception_gate_main - -align 16 -exception_gate_03: - push rax - mov al, 0x03 - jmp exception_gate_main - -align 16 -exception_gate_04: - push rax - mov al, 0x04 - jmp exception_gate_main - -align 16 -exception_gate_05: - push rax - mov al, 0x05 - jmp exception_gate_main - -align 16 -exception_gate_06: - push rax - mov al, 0x06 - jmp exception_gate_main - -align 16 -exception_gate_07: - push rax - mov al, 0x07 - jmp exception_gate_main - -align 16 -exception_gate_08: - push rax - mov al, 0x08 - jmp exception_gate_main - -align 16 -exception_gate_09: - push rax - mov al, 0x09 - jmp exception_gate_main - -align 16 -exception_gate_10: - push rax - mov al, 0x0A - jmp exception_gate_main - -align 16 -exception_gate_11: - push rax - mov al, 0x0B - jmp exception_gate_main - -align 16 -exception_gate_12: - push rax - mov al, 0x0C - jmp exception_gate_main - -align 16 -exception_gate_13: - push rax - mov al, 0x0D - jmp exception_gate_main - -align 16 -exception_gate_14: - push rax - mov al, 0x0E - jmp exception_gate_main - -align 16 -exception_gate_15: - push rax - mov al, 0x0F - jmp exception_gate_main - -align 16 -exception_gate_16: - push rax - mov al, 0x10 - jmp exception_gate_main - -align 16 -exception_gate_17: - push rax - mov al, 0x11 - jmp exception_gate_main - -align 16 -exception_gate_18: - push rax - mov al, 0x12 - jmp exception_gate_main - -align 16 -exception_gate_19: - push rax - mov al, 0x13 - jmp exception_gate_main - -align 16 -exception_gate_main: - push rbx - push rdi - push rsi - push rax ; Save RAX since os_smp_get_id clobers it - call os_print_newline - mov bl, 0x04 - mov rsi, int_string00 - call os_print_string_with_color - call os_smp_get_id ; Get the local CPU ID and print it - mov rdi, os_temp_string - mov rsi, rdi - call os_int_to_string - call os_print_string_with_color - mov rsi, int_string01 - call os_print_string - mov rsi, exc_string00 - pop rax - and rax, 0x00000000000000FF ; Clear out everything in RAX except for AL - push rax - mov bl, 52 - mul bl ; AX = AL x BL - add rsi, rax ; Use the value in RAX as an offset to get to the right message - pop rax - mov bl, 0x03 - call os_print_string_with_color - call os_print_newline - pop rsi - pop rdi - pop rbx - pop rax - call os_print_newline - call os_debug_dump_reg - mov rsi, rip_string - call os_print_string - push rax - mov rax, [rsp+0x08] ; RIP of caller - call os_debug_dump_rax - pop rax - call os_print_newline - push rax - push rcx - push rsi - mov rsi, stack_string - call os_print_string - mov rsi, rsp - add rsi, 0x18 - mov rcx, 4 -next_stack: - lodsq - call os_debug_dump_rax - mov al, ' ' - call os_print_char -; call os_print_char -; call os_print_char -; call os_print_char - loop next_stack - call os_print_newline - pop rsi - pop rcx - pop rax -; jmp $ ; For debugging - call init_memory_map - jmp ap_clear ; jump to AP clear code - - -int_string00 db 'BareMetal OS - CPU ', 0 -int_string01 db ' - ', 0 -; Strings for the error messages -exc_string db 'Unknown Fatal Exception!', 0 -exc_string00 db 'Interrupt 00 - Divide Error Exception (#DE) ', 0 -exc_string01 db 'Interrupt 01 - Debug Exception (#DB) ', 0 -exc_string02 db 'Interrupt 02 - NMI Interrupt ', 0 -exc_string03 db 'Interrupt 03 - Breakpoint Exception (#BP) ', 0 -exc_string04 db 'Interrupt 04 - Overflow Exception (#OF) ', 0 -exc_string05 db 'Interrupt 05 - BOUND Range Exceeded Exception (#BR)', 0 -exc_string06 db 'Interrupt 06 - Invalid Opcode Exception (#UD) ', 0 -exc_string07 db 'Interrupt 07 - Device Not Available Exception (#NM)', 0 -exc_string08 db 'Interrupt 08 - Double Fault Exception (#DF) ', 0 -exc_string09 db 'Interrupt 09 - Coprocessor Segment Overrun ', 0 ; No longer generated on new CPU's -exc_string10 db 'Interrupt 10 - Invalid TSS Exception (#TS) ', 0 -exc_string11 db 'Interrupt 11 - Segment Not Present (#NP) ', 0 -exc_string12 db 'Interrupt 12 - Stack Fault Exception (#SS) ', 0 -exc_string13 db 'Interrupt 13 - General Protection Exception (#GP) ', 0 -exc_string14 db 'Interrupt 14 - Page-Fault Exception (#PF) ', 0 -exc_string15 db 'Interrupt 15 - Undefined ', 0 -exc_string16 db 'Interrupt 16 - x87 FPU Floating-Point Error (#MF) ', 0 -exc_string17 db 'Interrupt 17 - Alignment Check Exception (#AC) ', 0 -exc_string18 db 'Interrupt 18 - Machine-Check Exception (#MC) ', 0 -exc_string19 db 'Interrupt 19 - SIMD Floating-Point Exception (#XM) ', 0 -rip_string db ' IP:', 0 -stack_string db ' ST:', 0 - - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Interrupts +; ============================================================================= + +align 16 +db 'DEBUG: INTERRUPT' +align 16 + + +; ----------------------------------------------------------------------------- +; Default exception handler +exception_gate: + mov rsi, int_string00 + call os_print_string + mov rsi, exc_string + call os_print_string + jmp $ ; Hang +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Default interrupt handler +align 16 +interrupt_gate: ; handler for all other interrupts + iretq ; It was an undefined interrupt so return to caller +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Keyboard interrupt. IRQ 0x01, INT 0x21 +; This IRQ runs whenever there is input on the keyboard +align 16 +keyboard: + push rax + push rbx + + xor rax, rax + +;keyboard_wait: +; in al, 0x64 +; and al, 0x01 +; jz keyboard_wait + + in al, 0x60 ; Get the scancode from the keyboard + cmp al, 0x01 + je keyboard_escape + cmp al, 0x2A ; Left Shift Make + je keyboard_shift + cmp al, 0x36 ; Right Shift Make + je keyboard_shift + cmp al, 0xAA ; Left Shift Break + je keyboard_noshift + cmp al, 0xB6 ; Right Shift Break + je keyboard_noshift + test al, 0x80 + jz keydown + jmp keyup + +keydown: + cmp byte [key_shift], 0x00 + jne keyboard_lowercase + jmp keyboard_uppercase + +keyboard_lowercase: + mov rbx, keylayoutupper + jmp keyboard_processkey + +keyboard_uppercase: + mov rbx, keylayoutlower + +keyboard_processkey: ; Convert the scancode + add rbx, rax + mov bl, [rbx] + mov [key], bl + mov al, [key] + jmp keyboard_done + +keyboard_escape: + jmp reboot + +keyup: + jmp keyboard_done + +keyboard_shift: + mov byte [key_shift], 0x01 + jmp keyboard_done + +keyboard_noshift: + mov byte [key_shift], 0x00 + jmp keyboard_done + +keyboard_done: + mov al, 0x20 ; Acknowledge the IRQ + out 0x20, al + call os_smp_wakeup_all ; A terrible hack + + pop rbx + pop rax + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Cascade interrupt. IRQ 0x02, INT 0x22 +align 16 +cascade: + push rax + + mov al, 0x20 ; Acknowledge the IRQ + out 0x20, al + + pop rax + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Real-time clock interrupt. IRQ 0x08, INT 0x28 +; Currently this IRQ runs 8 times per second (As defined in init_64.asm) +; The supervisor lives here +align 16 +rtc: + push rax + push rcx + push rsi + push rdi + + cld ; Clear direction flag + add qword [os_ClockCounter], 1 ; 64-bit counter started at bootup + + cmp byte [os_show_sysstatus], 0 + je rtc_no_sysstatus + call system_status ; Show System Status information on screen +rtc_no_sysstatus: + +; Check to make sure that at least one core is running something + cmp word [os_QueueLen], 0 ; Check the length of the Queue + jne rtc_end ; If it is greater than 0 then skip to the end + mov rcx, 256 + mov rsi, cpustatus +nextcpu: + lodsb + dec rcx + bt ax, 1 ; Is bit 1 set? If so then the CPU is running a job + jc rtc_end + cmp rcx, 0 + jne nextcpu + mov rax, os_command_line ; If nothing is running then restart the CLI + call os_smp_enqueue + +rtc_end: + mov al, 0x0C ; Select RTC register C + out 0x70, al ; Port 0x70 is the RTC index, and 0x71 is the RTC data + in al, 0x71 ; Read the value in register C + mov al, 0x20 ; Acknowledge the IRQ on the PICs + out 0xA0, al + out 0x20, al + + pop rdi + pop rsi + pop rcx + pop rax + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Network interrupt. +align 16 +network: + push rdi + push rsi + push rcx + push rax + + cld ; Clear direction flag + call os_ethernet_ack_int ; Call the driver function to acknowledge the interrupt internally + + bt ax, 0 ; TX bit set (caused the IRQ?) + jc network_tx ; If so then jump past RX section + mov byte [os_NetActivity_RX], 1 + + ; Max size of Ethernet packet: 1518 + ; + size: 2 = 1520 = 0x5F0 + ; Set each element size to 0x800 (2048). 262144 byte buffer / 2048 = room for 128 packets + ; Deal with the received packet + ; Get current offset in the ring buffer + mov rdi, os_EthernetBuffer + xor rax, rax + mov al, byte [os_EthernetBuffer_C2] + push rax ; Save the ring element value + shl rax, 11 ; Quickly multiply RAX by 2048 + add rdi, rax + push rdi + add rdi, 2 + call os_ethernet_rx_from_interrupt + pop rdi + mov rax, rcx + stosw ; Store the size of the packet + ; increment the offset in the ring buffer + pop rax ; Restore the ring element value + add al, 1 + cmp al, 128 ; Max element number is 127 + jne network_rx_buffer_nowrap + xor al, al +network_rx_buffer_nowrap: + mov byte [os_EthernetBuffer_C2], al + + ; Check the packet type + mov ax, [rdi+12] ; Grab the EtherType/Length + xchg al, ah ; Convert big endian to little endian + cmp ax, 0x0800 ; IPv4 + je network_IPv4_handler + cmp ax, 0x0806 ; ARP + je network_ARP_handler + cmp ax, 0x86DD ; IPv6 + je network_IPv6_handler + + jmp network_end + +network_tx: + mov byte [os_NetActivity_TX], 1 + +network_end: + mov al, 0x20 ; Acknowledge the IRQ on the PIC(s) + cmp byte [os_NetIRQ], 8 + jl network_ack_only_low ; If the network IRQ is less than 8 then the other PIC does not need to be ack'ed + out 0xA0, al +network_ack_only_low: + out 0x20, al + + pop rax + pop rcx + pop rsi + pop rdi + iretq + +network_ARP_handler: ; Copy the packet and call the handler + mov rsi, rdi ; Copy the packet location + mov rdi, os_eth_temp_buffer ; and copy it here + push rsi + push rcx + rep movsb + pop rcx + pop rsi + + ; Remove the ARP packet from the ring buffer +; mov al, byte [os_EthernetBuffer_C2] + + call os_arp_handler ; Handle the packet + jmp network_end + +network_IPv4_handler: + mov rsi, rdi ; Copy the packet location + mov rdi, os_eth_temp_buffer ; and copy it here + push rsi + push rcx + rep movsb + pop rcx + pop rsi + + mov al, [rsi+0x17] + cmp al, 0x01 ; ICMP + je network_IPv4_ICMP_handler + cmp al, 0x06 ; TCP + je network_end + cmp al, 0x11 ; UDP + je network_end + jmp network_end + +network_IPv4_ICMP_handler: + push rsi + mov rsi, network_string02 + call os_print_string + pop rsi + call os_icmp_handler + jmp network_end + +network_IPv6_handler: + jmp network_end + +network_string01 db 'ARP!', 0 +network_string02 db 'ICMP!', 0 +network_string03 db 'TCP!', 0 +network_string04 db 'UDP!', 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; A simple interrupt that just acknowledges an IPI. Useful for getting an AP past a 'hlt' in the code. +align 16 +ap_wakeup: + push rdi + push rax + + cld ; Clear direction flag + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI + add rdi, 0xB0 + xor rax, rax + stosd + + pop rax + pop rdi + iretq ; Return from the IPI. +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Resets a CPU to execute ap_clear +align 16 +ap_reset: + cld ; Clear direction flag + mov rax, ap_clear ; Set RAX to the address of ap_clear + mov [rsp], rax ; Overwrite the return address on the CPU's stack + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI + add rdi, 0xB0 + xor rax, rax + stosd + iretq ; Return from the IPI. CPU will execute code at ap_clear +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Enable an interrupt line +; Expects the interrupt line # in AL +align 16 +interrupt_enable: + push rdx + push rcx + push rbx + push rax + push rax + + in al, 0x21 ; low byte target 0x21 + mov bl, al + pop rax + mov dx, 0x21 ; Use the low byte pic + cmp al, 8 + jl interrupt_enable_low + sub al, 8 ; IRQ 8-16 + push rax + in al, 0xA1 ; High byte target 0xA1 + mov bl, al + pop rax + mov dx, 0xA1 ; Use the high byte pic +interrupt_enable_low: + mov cl, al + mov al, 1 + shl al, cl + not al + and al, bl + out dx, al + + pop rax + pop rbx + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; CPU Exception Gates +align 16 +exception_gate_00: + push rax + mov al, 0x00 + jmp exception_gate_main + +align 16 +exception_gate_01: + push rax + mov al, 0x01 + jmp exception_gate_main + +align 16 +exception_gate_02: + push rax + mov al, 0x02 + jmp exception_gate_main + +align 16 +exception_gate_03: + push rax + mov al, 0x03 + jmp exception_gate_main + +align 16 +exception_gate_04: + push rax + mov al, 0x04 + jmp exception_gate_main + +align 16 +exception_gate_05: + push rax + mov al, 0x05 + jmp exception_gate_main + +align 16 +exception_gate_06: + push rax + mov al, 0x06 + jmp exception_gate_main + +align 16 +exception_gate_07: + push rax + mov al, 0x07 + jmp exception_gate_main + +align 16 +exception_gate_08: + push rax + mov al, 0x08 + jmp exception_gate_main + +align 16 +exception_gate_09: + push rax + mov al, 0x09 + jmp exception_gate_main + +align 16 +exception_gate_10: + push rax + mov al, 0x0A + jmp exception_gate_main + +align 16 +exception_gate_11: + push rax + mov al, 0x0B + jmp exception_gate_main + +align 16 +exception_gate_12: + push rax + mov al, 0x0C + jmp exception_gate_main + +align 16 +exception_gate_13: + push rax + mov al, 0x0D + jmp exception_gate_main + +align 16 +exception_gate_14: + push rax + mov al, 0x0E + jmp exception_gate_main + +align 16 +exception_gate_15: + push rax + mov al, 0x0F + jmp exception_gate_main + +align 16 +exception_gate_16: + push rax + mov al, 0x10 + jmp exception_gate_main + +align 16 +exception_gate_17: + push rax + mov al, 0x11 + jmp exception_gate_main + +align 16 +exception_gate_18: + push rax + mov al, 0x12 + jmp exception_gate_main + +align 16 +exception_gate_19: + push rax + mov al, 0x13 + jmp exception_gate_main + +align 16 +exception_gate_main: + push rbx + push rdi + push rsi + push rax ; Save RAX since os_smp_get_id clobers it + call os_print_newline + mov bl, 0x04 + mov rsi, int_string00 + call os_print_string_with_color + call os_smp_get_id ; Get the local CPU ID and print it + mov rdi, os_temp_string + mov rsi, rdi + call os_int_to_string + call os_print_string_with_color + mov rsi, int_string01 + call os_print_string + mov rsi, exc_string00 + pop rax + and rax, 0x00000000000000FF ; Clear out everything in RAX except for AL + push rax + mov bl, 52 + mul bl ; AX = AL x BL + add rsi, rax ; Use the value in RAX as an offset to get to the right message + pop rax + mov bl, 0x03 + call os_print_string_with_color + call os_print_newline + pop rsi + pop rdi + pop rbx + pop rax + call os_print_newline + call os_debug_dump_reg + mov rsi, rip_string + call os_print_string + push rax + mov rax, [rsp+0x08] ; RIP of caller + call os_debug_dump_rax + pop rax + call os_print_newline + push rax + push rcx + push rsi + mov rsi, stack_string + call os_print_string + mov rsi, rsp + add rsi, 0x18 + mov rcx, 4 +next_stack: + lodsq + call os_debug_dump_rax + mov al, ' ' + call os_print_char +; call os_print_char +; call os_print_char +; call os_print_char + loop next_stack + call os_print_newline + pop rsi + pop rcx + pop rax +; jmp $ ; For debugging + call init_memory_map + jmp ap_clear ; jump to AP clear code + + +int_string00 db 'BareMetal OS - CPU ', 0 +int_string01 db ' - ', 0 +; Strings for the error messages +exc_string db 'Unknown Fatal Exception!', 0 +exc_string00 db 'Interrupt 00 - Divide Error Exception (#DE) ', 0 +exc_string01 db 'Interrupt 01 - Debug Exception (#DB) ', 0 +exc_string02 db 'Interrupt 02 - NMI Interrupt ', 0 +exc_string03 db 'Interrupt 03 - Breakpoint Exception (#BP) ', 0 +exc_string04 db 'Interrupt 04 - Overflow Exception (#OF) ', 0 +exc_string05 db 'Interrupt 05 - BOUND Range Exceeded Exception (#BR)', 0 +exc_string06 db 'Interrupt 06 - Invalid Opcode Exception (#UD) ', 0 +exc_string07 db 'Interrupt 07 - Device Not Available Exception (#NM)', 0 +exc_string08 db 'Interrupt 08 - Double Fault Exception (#DF) ', 0 +exc_string09 db 'Interrupt 09 - Coprocessor Segment Overrun ', 0 ; No longer generated on new CPU's +exc_string10 db 'Interrupt 10 - Invalid TSS Exception (#TS) ', 0 +exc_string11 db 'Interrupt 11 - Segment Not Present (#NP) ', 0 +exc_string12 db 'Interrupt 12 - Stack Fault Exception (#SS) ', 0 +exc_string13 db 'Interrupt 13 - General Protection Exception (#GP) ', 0 +exc_string14 db 'Interrupt 14 - Page-Fault Exception (#PF) ', 0 +exc_string15 db 'Interrupt 15 - Undefined ', 0 +exc_string16 db 'Interrupt 16 - x87 FPU Floating-Point Error (#MF) ', 0 +exc_string17 db 'Interrupt 17 - Alignment Check Exception (#AC) ', 0 +exc_string18 db 'Interrupt 18 - Machine-Check Exception (#MC) ', 0 +exc_string19 db 'Interrupt 19 - SIMD Floating-Point Exception (#XM) ', 0 +rip_string db ' IP:', 0 +stack_string db ' ST:', 0 + + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4.asm index d46d6025..b1983a42 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4.asm @@ -1,17 +1,17 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; IP (Internet Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 IP ' -align 16 - -%include "ipv4/arp.asm" -%include "ipv4/icmp.asm" - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; IP (Internet Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 IP ' +align 16 + +%include "ipv4/arp.asm" +%include "ipv4/icmp.asm" + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/arp.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/arp.asm index dc004575..5190b435 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/arp.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/arp.asm @@ -1,148 +1,148 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; ARP (Address Resolution Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: ARP ' -align 16 - - -; ARP Incoming Request layout: -; Ethernet header: -; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) -; 6-11, Source MAC -; 12-13, Type ARP (0x0806) -; ARP data: -; 14-15, Hardware type (0x0001 Ethernet) -; 16-17, Protocol type (0x0800 IP) -; 18, Hardware size (0x06) -; 19, Protocol size (0x04) -; 20-21, Opcode (0x0001 Request) -; 22-27, Sender MAC -; 28-31, Sender IP -; 32-37, Target MAC (0x000000000000) -; 38-41, Target IP - -; ARP Outgoing Request layout: -; Ethernet header: -; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) -; 6-11, Source MAC (This host) -; 12-13, Type ARP (0x0806) -; ARP data: -; 14-15, Hardware type (0x0001 Ethernet) -; 16-17, Protocol type (0x0800 IP) -; 18, Hardware size (0x06) -; 19, Protocol size (0x04) -; 20-21, Opcode (0x0001 Request) -; 22-27, Sender MAC (This host) -; 28-31, Sender IP (This host) -; 32-37, Target MAC (0x000000000000) -; 38-41, Target IP - -; ARP Outgoing Reply layout: -; Ethernet header: -; 0-5, Destination MAC (This host) -; 6-11, Source MAC -; 12-13, Type ARP (0x0806) -; ARP data: -; 14-15, Hardware type (0x0001 Ethernet) -; 16-17, Protocol type (0x0800 IP) -; 18, Hardware size (0x06) -; 19, Protocol size (0x04) -; 20-21, Opcode (0x0002 Reply) -; 22-27, Sender MAC -; 28-31, Sender IP -; 32-37, Target MAC -; 38-41, Target IP - - -; ----------------------------------------------------------------------------- -os_arp_request: - -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_arp_handler -- Handle an incoming ARP packet -; IN: RCX = packet length -; RSI = location of received ARP packet -os_arp_handler: - push rdi - push rsi - push rax - - mov ax, [rsi+0x14] ; Grab the Opcode - xchg al, ah ; Convert to proper endianess - cmp ax, 0x0001 ; Request - je os_arp_handler_request ; Respond if the ARP packet is for us - cmp ax, 0x0002 ; Reply - je os_arp_handler_reply ; Add to our local ARP table - jmp os_arp_handler_end ; Bail out - -os_arp_handler_request: - mov eax, [rsi+0x26] ; Grab the target IP address -; call os_debug_dump_eax - cmp eax, [ip] ; Does it match our IP? - jne os_arp_handler_end ; If not then we don't need to respond - - push rsi ; Save the address of the packet - mov rdi, rsi - add rsi, 0x1C ; Skip to Sender IP - mov eax, [rsi] - push rax ; Save the Sender IP - sub rsi, 0x16 ; Skip back to Source MAC - - movsd ; Copy destination MAC address - movsw - - push rsi ; Copy source MAC address - mov rsi, os_NetMAC - movsd - movsw - pop rsi - - add rdi, 9 - mov al, 0x02 ; Change the opcode to a reply - stosb - - push rsi ; Copy source MAC address (again) - mov rsi, os_NetMAC - movsd - movsw - pop rsi - - mov eax, [ip] ; Copy our IP - stosd - - sub rsi, 12 ; Copy destination MAC - movsd - movsw - - pop rax ; Restore the Sender IP - stosd - - pop rsi ; Restore the packet address - - mov cx, 60 - call os_ethernet_tx_raw ; Send the packet - - jmp os_arp_handler_end - -os_arp_handler_reply: - - jmp os_arp_handler_end - -os_arp_handler_end: - pop rax - pop rsi - pop rdi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; ARP (Address Resolution Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: ARP ' +align 16 + + +; ARP Incoming Request layout: +; Ethernet header: +; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) +; 6-11, Source MAC +; 12-13, Type ARP (0x0806) +; ARP data: +; 14-15, Hardware type (0x0001 Ethernet) +; 16-17, Protocol type (0x0800 IP) +; 18, Hardware size (0x06) +; 19, Protocol size (0x04) +; 20-21, Opcode (0x0001 Request) +; 22-27, Sender MAC +; 28-31, Sender IP +; 32-37, Target MAC (0x000000000000) +; 38-41, Target IP + +; ARP Outgoing Request layout: +; Ethernet header: +; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) +; 6-11, Source MAC (This host) +; 12-13, Type ARP (0x0806) +; ARP data: +; 14-15, Hardware type (0x0001 Ethernet) +; 16-17, Protocol type (0x0800 IP) +; 18, Hardware size (0x06) +; 19, Protocol size (0x04) +; 20-21, Opcode (0x0001 Request) +; 22-27, Sender MAC (This host) +; 28-31, Sender IP (This host) +; 32-37, Target MAC (0x000000000000) +; 38-41, Target IP + +; ARP Outgoing Reply layout: +; Ethernet header: +; 0-5, Destination MAC (This host) +; 6-11, Source MAC +; 12-13, Type ARP (0x0806) +; ARP data: +; 14-15, Hardware type (0x0001 Ethernet) +; 16-17, Protocol type (0x0800 IP) +; 18, Hardware size (0x06) +; 19, Protocol size (0x04) +; 20-21, Opcode (0x0002 Reply) +; 22-27, Sender MAC +; 28-31, Sender IP +; 32-37, Target MAC +; 38-41, Target IP + + +; ----------------------------------------------------------------------------- +os_arp_request: + +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_arp_handler -- Handle an incoming ARP packet +; IN: RCX = packet length +; RSI = location of received ARP packet +os_arp_handler: + push rdi + push rsi + push rax + + mov ax, [rsi+0x14] ; Grab the Opcode + xchg al, ah ; Convert to proper endianess + cmp ax, 0x0001 ; Request + je os_arp_handler_request ; Respond if the ARP packet is for us + cmp ax, 0x0002 ; Reply + je os_arp_handler_reply ; Add to our local ARP table + jmp os_arp_handler_end ; Bail out + +os_arp_handler_request: + mov eax, [rsi+0x26] ; Grab the target IP address +; call os_debug_dump_eax + cmp eax, [ip] ; Does it match our IP? + jne os_arp_handler_end ; If not then we don't need to respond + + push rsi ; Save the address of the packet + mov rdi, rsi + add rsi, 0x1C ; Skip to Sender IP + mov eax, [rsi] + push rax ; Save the Sender IP + sub rsi, 0x16 ; Skip back to Source MAC + + movsd ; Copy destination MAC address + movsw + + push rsi ; Copy source MAC address + mov rsi, os_NetMAC + movsd + movsw + pop rsi + + add rdi, 9 + mov al, 0x02 ; Change the opcode to a reply + stosb + + push rsi ; Copy source MAC address (again) + mov rsi, os_NetMAC + movsd + movsw + pop rsi + + mov eax, [ip] ; Copy our IP + stosd + + sub rsi, 12 ; Copy destination MAC + movsd + movsw + + pop rax ; Restore the Sender IP + stosd + + pop rsi ; Restore the packet address + + mov cx, 60 + call os_ethernet_tx_raw ; Send the packet + + jmp os_arp_handler_end + +os_arp_handler_reply: + + jmp os_arp_handler_end + +os_arp_handler_end: + pop rax + pop rsi + pop rdi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/icmp.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/icmp.asm index 666ee9a1..cf144d35 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/icmp.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/icmp.asm @@ -1,24 +1,24 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; ICMP (Internet Control Message Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 ICMP' -align 16 - - -; ----------------------------------------------------------------------------- -; os_icmp_handler -- Handle an incoming ICMP packet -; IN: RCX = packet length -; RSI = location of received ICMP packet -os_icmp_handler: - - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; ICMP (Internet Control Message Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 ICMP' +align 16 + + +; ----------------------------------------------------------------------------- +; os_icmp_handler -- Handle an incoming ICMP packet +; IN: RCX = packet length +; RSI = location of received ICMP packet +os_icmp_handler: + + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/tcp.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/tcp.asm index 6a663839..b26b38fe 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/tcp.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/tcp.asm @@ -1,16 +1,16 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; TCP (Transmission Control Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 TCP ' -align 16 - - - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; TCP (Transmission Control Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 TCP ' +align 16 + + + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/udp.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/udp.asm index e551ba89..5b7be0bc 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/udp.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv4/udp.asm @@ -1,16 +1,16 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; UDP (User Datagram Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 UDP ' -align 16 - - - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; UDP (User Datagram Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 UDP ' +align 16 + + + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv6/ndp.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv6/ndp.asm index b029ae15..cd2233f0 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv6/ndp.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/ipv6/ndp.asm @@ -1,14 +1,14 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; NDP (Neighbor Discovery Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: NDP ' -align 16 - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; NDP (Neighbor Discovery Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: NDP ' +align 16 + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/kernel64.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/kernel64.asm index 6998648b..b41cd26d 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/kernel64.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/kernel64.asm @@ -1,537 +1,537 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; The BareMetal OS kernel. Assemble with NASM -; ============================================================================= - - -USE64 -ORG 0x0000000000100000 - -%DEFINE BAREMETALOS_VER 'v0.5.2 (June 29, 2011)', 13, 'Copyright (C) 2008-2011 Return Infinity', 13, 0 -%DEFINE BAREMETALOS_API_VER 1 - -kernel_start: - jmp start ; Skip over the function call index - nop - db 'BAREMETAL' - - align 16 ; 0x0010 - jmp os_print_string ; Jump to function - align 8 - dq os_print_string ; Memory address of function - - align 8 ; 0x0020 - jmp os_print_char - align 8 - dq os_print_char - - align 8 ; 0x0030 - jmp os_print_char_hex - align 8 - dq os_print_char_hex - - align 8 ; 0x0040 - jmp os_print_newline - align 8 - dq os_print_newline - - align 8 ; 0x0050 - jmp os_input_key_check - align 8 - dq os_input_key_check - - align 8 ; 0x0060 - jmp os_input_key_wait - align 8 - dq os_input_key_wait - - align 8 ; 0x0070 - jmp os_input_string - align 8 - dq os_input_string - - align 8 ; 0x0080 - jmp os_delay - align 8 - dq os_delay - - align 8 ; 0x0090 - jmp os_speaker_tone - align 8 - dq os_speaker_tone - - align 8 ; 0x00A0 - jmp os_speaker_off - align 8 - dq os_speaker_off - - align 8 ; 0x00B0 - jmp os_speaker_beep - align 8 - dq os_speaker_beep - - align 8 ; 0x00C0 - jmp os_move_cursor - align 8 - dq os_move_cursor - - align 8 ; 0x00D0 - jmp os_string_length - align 8 - dq os_string_length - - align 8 ; 0x00E0 - jmp os_string_find_char - align 8 - dq os_string_find_char - - align 8 ; 0x00F0 - jmp os_string_copy - align 8 - dq os_string_copy - - align 8 ; 0x0100 - jmp os_string_truncate - align 8 - dq os_string_truncate - - align 8 ; 0x0110 - jmp os_string_join - align 8 - dq os_string_join - - align 8 ; 0x0120 - jmp os_string_chomp - align 8 - dq os_string_chomp - - align 8 ; 0x0130 - jmp os_string_strip - align 8 - dq os_string_strip - - align 8 ; 0x0140 - jmp os_string_compare - align 8 - dq os_string_compare - - align 8 ; 0x0150 - jmp os_string_uppercase - align 8 - dq os_string_uppercase - - align 8 ; 0x0160 - jmp os_string_lowercase - align 8 - dq os_string_lowercase - - align 8 ; 0x0170 - jmp os_int_to_string - align 8 - dq os_int_to_string - - align 8 ; 0x0180 - jmp os_string_to_int - align 8 - dq os_string_to_int - - align 8 ; 0x0190 - jmp os_debug_dump_reg - align 8 - dq os_debug_dump_reg - - align 8 ; 0x01A0 - jmp os_debug_dump_mem - align 8 - dq os_debug_dump_mem - - align 8 ; 0x01B0 - jmp os_debug_dump_rax - align 8 - dq os_debug_dump_rax - - align 8 ; 0x01C0 - jmp os_debug_dump_eax - align 8 - dq os_debug_dump_eax - - align 8 ; 0x01D0 - jmp os_debug_dump_ax - align 8 - dq os_debug_dump_ax - - align 8 ; 0x01E0 - jmp os_debug_dump_al - align 8 - dq os_debug_dump_al - - align 8 ; 0x01F0 - jmp os_smp_reset - align 8 - dq os_smp_reset - - align 8 ; 0x0200 - jmp os_smp_get_id - align 8 - dq os_smp_get_id - - align 8 ; 0x0210 - jmp os_smp_enqueue - align 8 - dq os_smp_enqueue - - align 8 ; 0x0220 - jmp os_smp_dequeue - align 8 - dq os_smp_dequeue - - align 8 ; 0x0230 - jmp os_serial_send - align 8 - dq os_serial_send - - align 8 ; 0x0240 - jmp os_serial_recv - align 8 - dq os_serial_recv - - align 8 ; 0x0250 - jmp os_string_parse - align 8 - dq os_string_parse - - align 8 ; 0x0260 - jmp os_get_argc - align 8 - dq os_get_argc - - align 8 ; 0x0270 - jmp os_get_argv - align 8 - dq os_get_argv - - align 8 ; 0x0280 - jmp os_smp_queuelen - align 8 - dq os_smp_queuelen - - align 8 ; 0x0290 - jmp os_smp_wait - align 8 - dq os_smp_wait - - align 8 ; 0x02A0 - jmp os_get_timecounter - align 8 - dq os_get_timecounter - - align 8 ; 0x02B0 - jmp os_string_append - align 8 - dq os_string_append - - align 8 ; 0x02C0 - jmp os_int_to_hex_string - align 8 - dq os_int_to_hex_string - - align 8 ; 0x02D0 - jmp os_hex_string_to_int - align 8 - dq os_hex_string_to_int - - align 8 ; 0x02E0 - jmp os_string_change_char - align 8 - dq os_string_change_char - - align 8 ; 0x02F0 - jmp os_is_digit - align 8 - dq os_is_digit - - align 8 ; 0x0300 - jmp os_is_alpha - align 8 - dq os_is_alpha - - align 8 ; 0x0310 - jmp os_file_read - align 8 - dq os_file_read - - align 8 ; 0x0320 - jmp os_file_write - align 8 - dq os_file_write - - align 8 ; 0x0330 - jmp os_file_delete - align 8 - dq os_file_delete - - align 8 ; 0x0340 - jmp os_file_get_list - align 8 - dq os_file_get_list - - align 8 ; 0x0350 - jmp os_smp_run - align 8 - dq os_smp_run - - align 8 ; 0x0360 - jmp os_smp_lock - align 8 - dq os_smp_lock - - align 8 ; 0x0370 - jmp os_smp_unlock - align 8 - dq os_smp_unlock - - align 8 ; 0x0380 - jmp os_print_string_with_color - align 8 - dq os_print_string_with_color - - align 8 ; 0x0390 - jmp os_print_char_with_color - align 8 - dq os_print_char_with_color - - align 8 ; 0x03A0 - jmp os_ethernet_tx - align 8 - dq os_ethernet_tx - - align 8 ; 0x03B0 - jmp os_ethernet_rx - align 8 - dq os_ethernet_rx - - align 8 ; 0x03C0 - jmp os_mem_allocate - align 8 - dq os_mem_allocate - - align 8 ; 0x03D0 - jmp os_mem_release - align 8 - dq os_mem_release - - align 8 ; 0x03E0 - jmp os_mem_get_free - align 8 - dq os_mem_get_free - - align 8 ; 0x03F0 - jmp os_smp_numcores - align 8 - dq os_smp_numcores - - align 8 ; 0x0400 - jmp os_file_get_size - align 8 - dq os_file_get_size - - align 8 ; 0x0410 - jmp os_ethernet_avail - align 8 - dq os_ethernet_avail - - align 8 ; 0x0420 - jmp os_print_char_hex_with_color - align 8 - dq os_print_char_hex_with_color - - align 8 ; 0x0430 - jmp os_ethernet_tx_raw - align 8 - dq os_ethernet_tx_raw - - align 8 ; 0x0440 - jmp os_screen_clear - align 8 - dq os_screen_clear - - align 8 ; 0x0450 - jmp os_show_cursor - align 8 - dq os_show_cursor - - align 8 ; 0x0460 - jmp os_hide_cursor - align 8 - dq os_hide_cursor - - align 8 ; 0x0470 - jmp os_show_statusbar - align 8 - dq os_show_statusbar - - align 8 ; 0x0480 - jmp os_hide_statusbar - align 8 - dq os_hide_statusbar - - align 8 ; 0x0490 - jmp os_screen_update - align 8 - dq os_screen_update - - align 8 ; 0x04A0 - jmp os_print_chars - align 8 - dq os_print_chars - - align 8 ; 0x04B0 - jmp os_print_chars_with_color - align 8 - dq os_print_chars_with_color - -align 16 - -start: - - call init_64 ; After this point we are in a working 64-bit enviroment - - call init_pci - - call init_net ; Initialize the network - - mov rdi, ip - mov al, 192 - stosb - mov al, 168 - stosb - mov al, 242 - stosb - mov al, 100 - stosb - - call hdd_setup ; Gather information about the harddrive and set it up - - call os_screen_clear - - cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) - jne start_no_network - mov ax, 0x0013 - call os_move_cursor - mov rsi, networkmsg - call os_print_string - call os_debug_dump_MAC -start_no_network: - - mov ax, 0x0016 ; Print the "ready" message - call os_move_cursor - mov rsi, readymsg - call os_print_string - - mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner - call os_move_cursor - call os_show_cursor - - mov rsi, startupapp ; Look for a file called startup.app - mov rdi, programlocation ; We load the program to this location in memory (currently 0x00200000 : at the 2MB mark) - call os_file_read ; Read the file into memory - jc ap_clear ; If carry is set then the file was not found - - xchg bx, bx - mov rax, programlocation ; 0x00200000 : at the 2MB mark - xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) - call os_smp_enqueue ; Queue the application to run on the next available core - - ; Fall through to ap_clear as align fills the space with No-Ops - ; At this point the BSP is just like one of the AP's - - -align 16 - -ap_clear: ; All cores start here on first startup and after an exception - - cli ; Disable interrupts on this core - - ; Get local ID of the core - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID - lodsd ; Load a 32-bit value. We only want the high 8 bits - shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID - - ; Calculate offset into CPU status table - mov rdi, cpustatus - add rdi, rax ; RDI points to this cores status byte (we will clear it later) - - ; Set up the stack - shl rax, 21 ; Shift left 21 bits for a 2 MiB stack - add rax, [os_StackBase] ; The stack decrements when you "push", start at 2 MiB in - mov rsp, rax - - ; Set the CPU status to "Present" and "Ready" - mov al, 00000001b ; Bit 0 set for "Present", Bit 1 clear for "Ready" - stosb ; Set status to Ready for this CPU - - sti ; Re-enable interrupts on this core - - ; Clear registers. Gives us a clean slate to work with - xor rax, rax ; aka r0 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rbx, rbx ; aka r3 - xor rbp, rbp ; aka r5, We skip RSP (aka r4) as it was previously set - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - -ap_spin: ; Spin until there is a workload in the queue - cmp word [os_QueueLen], 0 ; Check the length of the queue - je ap_halt ; If the queue was empty then jump to the HLT - call os_smp_dequeue ; Try to pull a workload out of the queue - jnc ap_process ; Carry clear if successful, jump to ap_process - -ap_halt: ; Halt until a wakup call is received - hlt ; If carry was set we fall through to the HLT - jmp ap_spin ; Try again - -ap_process: ; Set the status byte to "Busy" and run the code - push rdi ; Push RDI since it is used temporarily - push rax ; Push RAX since os_smp_get_id uses it - mov rdi, cpustatus - call os_smp_get_id ; Set RAX to the APIC ID - add rdi, rax - mov al, 00000011b ; Bit 0 set for "Present", Bit 1 set for "Busy" - stosb - pop rax ; Pop RAX (holds the workload code address) - pop rdi ; Pop RDI (holds the variable/variable address) - - call rax ; Run the code - - jmp ap_clear ; Reset the stack, clear the registers, and wait for something else to work on - - -; Includes -%include "init_64.asm" -%include "init_pci.asm" -%include "init_net.asm" -%include "init_hdd.asm" -%include "syscalls.asm" -%include "drivers.asm" -%include "interrupt.asm" -%include "cli.asm" -%include "ipv4.asm" -%include "sysvar.asm" ; Include this last to keep the read/write variables away from the code - -times 16384-($-$$) db 0 ; Set the compiled kernel binary to at least this size in bytes - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; The BareMetal OS kernel. Assemble with NASM +; ============================================================================= + + +USE64 +ORG 0x0000000000100000 + +%DEFINE BAREMETALOS_VER 'v0.5.2 (June 29, 2011)', 13, 'Copyright (C) 2008-2011 Return Infinity', 13, 0 +%DEFINE BAREMETALOS_API_VER 1 + +kernel_start: + jmp start ; Skip over the function call index + nop + db 'BAREMETAL' + + align 16 ; 0x0010 + jmp os_print_string ; Jump to function + align 8 + dq os_print_string ; Memory address of function + + align 8 ; 0x0020 + jmp os_print_char + align 8 + dq os_print_char + + align 8 ; 0x0030 + jmp os_print_char_hex + align 8 + dq os_print_char_hex + + align 8 ; 0x0040 + jmp os_print_newline + align 8 + dq os_print_newline + + align 8 ; 0x0050 + jmp os_input_key_check + align 8 + dq os_input_key_check + + align 8 ; 0x0060 + jmp os_input_key_wait + align 8 + dq os_input_key_wait + + align 8 ; 0x0070 + jmp os_input_string + align 8 + dq os_input_string + + align 8 ; 0x0080 + jmp os_delay + align 8 + dq os_delay + + align 8 ; 0x0090 + jmp os_speaker_tone + align 8 + dq os_speaker_tone + + align 8 ; 0x00A0 + jmp os_speaker_off + align 8 + dq os_speaker_off + + align 8 ; 0x00B0 + jmp os_speaker_beep + align 8 + dq os_speaker_beep + + align 8 ; 0x00C0 + jmp os_move_cursor + align 8 + dq os_move_cursor + + align 8 ; 0x00D0 + jmp os_string_length + align 8 + dq os_string_length + + align 8 ; 0x00E0 + jmp os_string_find_char + align 8 + dq os_string_find_char + + align 8 ; 0x00F0 + jmp os_string_copy + align 8 + dq os_string_copy + + align 8 ; 0x0100 + jmp os_string_truncate + align 8 + dq os_string_truncate + + align 8 ; 0x0110 + jmp os_string_join + align 8 + dq os_string_join + + align 8 ; 0x0120 + jmp os_string_chomp + align 8 + dq os_string_chomp + + align 8 ; 0x0130 + jmp os_string_strip + align 8 + dq os_string_strip + + align 8 ; 0x0140 + jmp os_string_compare + align 8 + dq os_string_compare + + align 8 ; 0x0150 + jmp os_string_uppercase + align 8 + dq os_string_uppercase + + align 8 ; 0x0160 + jmp os_string_lowercase + align 8 + dq os_string_lowercase + + align 8 ; 0x0170 + jmp os_int_to_string + align 8 + dq os_int_to_string + + align 8 ; 0x0180 + jmp os_string_to_int + align 8 + dq os_string_to_int + + align 8 ; 0x0190 + jmp os_debug_dump_reg + align 8 + dq os_debug_dump_reg + + align 8 ; 0x01A0 + jmp os_debug_dump_mem + align 8 + dq os_debug_dump_mem + + align 8 ; 0x01B0 + jmp os_debug_dump_rax + align 8 + dq os_debug_dump_rax + + align 8 ; 0x01C0 + jmp os_debug_dump_eax + align 8 + dq os_debug_dump_eax + + align 8 ; 0x01D0 + jmp os_debug_dump_ax + align 8 + dq os_debug_dump_ax + + align 8 ; 0x01E0 + jmp os_debug_dump_al + align 8 + dq os_debug_dump_al + + align 8 ; 0x01F0 + jmp os_smp_reset + align 8 + dq os_smp_reset + + align 8 ; 0x0200 + jmp os_smp_get_id + align 8 + dq os_smp_get_id + + align 8 ; 0x0210 + jmp os_smp_enqueue + align 8 + dq os_smp_enqueue + + align 8 ; 0x0220 + jmp os_smp_dequeue + align 8 + dq os_smp_dequeue + + align 8 ; 0x0230 + jmp os_serial_send + align 8 + dq os_serial_send + + align 8 ; 0x0240 + jmp os_serial_recv + align 8 + dq os_serial_recv + + align 8 ; 0x0250 + jmp os_string_parse + align 8 + dq os_string_parse + + align 8 ; 0x0260 + jmp os_get_argc + align 8 + dq os_get_argc + + align 8 ; 0x0270 + jmp os_get_argv + align 8 + dq os_get_argv + + align 8 ; 0x0280 + jmp os_smp_queuelen + align 8 + dq os_smp_queuelen + + align 8 ; 0x0290 + jmp os_smp_wait + align 8 + dq os_smp_wait + + align 8 ; 0x02A0 + jmp os_get_timecounter + align 8 + dq os_get_timecounter + + align 8 ; 0x02B0 + jmp os_string_append + align 8 + dq os_string_append + + align 8 ; 0x02C0 + jmp os_int_to_hex_string + align 8 + dq os_int_to_hex_string + + align 8 ; 0x02D0 + jmp os_hex_string_to_int + align 8 + dq os_hex_string_to_int + + align 8 ; 0x02E0 + jmp os_string_change_char + align 8 + dq os_string_change_char + + align 8 ; 0x02F0 + jmp os_is_digit + align 8 + dq os_is_digit + + align 8 ; 0x0300 + jmp os_is_alpha + align 8 + dq os_is_alpha + + align 8 ; 0x0310 + jmp os_file_read + align 8 + dq os_file_read + + align 8 ; 0x0320 + jmp os_file_write + align 8 + dq os_file_write + + align 8 ; 0x0330 + jmp os_file_delete + align 8 + dq os_file_delete + + align 8 ; 0x0340 + jmp os_file_get_list + align 8 + dq os_file_get_list + + align 8 ; 0x0350 + jmp os_smp_run + align 8 + dq os_smp_run + + align 8 ; 0x0360 + jmp os_smp_lock + align 8 + dq os_smp_lock + + align 8 ; 0x0370 + jmp os_smp_unlock + align 8 + dq os_smp_unlock + + align 8 ; 0x0380 + jmp os_print_string_with_color + align 8 + dq os_print_string_with_color + + align 8 ; 0x0390 + jmp os_print_char_with_color + align 8 + dq os_print_char_with_color + + align 8 ; 0x03A0 + jmp os_ethernet_tx + align 8 + dq os_ethernet_tx + + align 8 ; 0x03B0 + jmp os_ethernet_rx + align 8 + dq os_ethernet_rx + + align 8 ; 0x03C0 + jmp os_mem_allocate + align 8 + dq os_mem_allocate + + align 8 ; 0x03D0 + jmp os_mem_release + align 8 + dq os_mem_release + + align 8 ; 0x03E0 + jmp os_mem_get_free + align 8 + dq os_mem_get_free + + align 8 ; 0x03F0 + jmp os_smp_numcores + align 8 + dq os_smp_numcores + + align 8 ; 0x0400 + jmp os_file_get_size + align 8 + dq os_file_get_size + + align 8 ; 0x0410 + jmp os_ethernet_avail + align 8 + dq os_ethernet_avail + + align 8 ; 0x0420 + jmp os_print_char_hex_with_color + align 8 + dq os_print_char_hex_with_color + + align 8 ; 0x0430 + jmp os_ethernet_tx_raw + align 8 + dq os_ethernet_tx_raw + + align 8 ; 0x0440 + jmp os_screen_clear + align 8 + dq os_screen_clear + + align 8 ; 0x0450 + jmp os_show_cursor + align 8 + dq os_show_cursor + + align 8 ; 0x0460 + jmp os_hide_cursor + align 8 + dq os_hide_cursor + + align 8 ; 0x0470 + jmp os_show_statusbar + align 8 + dq os_show_statusbar + + align 8 ; 0x0480 + jmp os_hide_statusbar + align 8 + dq os_hide_statusbar + + align 8 ; 0x0490 + jmp os_screen_update + align 8 + dq os_screen_update + + align 8 ; 0x04A0 + jmp os_print_chars + align 8 + dq os_print_chars + + align 8 ; 0x04B0 + jmp os_print_chars_with_color + align 8 + dq os_print_chars_with_color + +align 16 + +start: + + call init_64 ; After this point we are in a working 64-bit enviroment + + call init_pci + + call init_net ; Initialize the network + + mov rdi, ip + mov al, 192 + stosb + mov al, 168 + stosb + mov al, 242 + stosb + mov al, 100 + stosb + + call hdd_setup ; Gather information about the harddrive and set it up + + call os_screen_clear + + cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) + jne start_no_network + mov ax, 0x0013 + call os_move_cursor + mov rsi, networkmsg + call os_print_string + call os_debug_dump_MAC +start_no_network: + + mov ax, 0x0016 ; Print the "ready" message + call os_move_cursor + mov rsi, readymsg + call os_print_string + + mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner + call os_move_cursor + call os_show_cursor + + mov rsi, startupapp ; Look for a file called startup.app + mov rdi, programlocation ; We load the program to this location in memory (currently 0x00200000 : at the 2MB mark) + call os_file_read ; Read the file into memory + jc ap_clear ; If carry is set then the file was not found + + xchg bx, bx + mov rax, programlocation ; 0x00200000 : at the 2MB mark + xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) + call os_smp_enqueue ; Queue the application to run on the next available core + + ; Fall through to ap_clear as align fills the space with No-Ops + ; At this point the BSP is just like one of the AP's + + +align 16 + +ap_clear: ; All cores start here on first startup and after an exception + + cli ; Disable interrupts on this core + + ; Get local ID of the core + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID + lodsd ; Load a 32-bit value. We only want the high 8 bits + shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID + + ; Calculate offset into CPU status table + mov rdi, cpustatus + add rdi, rax ; RDI points to this cores status byte (we will clear it later) + + ; Set up the stack + shl rax, 21 ; Shift left 21 bits for a 2 MiB stack + add rax, [os_StackBase] ; The stack decrements when you "push", start at 2 MiB in + mov rsp, rax + + ; Set the CPU status to "Present" and "Ready" + mov al, 00000001b ; Bit 0 set for "Present", Bit 1 clear for "Ready" + stosb ; Set status to Ready for this CPU + + sti ; Re-enable interrupts on this core + + ; Clear registers. Gives us a clean slate to work with + xor rax, rax ; aka r0 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rbx, rbx ; aka r3 + xor rbp, rbp ; aka r5, We skip RSP (aka r4) as it was previously set + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + +ap_spin: ; Spin until there is a workload in the queue + cmp word [os_QueueLen], 0 ; Check the length of the queue + je ap_halt ; If the queue was empty then jump to the HLT + call os_smp_dequeue ; Try to pull a workload out of the queue + jnc ap_process ; Carry clear if successful, jump to ap_process + +ap_halt: ; Halt until a wakup call is received + hlt ; If carry was set we fall through to the HLT + jmp ap_spin ; Try again + +ap_process: ; Set the status byte to "Busy" and run the code + push rdi ; Push RDI since it is used temporarily + push rax ; Push RAX since os_smp_get_id uses it + mov rdi, cpustatus + call os_smp_get_id ; Set RAX to the APIC ID + add rdi, rax + mov al, 00000011b ; Bit 0 set for "Present", Bit 1 set for "Busy" + stosb + pop rax ; Pop RAX (holds the workload code address) + pop rdi ; Pop RDI (holds the variable/variable address) + + call rax ; Run the code + + jmp ap_clear ; Reset the stack, clear the registers, and wait for something else to work on + + +; Includes +%include "init_64.asm" +%include "init_pci.asm" +%include "init_net.asm" +%include "init_hdd.asm" +%include "syscalls.asm" +%include "drivers.asm" +%include "interrupt.asm" +%include "cli.asm" +%include "ipv4.asm" +%include "sysvar.asm" ; Include this last to keep the read/write variables away from the code + +times 16384-($-$$) db 0 ; Set the compiled kernel binary to at least this size in bytes + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls.asm index e8aef8a7..a85da8da 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls.asm @@ -1,27 +1,27 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; System Call Section -- Accessible to user programs -; ============================================================================= - -align 16 -db 'DEBUG: SYSCALLS ' -align 16 - - -%include "syscalls/string.asm" -%include "syscalls/screen.asm" -%include "syscalls/input.asm" -%include "syscalls/sound.asm" -%include "syscalls/debug.asm" -%include "syscalls/misc.asm" -%include "syscalls/smp.asm" -%include "syscalls/serial.asm" -%include "syscalls/file.asm" -%include "syscalls/ethernet.asm" -%include "syscalls/memory.asm" - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; System Call Section -- Accessible to user programs +; ============================================================================= + +align 16 +db 'DEBUG: SYSCALLS ' +align 16 + + +%include "syscalls/string.asm" +%include "syscalls/screen.asm" +%include "syscalls/input.asm" +%include "syscalls/sound.asm" +%include "syscalls/debug.asm" +%include "syscalls/misc.asm" +%include "syscalls/smp.asm" +%include "syscalls/serial.asm" +%include "syscalls/file.asm" +%include "syscalls/ethernet.asm" +%include "syscalls/memory.asm" + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/debug.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/debug.asm index 16779449..7f5baab8 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/debug.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/debug.asm @@ -1,266 +1,266 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Debug functions -; ============================================================================= - -align 16 -db 'DEBUG: DEBUG ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_debug_dump_reg -- Dump the values on the registers to the screen (For debug purposes) -; IN: Nothing -; OUT: Nothing, all registers preserved -os_debug_dump_reg: - pushfq ; Push the registers used by this function - push rsi - push rbx - push rax - - pushfq ; Push the flags to the stack - push r15 ; Push all of the registers to the stack - push r14 - push r13 - push r12 - push r11 - push r10 - push r9 - push r8 - push rsp - push rbp - push rdi - push rsi - push rdx - push rcx - push rbx - push rax - - mov byte [os_debug_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting -os_debug_dump_reg_next: - mov rsi, os_debug_dump_reg_string00 - xor rax, rax - xor rbx, rbx - mov al, [os_debug_dump_reg_stage] - mov bl, 5 ; Each string is 5 bytes - mul bl ; AX = BL x AL - add rsi, rax ; Add the offset to get to the correct string - call os_print_string ; Print the register name - pop rax ; Pop the register from the stack - call os_debug_dump_rax ; Print the hex string value of RAX - inc byte [os_debug_dump_reg_stage] - cmp byte [os_debug_dump_reg_stage], 0x11 ; Check to see if all 16 registers as well as the flags are displayed - jne os_debug_dump_reg_next - - mov rbx, rax ; Store the flags in RBX - - mov rsi, os_debug_dump_flag_string0 ; Print the Carry flag - call os_print_string - bt rbx, 0 - jc carry_1 -carry_0: - mov al, '0' - jmp print_carry -carry_1: - mov al, '1' -print_carry: - call os_print_char - - mov rsi, os_debug_dump_flag_string1 ; Print the Zero flag - call os_print_string - bt rbx, 6 - jc zero_1 -zero_0: - mov al, '0' - jmp print_zero -zero_1: - mov al, '1' -print_zero: - call os_print_char - - mov rsi, os_debug_dump_flag_string2 ; Print the Sign flag - call os_print_string - bt rbx, 7 - jc sign_1 -sign_0: - mov al, '0' - jmp print_sign -sign_1: - mov al, '1' -print_sign: - call os_print_char - - mov rsi, os_debug_dump_flag_string3 ; Print the Direction flag - call os_print_string - bt rbx, 10 - jc dir_1 -dir_0: - mov al, '0' - jmp print_dir -dir_1: - mov al, '1' -print_dir: - call os_print_char - - mov rsi, os_debug_dump_flag_string4 ; Print the Overflow flag - call os_print_string - bt rbx, 11 - jc over_1 -over_0: - mov al, '0' - jmp print_over -over_1: - mov al, '1' -print_over: - call os_print_char - - -os_debug_dump_reg_done: - call os_print_newline - pop rax - pop rbx - pop rsi - popfq - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_dump_mem -- Dump some memory content to the screen -; IN: RSI = Start of memory address to dump -; RCX = number of bytes to dump -; OUT: Nothing, all registers preserved -os_debug_dump_mem: - push rsi - push rcx ; counter - push rdx ; total number of bytes to display - push rbx ; color attribute - push rax - mov bl, 0x07 ; Default of light grey on black - - cmp rcx, 0 - je os_debug_dump_mem_done - mov rdx, rcx ; Save the total number of bytes to display - add rdx, 15 - and rdx, 0xFFFFFFF0 - and rsi, 0xFFFFFFF0 - -os_debug_dump_mem_print_address: - mov rax, rsi - call os_debug_dump_rax - push rsi - mov rsi, divider - call os_print_string - pop rsi - xor rcx, rcx ; Clear the counter - -os_debug_dump_mem_next_byte_hex: - lodsb - call os_print_char_hex_with_color - xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey - add rcx, 1 - cmp rcx, 16 - jne os_debug_dump_mem_next_byte_hex - - push rsi - mov rsi, divider - call os_print_string - pop rsi - sub rsi, 0x10 - xor rcx, rcx ; Clear the counter - -os_debug_dump_mem_next_byte_ascii: - lodsb - call os_print_char_with_color - xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey - add rcx, 1 - cmp rcx, 16 - jne os_debug_dump_mem_next_byte_ascii - - sub rdx, 16 - cmp rdx, 0 - je os_debug_dump_mem_done - call os_print_newline - jmp os_debug_dump_mem_print_address - -os_debug_dump_mem_done: - pop rax - pop rbx - pop rcx - pop rdx - pop rsi - ret - -divider: db ' | ', 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_dump_(rax|eax|ax|al) -- Dump content of RAX, EAX, AX, or AL to the screen in hex format -; IN: RAX = content to dump -; OUT: Nothing, all registers preserved -os_debug_dump_rax: - ror rax, 56 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 32 -os_debug_dump_eax: - ror rax, 24 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 16 -os_debug_dump_ax: - ror rax, 8 - call os_print_char_hex - rol rax, 8 -os_debug_dump_al: - call os_print_char_hex - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_get_ip -- Dump content of RIP into RAX -; IN: Nothing -; OUT: RAX = RIP -os_debug_get_ip: - mov rax, qword [rsp] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_dump_MAC -- Dump MAC address to screen -; IN: Nothing -; OUT: Nothing, all registers preserved -os_debug_dump_MAC: - push rsi - push rcx - push rax - - mov ecx, 6 - mov rsi, os_NetMAC -os_debug_dump_MAC_display: - lodsb - call os_debug_dump_al - sub ecx, 1 - test ecx, ecx - jnz os_debug_dump_MAC_display - - pop rax - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Debug functions +; ============================================================================= + +align 16 +db 'DEBUG: DEBUG ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_debug_dump_reg -- Dump the values on the registers to the screen (For debug purposes) +; IN: Nothing +; OUT: Nothing, all registers preserved +os_debug_dump_reg: + pushfq ; Push the registers used by this function + push rsi + push rbx + push rax + + pushfq ; Push the flags to the stack + push r15 ; Push all of the registers to the stack + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rsp + push rbp + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + + mov byte [os_debug_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting +os_debug_dump_reg_next: + mov rsi, os_debug_dump_reg_string00 + xor rax, rax + xor rbx, rbx + mov al, [os_debug_dump_reg_stage] + mov bl, 5 ; Each string is 5 bytes + mul bl ; AX = BL x AL + add rsi, rax ; Add the offset to get to the correct string + call os_print_string ; Print the register name + pop rax ; Pop the register from the stack + call os_debug_dump_rax ; Print the hex string value of RAX + inc byte [os_debug_dump_reg_stage] + cmp byte [os_debug_dump_reg_stage], 0x11 ; Check to see if all 16 registers as well as the flags are displayed + jne os_debug_dump_reg_next + + mov rbx, rax ; Store the flags in RBX + + mov rsi, os_debug_dump_flag_string0 ; Print the Carry flag + call os_print_string + bt rbx, 0 + jc carry_1 +carry_0: + mov al, '0' + jmp print_carry +carry_1: + mov al, '1' +print_carry: + call os_print_char + + mov rsi, os_debug_dump_flag_string1 ; Print the Zero flag + call os_print_string + bt rbx, 6 + jc zero_1 +zero_0: + mov al, '0' + jmp print_zero +zero_1: + mov al, '1' +print_zero: + call os_print_char + + mov rsi, os_debug_dump_flag_string2 ; Print the Sign flag + call os_print_string + bt rbx, 7 + jc sign_1 +sign_0: + mov al, '0' + jmp print_sign +sign_1: + mov al, '1' +print_sign: + call os_print_char + + mov rsi, os_debug_dump_flag_string3 ; Print the Direction flag + call os_print_string + bt rbx, 10 + jc dir_1 +dir_0: + mov al, '0' + jmp print_dir +dir_1: + mov al, '1' +print_dir: + call os_print_char + + mov rsi, os_debug_dump_flag_string4 ; Print the Overflow flag + call os_print_string + bt rbx, 11 + jc over_1 +over_0: + mov al, '0' + jmp print_over +over_1: + mov al, '1' +print_over: + call os_print_char + + +os_debug_dump_reg_done: + call os_print_newline + pop rax + pop rbx + pop rsi + popfq + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_dump_mem -- Dump some memory content to the screen +; IN: RSI = Start of memory address to dump +; RCX = number of bytes to dump +; OUT: Nothing, all registers preserved +os_debug_dump_mem: + push rsi + push rcx ; counter + push rdx ; total number of bytes to display + push rbx ; color attribute + push rax + mov bl, 0x07 ; Default of light grey on black + + cmp rcx, 0 + je os_debug_dump_mem_done + mov rdx, rcx ; Save the total number of bytes to display + add rdx, 15 + and rdx, 0xFFFFFFF0 + and rsi, 0xFFFFFFF0 + +os_debug_dump_mem_print_address: + mov rax, rsi + call os_debug_dump_rax + push rsi + mov rsi, divider + call os_print_string + pop rsi + xor rcx, rcx ; Clear the counter + +os_debug_dump_mem_next_byte_hex: + lodsb + call os_print_char_hex_with_color + xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey + add rcx, 1 + cmp rcx, 16 + jne os_debug_dump_mem_next_byte_hex + + push rsi + mov rsi, divider + call os_print_string + pop rsi + sub rsi, 0x10 + xor rcx, rcx ; Clear the counter + +os_debug_dump_mem_next_byte_ascii: + lodsb + call os_print_char_with_color + xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey + add rcx, 1 + cmp rcx, 16 + jne os_debug_dump_mem_next_byte_ascii + + sub rdx, 16 + cmp rdx, 0 + je os_debug_dump_mem_done + call os_print_newline + jmp os_debug_dump_mem_print_address + +os_debug_dump_mem_done: + pop rax + pop rbx + pop rcx + pop rdx + pop rsi + ret + +divider: db ' | ', 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_dump_(rax|eax|ax|al) -- Dump content of RAX, EAX, AX, or AL to the screen in hex format +; IN: RAX = content to dump +; OUT: Nothing, all registers preserved +os_debug_dump_rax: + ror rax, 56 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 32 +os_debug_dump_eax: + ror rax, 24 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 16 +os_debug_dump_ax: + ror rax, 8 + call os_print_char_hex + rol rax, 8 +os_debug_dump_al: + call os_print_char_hex + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_get_ip -- Dump content of RIP into RAX +; IN: Nothing +; OUT: RAX = RIP +os_debug_get_ip: + mov rax, qword [rsp] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_dump_MAC -- Dump MAC address to screen +; IN: Nothing +; OUT: Nothing, all registers preserved +os_debug_dump_MAC: + push rsi + push rcx + push rax + + mov ecx, 6 + mov rsi, os_NetMAC +os_debug_dump_MAC_display: + lodsb + call os_debug_dump_al + sub ecx, 1 + test ecx, ecx + jnz os_debug_dump_MAC_display + + pop rax + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/ethernet.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/ethernet.asm index 848ead43..2f7769b8 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/ethernet.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/ethernet.asm @@ -1,294 +1,294 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Ethernet Functions -; ============================================================================= - -align 16 -db 'DEBUG: ETHERNET ' -align 16 - - -; Ethernet Type II Frame (64 - 1518 bytes) -; MAC Header (14 bytes) -; Destination MAC Address (6 bytes) -; Source MAC Address (6 bytes) -; EtherType/Length (2 bytes) -; Payload (46 - 1500 bytes) -; CRC (4 bytes) -; Network card handles the Preamble (7 bytes), Start-of-Frame-Delimiter (1 byte), and Interframe Gap (12 bytes) - - -; ----------------------------------------------------------------------------- -; os_ethernet_avail -- Check if Ethernet is available -; IN: Nothing -; OUT: RAX = MAC Address if Ethernet is enabled, otherwise 0 -os_ethernet_avail: - push rsi - push rcx - - cld - xor eax, eax - cmp byte [os_NetEnabled], 0 - je os_ethernet_avail_end - - mov ecx, 6 - mov rsi, os_NetMAC -os_ethernet_avail_loadMAC: - shl rax, 8 - lodsb - sub ecx, 1 - test ecx, ecx - jnz os_ethernet_avail_loadMAC - -os_ethernet_avail_end: - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_tx -- Transmit a packet via Ethernet -; IN: RSI = Memory location where data is stored -; RDI = Pointer to 48 bit destination address -; BX = Type of packet (If set to 0 then the EtherType will be set to the length of data) -; CX = Length of data -; OUT: Nothing. All registers preserved -os_ethernet_tx: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - cmp byte [os_NetEnabled], 1 - jne os_ethernet_tx_fail - cmp cx, 1500 ; Fail if more then 1500 bytes - jg os_ethernet_tx_fail - - mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time - call os_smp_lock - - push rsi - mov rsi, rdi - mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location - ; TODO: Ask the driver where in memory the packet should be assembled. - - ; Copy destination MAC address - movsd - movsw - - ; Copy source MAC address - mov rsi, os_NetMAC - movsd - movsw - - ; Set the EtherType/Length - cmp bx, 0 - jne os_ethernet_tx_typeset ; If EtherType is not set then use the Data Length instead - mov bx, cx ; Length of data (Does not include header) -os_ethernet_tx_typeset: - xchg bl, bh ; x86 is Little-endian but packets use Big-endian - mov [rdi], bx - add rdi, 2 - - ; Copy the packet data - pop rsi - mov rax, 0x000000000000FFFF - and rcx, rax ; Clear the top 48 bits - push rcx - rep movsb - pop rcx - - ; Add padding to the packet data if needed - cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) - jge os_ethernet_tx_nopadding - mov ax, 46 - sub ax, cx ; Padding needed = 46 - CX - mov cx, ax - xor ax, ax - rep stosb ; Store 0x00 CX times - mov cx, 46 -os_ethernet_tx_nopadding: - - xor eax, eax - stosd ; Store a blank CRC value - -; Call the send function of the ethernet card driver - add cx, 14 ; Add 14 for the header bytes - mov rsi, os_ethernet_tx_buffer - call qword [os_net_transmit] - - mov rax, os_EthernetBusyLock - call os_smp_unlock - -os_ethernet_tx_fail: - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_tx_raw -- Transmit a raw frame via Ethernet -; IN: RSI = Memory location where raw frame is stored -; CX = Length of frame -; OUT: Nothing. All registers preserved -os_ethernet_tx_raw: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - cmp byte [os_NetEnabled], 1 - jne os_ethernet_tx_raw_fail - cmp cx, 1500 ; Fail if more then 1500 bytes - jg os_ethernet_tx_raw_fail - - mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time - call os_smp_lock - - ; Copy the packet data - mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location - mov rax, 0x000000000000FFFF - and rcx, rax ; Clear the top 48 bits - push rcx - rep movsb - pop rcx - - ; Add padding to the packet data if needed - cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) - jge os_ethernet_tx_raw_nopadding - mov ax, 46 - sub ax, cx ; Padding needed = 46 - CX - mov cx, ax - xor ax, ax - rep stosb ; Store 0x00 CX times - mov cx, 46 -os_ethernet_tx_raw_nopadding: - - xor eax, eax - stosd ; Store a blank CRC value - -; Call the send function of the ethernet card driver - mov rsi, os_ethernet_tx_buffer - call qword [os_net_transmit] - - mov rax, os_EthernetBusyLock - call os_smp_unlock - -os_ethernet_tx_raw_fail: - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_rx -- Polls the Ethernet card for received data -; IN: RDI = Memory location where packet will be stored -; OUT: RCX = Length of packet -; All other registers preserved -os_ethernet_rx: - push rdi - push rsi - push rdx - push rax - - xor ecx, ecx - - cmp byte [os_NetEnabled], 1 - jne os_ethernet_rx_fail - -; Is there anything in the ring buffer? - mov al, byte [os_EthernetBuffer_C1] - mov dl, byte [os_EthernetBuffer_C2] - cmp al, dl ; If both counters are equal then the buffer is empty - je os_ethernet_rx_fail - -; Read the packet from the ring buffer to RDI - mov rsi, os_EthernetBuffer - xor rax, rax - mov al, byte [os_EthernetBuffer_C1] - push rax ; Save the ring element value - shl rax, 11 ; Quickly multiply RAX by 2048 - add rsi, rax ; RSI points to the packet in the ring buffer - lodsw ; Load the packet length - mov cx, ax ; Copy the packet length to RCX - push rcx - rep movsb ; Copy the packet to RDI - pop rcx - pop rax ; Restore the ring element value - add al, 1 - cmp al, 128 ; Max element number is 127 - jne os_ethernet_rx_buffer_nowrap - xor al, al -os_ethernet_rx_buffer_nowrap: - mov byte [os_EthernetBuffer_C1], al - -os_ethernet_rx_fail: - - pop rax - pop rdx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_ack_int -- Acknowledge an interrupt within the NIC -; IN: Nothing -; OUT: RAX = Type of interrupt trigger -; All other registers preserved -os_ethernet_ack_int: - push rdx - - call qword [os_net_ack_int] - - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_rx_from_interrupt -- Polls the Ethernet card for received data -; IN: RDI = Memory location where packet will be stored -; OUT: RCX = Length of packet -; All other registers preserved -os_ethernet_rx_from_interrupt: - push rdi - push rsi - push rdx - push rax - - xor ecx, ecx - -; Call the poll function of the ethernet card driver - call qword [os_net_poll] - - pop rax - pop rdx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Ethernet Functions +; ============================================================================= + +align 16 +db 'DEBUG: ETHERNET ' +align 16 + + +; Ethernet Type II Frame (64 - 1518 bytes) +; MAC Header (14 bytes) +; Destination MAC Address (6 bytes) +; Source MAC Address (6 bytes) +; EtherType/Length (2 bytes) +; Payload (46 - 1500 bytes) +; CRC (4 bytes) +; Network card handles the Preamble (7 bytes), Start-of-Frame-Delimiter (1 byte), and Interframe Gap (12 bytes) + + +; ----------------------------------------------------------------------------- +; os_ethernet_avail -- Check if Ethernet is available +; IN: Nothing +; OUT: RAX = MAC Address if Ethernet is enabled, otherwise 0 +os_ethernet_avail: + push rsi + push rcx + + cld + xor eax, eax + cmp byte [os_NetEnabled], 0 + je os_ethernet_avail_end + + mov ecx, 6 + mov rsi, os_NetMAC +os_ethernet_avail_loadMAC: + shl rax, 8 + lodsb + sub ecx, 1 + test ecx, ecx + jnz os_ethernet_avail_loadMAC + +os_ethernet_avail_end: + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_tx -- Transmit a packet via Ethernet +; IN: RSI = Memory location where data is stored +; RDI = Pointer to 48 bit destination address +; BX = Type of packet (If set to 0 then the EtherType will be set to the length of data) +; CX = Length of data +; OUT: Nothing. All registers preserved +os_ethernet_tx: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + cmp byte [os_NetEnabled], 1 + jne os_ethernet_tx_fail + cmp cx, 1500 ; Fail if more then 1500 bytes + jg os_ethernet_tx_fail + + mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time + call os_smp_lock + + push rsi + mov rsi, rdi + mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location + ; TODO: Ask the driver where in memory the packet should be assembled. + + ; Copy destination MAC address + movsd + movsw + + ; Copy source MAC address + mov rsi, os_NetMAC + movsd + movsw + + ; Set the EtherType/Length + cmp bx, 0 + jne os_ethernet_tx_typeset ; If EtherType is not set then use the Data Length instead + mov bx, cx ; Length of data (Does not include header) +os_ethernet_tx_typeset: + xchg bl, bh ; x86 is Little-endian but packets use Big-endian + mov [rdi], bx + add rdi, 2 + + ; Copy the packet data + pop rsi + mov rax, 0x000000000000FFFF + and rcx, rax ; Clear the top 48 bits + push rcx + rep movsb + pop rcx + + ; Add padding to the packet data if needed + cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) + jge os_ethernet_tx_nopadding + mov ax, 46 + sub ax, cx ; Padding needed = 46 - CX + mov cx, ax + xor ax, ax + rep stosb ; Store 0x00 CX times + mov cx, 46 +os_ethernet_tx_nopadding: + + xor eax, eax + stosd ; Store a blank CRC value + +; Call the send function of the ethernet card driver + add cx, 14 ; Add 14 for the header bytes + mov rsi, os_ethernet_tx_buffer + call qword [os_net_transmit] + + mov rax, os_EthernetBusyLock + call os_smp_unlock + +os_ethernet_tx_fail: + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_tx_raw -- Transmit a raw frame via Ethernet +; IN: RSI = Memory location where raw frame is stored +; CX = Length of frame +; OUT: Nothing. All registers preserved +os_ethernet_tx_raw: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + cmp byte [os_NetEnabled], 1 + jne os_ethernet_tx_raw_fail + cmp cx, 1500 ; Fail if more then 1500 bytes + jg os_ethernet_tx_raw_fail + + mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time + call os_smp_lock + + ; Copy the packet data + mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location + mov rax, 0x000000000000FFFF + and rcx, rax ; Clear the top 48 bits + push rcx + rep movsb + pop rcx + + ; Add padding to the packet data if needed + cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) + jge os_ethernet_tx_raw_nopadding + mov ax, 46 + sub ax, cx ; Padding needed = 46 - CX + mov cx, ax + xor ax, ax + rep stosb ; Store 0x00 CX times + mov cx, 46 +os_ethernet_tx_raw_nopadding: + + xor eax, eax + stosd ; Store a blank CRC value + +; Call the send function of the ethernet card driver + mov rsi, os_ethernet_tx_buffer + call qword [os_net_transmit] + + mov rax, os_EthernetBusyLock + call os_smp_unlock + +os_ethernet_tx_raw_fail: + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_rx -- Polls the Ethernet card for received data +; IN: RDI = Memory location where packet will be stored +; OUT: RCX = Length of packet +; All other registers preserved +os_ethernet_rx: + push rdi + push rsi + push rdx + push rax + + xor ecx, ecx + + cmp byte [os_NetEnabled], 1 + jne os_ethernet_rx_fail + +; Is there anything in the ring buffer? + mov al, byte [os_EthernetBuffer_C1] + mov dl, byte [os_EthernetBuffer_C2] + cmp al, dl ; If both counters are equal then the buffer is empty + je os_ethernet_rx_fail + +; Read the packet from the ring buffer to RDI + mov rsi, os_EthernetBuffer + xor rax, rax + mov al, byte [os_EthernetBuffer_C1] + push rax ; Save the ring element value + shl rax, 11 ; Quickly multiply RAX by 2048 + add rsi, rax ; RSI points to the packet in the ring buffer + lodsw ; Load the packet length + mov cx, ax ; Copy the packet length to RCX + push rcx + rep movsb ; Copy the packet to RDI + pop rcx + pop rax ; Restore the ring element value + add al, 1 + cmp al, 128 ; Max element number is 127 + jne os_ethernet_rx_buffer_nowrap + xor al, al +os_ethernet_rx_buffer_nowrap: + mov byte [os_EthernetBuffer_C1], al + +os_ethernet_rx_fail: + + pop rax + pop rdx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_ack_int -- Acknowledge an interrupt within the NIC +; IN: Nothing +; OUT: RAX = Type of interrupt trigger +; All other registers preserved +os_ethernet_ack_int: + push rdx + + call qword [os_net_ack_int] + + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_rx_from_interrupt -- Polls the Ethernet card for received data +; IN: RDI = Memory location where packet will be stored +; OUT: RCX = Length of packet +; All other registers preserved +os_ethernet_rx_from_interrupt: + push rdi + push rsi + push rdx + push rax + + xor ecx, ecx + +; Call the poll function of the ethernet card driver + call qword [os_net_poll] + + pop rax + pop rdx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/file.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/file.asm index d5d87deb..a2b7f73a 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/file.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/file.asm @@ -1,86 +1,86 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; File System Functions -; ============================================================================= - -align 16 -db 'DEBUG: FILESYS ' -align 16 - - -; This source acts as an abstraction layer between the OS and an actual File -; System driver. A check can go here to detect the actual FS used and call the -; appropriate FS driver. -; -; Example: -; os_file_read: -; cmp [os_FS], 1 ; FAT16 -; je os_fat16_file_read -; cmp [os_FS], 2 ; FAT32 -; je os_fat32_file_read -; etc... - - -; ----------------------------------------------------------------------------- -; os_file_read -- Read a file from disk into memory -; IN: RSI = Address of filename string -; RDI = Memory location where file will be loaded to -; OUT: Carry is set if the file was not found or an error occured -os_file_read: - jmp os_fat16_file_read -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_write -- Write a file from memory to disk -; IN: RSI = Memory location of data to be written -; RDI = Address of filename string -; RCX = Number of bytes to write -; OUT: Carry is set if an error occured -os_file_write: - jmp os_fat16_file_write -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_rename -- Rename a file on disk -; IN: RSI = Memory location of file name to change -; RDI = Memory location of new file name -; OUT: Carry is set if the file was not found or an error occured -os_file_rename: - jmp $ -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_delete -- Delete a file from disk -; IN: RSI = Memory location of file name to delete -; OUT: Carry is set if the file was not found or an error occured -os_file_delete: - jmp os_fat16_file_delete -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_get_list -- Generate a list of files on disk -; IN: RDI = location to store list -; OUT: RDI = pointer to end of list -os_file_get_list: - jmp os_fat16_get_file_list -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_size -- Return the size of a file on disk -; IN: RSI = Address of filename string -; OUT: RCX = Size in bytes -; Carry is set if the file was not found or an error occured -os_file_get_size: - jmp os_fat16_get_file_size -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; File System Functions +; ============================================================================= + +align 16 +db 'DEBUG: FILESYS ' +align 16 + + +; This source acts as an abstraction layer between the OS and an actual File +; System driver. A check can go here to detect the actual FS used and call the +; appropriate FS driver. +; +; Example: +; os_file_read: +; cmp [os_FS], 1 ; FAT16 +; je os_fat16_file_read +; cmp [os_FS], 2 ; FAT32 +; je os_fat32_file_read +; etc... + + +; ----------------------------------------------------------------------------- +; os_file_read -- Read a file from disk into memory +; IN: RSI = Address of filename string +; RDI = Memory location where file will be loaded to +; OUT: Carry is set if the file was not found or an error occured +os_file_read: + jmp os_fat16_file_read +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_write -- Write a file from memory to disk +; IN: RSI = Memory location of data to be written +; RDI = Address of filename string +; RCX = Number of bytes to write +; OUT: Carry is set if an error occured +os_file_write: + jmp os_fat16_file_write +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_rename -- Rename a file on disk +; IN: RSI = Memory location of file name to change +; RDI = Memory location of new file name +; OUT: Carry is set if the file was not found or an error occured +os_file_rename: + jmp $ +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_delete -- Delete a file from disk +; IN: RSI = Memory location of file name to delete +; OUT: Carry is set if the file was not found or an error occured +os_file_delete: + jmp os_fat16_file_delete +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_get_list -- Generate a list of files on disk +; IN: RDI = location to store list +; OUT: RDI = pointer to end of list +os_file_get_list: + jmp os_fat16_get_file_list +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_size -- Return the size of a file on disk +; IN: RSI = Address of filename string +; OUT: RCX = Size in bytes +; Carry is set if the file was not found or an error occured +os_file_get_size: + jmp os_fat16_get_file_size +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/input.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/input.asm index 57590b3d..5520e3a9 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/input.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/input.asm @@ -1,107 +1,107 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Input Functions -; ============================================================================= - -align 16 -db 'DEBUG: INPUT ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_input_key_check -- Scans keyboard for input, but doesn't wait -; IN: Nothing -; OUT: AL = 0 if no key pressed, otherwise ASCII code, other regs preserved -; Carry flag is set if there was a keystoke, clear if there was not -; All other registers preserved -os_input_key_check: - mov al, [key] - cmp al, 0 - je os_input_key_check_no_key - mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now - stc ; set the carry flag - ret - -os_input_key_check_no_key: - xor al, al ; mov al, 0x00 - clc ; clear the carry flag - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_input_key_wait -- Waits for keypress and returns key -; IN: Nothing -; OUT: AL = key pressed -; All other registers preserved -os_input_key_wait: - mov al, [key] - cmp al, 0 - je os_input_key_wait - mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_input_string -- Take string from keyboard entry -; IN: RDI = location where string will be stored -; RCX = number of characters to accept -; OUT: RCX = length of string that was inputed (NULL not counted) -; All other registers preserved -os_input_string: - push rdi - push rdx ; Counter to keep track of max accepted characters - push rax - - mov rdx, rcx - xor rcx, rcx -os_input_string_more: - call os_input_key_check - jnc os_input_string_halt ; No key entered... halt until an interrupt is received - cmp al, 0x1C ; If Enter key pressed, finish - je os_input_string_done - cmp al, 0x0E ; Backspace - je os_input_string_backspace - cmp al, 32 ; In ASCII range (32 - 126)? - jl os_input_string_more - cmp al, 126 - jg os_input_string_more - cmp rcx, rdx ; Check if we have reached the max number of chars - je os_input_string_more ; Jump if we have (should beep as well) - stosb ; Store AL at RDI and increment RDI by 1 - inc rcx ; Increment the couter - call os_print_char ; Display char - jmp os_input_string_more - -os_input_string_backspace: - cmp rcx, 0 ; backspace at the beginning? get a new char - je os_input_string_more - call os_dec_cursor ; Decrement the cursor - mov al, 0x20 ; 0x20 is the character for a space - call os_print_char ; Write over the last typed character with the space - call os_dec_cursor ; Decremnt the cursor again - dec rdi ; go back one in the string - mov byte [rdi], 0x00 ; NULL out the char - dec rcx ; decrement the counter by one - jmp os_input_string_more - -os_input_string_halt: - hlt ; Halt until another keystroke is received - jmp os_input_string_more - -os_input_string_done: - mov al, 0x00 - stosb ; We NULL terminate the string - - pop rax - pop rdx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Input Functions +; ============================================================================= + +align 16 +db 'DEBUG: INPUT ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_input_key_check -- Scans keyboard for input, but doesn't wait +; IN: Nothing +; OUT: AL = 0 if no key pressed, otherwise ASCII code, other regs preserved +; Carry flag is set if there was a keystoke, clear if there was not +; All other registers preserved +os_input_key_check: + mov al, [key] + cmp al, 0 + je os_input_key_check_no_key + mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now + stc ; set the carry flag + ret + +os_input_key_check_no_key: + xor al, al ; mov al, 0x00 + clc ; clear the carry flag + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_input_key_wait -- Waits for keypress and returns key +; IN: Nothing +; OUT: AL = key pressed +; All other registers preserved +os_input_key_wait: + mov al, [key] + cmp al, 0 + je os_input_key_wait + mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_input_string -- Take string from keyboard entry +; IN: RDI = location where string will be stored +; RCX = number of characters to accept +; OUT: RCX = length of string that was inputed (NULL not counted) +; All other registers preserved +os_input_string: + push rdi + push rdx ; Counter to keep track of max accepted characters + push rax + + mov rdx, rcx + xor rcx, rcx +os_input_string_more: + call os_input_key_check + jnc os_input_string_halt ; No key entered... halt until an interrupt is received + cmp al, 0x1C ; If Enter key pressed, finish + je os_input_string_done + cmp al, 0x0E ; Backspace + je os_input_string_backspace + cmp al, 32 ; In ASCII range (32 - 126)? + jl os_input_string_more + cmp al, 126 + jg os_input_string_more + cmp rcx, rdx ; Check if we have reached the max number of chars + je os_input_string_more ; Jump if we have (should beep as well) + stosb ; Store AL at RDI and increment RDI by 1 + inc rcx ; Increment the couter + call os_print_char ; Display char + jmp os_input_string_more + +os_input_string_backspace: + cmp rcx, 0 ; backspace at the beginning? get a new char + je os_input_string_more + call os_dec_cursor ; Decrement the cursor + mov al, 0x20 ; 0x20 is the character for a space + call os_print_char ; Write over the last typed character with the space + call os_dec_cursor ; Decremnt the cursor again + dec rdi ; go back one in the string + mov byte [rdi], 0x00 ; NULL out the char + dec rcx ; decrement the counter by one + jmp os_input_string_more + +os_input_string_halt: + hlt ; Halt until another keystroke is received + jmp os_input_string_more + +os_input_string_done: + mov al, 0x00 + stosb ; We NULL terminate the string + + pop rax + pop rdx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/math.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/math.asm index 66e73bf9..ab803dbc 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/math.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/math.asm @@ -1,26 +1,26 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Math Functions -; ============================================================================= - -align 16 -db 'DEBUG: MATH ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_oword_add -- Add two 128-bit integer together -; IN: RDX,RAX = Integer 1, RCX,RBX = Integer 2 -; OUT: RDX,RAX = Result -; Note: Carry set if overflow -os_oword_add: - add rax, rbx - adc rdx, rcx - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Math Functions +; ============================================================================= + +align 16 +db 'DEBUG: MATH ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_oword_add -- Add two 128-bit integer together +; IN: RDX,RAX = Integer 1, RCX,RBX = Integer 2 +; OUT: RDX,RAX = Result +; Note: Carry set if overflow +os_oword_add: + add rax, rbx + adc rdx, rcx + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/memory.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/memory.asm index 81da14e3..13ed0a74 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/memory.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/memory.asm @@ -1,142 +1,142 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Memory functions -; ============================================================================= - -align 16 -db 'DEBUG: MEMORY ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_mem_allocate -- Allocates the requested number of 2 MiB pages -; IN: RCX = Number of pages to allocate -; OUT: RAX = Starting address -; RCX = Number of pages allocated (Set to the value asked for or 0 on failure) -; This function will only allocate continous pages -os_mem_allocate: - push rdi - push rsi - push rdx - push rbx - - cmp rcx, 0 - je os_mem_allocate_fail ; At least 1 page must be allocated - xor rax, rax - mov rsi, os_MemoryMap - mov ax, word [os_MemAmount] - shr ax, 1 ; Divide actual memory by 2 - add rsi, rax ; RSI now points to the last page - sub rsi, 1 - std ; Set direction flag to backward - -os_mem_allocate_start: ; Find a free page of memory - lodsb - cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no free pages - je os_mem_allocate_fail - cmp al, 1 ; If the byte is one then we found a free memory page - jne os_mem_allocate_start - mov rbx, rcx ; RBX is our temporary counter - sub rbx, 1 ; One free page was already found - cmp rbx, 0 ; Was only one page requested? - je os_mem_allocate_mark - -os_mem_allocate_nextpage: - lodsb - cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no more free pages - je os_mem_allocate_fail - cmp al, 1 - jne os_mem_allocate_start - sub rbx, 1 - cmp rbx, 0 - jne os_mem_allocate_nextpage - -os_mem_allocate_mark: - ; We have a suitable free series of pages. Allocate them. - cld ; Set direction flag to forward - mov rdi, rsi - add rdi, 1 - mov rdx, rdi ; RDX points to the starting page - mov al, 2 - push rcx - rep stosb - pop rcx - sub rdx, os_MemoryMap ; RDX now contains the memory page number - shl rdx, 21 ; Quick multiply by 2097152 (2 MiB) to get the starting memory address - mov rax, rdx ; Return the starting address in RAX - jmp os_mem_allocate_end - -os_mem_allocate_fail: - cld ; Set direction flag to forward - xor rcx, rcx ; Failure so set RCX to 0 (No pages allocated) - xor rax, rax - -os_mem_allocate_end: - pop rbx - pop rdx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_mem_release -- Frees the requested number of 2 MiB pages -; IN: RAX = Starting address -; RCX = Number of pages to free -; OUT: RCX = Number of pages freed -os_mem_release: - push rdi - push rcx - push rax - - shr rax, 21 ; Quick divide by 2097152 (2 MiB) to get the starting page number - add rax, os_MemoryMap - mov rdi, rax - mov al, 1 - rep stosb - - pop rax - pop rcx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_mem_get_free -- Returns the number of 2 MiB pages that are available -; IN: Nothing -; OUT: RCX = Number of free 2 MiB pages -os_mem_get_free: - push rsi - push rbx - push rax - - mov rsi, os_MemoryMap - xor rcx, rcx - xor rbx, rbx - -os_mem_get_free_next: - lodsb - add rcx, 1 - cmp rcx, 65536 - je os_mem_get_free_end - cmp al, 1 - jne os_mem_get_free_next - add rbx, 1 - jmp os_mem_get_free_next - -os_mem_get_free_end: - mov rcx, rbx - - pop rax - pop rbx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Memory functions +; ============================================================================= + +align 16 +db 'DEBUG: MEMORY ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_mem_allocate -- Allocates the requested number of 2 MiB pages +; IN: RCX = Number of pages to allocate +; OUT: RAX = Starting address +; RCX = Number of pages allocated (Set to the value asked for or 0 on failure) +; This function will only allocate continous pages +os_mem_allocate: + push rdi + push rsi + push rdx + push rbx + + cmp rcx, 0 + je os_mem_allocate_fail ; At least 1 page must be allocated + xor rax, rax + mov rsi, os_MemoryMap + mov ax, word [os_MemAmount] + shr ax, 1 ; Divide actual memory by 2 + add rsi, rax ; RSI now points to the last page + sub rsi, 1 + std ; Set direction flag to backward + +os_mem_allocate_start: ; Find a free page of memory + lodsb + cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no free pages + je os_mem_allocate_fail + cmp al, 1 ; If the byte is one then we found a free memory page + jne os_mem_allocate_start + mov rbx, rcx ; RBX is our temporary counter + sub rbx, 1 ; One free page was already found + cmp rbx, 0 ; Was only one page requested? + je os_mem_allocate_mark + +os_mem_allocate_nextpage: + lodsb + cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no more free pages + je os_mem_allocate_fail + cmp al, 1 + jne os_mem_allocate_start + sub rbx, 1 + cmp rbx, 0 + jne os_mem_allocate_nextpage + +os_mem_allocate_mark: + ; We have a suitable free series of pages. Allocate them. + cld ; Set direction flag to forward + mov rdi, rsi + add rdi, 1 + mov rdx, rdi ; RDX points to the starting page + mov al, 2 + push rcx + rep stosb + pop rcx + sub rdx, os_MemoryMap ; RDX now contains the memory page number + shl rdx, 21 ; Quick multiply by 2097152 (2 MiB) to get the starting memory address + mov rax, rdx ; Return the starting address in RAX + jmp os_mem_allocate_end + +os_mem_allocate_fail: + cld ; Set direction flag to forward + xor rcx, rcx ; Failure so set RCX to 0 (No pages allocated) + xor rax, rax + +os_mem_allocate_end: + pop rbx + pop rdx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_mem_release -- Frees the requested number of 2 MiB pages +; IN: RAX = Starting address +; RCX = Number of pages to free +; OUT: RCX = Number of pages freed +os_mem_release: + push rdi + push rcx + push rax + + shr rax, 21 ; Quick divide by 2097152 (2 MiB) to get the starting page number + add rax, os_MemoryMap + mov rdi, rax + mov al, 1 + rep stosb + + pop rax + pop rcx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_mem_get_free -- Returns the number of 2 MiB pages that are available +; IN: Nothing +; OUT: RCX = Number of free 2 MiB pages +os_mem_get_free: + push rsi + push rbx + push rax + + mov rsi, os_MemoryMap + xor rcx, rcx + xor rbx, rbx + +os_mem_get_free_next: + lodsb + add rcx, 1 + cmp rcx, 65536 + je os_mem_get_free_end + cmp al, 1 + jne os_mem_get_free_next + add rbx, 1 + jmp os_mem_get_free_next + +os_mem_get_free_end: + mov rcx, rbx + + pop rax + pop rbx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/misc.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/misc.asm index d619e4d1..d42a5dc1 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/misc.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/misc.asm @@ -1,504 +1,504 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Misc Functions -; ============================================================================= - -align 16 -db 'DEBUG: MISC ' -align 16 - - -; ----------------------------------------------------------------------------- -; Display Core activity with flashing blocks on screen -; Blocks flash every quarter of a second -system_status: - push rsi - push rdi - push rdx - push rcx - push rax - - ; Display the dark grey bar - mov ax, 0x8720 ; 0x87 for dark grey background/white foreground, 0x20 for space (blank) character - mov rdi, os_screen ;0x00000000000B8000 - mov rcx, 80 - rep stosw - - ; Display CPU status - mov rdi, os_screen ; 0x00000000000B8000 - mov al, '[' - stosb - add rdi, 1 ; Skip the attribute byte - mov ax, 0x8F63 ; 'c' - stosw - mov ax, 0x8F70 ; 'p' - stosw - mov ax, 0x8F75 ; 'u' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 ; Skip to the next char - - xor ecx, ecx - mov rsi, cpustatus -system_status_cpu_next: - cmp cx, 256 - je system_status_cpu_done - add rcx, 1 - lodsb - bt ax, 0 ; Check to see if the Core is Present - jnc system_status_cpu_next ; If not then check the next - ror ax, 8 ; Exchange AL and AH - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - rol ax, 8 ; Exchange AL and AH - bt ax, 1 ; Check to see if the Core is Ready or Busy - jc system_status_cpu_busy ; Jump if it is Busy.. otherwise fall through for Idle - mov al, 0x80 ; Black on Dark Gray (Idle Core) - jmp system_status_cpu_color - -system_status_cpu_busy: - mov rax, [os_ClockCounter] - bt rax, 0 ; Check bit 0. Store bit 0 in CF - jc system_status_cpu_flash_hi - mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) - jmp system_status_cpu_color -system_status_cpu_flash_hi: - mov al, 0x8F ; White on Dark Gray (Active Core High) -system_status_cpu_color: - stosb ; Store the color (attribute) byte - jmp system_status_cpu_next ; Check the next Core - -system_status_cpu_done: - mov al, ']' - stosb - add rdi, 1 - - ; Display memory status - add rdi, 4 - mov al, '[' - stosb - add rdi, 1 ; Skip the attribute byte - mov ax, 0x8F6D ; 'm' - stosw - mov ax, 0x8F65 ; 'e' - stosw - mov ax, 0x8F6D ; 'm' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 ; Skip to the next char - - call os_mem_get_free ; Store number of free 2 MiB pages in RCX - xor rax, rax - mov ax, word [os_MemAmount] - shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) - push rax - sub rax, rcx ; RAX holds inuse pages (ex 6) - pop rcx ; RCX holds total pages (ex 512) - shr rcx, 3 ; Quickly divide RCX by 8, RCX now holds pages/block (ex 64) - xor rdx, rdx - div rcx ; Divide inuse pages by pages/block - mov rcx, rax - mov ax, 8 - cmp cx, 0 - jne notzero - add cx, 1 -notzero: - sub ax, cx - push rax - -system_status_mem_used: - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x8F ; Light Gray on Blue - stosb ; Put the block character on the screen - sub rcx, 1 - jrcxz system_status_mem_used_finish - jmp system_status_mem_used - -system_status_mem_used_finish: - - pop rcx -system_status_mem_free: - jrcxz system_status_mem_finish - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x80 ; Light Gray on Blue - stosb ; Put the block character on the screen - sub rcx, 1 - jrcxz system_status_mem_finish - jmp system_status_mem_free - -system_status_mem_finish: - mov al, ']' - stosb - add rdi, 1 - - ; Display network status - cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) - jne system_status_no_network - add rdi, 4 - mov al, '[' - stosb - add rdi, 1 - mov ax, 0x8F6E ; 'n' - stosw - mov ax, 0x8F65 ; 'e' - stosw - mov ax, 0x8F74 ; 't' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 - mov al, 'T' - stosb - add rdi, 1 - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x80 ; Black on Dark Gray (No Activity) - cmp byte [os_NetActivity_TX], 1 - jne tx_idle - mov al, 0x8F - mov byte [os_NetActivity_TX], 0 -tx_idle: - stosb - mov al, 'R' - stosb - add rdi, 1 - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x80 ; Black on Dark Gray (No Activity) - cmp byte [os_NetActivity_RX], 1 - jne rx_idle - mov al, 0x8F - mov byte [os_NetActivity_RX], 0 -rx_idle: - stosb - mov al, ']' - stosb - add rdi, 1 -system_status_no_network: - - ; Display the RTC pulse - add rdi, 4 - mov al, '[' - stosb - add rdi, 1 - mov ax, 0x8F72 ; 'r' - stosw - mov ax, 0x8F74 ; 't' - stosw - mov ax, 0x8F63 ; 'c' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov rax, [os_ClockCounter] - bt rax, 0 ; Check bit 0. Store bit 0 in CF - jc system_status_rtc_flash_hi - mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) - jmp system_status_rtc_flash_lo -system_status_rtc_flash_hi: - mov al, 0x8F ; White on Dark Gray (Active Core High) -system_status_rtc_flash_lo: - stosb ; Store the color (attribute) byte - mov al, ']' - stosb - add rdi, 1 - - ; Display header text - mov rdi, os_screen ;0x00000000000B8080 - add rdi, 0x80 - mov rsi, system_status_header - mov rcx, 16 -headernext: - lodsb - stosb - inc rdi - dec rcx - cmp rcx, 0 - jne headernext - - ; Copy the system status to the screen - mov rsi, os_screen - mov rdi, 0xB8000 - mov rcx, 80 - rep movsw - - pop rax - pop rcx - pop rdx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_delay -- Delay by X eights of a second -; IN: RAX = Time in eights of a second -; OUT: All registers preserved -; A value of 8 in RAX will delay 1 second and a value of 1 will delay 1/8 of a second -; This function depends on the RTC (IRQ 8) so interrupts must be enabled. -os_delay: - push rcx - push rax - - mov rcx, [os_ClockCounter] ; Grab the initial timer counter. It increments 8 times a second - add rax, rcx ; Add RCX so we get the end time we want -os_delay_loop: - cmp qword [os_ClockCounter], rax ; Compare it against our end time - jle os_delay_loop ; Loop if RAX is still lower - - pop rax - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_seed_random -- Seed the RNG based on the current date and time -; IN: Nothing -; OUT: All registers preserved -os_seed_random: - push rdx - push rbx - push rax - - xor rbx, rbx - mov al, 0x09 ; year - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x08 ; month - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x07 ; day - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x04 ; hour - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x02 ; minute - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x00 ; second - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 16 - rdtsc ; Read the Time Stamp Counter in EDX:EAX - mov bx, ax ; Only use the last 2 bytes - - mov [os_RandomSeed], rbx ; Seed will be something like 0x091229164435F30A - - pop rax - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_random -- Return a random integer -; IN: Nothing -; OUT: RAX = Random number -; All other registers preserved -os_get_random: - push rdx - push rbx - - mov rax, [os_RandomSeed] - mov rdx, 0x23D8AD1401DE7383 ; The magic number (random.org) - mul rdx ; RDX:RAX = RAX * RDX - mov [os_RandomSeed], rax - - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_random_integer -- Return a random integer between Low and High (incl) -; IN: RAX = Low integer -; RBX = High integer -; OUT: RCX = Random integer -os_get_random_integer: - push rdx - push rbx - push rax - - sub rbx, rax ; We want to look for a number between 0 and (High-Low) - call os_get_random - mov rdx, rbx - add rdx, 1 - mul rdx - mov rcx, rdx - - pop rax - pop rbx - pop rdx - add rcx, rax ; Add the low offset back - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_argc -- Return the number arguments passed to the program -; IN: Nothing -; OUT: AL = Number of arguments -os_get_argc: - xor eax, eax - mov al, [cli_args] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_argv -- Get the value of an argument that was passed to the program -; IN: AL = Argument number -; OUT: RSI = Start of numbered argument string -os_get_argv: - push rcx - push rax - mov rsi, cli_temp_string - cmp al, 0x00 - je os_get_argv_end - mov cl, al - -os_get_argv_nextchar: - lodsb - cmp al, 0x00 - jne os_get_argv_nextchar - dec cl - cmp cl, 0 - jne os_get_argv_nextchar - -os_get_argv_end: - pop rax - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_timecounter -- Get the current RTC clock couter value -; IN: Nothing -; OUT: RAX = Time in eights of a second since clock started -; This function depends on the RTC (IRQ 8) so interrupts must be enabled. -os_get_timecounter: - mov rax, [os_ClockCounter] ; Grab the timer counter value. It increments 8 times a second - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_time_data -- -; IN: RAX = Pointer to structure to be filled (needs 36 bytes) -os_get_time_data: - push rdi - push rbx - push rax - mov rdi, rax - xor rax, rax - -os_get_time_data_wait: - mov al, 10 - out 0x70, al - in al, 0x71 - test al, 0x80 ; Is there an update in progress? - jne os_get_time_data_wait ; If so then try again - - mov al, 0x00 ; Seconds after the minute (0-60) - out 0x70, al - in al, 0x71 - stosd - mov al, 0x02 ; Minutes after the hour (0-59) - out 0x70, al - in al, 0x71 - stosd - mov al, 0x04 ; Hours since midnight (0-23) - out 0x70, al - in al, 0x71 - stosd - mov al, 0x07 ; Day of the month (1-31) - out 0x70, al - in al, 0x71 - stosd - mov al, 0x08 ; Months since January (0-11) - out 0x70, al - in al, 0x71 - stosd - - mov al, 0x32 ; Years since 1900 - out 0x70, al ; Century - in al, 0x71 - mov bl, 100 - mul bl - mov bx, ax - xor eax, eax - mov al, 0x09 ; Year - out 0x70, al - in al, 0x71 - add ax, bx - sub ax, 1900 - stosd - - xor eax, eax - mov al, 0x06 ; Day number of the Week (0-6) - out 0x70, al - in al, 0x71 - sub al, 1 ; RTC returns 1-7 - stosd - - xor eax, eax ; Days since January 1 - stosd - - mov al, 0x0B ; Daylight Savings Enable - out 0x70, al - in al, 0x71 - and al, 00000001b - stosd - - pop rax - pop rbx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_hide_statusbar -- Hide the system status bar -; IN: -os_hide_statusbar: - mov byte [os_show_sysstatus], 0 - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_show_statusbar -- Show the system status bar -; IN: -os_show_statusbar: - mov byte [os_show_sysstatus], 1 - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Misc Functions +; ============================================================================= + +align 16 +db 'DEBUG: MISC ' +align 16 + + +; ----------------------------------------------------------------------------- +; Display Core activity with flashing blocks on screen +; Blocks flash every quarter of a second +system_status: + push rsi + push rdi + push rdx + push rcx + push rax + + ; Display the dark grey bar + mov ax, 0x8720 ; 0x87 for dark grey background/white foreground, 0x20 for space (blank) character + mov rdi, os_screen ;0x00000000000B8000 + mov rcx, 80 + rep stosw + + ; Display CPU status + mov rdi, os_screen ; 0x00000000000B8000 + mov al, '[' + stosb + add rdi, 1 ; Skip the attribute byte + mov ax, 0x8F63 ; 'c' + stosw + mov ax, 0x8F70 ; 'p' + stosw + mov ax, 0x8F75 ; 'u' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 ; Skip to the next char + + xor ecx, ecx + mov rsi, cpustatus +system_status_cpu_next: + cmp cx, 256 + je system_status_cpu_done + add rcx, 1 + lodsb + bt ax, 0 ; Check to see if the Core is Present + jnc system_status_cpu_next ; If not then check the next + ror ax, 8 ; Exchange AL and AH + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + rol ax, 8 ; Exchange AL and AH + bt ax, 1 ; Check to see if the Core is Ready or Busy + jc system_status_cpu_busy ; Jump if it is Busy.. otherwise fall through for Idle + mov al, 0x80 ; Black on Dark Gray (Idle Core) + jmp system_status_cpu_color + +system_status_cpu_busy: + mov rax, [os_ClockCounter] + bt rax, 0 ; Check bit 0. Store bit 0 in CF + jc system_status_cpu_flash_hi + mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) + jmp system_status_cpu_color +system_status_cpu_flash_hi: + mov al, 0x8F ; White on Dark Gray (Active Core High) +system_status_cpu_color: + stosb ; Store the color (attribute) byte + jmp system_status_cpu_next ; Check the next Core + +system_status_cpu_done: + mov al, ']' + stosb + add rdi, 1 + + ; Display memory status + add rdi, 4 + mov al, '[' + stosb + add rdi, 1 ; Skip the attribute byte + mov ax, 0x8F6D ; 'm' + stosw + mov ax, 0x8F65 ; 'e' + stosw + mov ax, 0x8F6D ; 'm' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 ; Skip to the next char + + call os_mem_get_free ; Store number of free 2 MiB pages in RCX + xor rax, rax + mov ax, word [os_MemAmount] + shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) + push rax + sub rax, rcx ; RAX holds inuse pages (ex 6) + pop rcx ; RCX holds total pages (ex 512) + shr rcx, 3 ; Quickly divide RCX by 8, RCX now holds pages/block (ex 64) + xor rdx, rdx + div rcx ; Divide inuse pages by pages/block + mov rcx, rax + mov ax, 8 + cmp cx, 0 + jne notzero + add cx, 1 +notzero: + sub ax, cx + push rax + +system_status_mem_used: + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x8F ; Light Gray on Blue + stosb ; Put the block character on the screen + sub rcx, 1 + jrcxz system_status_mem_used_finish + jmp system_status_mem_used + +system_status_mem_used_finish: + + pop rcx +system_status_mem_free: + jrcxz system_status_mem_finish + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x80 ; Light Gray on Blue + stosb ; Put the block character on the screen + sub rcx, 1 + jrcxz system_status_mem_finish + jmp system_status_mem_free + +system_status_mem_finish: + mov al, ']' + stosb + add rdi, 1 + + ; Display network status + cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) + jne system_status_no_network + add rdi, 4 + mov al, '[' + stosb + add rdi, 1 + mov ax, 0x8F6E ; 'n' + stosw + mov ax, 0x8F65 ; 'e' + stosw + mov ax, 0x8F74 ; 't' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 + mov al, 'T' + stosb + add rdi, 1 + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x80 ; Black on Dark Gray (No Activity) + cmp byte [os_NetActivity_TX], 1 + jne tx_idle + mov al, 0x8F + mov byte [os_NetActivity_TX], 0 +tx_idle: + stosb + mov al, 'R' + stosb + add rdi, 1 + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x80 ; Black on Dark Gray (No Activity) + cmp byte [os_NetActivity_RX], 1 + jne rx_idle + mov al, 0x8F + mov byte [os_NetActivity_RX], 0 +rx_idle: + stosb + mov al, ']' + stosb + add rdi, 1 +system_status_no_network: + + ; Display the RTC pulse + add rdi, 4 + mov al, '[' + stosb + add rdi, 1 + mov ax, 0x8F72 ; 'r' + stosw + mov ax, 0x8F74 ; 't' + stosw + mov ax, 0x8F63 ; 'c' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov rax, [os_ClockCounter] + bt rax, 0 ; Check bit 0. Store bit 0 in CF + jc system_status_rtc_flash_hi + mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) + jmp system_status_rtc_flash_lo +system_status_rtc_flash_hi: + mov al, 0x8F ; White on Dark Gray (Active Core High) +system_status_rtc_flash_lo: + stosb ; Store the color (attribute) byte + mov al, ']' + stosb + add rdi, 1 + + ; Display header text + mov rdi, os_screen ;0x00000000000B8080 + add rdi, 0x80 + mov rsi, system_status_header + mov rcx, 16 +headernext: + lodsb + stosb + inc rdi + dec rcx + cmp rcx, 0 + jne headernext + + ; Copy the system status to the screen + mov rsi, os_screen + mov rdi, 0xB8000 + mov rcx, 80 + rep movsw + + pop rax + pop rcx + pop rdx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_delay -- Delay by X eights of a second +; IN: RAX = Time in eights of a second +; OUT: All registers preserved +; A value of 8 in RAX will delay 1 second and a value of 1 will delay 1/8 of a second +; This function depends on the RTC (IRQ 8) so interrupts must be enabled. +os_delay: + push rcx + push rax + + mov rcx, [os_ClockCounter] ; Grab the initial timer counter. It increments 8 times a second + add rax, rcx ; Add RCX so we get the end time we want +os_delay_loop: + cmp qword [os_ClockCounter], rax ; Compare it against our end time + jle os_delay_loop ; Loop if RAX is still lower + + pop rax + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_seed_random -- Seed the RNG based on the current date and time +; IN: Nothing +; OUT: All registers preserved +os_seed_random: + push rdx + push rbx + push rax + + xor rbx, rbx + mov al, 0x09 ; year + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x08 ; month + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x07 ; day + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x04 ; hour + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x02 ; minute + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x00 ; second + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 16 + rdtsc ; Read the Time Stamp Counter in EDX:EAX + mov bx, ax ; Only use the last 2 bytes + + mov [os_RandomSeed], rbx ; Seed will be something like 0x091229164435F30A + + pop rax + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_random -- Return a random integer +; IN: Nothing +; OUT: RAX = Random number +; All other registers preserved +os_get_random: + push rdx + push rbx + + mov rax, [os_RandomSeed] + mov rdx, 0x23D8AD1401DE7383 ; The magic number (random.org) + mul rdx ; RDX:RAX = RAX * RDX + mov [os_RandomSeed], rax + + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_random_integer -- Return a random integer between Low and High (incl) +; IN: RAX = Low integer +; RBX = High integer +; OUT: RCX = Random integer +os_get_random_integer: + push rdx + push rbx + push rax + + sub rbx, rax ; We want to look for a number between 0 and (High-Low) + call os_get_random + mov rdx, rbx + add rdx, 1 + mul rdx + mov rcx, rdx + + pop rax + pop rbx + pop rdx + add rcx, rax ; Add the low offset back + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_argc -- Return the number arguments passed to the program +; IN: Nothing +; OUT: AL = Number of arguments +os_get_argc: + xor eax, eax + mov al, [cli_args] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_argv -- Get the value of an argument that was passed to the program +; IN: AL = Argument number +; OUT: RSI = Start of numbered argument string +os_get_argv: + push rcx + push rax + mov rsi, cli_temp_string + cmp al, 0x00 + je os_get_argv_end + mov cl, al + +os_get_argv_nextchar: + lodsb + cmp al, 0x00 + jne os_get_argv_nextchar + dec cl + cmp cl, 0 + jne os_get_argv_nextchar + +os_get_argv_end: + pop rax + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_timecounter -- Get the current RTC clock couter value +; IN: Nothing +; OUT: RAX = Time in eights of a second since clock started +; This function depends on the RTC (IRQ 8) so interrupts must be enabled. +os_get_timecounter: + mov rax, [os_ClockCounter] ; Grab the timer counter value. It increments 8 times a second + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_time_data -- +; IN: RAX = Pointer to structure to be filled (needs 36 bytes) +os_get_time_data: + push rdi + push rbx + push rax + mov rdi, rax + xor rax, rax + +os_get_time_data_wait: + mov al, 10 + out 0x70, al + in al, 0x71 + test al, 0x80 ; Is there an update in progress? + jne os_get_time_data_wait ; If so then try again + + mov al, 0x00 ; Seconds after the minute (0-60) + out 0x70, al + in al, 0x71 + stosd + mov al, 0x02 ; Minutes after the hour (0-59) + out 0x70, al + in al, 0x71 + stosd + mov al, 0x04 ; Hours since midnight (0-23) + out 0x70, al + in al, 0x71 + stosd + mov al, 0x07 ; Day of the month (1-31) + out 0x70, al + in al, 0x71 + stosd + mov al, 0x08 ; Months since January (0-11) + out 0x70, al + in al, 0x71 + stosd + + mov al, 0x32 ; Years since 1900 + out 0x70, al ; Century + in al, 0x71 + mov bl, 100 + mul bl + mov bx, ax + xor eax, eax + mov al, 0x09 ; Year + out 0x70, al + in al, 0x71 + add ax, bx + sub ax, 1900 + stosd + + xor eax, eax + mov al, 0x06 ; Day number of the Week (0-6) + out 0x70, al + in al, 0x71 + sub al, 1 ; RTC returns 1-7 + stosd + + xor eax, eax ; Days since January 1 + stosd + + mov al, 0x0B ; Daylight Savings Enable + out 0x70, al + in al, 0x71 + and al, 00000001b + stosd + + pop rax + pop rbx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_hide_statusbar -- Hide the system status bar +; IN: +os_hide_statusbar: + mov byte [os_show_sysstatus], 0 + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_show_statusbar -- Show the system status bar +; IN: +os_show_statusbar: + mov byte [os_show_sysstatus], 1 + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/screen.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/screen.asm index b23a1515..e44a9de3 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/screen.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/screen.asm @@ -1,527 +1,527 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Screen Output Functions -; ============================================================================= - -align 16 -db 'DEBUG: SCREEN ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_move_cursor -- Moves cursor in text mode -; IN: AH = row -; AL = column -; OUT: All registers preserved -os_move_cursor: - push rdx - push rcx - push rbx - push rax - - mov [screen_cursor_x], ah - mov [screen_cursor_y], al - push rax - and rax, 0x000000000000FFFF ; only keep the low 16 bits - ;calculate the new offset - mov cl, 80 - mul cl ; AX = AL * CL - xor rbx, rbx - mov bl, [screen_cursor_x] - add ax, bx - shl ax, 1 ; multiply by 2 - add rax, os_screen ;0x00000000000B8000 - mov [screen_cursor_offset], rax - pop rax ; Move the hardware cursor - mov bh, ah - mov bl, al - xor ax, ax - mov al, 0x50 - mul bl ; bl * al = ax - movzx bx, bh - add bx, ax - mov al, 0x0E - mov ah, bh - mov dx, 0x03D4 - out dx, ax - inc ax - mov ah, bl - out dx, ax - - pop rax - pop rbx - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_inc_cursor -- Increment the hardware cursor by one -; IN: Nothing -; OUT: All registers preserved -os_inc_cursor: - push rax - - mov ah, [screen_cursor_x] ; grab the current cursor location values - mov al, [screen_cursor_y] - inc ah - cmp ah, [screen_cols] ; 80 - jne os_inc_cursor_done - xor ah, ah - inc al - cmp al, [screen_rows] ; 25 - jne os_inc_cursor_done - call os_screen_scroll ; we are on the last column of the last row (bottom right) so we need to scroll the screen up by one line - mov ah, 0x00 ; now reset the cursor to be in the first colum of the last row (bottom left) - mov al, [screen_rows] - dec al - -os_inc_cursor_done: - call os_move_cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_dec_cursor -- Decrement the hardware cursor by one -; IN: Nothing -; OUT: All registers preserved -os_dec_cursor: - push rax - - mov ah, [screen_cursor_x] ; Get the current cursor location values - mov al, [screen_cursor_y] - cmp ah, 0 ; Check if the cursor in located on the first column? - jne os_dec_cursor_done - dec al ; Wrap the cursor back to the above line - mov ah, [screen_cols] - -os_dec_cursor_done: - dec ah - call os_move_cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_newline -- Reset cursor to start of next line and scroll if needed -; IN: Nothing -; OUT: All registers perserved -os_print_newline: - push rax - - mov ah, 0 ; Set the cursor x value to 0 - mov al, [screen_cursor_y] ; Grab the cursor y value - cmp al, 24 ; Compare to see if we are on the last line - je os_print_newline_scroll ; If so then we need to scroll the sreen - inc al ; If not then we can go ahead an increment the y value - jmp os_print_newline_done - -os_print_newline_scroll: - call os_screen_scroll - -os_print_newline_done: - call os_move_cursor ; Update the cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_string -- Displays text -; IN: RSI = message location (zero-terminated string) -; OUT: All registers perserved -os_print_string: - push rdi - push rsi - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on - -os_print_string_nextchar: - lodsb ; Get char from string and store in AL - cmp al, 0 ; Strings are Zero terminated. - je os_print_string_done ; If char is Zero then it is the end of the string - cmp al, 10 ; Check if there was a newline character in the string - je os_print_string_newline ; If so then we print a new line - cmp al, 13 ; Check if there was a newline character in the string - je os_print_string_newline ; If so then we print a new line - mov rdi, [screen_cursor_offset] - stosw ; Write the character and attribute with one call - call os_inc_cursor - jmp os_print_string_nextchar - -os_print_string_newline: - call os_print_newline - jmp os_print_string_nextchar - -os_print_string_done: - call os_screen_update - - pop rax - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_string_with_color -- Displays text with color -; IN: RSI = message location (zero-terminated string) -; BL = color -; OUT: All registers perserved -; This function uses the the os_print_string function to do the actual printing -os_print_string_with_color: - push rdi - push rsi - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, bl ; Copy the attribute into AH so STOSW can be used later on - - jmp os_print_string_nextchar ; Use the logic from os_print_string -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char -- Displays a char -; IN: AL = char to display -; OUT: All registers perserved -os_print_char: - push rdi - push rsi - push rax - - mov rdi, [screen_cursor_offset] - mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on - stosw ; Write the character and attribute with one call - - call os_inc_cursor - sub rdi, 2 - mov rsi, rdi - sub rdi, os_screen - add rdi, 0xB8000 ; Offset to video text memory - movsw - - pop rax - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_with_color -- Displays a char with color -; IN: AL = char to display -; BL = color -; OUT: All registers perserved -os_print_char_with_color: - push rdi - push rsi - - mov rdi, [screen_cursor_offset] - stosb ; Store the character to video memory - xchg al, bl ; Swap AL and BL as stosb uses AL - stosb ; Store the color attribute to video memory - xchg al, bl ; Swap AL and BL back again - call os_inc_cursor - sub rdi, 2 - mov rsi, rdi - sub rdi, os_screen - add rdi, 0xB8000 ; Offset to video text memory - movsw - - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_chars -- Displays text -; IN: RSI = message location (A string, not zero-terminated) -; RCX = number of chars to print -; OUT: All registers perserved -os_print_chars: - push rdi - push rsi - push rcx - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on - -os_print_chars_nextchar: - jrcxz os_print_chars_done - sub rcx, 1 - lodsb ; Get char from string and store in AL - cmp al, 10 ; Check if there was a newline character in the string - je os_print_chars_newline ; If so then we print a new line - cmp al, 13 ; Check if there was a newline character in the string - je os_print_chars_newline ; If so then we print a new line - mov rdi, [screen_cursor_offset] - stosw ; Write the character and attribute with one call - call os_inc_cursor - jmp os_print_chars_nextchar - -os_print_chars_newline: - call os_print_newline - jmp os_print_chars_nextchar - -os_print_chars_done: - call os_screen_update - - pop rax - pop rcx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_chars_with_color -- Displays text with color -; IN: RSI = message location (A string, not zero-terminated) -; BL = color -; RCX = number of chars to print -; OUT: All registers perserved -; This function uses the the os_print_chars function to do the actual printing -os_print_chars_with_color: - push rdi - push rsi - push rcx - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, bl ; Store the attribute into AH so STOSW can be used later on - - jmp os_print_chars_nextchar ; Use the logic from os_print_chars -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_hex -- Displays a char in hex mode -; IN: AL = char to display -; OUT: All registers perserved -os_print_char_hex: - push rbx - push rax - - mov rbx, hextable - - push rax ; save rax for the next part - shr al, 4 ; we want to work on the high part so shift right by 4 bits - xlatb - call os_print_char - - pop rax - and al, 0x0f ; we want to work on the low part so clear the high part - xlatb - call os_print_char - - pop rax - pop rbx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_hex_with_color -- Displays a char in hex mode -; IN: AL = char to display -; BL = color -; OUT: All registers perserved -os_print_char_hex_with_color: - push rcx - push rbx - push rax - - mov cl, bl - mov rbx, hextable - - push rax ; save rax for the next part - shr al, 4 ; we want to work on the high part so shift right by 4 bits - xlatb - push rbx - mov bl, cl - call os_print_char_with_color - pop rbx - - pop rax - and al, 0x0f ; we want to work on the low part so clear the high part - xlatb - push rbx - mov bl, cl - call os_print_char_with_color - pop rbx - - pop rax - pop rbx - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_scroll_screen -- Scrolls the screen up by one line -; IN: Nothing -; OUT: All registers perserved -os_screen_scroll: - push rsi - push rdi - push rcx - push rax - - cld ; Clear the direction flag as we want to increment through memory - - cmp byte [os_show_sysstatus], 0 - je os_screen_scroll_no_sysstatus - - mov rsi, os_screen ; Start of video text memory for row 3 - add rsi, 0x140 - mov rdi, os_screen ; Start of video text memory for row 2 - add rdi, 0xa0 - mov rcx, 1840 ; 80 x 23 - rep movsw ; Copy the Character and Attribute - jmp os_screen_scroll_lastline - -os_screen_scroll_no_sysstatus: - mov rsi, os_screen ; Start of video text memory for row 2 - add rsi, 0xa0 - mov rdi, os_screen ; Start of video text memory for row 1 - mov rcx, 1920 ; 80 x 24 - rep movsw ; Copy the Character and Attribute - -os_screen_scroll_lastline: ; Clear the last line in video memory - mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character - mov rdi, os_screen - add rdi, 0xf00 - mov rcx, 80 - rep stosw ; Store word in AX to RDI, RCX times - - call os_screen_update - - pop rax - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_screen_clear -- Clear the screen -; IN: Nothing -; OUT: All registers perserved -os_screen_clear: - push rdi - push rcx - push rax - - mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character - mov rdi, os_screen ; Address for start of color video memory - mov rcx, 2000 - rep stosw ; Clear the screen. Store word in AX to RDI, RCX times - - call os_screen_update ; Copy the video buffer to video memory - - pop rax - pop rcx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_hide_cursor -- Turns off cursor in text mode -; IN: Nothing -; OUT: All registers perserved -os_hide_cursor: - push rdx - push rbx - push rax - - mov dx, 0x03d4 - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - xor ax, ax - in al, dx - mov bl, al - or bl, 00100000b ; Bit 5 set to 1 to disable cursor - dec dx - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - mov al, bl - out dx, al - - pop rax - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_show_cursor -- Turns on cursor in text mode -; IN: Nothing -; OUT: All registers perserved -os_show_cursor: - push rdx - push rbx - push rax - - mov dx, 0x03d4 - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - xor ax, ax - in al, dx - mov bl, al - and bl, 11011111b ; Bit 5 set to 0 to enable cursor - dec dx - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - mov al, bl - out dx, al - - pop rax - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_show_cursor -- Manually refresh the screen from the frame buffer -; IN: Nothing -; OUT: All registers perserved -os_screen_update: - push rsi - push rdi - push rcx - - mov rsi, os_screen - mov rdi, 0xb8000 - mov rcx, 2000 - rep movsw - - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Screen Output Functions +; ============================================================================= + +align 16 +db 'DEBUG: SCREEN ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_move_cursor -- Moves cursor in text mode +; IN: AH = row +; AL = column +; OUT: All registers preserved +os_move_cursor: + push rdx + push rcx + push rbx + push rax + + mov [screen_cursor_x], ah + mov [screen_cursor_y], al + push rax + and rax, 0x000000000000FFFF ; only keep the low 16 bits + ;calculate the new offset + mov cl, 80 + mul cl ; AX = AL * CL + xor rbx, rbx + mov bl, [screen_cursor_x] + add ax, bx + shl ax, 1 ; multiply by 2 + add rax, os_screen ;0x00000000000B8000 + mov [screen_cursor_offset], rax + pop rax ; Move the hardware cursor + mov bh, ah + mov bl, al + xor ax, ax + mov al, 0x50 + mul bl ; bl * al = ax + movzx bx, bh + add bx, ax + mov al, 0x0E + mov ah, bh + mov dx, 0x03D4 + out dx, ax + inc ax + mov ah, bl + out dx, ax + + pop rax + pop rbx + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_inc_cursor -- Increment the hardware cursor by one +; IN: Nothing +; OUT: All registers preserved +os_inc_cursor: + push rax + + mov ah, [screen_cursor_x] ; grab the current cursor location values + mov al, [screen_cursor_y] + inc ah + cmp ah, [screen_cols] ; 80 + jne os_inc_cursor_done + xor ah, ah + inc al + cmp al, [screen_rows] ; 25 + jne os_inc_cursor_done + call os_screen_scroll ; we are on the last column of the last row (bottom right) so we need to scroll the screen up by one line + mov ah, 0x00 ; now reset the cursor to be in the first colum of the last row (bottom left) + mov al, [screen_rows] + dec al + +os_inc_cursor_done: + call os_move_cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_dec_cursor -- Decrement the hardware cursor by one +; IN: Nothing +; OUT: All registers preserved +os_dec_cursor: + push rax + + mov ah, [screen_cursor_x] ; Get the current cursor location values + mov al, [screen_cursor_y] + cmp ah, 0 ; Check if the cursor in located on the first column? + jne os_dec_cursor_done + dec al ; Wrap the cursor back to the above line + mov ah, [screen_cols] + +os_dec_cursor_done: + dec ah + call os_move_cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_newline -- Reset cursor to start of next line and scroll if needed +; IN: Nothing +; OUT: All registers perserved +os_print_newline: + push rax + + mov ah, 0 ; Set the cursor x value to 0 + mov al, [screen_cursor_y] ; Grab the cursor y value + cmp al, 24 ; Compare to see if we are on the last line + je os_print_newline_scroll ; If so then we need to scroll the sreen + inc al ; If not then we can go ahead an increment the y value + jmp os_print_newline_done + +os_print_newline_scroll: + call os_screen_scroll + +os_print_newline_done: + call os_move_cursor ; Update the cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_string -- Displays text +; IN: RSI = message location (zero-terminated string) +; OUT: All registers perserved +os_print_string: + push rdi + push rsi + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on + +os_print_string_nextchar: + lodsb ; Get char from string and store in AL + cmp al, 0 ; Strings are Zero terminated. + je os_print_string_done ; If char is Zero then it is the end of the string + cmp al, 10 ; Check if there was a newline character in the string + je os_print_string_newline ; If so then we print a new line + cmp al, 13 ; Check if there was a newline character in the string + je os_print_string_newline ; If so then we print a new line + mov rdi, [screen_cursor_offset] + stosw ; Write the character and attribute with one call + call os_inc_cursor + jmp os_print_string_nextchar + +os_print_string_newline: + call os_print_newline + jmp os_print_string_nextchar + +os_print_string_done: + call os_screen_update + + pop rax + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_string_with_color -- Displays text with color +; IN: RSI = message location (zero-terminated string) +; BL = color +; OUT: All registers perserved +; This function uses the the os_print_string function to do the actual printing +os_print_string_with_color: + push rdi + push rsi + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, bl ; Copy the attribute into AH so STOSW can be used later on + + jmp os_print_string_nextchar ; Use the logic from os_print_string +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char -- Displays a char +; IN: AL = char to display +; OUT: All registers perserved +os_print_char: + push rdi + push rsi + push rax + + mov rdi, [screen_cursor_offset] + mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on + stosw ; Write the character and attribute with one call + + call os_inc_cursor + sub rdi, 2 + mov rsi, rdi + sub rdi, os_screen + add rdi, 0xB8000 ; Offset to video text memory + movsw + + pop rax + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_with_color -- Displays a char with color +; IN: AL = char to display +; BL = color +; OUT: All registers perserved +os_print_char_with_color: + push rdi + push rsi + + mov rdi, [screen_cursor_offset] + stosb ; Store the character to video memory + xchg al, bl ; Swap AL and BL as stosb uses AL + stosb ; Store the color attribute to video memory + xchg al, bl ; Swap AL and BL back again + call os_inc_cursor + sub rdi, 2 + mov rsi, rdi + sub rdi, os_screen + add rdi, 0xB8000 ; Offset to video text memory + movsw + + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_chars -- Displays text +; IN: RSI = message location (A string, not zero-terminated) +; RCX = number of chars to print +; OUT: All registers perserved +os_print_chars: + push rdi + push rsi + push rcx + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on + +os_print_chars_nextchar: + jrcxz os_print_chars_done + sub rcx, 1 + lodsb ; Get char from string and store in AL + cmp al, 10 ; Check if there was a newline character in the string + je os_print_chars_newline ; If so then we print a new line + cmp al, 13 ; Check if there was a newline character in the string + je os_print_chars_newline ; If so then we print a new line + mov rdi, [screen_cursor_offset] + stosw ; Write the character and attribute with one call + call os_inc_cursor + jmp os_print_chars_nextchar + +os_print_chars_newline: + call os_print_newline + jmp os_print_chars_nextchar + +os_print_chars_done: + call os_screen_update + + pop rax + pop rcx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_chars_with_color -- Displays text with color +; IN: RSI = message location (A string, not zero-terminated) +; BL = color +; RCX = number of chars to print +; OUT: All registers perserved +; This function uses the the os_print_chars function to do the actual printing +os_print_chars_with_color: + push rdi + push rsi + push rcx + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, bl ; Store the attribute into AH so STOSW can be used later on + + jmp os_print_chars_nextchar ; Use the logic from os_print_chars +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_hex -- Displays a char in hex mode +; IN: AL = char to display +; OUT: All registers perserved +os_print_char_hex: + push rbx + push rax + + mov rbx, hextable + + push rax ; save rax for the next part + shr al, 4 ; we want to work on the high part so shift right by 4 bits + xlatb + call os_print_char + + pop rax + and al, 0x0f ; we want to work on the low part so clear the high part + xlatb + call os_print_char + + pop rax + pop rbx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_hex_with_color -- Displays a char in hex mode +; IN: AL = char to display +; BL = color +; OUT: All registers perserved +os_print_char_hex_with_color: + push rcx + push rbx + push rax + + mov cl, bl + mov rbx, hextable + + push rax ; save rax for the next part + shr al, 4 ; we want to work on the high part so shift right by 4 bits + xlatb + push rbx + mov bl, cl + call os_print_char_with_color + pop rbx + + pop rax + and al, 0x0f ; we want to work on the low part so clear the high part + xlatb + push rbx + mov bl, cl + call os_print_char_with_color + pop rbx + + pop rax + pop rbx + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_scroll_screen -- Scrolls the screen up by one line +; IN: Nothing +; OUT: All registers perserved +os_screen_scroll: + push rsi + push rdi + push rcx + push rax + + cld ; Clear the direction flag as we want to increment through memory + + cmp byte [os_show_sysstatus], 0 + je os_screen_scroll_no_sysstatus + + mov rsi, os_screen ; Start of video text memory for row 3 + add rsi, 0x140 + mov rdi, os_screen ; Start of video text memory for row 2 + add rdi, 0xa0 + mov rcx, 1840 ; 80 x 23 + rep movsw ; Copy the Character and Attribute + jmp os_screen_scroll_lastline + +os_screen_scroll_no_sysstatus: + mov rsi, os_screen ; Start of video text memory for row 2 + add rsi, 0xa0 + mov rdi, os_screen ; Start of video text memory for row 1 + mov rcx, 1920 ; 80 x 24 + rep movsw ; Copy the Character and Attribute + +os_screen_scroll_lastline: ; Clear the last line in video memory + mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character + mov rdi, os_screen + add rdi, 0xf00 + mov rcx, 80 + rep stosw ; Store word in AX to RDI, RCX times + + call os_screen_update + + pop rax + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_screen_clear -- Clear the screen +; IN: Nothing +; OUT: All registers perserved +os_screen_clear: + push rdi + push rcx + push rax + + mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character + mov rdi, os_screen ; Address for start of color video memory + mov rcx, 2000 + rep stosw ; Clear the screen. Store word in AX to RDI, RCX times + + call os_screen_update ; Copy the video buffer to video memory + + pop rax + pop rcx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_hide_cursor -- Turns off cursor in text mode +; IN: Nothing +; OUT: All registers perserved +os_hide_cursor: + push rdx + push rbx + push rax + + mov dx, 0x03d4 + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + xor ax, ax + in al, dx + mov bl, al + or bl, 00100000b ; Bit 5 set to 1 to disable cursor + dec dx + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + mov al, bl + out dx, al + + pop rax + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_show_cursor -- Turns on cursor in text mode +; IN: Nothing +; OUT: All registers perserved +os_show_cursor: + push rdx + push rbx + push rax + + mov dx, 0x03d4 + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + xor ax, ax + in al, dx + mov bl, al + and bl, 11011111b ; Bit 5 set to 0 to enable cursor + dec dx + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + mov al, bl + out dx, al + + pop rax + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_show_cursor -- Manually refresh the screen from the frame buffer +; IN: Nothing +; OUT: All registers perserved +os_screen_update: + push rsi + push rdi + push rcx + + mov rsi, os_screen + mov rdi, 0xb8000 + mov rcx, 2000 + rep movsw + + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/serial.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/serial.asm index 422e951c..d1ad227a 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/serial.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/serial.asm @@ -1,58 +1,58 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Serial Port Functions -; ============================================================================= - -align 16 -db 'DEBUG: SERIAL ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_serial_send -- Send a byte over the primary serial port -; IN: AL = Byte to send over serial port -; OUT: All registers preserved -os_serial_send: - push rdx - - push rax ; Save RAX since the serial line status check clobbers AL - mov dx, 0x03FD ; Serial Line Status register -os_serial_send_wait: - in al, dx - bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag - jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte - pop rax ; Get the byte back from the stack - mov dx, 0x03F8 ; Serial data register - out dx, al ; Send the byte - - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_serial_recv -- Receive a byte from the primary serial port -; IN: Nothing -; OUT: AL = Byte recevied -; Carry flag is set if a byte was received, otherwise AL is trashed -; All other registers preserved -os_serial_recv: - push rdx - - mov dx, 0x03FD ; Serial Line Status register - in al, dx - bt ax, 0 ; Copy bit 0 (Data available) to the Carry Flag - jnc os_serial_recv_no_data - mov dx, 0x03F8 ; Serial data register - in al, dx ; Grab the byte - -os_serial_recv_no_data: - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Serial Port Functions +; ============================================================================= + +align 16 +db 'DEBUG: SERIAL ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_serial_send -- Send a byte over the primary serial port +; IN: AL = Byte to send over serial port +; OUT: All registers preserved +os_serial_send: + push rdx + + push rax ; Save RAX since the serial line status check clobbers AL + mov dx, 0x03FD ; Serial Line Status register +os_serial_send_wait: + in al, dx + bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag + jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte + pop rax ; Get the byte back from the stack + mov dx, 0x03F8 ; Serial data register + out dx, al ; Send the byte + + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_serial_recv -- Receive a byte from the primary serial port +; IN: Nothing +; OUT: AL = Byte recevied +; Carry flag is set if a byte was received, otherwise AL is trashed +; All other registers preserved +os_serial_recv: + push rdx + + mov dx, 0x03FD ; Serial Line Status register + in al, dx + bt ax, 0 ; Copy bit 0 (Data available) to the Carry Flag + jnc os_serial_recv_no_data + mov dx, 0x03F8 ; Serial data register + in al, dx ; Grab the byte + +os_serial_recv_no_data: + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/smp.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/smp.asm index dadb122c..be6c1286 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/smp.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/smp.asm @@ -1,307 +1,307 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; SMP Functions -; ============================================================================= - -align 16 -db 'DEBUG: SMP ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_smp_reset -- Resets a CPU Core -; IN: AL = CPU # -; OUT: Nothing. All registers preserved. -; Note: This code resets an AP -; For setup use only. -os_smp_reset: - push rdi - push rax - - mov rdi, [os_LocalAPICAddress] - shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved - mov [rdi+0x0310], eax ; Write to the high bits first - xor eax, eax ; Clear EAX, namely bits 31:24 - mov al, 0x81 ; Execute interrupt 0x81 - mov [rdi+0x0300], eax ; Then write to the low bits - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_wakeup -- Wake up a CPU Core -; IN: AL = CPU # -; OUT: Nothing. All registers preserved. -os_smp_wakeup: - push rdi - push rax - - mov rdi, [os_LocalAPICAddress] - shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved - mov [rdi+0x0310], eax ; Write to the high bits first - xor eax, eax ; Clear EAX, namely bits 31:24 - mov al, 0x80 ; Execute interrupt 0x80 - mov [rdi+0x0300], eax ; Then write to the low bits - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_wakeup_all -- Wake up all CPU Cores -; IN: Nothing. -; OUT: Nothing. All registers preserved. -os_smp_wakeup_all: - push rdi - push rax - - mov rdi, [os_LocalAPICAddress] - xor eax, eax - mov [rdi+0x0310], eax ; Write to the high bits first - mov eax, 0x000C0080 ; Execute interrupt 0x80 - mov [rdi+0x0300], eax ; Then write to the low bits - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_get_id -- Returns the APIC ID of the CPU that ran this function -; IN: Nothing -; OUT: RAX = CPU's APIC ID number, All other registers perserved. -os_smp_get_id: - push rsi - - xor eax, eax - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) - - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_enqueue -- Add a workload to the processing queue -; IN: RAX = Address of code to execute, RSI = Variable -; OUT: Nothing -os_smp_enqueue: - push rdi - push rsi - push rcx - push rax - -os_smp_enqueue_spin: - bt word [os_QueueLock], 0 ; Check if the mutex is free - jc os_smp_enqueue_spin ; If not check it again - lock ; The mutex was free, lock the bus - bts word [os_QueueLock], 0 ; Try to grab the mutex - jc os_smp_enqueue_spin ; Jump if we were unsuccessful - - cmp word [os_QueueLen], 256 ; aka cpuqueuemax - je os_smp_enqueue_fail - - xor ecx, ecx - mov rdi, cpuqueue - mov cx, [cpuqueuefinish] - shl rcx, 4 ; Quickly multiply RCX by 16 - add rdi, rcx - - stosq ; Store the code address from RAX - mov rax, rsi - stosq ; Store the variable - - add word [os_QueueLen], 1 - shr rcx, 4 ; Quickly divide RCX by 16 - add cx, 1 - cmp cx, [cpuqueuemax] - jne os_smp_enqueue_end - xor cx, cx ; We wrap around - xchg bx, bx - -os_smp_enqueue_end: - mov [cpuqueuefinish], cx - pop rax - pop rcx - pop rsi - pop rdi - btr word [os_QueueLock], 0 ; Release the lock - call os_smp_wakeup_all - clc ; Carry clear for success - ret - -os_smp_enqueue_fail: - pop rax - pop rcx - pop rsi - pop rdi - btr word [os_QueueLock], 0 ; Release the lock - stc ; Carry set for failure (Queue full) - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_dequeue -- Dequeue a workload from the processing queue -; IN: Nothing -; OUT: RAX = Address of code to execute (Set to 0 if queue is empty), RDI = Variable -os_smp_dequeue: - push rsi - push rcx - -os_smp_dequeue_spin: - bt word [os_QueueLock], 0 ; Check if the mutex is free - jc os_smp_dequeue_spin ; If not check it again - lock ; The mutex was free, lock the bus - bts word [os_QueueLock], 0 ; Try to grab the mutex - jc os_smp_dequeue_spin ; Jump if we were unsuccessful - - cmp word [os_QueueLen], 0 - je os_smp_dequeue_fail - - xor ecx, ecx - mov rsi, cpuqueue - mov cx, [cpuqueuestart] - shl rcx, 4 ; Quickly multiply RCX by 16 - add rsi, rcx - - lodsq ; Load the code address into RAX - push rax - lodsq ; Load the variable - mov rdi, rax - pop rax - - sub word [os_QueueLen], 1 - shr rcx, 4 ; Quickly divide RCX by 16 - add cx, 1 - cmp cx, [cpuqueuemax] - jne os_smp_dequeue_end - xor cx, cx ; We wrap around - -os_smp_dequeue_end: - mov word [cpuqueuestart], cx - pop rcx - pop rsi - btr word [os_QueueLock], 0 ; Release the lock - clc ; If we got here then ok - ret - -os_smp_dequeue_fail: - xor rax, rax - pop rcx - pop rsi - btr word [os_QueueLock], 0 ; Release the lock - stc - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_run -- Call the code address stored in RAX -; IN: RAX = Address of code to execute -; OUT: Nothing -os_smp_run: - call rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_queuelen -- Returns the number of items in the processing queue -; IN: Nothing -; OUT: RAX = number of items in processing queue -os_smp_queuelen: - xor eax, eax - mov ax, [os_QueueLen] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_numcores -- Returns the number of cores in this computer -; IN: Nothing -; OUT: RAX = number of cores in this computer -os_smp_numcores: - xor eax, eax - mov ax, [os_NumCores] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_wait -- Wait until all other CPU Cores are finished processing -; IN: Nothing -; OUT: Nothing. All registers preserved. -os_smp_wait: - push rsi - push rcx - push rbx - push rax - - call os_smp_get_id - mov rbx, rax - - xor eax, eax - xor ecx, ecx - mov rsi, cpustatus - -checkit: - lodsb - cmp rbx, rcx ; Check to see if it is looking at itself - je skipit ; If so then skip as it shouild be marked as busy - bt ax, 0 ; Check the Present bit - jnc skipit ; If carry is not set then the CPU does not exist - bt ax, 1 ; Check the Ready/Busy bit - jnc skipit ; If carry is not set then the CPU is Ready - sub rsi, 1 - jmp checkit ; Core is marked as Busy, check it again -skipit: - add rcx, 1 - cmp rcx, 256 - jne checkit - - pop rax - pop rbx - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_lock -- Attempt to lock a mutex -; IN: RAX = Address of lock variable -; OUT: Nothing. All registers preserved. -os_smp_lock: - bt word [rax], 0 ; Check if the mutex is free (Bit 0 cleared to 0) - jc os_smp_lock ; If not check it again - lock ; The mutex was free, lock the bus - bts word [rax], 0 ; Try to grab the mutex (Bit 0 set to 1) - jc os_smp_lock ; Jump if we were unsuccessful - ret ; Lock acquired. Return to the caller -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_unlock -- Unlock a mutex -; IN: RAX = Address of lock variable -; OUT: Nothing. All registers preserved. -os_smp_unlock: - btr word [rax], 0 ; Release the lock (Bit 0 cleared to 0) - ret ; Lock released. Return to the caller -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; SMP Functions +; ============================================================================= + +align 16 +db 'DEBUG: SMP ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_smp_reset -- Resets a CPU Core +; IN: AL = CPU # +; OUT: Nothing. All registers preserved. +; Note: This code resets an AP +; For setup use only. +os_smp_reset: + push rdi + push rax + + mov rdi, [os_LocalAPICAddress] + shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved + mov [rdi+0x0310], eax ; Write to the high bits first + xor eax, eax ; Clear EAX, namely bits 31:24 + mov al, 0x81 ; Execute interrupt 0x81 + mov [rdi+0x0300], eax ; Then write to the low bits + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_wakeup -- Wake up a CPU Core +; IN: AL = CPU # +; OUT: Nothing. All registers preserved. +os_smp_wakeup: + push rdi + push rax + + mov rdi, [os_LocalAPICAddress] + shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved + mov [rdi+0x0310], eax ; Write to the high bits first + xor eax, eax ; Clear EAX, namely bits 31:24 + mov al, 0x80 ; Execute interrupt 0x80 + mov [rdi+0x0300], eax ; Then write to the low bits + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_wakeup_all -- Wake up all CPU Cores +; IN: Nothing. +; OUT: Nothing. All registers preserved. +os_smp_wakeup_all: + push rdi + push rax + + mov rdi, [os_LocalAPICAddress] + xor eax, eax + mov [rdi+0x0310], eax ; Write to the high bits first + mov eax, 0x000C0080 ; Execute interrupt 0x80 + mov [rdi+0x0300], eax ; Then write to the low bits + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_get_id -- Returns the APIC ID of the CPU that ran this function +; IN: Nothing +; OUT: RAX = CPU's APIC ID number, All other registers perserved. +os_smp_get_id: + push rsi + + xor eax, eax + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) + + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_enqueue -- Add a workload to the processing queue +; IN: RAX = Address of code to execute, RSI = Variable +; OUT: Nothing +os_smp_enqueue: + push rdi + push rsi + push rcx + push rax + +os_smp_enqueue_spin: + bt word [os_QueueLock], 0 ; Check if the mutex is free + jc os_smp_enqueue_spin ; If not check it again + lock ; The mutex was free, lock the bus + bts word [os_QueueLock], 0 ; Try to grab the mutex + jc os_smp_enqueue_spin ; Jump if we were unsuccessful + + cmp word [os_QueueLen], 256 ; aka cpuqueuemax + je os_smp_enqueue_fail + + xor ecx, ecx + mov rdi, cpuqueue + mov cx, [cpuqueuefinish] + shl rcx, 4 ; Quickly multiply RCX by 16 + add rdi, rcx + + stosq ; Store the code address from RAX + mov rax, rsi + stosq ; Store the variable + + add word [os_QueueLen], 1 + shr rcx, 4 ; Quickly divide RCX by 16 + add cx, 1 + cmp cx, [cpuqueuemax] + jne os_smp_enqueue_end + xor cx, cx ; We wrap around + xchg bx, bx + +os_smp_enqueue_end: + mov [cpuqueuefinish], cx + pop rax + pop rcx + pop rsi + pop rdi + btr word [os_QueueLock], 0 ; Release the lock + call os_smp_wakeup_all + clc ; Carry clear for success + ret + +os_smp_enqueue_fail: + pop rax + pop rcx + pop rsi + pop rdi + btr word [os_QueueLock], 0 ; Release the lock + stc ; Carry set for failure (Queue full) + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_dequeue -- Dequeue a workload from the processing queue +; IN: Nothing +; OUT: RAX = Address of code to execute (Set to 0 if queue is empty), RDI = Variable +os_smp_dequeue: + push rsi + push rcx + +os_smp_dequeue_spin: + bt word [os_QueueLock], 0 ; Check if the mutex is free + jc os_smp_dequeue_spin ; If not check it again + lock ; The mutex was free, lock the bus + bts word [os_QueueLock], 0 ; Try to grab the mutex + jc os_smp_dequeue_spin ; Jump if we were unsuccessful + + cmp word [os_QueueLen], 0 + je os_smp_dequeue_fail + + xor ecx, ecx + mov rsi, cpuqueue + mov cx, [cpuqueuestart] + shl rcx, 4 ; Quickly multiply RCX by 16 + add rsi, rcx + + lodsq ; Load the code address into RAX + push rax + lodsq ; Load the variable + mov rdi, rax + pop rax + + sub word [os_QueueLen], 1 + shr rcx, 4 ; Quickly divide RCX by 16 + add cx, 1 + cmp cx, [cpuqueuemax] + jne os_smp_dequeue_end + xor cx, cx ; We wrap around + +os_smp_dequeue_end: + mov word [cpuqueuestart], cx + pop rcx + pop rsi + btr word [os_QueueLock], 0 ; Release the lock + clc ; If we got here then ok + ret + +os_smp_dequeue_fail: + xor rax, rax + pop rcx + pop rsi + btr word [os_QueueLock], 0 ; Release the lock + stc + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_run -- Call the code address stored in RAX +; IN: RAX = Address of code to execute +; OUT: Nothing +os_smp_run: + call rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_queuelen -- Returns the number of items in the processing queue +; IN: Nothing +; OUT: RAX = number of items in processing queue +os_smp_queuelen: + xor eax, eax + mov ax, [os_QueueLen] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_numcores -- Returns the number of cores in this computer +; IN: Nothing +; OUT: RAX = number of cores in this computer +os_smp_numcores: + xor eax, eax + mov ax, [os_NumCores] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_wait -- Wait until all other CPU Cores are finished processing +; IN: Nothing +; OUT: Nothing. All registers preserved. +os_smp_wait: + push rsi + push rcx + push rbx + push rax + + call os_smp_get_id + mov rbx, rax + + xor eax, eax + xor ecx, ecx + mov rsi, cpustatus + +checkit: + lodsb + cmp rbx, rcx ; Check to see if it is looking at itself + je skipit ; If so then skip as it shouild be marked as busy + bt ax, 0 ; Check the Present bit + jnc skipit ; If carry is not set then the CPU does not exist + bt ax, 1 ; Check the Ready/Busy bit + jnc skipit ; If carry is not set then the CPU is Ready + sub rsi, 1 + jmp checkit ; Core is marked as Busy, check it again +skipit: + add rcx, 1 + cmp rcx, 256 + jne checkit + + pop rax + pop rbx + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_lock -- Attempt to lock a mutex +; IN: RAX = Address of lock variable +; OUT: Nothing. All registers preserved. +os_smp_lock: + bt word [rax], 0 ; Check if the mutex is free (Bit 0 cleared to 0) + jc os_smp_lock ; If not check it again + lock ; The mutex was free, lock the bus + bts word [rax], 0 ; Try to grab the mutex (Bit 0 set to 1) + jc os_smp_lock ; Jump if we were unsuccessful + ret ; Lock acquired. Return to the caller +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_unlock -- Unlock a mutex +; IN: RAX = Address of lock variable +; OUT: Nothing. All registers preserved. +os_smp_unlock: + btr word [rax], 0 ; Release the lock (Bit 0 cleared to 0) + ret ; Lock released. Return to the caller +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/sound.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/sound.asm index 5ecd565f..92957e79 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/sound.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/sound.asm @@ -1,77 +1,77 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; PC Speaker Sound Functions -; ============================================================================= - -align 16 -db 'DEBUG: SOUND ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_speaker_tone -- Generate a tone on the PC speaker -; IN: RAX = note frequency -; OUT: All registers preserved -; Note: Call os_speaker_off to stop the tone -os_speaker_tone: - push rax - push rcx - - mov cx, ax ; Store note value for now - mov al, 182 - out 0x43, al ; System timers.. - mov ax, cx ; Set up frequency - out 0x42, al - mov al, ah ; 64-bit mode.... AH allowed???? - out 0x42, al - in al, 0x61 ; Switch PC speaker on - or al, 0x03 - out 0x61, al - - pop rcx - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_speaker_off -- Turn off PC speaker -; IN: Nothing -; OUT: All registers preserved -os_speaker_off: - push rax - - in al, 0x61 ; Switch PC speaker off - and al, 0xFC - out 0x61, al - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_speaker_beep -- Create a standard OS beep -; IN: Nothing -; OUT: All registers preserved -os_speaker_beep: - push rax - push rcx - - xor eax, eax - mov ax, 0x0C80 - call os_speaker_tone - mov ax, 2 ; A quarter of a second - call os_delay - call os_speaker_off - - pop rcx - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; PC Speaker Sound Functions +; ============================================================================= + +align 16 +db 'DEBUG: SOUND ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_speaker_tone -- Generate a tone on the PC speaker +; IN: RAX = note frequency +; OUT: All registers preserved +; Note: Call os_speaker_off to stop the tone +os_speaker_tone: + push rax + push rcx + + mov cx, ax ; Store note value for now + mov al, 182 + out 0x43, al ; System timers.. + mov ax, cx ; Set up frequency + out 0x42, al + mov al, ah ; 64-bit mode.... AH allowed???? + out 0x42, al + in al, 0x61 ; Switch PC speaker on + or al, 0x03 + out 0x61, al + + pop rcx + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_speaker_off -- Turn off PC speaker +; IN: Nothing +; OUT: All registers preserved +os_speaker_off: + push rax + + in al, 0x61 ; Switch PC speaker off + and al, 0xFC + out 0x61, al + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_speaker_beep -- Create a standard OS beep +; IN: Nothing +; OUT: All registers preserved +os_speaker_beep: + push rax + push rcx + + xor eax, eax + mov ax, 0x0C80 + call os_speaker_tone + mov ax, 2 ; A quarter of a second + call os_delay + call os_speaker_off + + pop rcx + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/string.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/string.asm index b1fa2e22..aaa547c2 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/string.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/syscalls/string.asm @@ -1,745 +1,745 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; String Functions -; ============================================================================= - -align 16 -db 'DEBUG: STRING ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_int_to_string -- Convert a binary interger into an string -; IN: RAX = binary integer -; RDI = location to store string -; OUT: RDI = points to end of string -; All other registers preserved -; Min return value is 0 and max return value is 18446744073709551615 so your -; string needs to be able to store at least 21 characters (20 for the digits -; and 1 for the string terminator). -; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s -os_int_to_string: - push rdx - push rcx - push rbx - push rax - - mov rbx, 10 ; base of the decimal system - xor ecx, ecx ; number of digits generated -os_int_to_string_next_divide: - xor edx, edx ; RAX extended to (RDX,RAX) - div rbx ; divide by the number-base - push rdx ; save remainder on the stack - inc rcx ; and count this remainder - cmp rax, 0 ; was the quotient zero? - jne os_int_to_string_next_divide ; no, do another division - -os_int_to_string_next_digit: - pop rax ; else pop recent remainder - add al, '0' ; and convert to a numeral - stosb ; store to memory-buffer - loop os_int_to_string_next_digit ; again for other remainders - xor al, al - stosb ; Store the null terminator at the end of the string - - pop rax - pop rbx - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_to_int -- Convert a string into a binary interger -; IN: RSI = location of string -; OUT: RAX = integer value -; All other registers preserved -; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/uint2rax.s -os_string_to_int: - push rsi - push rdx - push rcx - push rbx - - xor eax, eax ; initialize accumulator - mov rbx, 10 ; decimal-system's radix -os_string_to_int_next_digit: - mov cl, [rsi] ; fetch next character - cmp cl, '0' ; char preceeds '0'? - jb os_string_to_int_invalid ; yes, not a numeral - cmp cl, '9' ; char follows '9'? - ja os_string_to_int_invalid ; yes, not a numeral - mul rbx ; ten times prior sum - and rcx, 0x0F ; convert char to int - add rax, rcx ; add to prior total - inc rsi ; advance source index - jmp os_string_to_int_next_digit ; and check another char - -os_string_to_int_invalid: - pop rbx - pop rcx - pop rdx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_int_to_hex_string -- Convert an integer to a hex string -; IN: RAX = Integer value -; RDI = location to store string -; OUT: All registers preserved -os_int_to_hex_string: - push rdi - push rdx - push rcx - push rbx - push rax - - mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes -os_int_to_hex_string_next_nibble: - rol rax, 4 ; next nibble into AL - mov bl, al ; copy nibble into BL - and rbx, 0x0F ; and convert to word - mov dl, [hextable + rbx] ; lookup ascii numeral - push rax - mov al, dl - stosb - pop rax - loop os_int_to_hex_string_next_nibble ; again for next nibble - xor eax, eax ; clear RAX to 0 - stosb ; Store AL to terminate string - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_hex_string_to_int -- Convert up to 8 hexascii to bin -; IN: RSI = Location of hex asciiz string -; OUT: RAX = binary value of hex string -; All other registers preserved -os_hex_string_to_int: - push rsi - push rcx - push rbx - - cld - xor ebx, ebx -os_hex_string_to_int_loop: - lodsb - mov cl, 4 - cmp al, 'a' - jb os_hex_string_to_int_ok - sub al, 0x20 ; convert to upper case if alpha -os_hex_string_to_int_ok: - sub al, '0' ; check if legal - jc os_hex_string_to_int_exit ; jmp if out of range - cmp al, 9 - jle os_hex_string_to_int_got ; jmp if number is 0-9 - sub al, 7 ; convert to number from A-F or 10-15 - cmp al, 15 ; check if legal - ja os_hex_string_to_int_exit ; jmp if illegal hex char -os_hex_string_to_int_got: - shl rbx, cl - or bl, al - jmp os_hex_string_to_int_loop -os_hex_string_to_int_exit: - mov rax, rbx ; int value stored in RBX, move to RAX - - pop rbx - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_length -- Return length of a string -; IN: RSI = string location -; OUT: RCX = length (not including the NULL terminator) -; All other registers preserved -os_string_length: - push rdi - push rax - - xor ecx, ecx - xor eax, eax - mov rdi, rsi - not rcx - cld - repne scasb ; compare byte at RDI to value in AL - not rcx - dec rcx - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_find_char -- Find first location of character in a string -; IN: RSI = string location -; AL = character to find -; OUT: RAX = location in string, or 0 if char not present -; All other registers preserved -os_string_find_char: - push rsi - push rcx - - mov rcx, 1 ; Counter -- start at first char -os_string_find_char_more: - cmp byte [rsi], al - je os_string_find_char_done - cmp byte [rsi], 0 - je os_string_find_char_not_found - inc rsi - inc rcx - jmp os_string_find_char_more - -os_string_find_char_done: - mov rax, rcx - - pop rcx - pop rsi - ret - -os_string_find_char_not_found: - pop rcx - pop rsi - xor eax, eax ; not found, set RAX to 0 - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_change_char -- Change all instances of a character in a string -; IN: RSI = string location -; AL = character to replace -; BL = replacement character -; OUT: All registers preserved -os_string_change_char: - push rsi - push rcx - push rbx - push rax - - mov cl, al -os_string_change_char_loop: - mov byte al, [rsi] - cmp al, 0 - je os_string_change_char_done - cmp al, cl - jne os_string_change_char_no_change - mov byte [rsi], bl - -os_string_change_char_no_change: - inc rsi - jmp os_string_change_char_loop - -os_string_change_char_done: - pop rax - pop rbx - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_copy -- Copy the contents of one string into another -; IN: RSI = source -; RDI = destination -; OUT: All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_copy: - push rsi - push rdi - push rax - -os_string_copy_more: - lodsb ; Load a character from the source string - stosb - cmp al, 0 ; If source string is empty, quit out - jne os_string_copy_more - - pop rax - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_truncate -- Chop string down to specified number of characters -; IN: RSI = string location -; RAX = number of characters -; OUT: All registers preserved -os_string_truncate: - push rsi - - add rsi, rax - mov byte [rsi], 0x00 - - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_join -- Join two strings into a third string -; IN: RAX = string one -; RBX = string two -; RDI = destination string -; OUT: All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_join: - push rsi - push rdi - push rcx - push rbx - push rax - - mov rsi, rax ; Copy first string to location in RDI - call os_string_copy - call os_string_length ; Get length of first string - add rdi, rcx ; Position at end of first string - mov rsi, rbx ; Add second string onto it - call os_string_copy - - pop rax - pop rbx - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_append -- Append a string to an existing string -; IN: RSI = String to be appended -; RDI = Destination string -; OUT: All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_append: - push rsi - push rdi - push rcx - - xchg rsi, rdi - call os_string_length - xchg rsi, rdi - add rdi, rcx - call os_string_copy - - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_chomp -- Strip leading and trailing spaces from a string -; IN: RSI = string location -; OUT: All registers preserved -os_string_chomp: - push rsi - push rdi - push rcx - push rax - - call os_string_length ; Quick check to see if there are any characters in the string - jrcxz os_string_chomp_done ; No need to work on it if there is no data - - mov rdi, rsi ; RDI will point to the start of the string... - push rdi ; ...while RSI will point to the "actual" start (without the spaces) - add rdi, rcx ; os_string_length stored the length in RCX - -os_string_chomp_findend: ; we start at the end of the string and move backwards until we don't find a space - dec rdi - cmp rsi, rdi ; Check to make sure we are not reading backward past the string start - jg os_string_chomp_fail ; If so then fail (string only contained spaces) - cmp byte [rdi], ' ' - je os_string_chomp_findend - - inc rdi ; we found the real end of the string so null terminate it - mov byte [rdi], 0x00 - pop rdi - -os_string_chomp_start_count: ; read through string until we find a non-space character - cmp byte [rsi], ' ' - jne os_string_chomp_copy - inc rsi - jmp os_string_chomp_start_count - -os_string_chomp_fail: ; In this situataion the string is all spaces - pop rdi ; We are about to bail out so make sure the stack is sane - mov al, 0x00 - stosb - jmp os_string_chomp_done - -; At this point RSI points to the actual start of the string (minus the leading spaces, if any) -; And RDI point to the start of the string - -os_string_chomp_copy: ; Copy a byte from RSI to RDI one byte at a time until we find a NULL - lodsb - stosb - cmp al, 0x00 - jne os_string_chomp_copy - -os_string_chomp_done: - pop rax - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_strip -- Removes specified character from a string -; IN: RSI = string location -; AL = character to remove -; OUT: All registers preserved -os_string_strip: - push rsi - push rdi - push rbx - push rax - - mov rdi, rsi - mov bl, al ; copy the char into BL since LODSB and STOSB use AL -os_string_strip_nextchar: - lodsb - stosb - cmp al, 0x00 ; check if we reached the end of the string - je os_string_strip_done ; if so bail out - cmp al, bl ; check to see if the character we read is the interesting char - jne os_string_strip_nextchar ; if not skip to the next character - -os_string_strip_skip: ; if so the fall through to here - dec rdi ; decrement RDI so we overwrite on the next pass - jmp os_string_strip_nextchar - -os_string_strip_done: - pop rax - pop rbx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_compare -- See if two strings match -; IN: RSI = string one -; RDI = string two -; OUT: Carry flag set if same -os_string_compare: - push rsi - push rdi - push rbx - push rax - -os_string_compare_more: - mov al, [rsi] ; Store string contents - mov bl, [rdi] - cmp al, 0 ; End of first string? - je os_string_compare_terminated - cmp al, bl - jne os_string_compare_not_same - inc rsi - inc rdi - jmp os_string_compare_more - -os_string_compare_not_same: - pop rax - pop rbx - pop rdi - pop rsi - clc - ret - -os_string_compare_terminated: - cmp bl, 0 ; End of second string? - jne os_string_compare_not_same - - pop rax - pop rbx - pop rdi - pop rsi - stc - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_uppercase -- Convert zero-terminated string to uppercase -; IN: RSI = string location -; OUT: All registers preserved -os_string_uppercase: - push rsi - -os_string_uppercase_more: - cmp byte [rsi], 0x00 ; Zero-termination of string? - je os_string_uppercase_done ; If so, quit - cmp byte [rsi], 97 ; In the uppercase A to Z range? - jl os_string_uppercase_noatoz - cmp byte [rsi], 122 - jg os_string_uppercase_noatoz - sub byte [rsi], 0x20 ; If so, convert input char to uppercase - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_noatoz: - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_done: - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_lowercase -- Convert zero-terminated string to lowercase -; IN: RSI = string location -; OUT: All registers preserved -os_string_lowercase: - push rsi - -os_string_lowercase_more: - cmp byte [rsi], 0x00 ; Zero-termination of string? - je os_string_lowercase_done ; If so, quit - cmp byte [rsi], 65 ; In the lowercase A to Z range? - jl os_string_lowercase_noatoz - cmp byte [rsi], 90 - jg os_string_lowercase_noatoz - add byte [rsi], 0x20 ; If so, convert input char to lowercase - inc rsi - jmp os_string_lowercase_more - -os_string_lowercase_noatoz: - inc rsi - jmp os_string_lowercase_more - -os_string_lowercase_done: - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_time_string -- Store the current time in a string in format "HH:MM:SS" -; IN: RDI = location to store string (must be able to fit 9 bytes, 8 data plus null terminator) -; OUT: All registers preserved -os_get_time_string: - push rdi - push rbx - push rax - -os_get_time_string_wait: - mov al, 10 - out 0x70, al - in al, 0x71 - test al, 0x80 ; Is there an update in progress? - jne os_get_time_string_wait ; If so then try again - mov al, 0x04 ; Hours - out 0x70, al - xor eax, eax - in al, 0x71 - cmp al, 9 - jg os_get_time_string_lead_hours - call os_leading_zero -os_get_time_string_lead_hours: - call os_int_to_string - sub rdi, 1 - mov al, ':' - stosb - mov al, 0x02 ; Minutes - out 0x70, al - xor eax, eax - in al, 0x71 - cmp al, 9 - jg os_get_time_string_lead_minutes - call os_leading_zero -os_get_time_string_lead_minutes: - call os_int_to_string - sub rdi, 1 - mov al, ':' - stosb - mov al, 0x00 ; Seconds - out 0x70, al - xor eax, eax - in al, 0x71 - cmp al, 9 - jg os_get_time_string_lead_seconds - call os_leading_zero -os_get_time_string_lead_seconds: - call os_int_to_string - stosb - - pop rax - pop rbx - pop rdi - ret - -os_leading_zero: - push ax - mov al, '0' - stosb - pop ax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_date_string -- Store the current time in a string in format "YYYY/MM/DD" -; IN: RDI = location to store string (must be able to fit 11 bytes, 10 data plus null terminator) -; OUT: All registers preserved -; Note: Uses the os_get_time_string_processor function -os_get_date_string: - push rdi - push rbx - push rax - -os_get_date_string_wait: - mov al, 10 - out 0x70, al - in al, 0x71 - test al, 0x80 ; Is there an update in progress? - jne os_get_date_string_wait ; If so then try again -; mov al, 0x32 ; Century -; out 0x70, al - xor eax, eax -; in al, 0x71 - mov al, 20 - call os_int_to_string - sub rdi, 1 - mov al, 0x09 ; Year - out 0x70, al - xor eax, eax - in al, 0x71 - call os_int_to_string - sub rdi, 1 - mov al, '/' - stosb - mov al, 0x08 ; Month - out 0x70, al - xor eax, eax - in al, 0x71 - call os_int_to_string - sub rdi, 1 - mov al, '/' - stosb - mov al, 0x07 ; Day - out 0x70, al - xor eax, eax - in al, 0x71 - call os_int_to_string -; sub rdi, 1 -; mov al, 0x00 ; Terminate the string - stosb - - pop rax - pop rbx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_is_digit -- Check if character is a digit -; IN: AL = ASCII char -; OUT: EQ flag set if numeric -; Note: JE (Jump if Equal) can be used after this function is called -os_is_digit: - cmp al, '0' - jb os_is_digit_not_digit - cmp al, '9' - ja os_is_digit_not_digit - cmp al, al ; To set the equal flag - -os_is_digit_not_digit: - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_is_alpha -- Check if character is a letter -; IN: AL = ASCII char -; OUT: EQ flag set if alpha -; Note: JE (Jump if Equal) can be used after this function is called -os_is_alpha: - cmp al, ' ' - jb os_is_alpha_not_alpha - cmp al, 0x7E - ja os_is_alpha_not_alpha - cmp al, al ; To set the equal flag - -os_is_alpha_not_alpha: - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_parse -- Parse a string into individual words -; IN: RSI = Address of string -; OUT: RCX = word count -; Note: This function will remove "extra" whitespace in the source string -; "This is a test. " will update to "This is a test." -os_string_parse: - push rsi - push rdi - push rax - - xor ecx, ecx ; RCX is our word counter - mov rdi, rsi - - call os_string_chomp ; Remove leading and trailing spaces - - cmp byte [rsi], 0x00 ; Check the first byte - je os_string_parse_done ; If it is a null then bail out - inc rcx ; At this point we know we have at least one word - -os_string_parse_next_char: - lodsb - stosb - cmp al, 0x00 ; Check if we are at the end - je os_string_parse_done ; If so then bail out - cmp al, ' ' ; Is it a space? - je os_string_parse_found_a_space - jmp os_string_parse_next_char ; If not then grab the next char - -os_string_parse_found_a_space: - lodsb ; We found a space.. grab the next char - cmp al, ' ' ; Is it a space as well? - jne os_string_parse_no_more_spaces - jmp os_string_parse_found_a_space - -os_string_parse_no_more_spaces: - dec rsi ; Decrement so the next lodsb will read in the non-space - inc rcx - jmp os_string_parse_next_char - -os_string_parse_done: - pop rax - pop rdi - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; String Functions +; ============================================================================= + +align 16 +db 'DEBUG: STRING ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_int_to_string -- Convert a binary interger into an string +; IN: RAX = binary integer +; RDI = location to store string +; OUT: RDI = points to end of string +; All other registers preserved +; Min return value is 0 and max return value is 18446744073709551615 so your +; string needs to be able to store at least 21 characters (20 for the digits +; and 1 for the string terminator). +; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s +os_int_to_string: + push rdx + push rcx + push rbx + push rax + + mov rbx, 10 ; base of the decimal system + xor ecx, ecx ; number of digits generated +os_int_to_string_next_divide: + xor edx, edx ; RAX extended to (RDX,RAX) + div rbx ; divide by the number-base + push rdx ; save remainder on the stack + inc rcx ; and count this remainder + cmp rax, 0 ; was the quotient zero? + jne os_int_to_string_next_divide ; no, do another division + +os_int_to_string_next_digit: + pop rax ; else pop recent remainder + add al, '0' ; and convert to a numeral + stosb ; store to memory-buffer + loop os_int_to_string_next_digit ; again for other remainders + xor al, al + stosb ; Store the null terminator at the end of the string + + pop rax + pop rbx + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_to_int -- Convert a string into a binary interger +; IN: RSI = location of string +; OUT: RAX = integer value +; All other registers preserved +; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/uint2rax.s +os_string_to_int: + push rsi + push rdx + push rcx + push rbx + + xor eax, eax ; initialize accumulator + mov rbx, 10 ; decimal-system's radix +os_string_to_int_next_digit: + mov cl, [rsi] ; fetch next character + cmp cl, '0' ; char preceeds '0'? + jb os_string_to_int_invalid ; yes, not a numeral + cmp cl, '9' ; char follows '9'? + ja os_string_to_int_invalid ; yes, not a numeral + mul rbx ; ten times prior sum + and rcx, 0x0F ; convert char to int + add rax, rcx ; add to prior total + inc rsi ; advance source index + jmp os_string_to_int_next_digit ; and check another char + +os_string_to_int_invalid: + pop rbx + pop rcx + pop rdx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_int_to_hex_string -- Convert an integer to a hex string +; IN: RAX = Integer value +; RDI = location to store string +; OUT: All registers preserved +os_int_to_hex_string: + push rdi + push rdx + push rcx + push rbx + push rax + + mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes +os_int_to_hex_string_next_nibble: + rol rax, 4 ; next nibble into AL + mov bl, al ; copy nibble into BL + and rbx, 0x0F ; and convert to word + mov dl, [hextable + rbx] ; lookup ascii numeral + push rax + mov al, dl + stosb + pop rax + loop os_int_to_hex_string_next_nibble ; again for next nibble + xor eax, eax ; clear RAX to 0 + stosb ; Store AL to terminate string + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_hex_string_to_int -- Convert up to 8 hexascii to bin +; IN: RSI = Location of hex asciiz string +; OUT: RAX = binary value of hex string +; All other registers preserved +os_hex_string_to_int: + push rsi + push rcx + push rbx + + cld + xor ebx, ebx +os_hex_string_to_int_loop: + lodsb + mov cl, 4 + cmp al, 'a' + jb os_hex_string_to_int_ok + sub al, 0x20 ; convert to upper case if alpha +os_hex_string_to_int_ok: + sub al, '0' ; check if legal + jc os_hex_string_to_int_exit ; jmp if out of range + cmp al, 9 + jle os_hex_string_to_int_got ; jmp if number is 0-9 + sub al, 7 ; convert to number from A-F or 10-15 + cmp al, 15 ; check if legal + ja os_hex_string_to_int_exit ; jmp if illegal hex char +os_hex_string_to_int_got: + shl rbx, cl + or bl, al + jmp os_hex_string_to_int_loop +os_hex_string_to_int_exit: + mov rax, rbx ; int value stored in RBX, move to RAX + + pop rbx + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_length -- Return length of a string +; IN: RSI = string location +; OUT: RCX = length (not including the NULL terminator) +; All other registers preserved +os_string_length: + push rdi + push rax + + xor ecx, ecx + xor eax, eax + mov rdi, rsi + not rcx + cld + repne scasb ; compare byte at RDI to value in AL + not rcx + dec rcx + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_find_char -- Find first location of character in a string +; IN: RSI = string location +; AL = character to find +; OUT: RAX = location in string, or 0 if char not present +; All other registers preserved +os_string_find_char: + push rsi + push rcx + + mov rcx, 1 ; Counter -- start at first char +os_string_find_char_more: + cmp byte [rsi], al + je os_string_find_char_done + cmp byte [rsi], 0 + je os_string_find_char_not_found + inc rsi + inc rcx + jmp os_string_find_char_more + +os_string_find_char_done: + mov rax, rcx + + pop rcx + pop rsi + ret + +os_string_find_char_not_found: + pop rcx + pop rsi + xor eax, eax ; not found, set RAX to 0 + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_change_char -- Change all instances of a character in a string +; IN: RSI = string location +; AL = character to replace +; BL = replacement character +; OUT: All registers preserved +os_string_change_char: + push rsi + push rcx + push rbx + push rax + + mov cl, al +os_string_change_char_loop: + mov byte al, [rsi] + cmp al, 0 + je os_string_change_char_done + cmp al, cl + jne os_string_change_char_no_change + mov byte [rsi], bl + +os_string_change_char_no_change: + inc rsi + jmp os_string_change_char_loop + +os_string_change_char_done: + pop rax + pop rbx + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_copy -- Copy the contents of one string into another +; IN: RSI = source +; RDI = destination +; OUT: All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_copy: + push rsi + push rdi + push rax + +os_string_copy_more: + lodsb ; Load a character from the source string + stosb + cmp al, 0 ; If source string is empty, quit out + jne os_string_copy_more + + pop rax + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_truncate -- Chop string down to specified number of characters +; IN: RSI = string location +; RAX = number of characters +; OUT: All registers preserved +os_string_truncate: + push rsi + + add rsi, rax + mov byte [rsi], 0x00 + + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_join -- Join two strings into a third string +; IN: RAX = string one +; RBX = string two +; RDI = destination string +; OUT: All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_join: + push rsi + push rdi + push rcx + push rbx + push rax + + mov rsi, rax ; Copy first string to location in RDI + call os_string_copy + call os_string_length ; Get length of first string + add rdi, rcx ; Position at end of first string + mov rsi, rbx ; Add second string onto it + call os_string_copy + + pop rax + pop rbx + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_append -- Append a string to an existing string +; IN: RSI = String to be appended +; RDI = Destination string +; OUT: All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_append: + push rsi + push rdi + push rcx + + xchg rsi, rdi + call os_string_length + xchg rsi, rdi + add rdi, rcx + call os_string_copy + + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_chomp -- Strip leading and trailing spaces from a string +; IN: RSI = string location +; OUT: All registers preserved +os_string_chomp: + push rsi + push rdi + push rcx + push rax + + call os_string_length ; Quick check to see if there are any characters in the string + jrcxz os_string_chomp_done ; No need to work on it if there is no data + + mov rdi, rsi ; RDI will point to the start of the string... + push rdi ; ...while RSI will point to the "actual" start (without the spaces) + add rdi, rcx ; os_string_length stored the length in RCX + +os_string_chomp_findend: ; we start at the end of the string and move backwards until we don't find a space + dec rdi + cmp rsi, rdi ; Check to make sure we are not reading backward past the string start + jg os_string_chomp_fail ; If so then fail (string only contained spaces) + cmp byte [rdi], ' ' + je os_string_chomp_findend + + inc rdi ; we found the real end of the string so null terminate it + mov byte [rdi], 0x00 + pop rdi + +os_string_chomp_start_count: ; read through string until we find a non-space character + cmp byte [rsi], ' ' + jne os_string_chomp_copy + inc rsi + jmp os_string_chomp_start_count + +os_string_chomp_fail: ; In this situataion the string is all spaces + pop rdi ; We are about to bail out so make sure the stack is sane + mov al, 0x00 + stosb + jmp os_string_chomp_done + +; At this point RSI points to the actual start of the string (minus the leading spaces, if any) +; And RDI point to the start of the string + +os_string_chomp_copy: ; Copy a byte from RSI to RDI one byte at a time until we find a NULL + lodsb + stosb + cmp al, 0x00 + jne os_string_chomp_copy + +os_string_chomp_done: + pop rax + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_strip -- Removes specified character from a string +; IN: RSI = string location +; AL = character to remove +; OUT: All registers preserved +os_string_strip: + push rsi + push rdi + push rbx + push rax + + mov rdi, rsi + mov bl, al ; copy the char into BL since LODSB and STOSB use AL +os_string_strip_nextchar: + lodsb + stosb + cmp al, 0x00 ; check if we reached the end of the string + je os_string_strip_done ; if so bail out + cmp al, bl ; check to see if the character we read is the interesting char + jne os_string_strip_nextchar ; if not skip to the next character + +os_string_strip_skip: ; if so the fall through to here + dec rdi ; decrement RDI so we overwrite on the next pass + jmp os_string_strip_nextchar + +os_string_strip_done: + pop rax + pop rbx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_compare -- See if two strings match +; IN: RSI = string one +; RDI = string two +; OUT: Carry flag set if same +os_string_compare: + push rsi + push rdi + push rbx + push rax + +os_string_compare_more: + mov al, [rsi] ; Store string contents + mov bl, [rdi] + cmp al, 0 ; End of first string? + je os_string_compare_terminated + cmp al, bl + jne os_string_compare_not_same + inc rsi + inc rdi + jmp os_string_compare_more + +os_string_compare_not_same: + pop rax + pop rbx + pop rdi + pop rsi + clc + ret + +os_string_compare_terminated: + cmp bl, 0 ; End of second string? + jne os_string_compare_not_same + + pop rax + pop rbx + pop rdi + pop rsi + stc + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_uppercase -- Convert zero-terminated string to uppercase +; IN: RSI = string location +; OUT: All registers preserved +os_string_uppercase: + push rsi + +os_string_uppercase_more: + cmp byte [rsi], 0x00 ; Zero-termination of string? + je os_string_uppercase_done ; If so, quit + cmp byte [rsi], 97 ; In the uppercase A to Z range? + jl os_string_uppercase_noatoz + cmp byte [rsi], 122 + jg os_string_uppercase_noatoz + sub byte [rsi], 0x20 ; If so, convert input char to uppercase + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_noatoz: + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_done: + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_lowercase -- Convert zero-terminated string to lowercase +; IN: RSI = string location +; OUT: All registers preserved +os_string_lowercase: + push rsi + +os_string_lowercase_more: + cmp byte [rsi], 0x00 ; Zero-termination of string? + je os_string_lowercase_done ; If so, quit + cmp byte [rsi], 65 ; In the lowercase A to Z range? + jl os_string_lowercase_noatoz + cmp byte [rsi], 90 + jg os_string_lowercase_noatoz + add byte [rsi], 0x20 ; If so, convert input char to lowercase + inc rsi + jmp os_string_lowercase_more + +os_string_lowercase_noatoz: + inc rsi + jmp os_string_lowercase_more + +os_string_lowercase_done: + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_time_string -- Store the current time in a string in format "HH:MM:SS" +; IN: RDI = location to store string (must be able to fit 9 bytes, 8 data plus null terminator) +; OUT: All registers preserved +os_get_time_string: + push rdi + push rbx + push rax + +os_get_time_string_wait: + mov al, 10 + out 0x70, al + in al, 0x71 + test al, 0x80 ; Is there an update in progress? + jne os_get_time_string_wait ; If so then try again + mov al, 0x04 ; Hours + out 0x70, al + xor eax, eax + in al, 0x71 + cmp al, 9 + jg os_get_time_string_lead_hours + call os_leading_zero +os_get_time_string_lead_hours: + call os_int_to_string + sub rdi, 1 + mov al, ':' + stosb + mov al, 0x02 ; Minutes + out 0x70, al + xor eax, eax + in al, 0x71 + cmp al, 9 + jg os_get_time_string_lead_minutes + call os_leading_zero +os_get_time_string_lead_minutes: + call os_int_to_string + sub rdi, 1 + mov al, ':' + stosb + mov al, 0x00 ; Seconds + out 0x70, al + xor eax, eax + in al, 0x71 + cmp al, 9 + jg os_get_time_string_lead_seconds + call os_leading_zero +os_get_time_string_lead_seconds: + call os_int_to_string + stosb + + pop rax + pop rbx + pop rdi + ret + +os_leading_zero: + push ax + mov al, '0' + stosb + pop ax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_date_string -- Store the current time in a string in format "YYYY/MM/DD" +; IN: RDI = location to store string (must be able to fit 11 bytes, 10 data plus null terminator) +; OUT: All registers preserved +; Note: Uses the os_get_time_string_processor function +os_get_date_string: + push rdi + push rbx + push rax + +os_get_date_string_wait: + mov al, 10 + out 0x70, al + in al, 0x71 + test al, 0x80 ; Is there an update in progress? + jne os_get_date_string_wait ; If so then try again +; mov al, 0x32 ; Century +; out 0x70, al + xor eax, eax +; in al, 0x71 + mov al, 20 + call os_int_to_string + sub rdi, 1 + mov al, 0x09 ; Year + out 0x70, al + xor eax, eax + in al, 0x71 + call os_int_to_string + sub rdi, 1 + mov al, '/' + stosb + mov al, 0x08 ; Month + out 0x70, al + xor eax, eax + in al, 0x71 + call os_int_to_string + sub rdi, 1 + mov al, '/' + stosb + mov al, 0x07 ; Day + out 0x70, al + xor eax, eax + in al, 0x71 + call os_int_to_string +; sub rdi, 1 +; mov al, 0x00 ; Terminate the string + stosb + + pop rax + pop rbx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_is_digit -- Check if character is a digit +; IN: AL = ASCII char +; OUT: EQ flag set if numeric +; Note: JE (Jump if Equal) can be used after this function is called +os_is_digit: + cmp al, '0' + jb os_is_digit_not_digit + cmp al, '9' + ja os_is_digit_not_digit + cmp al, al ; To set the equal flag + +os_is_digit_not_digit: + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_is_alpha -- Check if character is a letter +; IN: AL = ASCII char +; OUT: EQ flag set if alpha +; Note: JE (Jump if Equal) can be used after this function is called +os_is_alpha: + cmp al, ' ' + jb os_is_alpha_not_alpha + cmp al, 0x7E + ja os_is_alpha_not_alpha + cmp al, al ; To set the equal flag + +os_is_alpha_not_alpha: + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_parse -- Parse a string into individual words +; IN: RSI = Address of string +; OUT: RCX = word count +; Note: This function will remove "extra" whitespace in the source string +; "This is a test. " will update to "This is a test." +os_string_parse: + push rsi + push rdi + push rax + + xor ecx, ecx ; RCX is our word counter + mov rdi, rsi + + call os_string_chomp ; Remove leading and trailing spaces + + cmp byte [rsi], 0x00 ; Check the first byte + je os_string_parse_done ; If it is a null then bail out + inc rcx ; At this point we know we have at least one word + +os_string_parse_next_char: + lodsb + stosb + cmp al, 0x00 ; Check if we are at the end + je os_string_parse_done ; If so then bail out + cmp al, ' ' ; Is it a space? + je os_string_parse_found_a_space + jmp os_string_parse_next_char ; If not then grab the next char + +os_string_parse_found_a_space: + lodsb ; We found a space.. grab the next char + cmp al, ' ' ; Is it a space as well? + jne os_string_parse_no_more_spaces + jmp os_string_parse_found_a_space + +os_string_parse_no_more_spaces: + dec rsi ; Decrement so the next lodsb will read in the non-space + inc rcx + jmp os_string_parse_next_char + +os_string_parse_done: + pop rax + pop rdi + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/sysvar.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/sysvar.asm index eef41e2a..662f99c3 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/sysvar.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/os/sysvar.asm @@ -1,181 +1,181 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; System Variables -; ============================================================================= - -align 16 -db 'DEBUG: SYSVAR ' -align 16 - -; Constants -hextable: db '0123456789ABCDEF' - -; Strings -system_status_header: db 'BareMetal v0.5.2', 0 -readymsg: db 'BareMetal is ready.', 0 -networkmsg: db 'Network Address: ', 0 -prompt: db '> ', 0 -space: db ' ', 0 -newline: db 13, 0 -appextension: db '.APP', 0 -memory_message: db 'Not enough system memory for CPU stacks! System halted.', 0 -startupapp: db 'startup.app', 0 - -; Memory addresses -hdbuffer0: equ 0x0000000000070000 ; 32768 bytes 0x070000 -> 0x077FFF -hdbuffer1: equ 0x0000000000078000 ; 32768 bytes 0x078000 -> 0x07FFFF -cli_temp_string: equ 0x0000000000080000 ; 1024 bytes 0x080000 -> 0x0803FF -os_temp_string: equ 0x0000000000080400 ; 1024 bytes 0x080400 -> 0x0807FF -secbuffer0: equ 0x0000000000080800 ; 512 bytes 0x080800 -> 0x0809FF -secbuffer1: equ 0x0000000000080A00 ; 512 bytes 0x080A00 -> 0x080BFF -os_KernelStart: equ 0x0000000000100000 ; 65536 bytes 0x100000 -> 0x10FFFF - Location of Kernel -os_SystemVariables: equ 0x0000000000110000 ; 65536 bytes 0x110000 -> 0x11FFFF - Location of System Variables -os_MemoryMap: equ 0x0000000000120000 ; 131072 bytes 0x120000 -> 0x13FFFF - Location of Memory Map - Room to map 256 GiB with 2 MiB pages -os_EthernetBuffer: equ 0x0000000000140000 ; 262144 bytes 0x140000 -> 0x17FFFF - Location of Ethernet RX Ring Buffer - Room for 170 packets -os_screen: equ 0x0000000000180000 ; 4096 bytes 80x25x2 = 4000 -os_ethernet_rx_buffer: equ 0x00000000001C0000 -os_eth_rx_buffer: equ 0x00000000001C8000 -os_ethernet_tx_buffer: equ 0x00000000001D0000 -os_eth_tx_buffer: equ 0x00000000001D8000 -os_eth_temp_buffer: equ 0x00000000001E0000 -cpustatus: equ 0x00000000001FEF00 ; Location of CPU status data (256 bytes) Bit 0 = Avaiable, Bit 1 = Free/Busy -cpuqueue: equ 0x00000000001FF000 ; Location of CPU Queue. Each queue item is 16 bytes. (4KiB before the 2MiB mark, Room for 256 entries) -programlocation: equ 0x0000000000200000 ; Location in memory where programs are loaded (the start of 2MiB) - -; DQ - Starting at offset 0, increments by 0x8 -os_LocalAPICAddress: equ os_SystemVariables + 0x00 -os_IOAPICAddress: equ os_SystemVariables + 0x08 -os_ClockCounter: equ os_SystemVariables + 0x10 -os_RandomSeed: equ os_SystemVariables + 0x18 ; Seed for RNG -screen_cursor_offset: equ os_SystemVariables + 0x20 -hd1_maxlba: equ os_SystemVariables + 0x28 ; 64-bit value since at most it will hold a 48-bit value -os_StackBase: equ os_SystemVariables + 0x30 -os_net_transmit: equ os_SystemVariables + 0x38 -os_net_poll: equ os_SystemVariables + 0x40 -os_net_ack_int: equ os_SystemVariables + 0x48 -os_NetIOBaseMem: equ os_SystemVariables + 0x50 -os_NetMAC: equ os_SystemVariables + 0x58 - -; DD - Starting at offset 128, increments by 4 -cpu_speed: equ os_SystemVariables + 128 ; in MHz -hd1_size: equ os_SystemVariables + 132 ; Size in MiB -ip: equ os_SystemVariables + 136 ; IPv4 Address -sn: equ os_SystemVariables + 140 ; IPv4 Subnet -gw: equ os_SystemVariables + 144 ; IPv4 Gateway - -; DW - Starting at offset 256, increments by 2 -os_MemAmount: equ os_SystemVariables + 256 ; in MiB -os_NumCores: equ os_SystemVariables + 258 -cpuqueuestart: equ os_SystemVariables + 260 -cpuqueuefinish: equ os_SystemVariables + 262 -os_QueueLen: equ os_SystemVariables + 264 -os_QueueLock: equ os_SystemVariables + 266 ; Bit 0 clear for unlocked, set for locked. -os_NetIOAddress: equ os_SystemVariables + 268 -os_EthernetBusyLock: equ os_SystemVariables + 270 - -; DB - Starting at offset 384, increments by 1 -cursorx: equ os_SystemVariables + 384 ; cursor row location -cursory: equ os_SystemVariables + 385 ; cursor column location -scancode: equ os_SystemVariables + 386 -key: equ os_SystemVariables + 387 -key_shift: equ os_SystemVariables + 388 -screen_cursor_x: equ os_SystemVariables + 389 -screen_cursor_y: equ os_SystemVariables + 390 -hd1_enable: equ os_SystemVariables + 391 ; 1 if the drive is there and enabled -hd1_lba48: equ os_SystemVariables + 392 ; 1 if LBA48 is allowed -os_PCIEnabled: equ os_SystemVariables + 393 ; 1 if PCI is detected -os_NetEnabled: equ os_SystemVariables + 394 ; 1 if a supported network card was enabled -os_NetIRQ: equ os_SystemVariables + 395 ; Set to Interrupt line that NIC is connected to -os_NetActivity_TX: equ os_SystemVariables + 396 -os_NetActivity_RX: equ os_SystemVariables + 397 -os_EthernetBuffer_C1: equ os_SystemVariables + 398 ; Counter 1 for the Ethernet RX Ring Buffer -os_EthernetBuffer_C2: equ os_SystemVariables + 399 ; Counter 2 for the Ethernet RX Ring Buffer - - -cpuqueuemax: dw 256 -screen_rows: db 25 ; x -screen_cols: db 80 ; y -os_show_sysstatus: db 1 - -; Function variables -os_debug_dump_reg_stage: db 0x00 - -; File System -fat16_FatStart: dd 0x00000000 -fat16_TotalSectors: dd 0x00000000 -fat16_DataStart: dd 0x00000000 -fat16_RootStart: dd 0x00000000 -fat16_PartitionOffset: dd 0x00000000 -fat16_ReservedSectors: dw 0x0000 -fat16_RootDirEnts: dw 0x0000 -fat16_SectorsPerFat: dw 0x0000 -fat16_BytesPerSector: dw 0x0000 -fat16_SectorsPerCluster: db 0x00 -fat16_Fats: db 0x00 - - -keylayoutlower: -db 0x00, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x0e, 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x1c, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 0, '`', 0, 0, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, ' ', 0 -keylayoutupper: -db 0x00, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x0e, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0x1c, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 0, '~', 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, ' ', 0 -; 0e = backspace -; 1c = enter - -palette: ; These colors are in RGB format. Each color byte is actually 6 bits (0x00 - 0x3F) -db 0x00, 0x00, 0x00 ; 0 Black -db 0x33, 0x00, 0x00 ; 1 Red -db 0x0F, 0x26, 0x01 ; 2 Green -db 0x0D, 0x19, 0x29 ; 3 Blue -db 0x31, 0x28, 0x00 ; 4 Orange -db 0x1D, 0x14, 0x1E ; 5 Purple -db 0x01, 0x26, 0x26 ; 6 Teal -db 0x2A, 0x2A, 0x2A ; 7 Light Gray -db 0x15, 0x15, 0x15 ; 8 Dark Gray -db 0x3B, 0x0A, 0x0A ; 9 Bright Red -db 0x22, 0x38, 0x0D ; 10 Bright Green -db 0x1C, 0x27, 0x33 ; 11 Bright Blue -db 0x3F, 0x3A, 0x13 ; 12 Yellow -db 0x2B, 0x1F, 0x2A ; 13 Bright Purple -db 0x0D, 0x38, 0x38 ; 14 Bright Teal -db 0x3F, 0x3F, 0x3F ; 15 White - - -os_debug_dump_reg_string00: db ' A:', 0 -os_debug_dump_reg_string01: db ' B:', 0 -os_debug_dump_reg_string02: db ' C:', 0 -os_debug_dump_reg_string03: db ' D:', 0 -os_debug_dump_reg_string04: db ' SI:', 0 -os_debug_dump_reg_string05: db ' DI:', 0 -os_debug_dump_reg_string06: db ' BP:', 0 -os_debug_dump_reg_string07: db ' SP:', 0 -os_debug_dump_reg_string08: db ' 8:', 0 -os_debug_dump_reg_string09: db ' 9:', 0 -os_debug_dump_reg_string0A: db ' 10:', 0 -os_debug_dump_reg_string0B: db ' 11:', 0 -os_debug_dump_reg_string0C: db ' 12:', 0 -os_debug_dump_reg_string0D: db ' 13:', 0 -os_debug_dump_reg_string0E: db ' 14:', 0 -os_debug_dump_reg_string0F: db ' 15:', 0 -os_debug_dump_reg_string10: db ' RF:', 0 - -os_debug_dump_flag_string0: db ' C:', 0 -os_debug_dump_flag_string1: db ' Z:', 0 -os_debug_dump_flag_string2: db ' S:', 0 -os_debug_dump_flag_string3: db ' D:', 0 -os_debug_dump_flag_string4: db ' O:', 0 - - -cli_command_string: times 14 db 0 -cli_args: db 0 - -align 16 -this_is_the_end: db 'This is the end.' - -;------------------------------------------------------------------------------ - -SYS64_CODE_SEL equ 8 ; defined by Pure64 - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; System Variables +; ============================================================================= + +align 16 +db 'DEBUG: SYSVAR ' +align 16 + +; Constants +hextable: db '0123456789ABCDEF' + +; Strings +system_status_header: db 'BareMetal v0.5.2', 0 +readymsg: db 'BareMetal is ready.', 0 +networkmsg: db 'Network Address: ', 0 +prompt: db '> ', 0 +space: db ' ', 0 +newline: db 13, 0 +appextension: db '.APP', 0 +memory_message: db 'Not enough system memory for CPU stacks! System halted.', 0 +startupapp: db 'startup.app', 0 + +; Memory addresses +hdbuffer0: equ 0x0000000000070000 ; 32768 bytes 0x070000 -> 0x077FFF +hdbuffer1: equ 0x0000000000078000 ; 32768 bytes 0x078000 -> 0x07FFFF +cli_temp_string: equ 0x0000000000080000 ; 1024 bytes 0x080000 -> 0x0803FF +os_temp_string: equ 0x0000000000080400 ; 1024 bytes 0x080400 -> 0x0807FF +secbuffer0: equ 0x0000000000080800 ; 512 bytes 0x080800 -> 0x0809FF +secbuffer1: equ 0x0000000000080A00 ; 512 bytes 0x080A00 -> 0x080BFF +os_KernelStart: equ 0x0000000000100000 ; 65536 bytes 0x100000 -> 0x10FFFF - Location of Kernel +os_SystemVariables: equ 0x0000000000110000 ; 65536 bytes 0x110000 -> 0x11FFFF - Location of System Variables +os_MemoryMap: equ 0x0000000000120000 ; 131072 bytes 0x120000 -> 0x13FFFF - Location of Memory Map - Room to map 256 GiB with 2 MiB pages +os_EthernetBuffer: equ 0x0000000000140000 ; 262144 bytes 0x140000 -> 0x17FFFF - Location of Ethernet RX Ring Buffer - Room for 170 packets +os_screen: equ 0x0000000000180000 ; 4096 bytes 80x25x2 = 4000 +os_ethernet_rx_buffer: equ 0x00000000001C0000 +os_eth_rx_buffer: equ 0x00000000001C8000 +os_ethernet_tx_buffer: equ 0x00000000001D0000 +os_eth_tx_buffer: equ 0x00000000001D8000 +os_eth_temp_buffer: equ 0x00000000001E0000 +cpustatus: equ 0x00000000001FEF00 ; Location of CPU status data (256 bytes) Bit 0 = Avaiable, Bit 1 = Free/Busy +cpuqueue: equ 0x00000000001FF000 ; Location of CPU Queue. Each queue item is 16 bytes. (4KiB before the 2MiB mark, Room for 256 entries) +programlocation: equ 0x0000000000200000 ; Location in memory where programs are loaded (the start of 2MiB) + +; DQ - Starting at offset 0, increments by 0x8 +os_LocalAPICAddress: equ os_SystemVariables + 0x00 +os_IOAPICAddress: equ os_SystemVariables + 0x08 +os_ClockCounter: equ os_SystemVariables + 0x10 +os_RandomSeed: equ os_SystemVariables + 0x18 ; Seed for RNG +screen_cursor_offset: equ os_SystemVariables + 0x20 +hd1_maxlba: equ os_SystemVariables + 0x28 ; 64-bit value since at most it will hold a 48-bit value +os_StackBase: equ os_SystemVariables + 0x30 +os_net_transmit: equ os_SystemVariables + 0x38 +os_net_poll: equ os_SystemVariables + 0x40 +os_net_ack_int: equ os_SystemVariables + 0x48 +os_NetIOBaseMem: equ os_SystemVariables + 0x50 +os_NetMAC: equ os_SystemVariables + 0x58 + +; DD - Starting at offset 128, increments by 4 +cpu_speed: equ os_SystemVariables + 128 ; in MHz +hd1_size: equ os_SystemVariables + 132 ; Size in MiB +ip: equ os_SystemVariables + 136 ; IPv4 Address +sn: equ os_SystemVariables + 140 ; IPv4 Subnet +gw: equ os_SystemVariables + 144 ; IPv4 Gateway + +; DW - Starting at offset 256, increments by 2 +os_MemAmount: equ os_SystemVariables + 256 ; in MiB +os_NumCores: equ os_SystemVariables + 258 +cpuqueuestart: equ os_SystemVariables + 260 +cpuqueuefinish: equ os_SystemVariables + 262 +os_QueueLen: equ os_SystemVariables + 264 +os_QueueLock: equ os_SystemVariables + 266 ; Bit 0 clear for unlocked, set for locked. +os_NetIOAddress: equ os_SystemVariables + 268 +os_EthernetBusyLock: equ os_SystemVariables + 270 + +; DB - Starting at offset 384, increments by 1 +cursorx: equ os_SystemVariables + 384 ; cursor row location +cursory: equ os_SystemVariables + 385 ; cursor column location +scancode: equ os_SystemVariables + 386 +key: equ os_SystemVariables + 387 +key_shift: equ os_SystemVariables + 388 +screen_cursor_x: equ os_SystemVariables + 389 +screen_cursor_y: equ os_SystemVariables + 390 +hd1_enable: equ os_SystemVariables + 391 ; 1 if the drive is there and enabled +hd1_lba48: equ os_SystemVariables + 392 ; 1 if LBA48 is allowed +os_PCIEnabled: equ os_SystemVariables + 393 ; 1 if PCI is detected +os_NetEnabled: equ os_SystemVariables + 394 ; 1 if a supported network card was enabled +os_NetIRQ: equ os_SystemVariables + 395 ; Set to Interrupt line that NIC is connected to +os_NetActivity_TX: equ os_SystemVariables + 396 +os_NetActivity_RX: equ os_SystemVariables + 397 +os_EthernetBuffer_C1: equ os_SystemVariables + 398 ; Counter 1 for the Ethernet RX Ring Buffer +os_EthernetBuffer_C2: equ os_SystemVariables + 399 ; Counter 2 for the Ethernet RX Ring Buffer + + +cpuqueuemax: dw 256 +screen_rows: db 25 ; x +screen_cols: db 80 ; y +os_show_sysstatus: db 1 + +; Function variables +os_debug_dump_reg_stage: db 0x00 + +; File System +fat16_FatStart: dd 0x00000000 +fat16_TotalSectors: dd 0x00000000 +fat16_DataStart: dd 0x00000000 +fat16_RootStart: dd 0x00000000 +fat16_PartitionOffset: dd 0x00000000 +fat16_ReservedSectors: dw 0x0000 +fat16_RootDirEnts: dw 0x0000 +fat16_SectorsPerFat: dw 0x0000 +fat16_BytesPerSector: dw 0x0000 +fat16_SectorsPerCluster: db 0x00 +fat16_Fats: db 0x00 + + +keylayoutlower: +db 0x00, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x0e, 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x1c, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 0, '`', 0, 0, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, ' ', 0 +keylayoutupper: +db 0x00, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x0e, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0x1c, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 0, '~', 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, ' ', 0 +; 0e = backspace +; 1c = enter + +palette: ; These colors are in RGB format. Each color byte is actually 6 bits (0x00 - 0x3F) +db 0x00, 0x00, 0x00 ; 0 Black +db 0x33, 0x00, 0x00 ; 1 Red +db 0x0F, 0x26, 0x01 ; 2 Green +db 0x0D, 0x19, 0x29 ; 3 Blue +db 0x31, 0x28, 0x00 ; 4 Orange +db 0x1D, 0x14, 0x1E ; 5 Purple +db 0x01, 0x26, 0x26 ; 6 Teal +db 0x2A, 0x2A, 0x2A ; 7 Light Gray +db 0x15, 0x15, 0x15 ; 8 Dark Gray +db 0x3B, 0x0A, 0x0A ; 9 Bright Red +db 0x22, 0x38, 0x0D ; 10 Bright Green +db 0x1C, 0x27, 0x33 ; 11 Bright Blue +db 0x3F, 0x3A, 0x13 ; 12 Yellow +db 0x2B, 0x1F, 0x2A ; 13 Bright Purple +db 0x0D, 0x38, 0x38 ; 14 Bright Teal +db 0x3F, 0x3F, 0x3F ; 15 White + + +os_debug_dump_reg_string00: db ' A:', 0 +os_debug_dump_reg_string01: db ' B:', 0 +os_debug_dump_reg_string02: db ' C:', 0 +os_debug_dump_reg_string03: db ' D:', 0 +os_debug_dump_reg_string04: db ' SI:', 0 +os_debug_dump_reg_string05: db ' DI:', 0 +os_debug_dump_reg_string06: db ' BP:', 0 +os_debug_dump_reg_string07: db ' SP:', 0 +os_debug_dump_reg_string08: db ' 8:', 0 +os_debug_dump_reg_string09: db ' 9:', 0 +os_debug_dump_reg_string0A: db ' 10:', 0 +os_debug_dump_reg_string0B: db ' 11:', 0 +os_debug_dump_reg_string0C: db ' 12:', 0 +os_debug_dump_reg_string0D: db ' 13:', 0 +os_debug_dump_reg_string0E: db ' 14:', 0 +os_debug_dump_reg_string0F: db ' 15:', 0 +os_debug_dump_reg_string10: db ' RF:', 0 + +os_debug_dump_flag_string0: db ' C:', 0 +os_debug_dump_flag_string1: db ' Z:', 0 +os_debug_dump_flag_string2: db ' S:', 0 +os_debug_dump_flag_string3: db ' D:', 0 +os_debug_dump_flag_string4: db ' O:', 0 + + +cli_command_string: times 14 db 0 +cli_args: db 0 + +align 16 +this_is_the_end: db 'This is the end.' + +;------------------------------------------------------------------------------ + +SYS64_CODE_SEL equ 8 ; defined by Pure64 + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/argtest.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/argtest.asm index cbb8588b..f9abf388 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/argtest.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/argtest.asm @@ -1,35 +1,35 @@ -; Argument Test Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm argtest.asm -o argtest.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - call b_get_argc ; Get the number of arguments that were passed - cmp al, 1 ; Was the number 1? - je noargs ; If so then bail out. The first argument is the program name - mov rsi, hello_message ; Load RSI with memory address of string - call b_print_string ; Print the string that RSI points to - mov al, 1 ; Argument values start at 0 so we want the second one - call b_get_argv ; Set RSI to point to the second argument - call b_print_string ; Print the string - call b_print_newline ; Print a new line - jmp fin ; Skip to the end - -noargs: - mov rsi, noargs_message ; Print the error message - call b_print_string - -fin: - -ret ; Return to OS - -hello_message: db 'Hello, ', 0 -noargs_message: db 'Abort: No arguments supplied.', 13, 0 +; Argument Test Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm argtest.asm -o argtest.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + call b_get_argc ; Get the number of arguments that were passed + cmp al, 1 ; Was the number 1? + je noargs ; If so then bail out. The first argument is the program name + mov rsi, hello_message ; Load RSI with memory address of string + call b_print_string ; Print the string that RSI points to + mov al, 1 ; Argument values start at 0 so we want the second one + call b_get_argv ; Set RSI to point to the second argument + call b_print_string ; Print the string + call b_print_newline ; Print a new line + jmp fin ; Skip to the end + +noargs: + mov rsi, noargs_message ; Print the error message + call b_print_string + +fin: + +ret ; Return to OS + +hello_message: db 'Hello, ', 0 +noargs_message: db 'Abort: No arguments supplied.', 13, 0 diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/basic.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/basic.asm index 05564acc..09dad441 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/basic.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/basic.asm @@ -1,1737 +1,1737 @@ -; ================================================================== -; basic.asm - BASIC Interpreter for BareMetal OS -; Ported by Ian Seyler -; -; Based on the "OS-independent" version of MIBASIC by Neville Watkin -; which is based on MIKEOS BASIC by Mike Saunders -; ================================================================== - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -; ------------------------------------------------------------------ -; Token types -VARIABLE equ 1 -STRING_VAR equ 2 -NUMBER equ 3 -STRING equ 4 -QUOTE equ 5 -CHAR equ 6 -UNKNOWN equ 7 -LABEL equ 8 - -; ------------------------------------------------------------------ -; The BASIC intepreter execution starts here... - -os_run_basic: - mov dword [orig_stack], esp ; Save stack pointer -- we might jump to the - ; error printing code and quit in the middle - ; some nested loops, and we want to preserve - ; the stack - mov eax, basic_prog ;embedded test program for a quick DOS test - mov ebx, 8192 ;default size for test program (not critical) - mov dword [load_point], eax ; EAX was passed as starting location of code - mov dword [prog], eax ; prog = pointer to current execution point in code - add ebx, eax ; We were passed the .BAS byte size in BX - dec ebx - dec ebx - mov dword [prog_end], ebx ; Make note of program end point - call clear_ram ; Clear variables etc. from previous run - ; of a BASIC program -mainloop: - call get_token ; Get a token from the start of the line - cmp eax, STRING ; Is the type a string of characters? - je .keyword ; If so, let's see if it's a keyword to process - cmp eax, VARIABLE ; If it's a variable at the start of the line, - je near assign ; this is an assign (eg "X = Y + 5") - cmp eax, STRING_VAR ; Same for a string variable (eg $1) - je near assign - cmp eax, LABEL ; Don't need to do anything here - skip - je mainloop - mov esi, err_syntax ; Otherwise show an error and quit - jmp error -.keyword: - mov esi, token ; Start trying to match commands - mov edi, alert_cmd - call b_string_compare - jc near do_alert - mov edi, call_cmd - call b_string_compare - jc near do_call - mov edi, cls_cmd - call b_string_compare - jc near do_cls - mov edi, cursor_cmd - call b_string_compare - jc near do_cursor - mov edi, curschar_cmd - call b_string_compare - jc near do_curschar - mov edi, end_cmd - call b_string_compare - jc near do_end - mov edi, for_cmd - call b_string_compare - jc near do_for - mov edi, getkey_cmd - call b_string_compare - jc near do_getkey - mov edi, gosub_cmd - call b_string_compare - jc near do_gosub - mov edi, goto_cmd - call b_string_compare - jc near do_goto - mov edi, input_cmd - call b_string_compare - jc near do_input - mov edi, if_cmd - call b_string_compare - jc near do_if -; mov edi, load_cmd -; call b_string_compare -; jc near do_load - mov edi, move_cmd - call b_string_compare - jc near do_move - mov edi, next_cmd - call b_string_compare - jc near do_next - mov edi, pause_cmd - call b_string_compare - jc near do_pause - mov edi, peek_cmd - call b_string_compare - jc near do_peek - mov edi, poke_cmd - call b_string_compare - jc near do_poke - mov edi, port_cmd - call b_string_compare - jc near do_port - mov edi, print_cmd - call b_string_compare - jc near do_print - mov edi, rand_cmd - call b_string_compare - jc near do_rand - mov edi, rem_cmd - call b_string_compare - jc near do_rem - mov edi, return_cmd - call b_string_compare - jc near do_return -; mov edi, save_cmd -; call b_string_compare -; jc near do_save - mov edi, serial_cmd - call b_string_compare - jc near do_serial - mov edi, sound_cmd - call b_string_compare - jc near do_sound - mov edi, waitkey_cmd - call b_string_compare - jc near do_waitkey - mov esi, err_cmd_unknown ; Command not found? - jmp error - -; ------------------------------------------------------------------ -; CLEAR RAM -clear_ram: - mov al, 0 - mov edi, variables - mov ecx, 52 - rep stosb - mov edi, for_variables - mov ecx, 52 - rep stosb - mov edi, for_code_points - mov ecx, 52 - rep stosb - mov byte [gosub_depth], 0 - mov edi, gosub_points - mov ecx, 20 - rep stosb - mov edi, string_vars - mov ecx, 1024 - rep stosb - ret -; ------------------------------------------------------------------ -; ASSIGNMENT -assign: - cmp eax, VARIABLE ; Are we starting with a number var? - je .do_num_var - mov edi, string_vars ; Otherwise it's a string var - mov eax, 128 - mul ebx ; (EBX = string number, passed back from get_token) - add edi, eax - push rdi - call get_token - mov byte al, [token] - cmp al, '=' - jne near .error - call get_token - cmp eax, QUOTE - je .second_is_quote - cmp eax, STRING_VAR - jne near .error - mov esi, string_vars ; Otherwise it's a string var - mov eax, 128 - mul ebx ; (EBX = string number, passed back from get_token) - add esi, eax - pop rdi - call b_string_copy - jmp mainloop -.second_is_quote: - mov esi, token - pop rdi - call b_string_copy - jmp mainloop -.do_num_var: - mov eax, 0 - mov byte al, [token] - mov byte [.tmp], al - call get_token - mov byte al, [token] - cmp al, '=' - jne near .error - call get_token - cmp eax, NUMBER - je .second_is_num - cmp eax, VARIABLE - je .second_is_variable - cmp eax, STRING - je near .second_is_string - cmp eax, UNKNOWN - jne near .error - mov byte al, [token] ; Address of string var? - cmp al, '&' - jne near .error - call get_token ; Let's see if there's a string var - cmp eax, STRING_VAR - jne near .error - mov edi, string_vars - mov eax, 128 - mul ebx - add edi, eax - mov ebx, edi - mov byte al, [.tmp] - call set_var - jmp mainloop -.second_is_variable: - mov eax, 0 - mov byte al, [token] - call get_var - mov ebx, eax - mov byte al, [.tmp] - call set_var - jmp .check_for_more -.second_is_num: - mov esi, token - call b_string_to_int - mov ebx, eax ; Number to insert in variable table - mov eax, 0 - mov byte al, [.tmp] - call set_var - ; The assignment could be simply "X = 5" etc. Or it could be - ; "X = Y + 5" -- ie more complicated. So here we check to see if - ; there's a delimiter... -.check_for_more: - mov dword eax, [prog] ; Save code location in case there's no delimiter - mov dword [.tmp_loc], eax - call get_token ; Any more to deal with in this assignment? - mov byte al, [token] - cmp al, '+' - je .theres_more - cmp al, '-' - je .theres_more - cmp al, '*' - je .theres_more - cmp al, '/' - je .theres_more - cmp al, '%' - je .theres_more - mov dword eax, [.tmp_loc] ; Not a delimiter, so step back before the token - mov dword [prog], eax ; that we just grabbed - jmp mainloop ; And go back to the code interpreter! -.theres_more: - mov byte [.delim], al - call get_token - cmp eax, VARIABLE - je .handle_variable - mov esi, token - call b_string_to_int - mov ebx, eax - mov eax, 0 - mov byte al, [.tmp] - call get_var ; This also points ESI at right place in variable table - cmp byte [.delim], '+' - jne .not_plus - add eax, ebx - jmp .finish -.not_plus: - cmp byte [.delim], '-' - jne .not_minus - sub eax, ebx - jmp .finish -.not_minus: - cmp byte [.delim], '*' - jne .not_times - mul ebx - jmp .finish -.not_times: - cmp byte [.delim], '/' - jne .not_divide - mov edx, 0 - div ebx - jmp .finish -.not_divide: - mov edx, 0 - div ebx - mov eax, edx ; Get remainder -.finish: - mov ebx, eax - mov byte al, [.tmp] - call set_var - jmp .check_for_more -.handle_variable: - mov eax, 0 - mov byte al, [token] - call get_var - mov ebx, eax - mov eax, 0 - mov byte al, [.tmp] - call get_var - cmp byte [.delim], '+' - jne .vnot_plus - add eax, ebx - jmp .vfinish -.vnot_plus: - cmp byte [.delim], '-' - jne .vnot_minus - sub eax, ebx - jmp .vfinish -.vnot_minus: - cmp byte [.delim], '*' - jne .vnot_times - mul ebx - jmp .vfinish -.vnot_times: - cmp byte [.delim], '/' - jne .vnot_divide - mov edx, 0 - div ebx - jmp .finish -.vnot_divide: - mov edx, 0 - div ebx - mov eax, edx ; Get remainder -.vfinish: - mov ebx, eax - mov byte al, [.tmp] - call set_var - jmp .check_for_more -.second_is_string: - mov edi, token - mov esi, progstart_keyword - call b_string_compare - je .is_progstart - mov esi, ramstart_keyword - call b_string_compare - je .is_ramstart - jmp .error -.is_progstart: - mov eax, 0 - mov byte al, [.tmp] - mov dword ebx, [load_point] - call set_var - jmp mainloop -.is_ramstart: - mov eax, 0 - mov byte al, [.tmp] - mov dword ebx, [prog_end] - inc ebx - inc ebx - inc ebx - call set_var - jmp mainloop -.error: - mov esi, err_syntax - jmp error -.tmp db 0 -.tmp_loc dd 0 -.delim db 0 -; ================================================================== -; SPECIFIC COMMAND CODE STARTS HERE -; ------------------------------------------------------------------ -; ALERT -do_alert: - call get_token - cmp eax, QUOTE - je .is_quote - mov esi, err_syntax - jmp error -.is_quote: - mov eax, token ; First string for alert box - mov ebx, 0 ; Others are blank - mov ecx, 0 - mov edx, 0 ; One-choice box -; call b_dialog_box - jmp mainloop -; ------------------------------------------------------------------ -; CALL -do_call: - call get_token - cmp eax, NUMBER - je .is_number - xor eax, eax - mov byte al, [token] - call get_var - jmp .execute_call -.is_number: - mov esi, token - call b_string_to_int -.execute_call: - mov ebx, 0 - mov ecx, 0 - mov edx, 0 - mov edi, 0 - mov esi, 0 - call rax - jmp mainloop -; ------------------------------------------------------------------ -; CLS -do_cls: - call b_screen_clear - jmp mainloop -; ------------------------------------------------------------------ -; CURSOR -do_cursor: - call get_token - mov esi, token - mov edi, .on_str - call b_string_compare - jc .turn_on - mov esi, token - mov edi, .off_str - call b_string_compare - jc .turn_off - mov esi, err_syntax - jmp error -.turn_on: - call b_show_cursor - jmp mainloop -.turn_off: - call b_hide_cursor - jmp mainloop -.on_str db "ON", 0 -.off_str db "OFF", 0 -; ------------------------------------------------------------------ -; CURSCHAR -do_curschar: - call get_token - cmp eax, VARIABLE - je .is_ok - mov esi, err_syntax - jmp error -.is_ok: - mov eax, 0 - mov byte al, [token] - push rax ; Store variable we're going to use - mov ah, 08h - mov ebx, 0 -; int 10h ; Get char at current cursor location - mov ebx, 0 ; We only want the lower byte (the char, not attribute) - mov bl, al - pop rax ; Get the variable back - call set_var ; And store the value - jmp mainloop -; ------------------------------------------------------------------ -; END -do_end: - mov dword esp, [orig_stack] - ret -; ------------------------------------------------------------------ -; FOR -do_for: - call get_token ; Get the variable we're using in this loop - cmp eax, VARIABLE - jne near .error - mov eax, 0 - mov byte al, [token] - mov byte [.tmp_var], al ; Store it in a temporary location for now - call get_token - mov eax, 0 ; Check it's followed up with '=' - mov byte al, [token] - cmp al, '=' - jne .error - call get_token ; Next we want a number - cmp eax, NUMBER - jne .error - mov esi, token ; Convert it - call b_string_to_int - ; At this stage, we've read something like "FOR X = 1" - ; so let's store that 1 in the variable table - mov ebx, eax - mov eax, 0 - mov byte al, [.tmp_var] - call set_var - call get_token ; Next we're looking for "TO" - cmp eax, STRING - jne .error - mov eax, token - call b_string_uppercase - mov esi, token - mov edi, .to_string - call b_string_compare - jnc .error - ; So now we're at "FOR X = 1 TO" - call get_token - cmp eax, NUMBER - jne .error - mov esi, token ; Get target number - call b_string_to_int - mov ebx, eax - mov eax, 0 - mov byte al, [.tmp_var] - sub al, 65 ; Store target number in table - mov edi, for_variables - add edi, eax - add edi, eax - mov eax, ebx - stosw - ; So we've got the variable, assigned it the starting number, and put into - ; our table the limit it should reach. But we also need to store the point in - ; code after the FOR line we should return to if NEXT X doesn't complete the loop... - mov eax, 0 - mov byte al, [.tmp_var] - sub al, 65 ; Store code position to return to in table - mov edi, for_code_points - add edi, eax - add edi, eax - mov dword eax, [prog] - stosw - jmp mainloop -.error: - mov esi, err_syntax - jmp error -.tmp_var db 0 -.to_string db 'TO', 0 -; ------------------------------------------------------------------ -; GETKEY -do_getkey: - call get_token - cmp eax, VARIABLE - je .is_variable - mov esi, err_syntax - jmp error -.is_variable: - mov eax, 0 - mov byte al, [token] - push rax - call b_input_key_check - mov ebx, 0 - mov bl, al - pop rax - call set_var - jmp mainloop -; ------------------------------------------------------------------ -; GOSUB -do_gosub: - call get_token ; Get the number (label) - cmp eax, STRING - je .is_ok - mov esi, err_goto_notlabel - jmp error -.is_ok: - mov esi, token ; Back up this label - mov edi, .tmp_token - call b_string_copy - mov eax, .tmp_token - call b_string_length - mov edi, .tmp_token ; Add ':' char to end for searching - add edi, eax - mov al, ':' - stosb - mov al, 0 - stosb - inc byte [gosub_depth] - mov eax, 0 - mov byte al, [gosub_depth] ; Get current GOSUB nest level - cmp al, 9 - jle .within_limit - mov esi, err_nest_limit - jmp error -.within_limit: - mov edi, gosub_points ; Move into our table of pointers - add edi, eax ; Table is words (not bytes) - add edi, eax - mov dword eax, [prog] - stosw ; Store current location before jump - mov dword eax, [load_point] - mov dword [prog], eax ; Return to start of program to find label -.loop: - call get_token - cmp eax, LABEL - jne .line_loop - mov esi, token - mov edi, .tmp_token - call b_string_compare - jc mainloop -.line_loop: ; Go to end of line - mov dword esi, [prog] - mov byte al, [esi] - inc dword [prog] - cmp al, 10 - jne .line_loop - mov dword eax, [prog] - mov dword ebx, [prog_end] - cmp eax, ebx - jg .past_end - jmp .loop -.past_end: - mov esi, err_label_notfound - jmp error -.tmp_token: times 30 db 0 -; ------------------------------------------------------------------ -; GOTO -do_goto: - call get_token ; Get the next token - cmp eax, STRING - je .is_ok - mov esi, err_goto_notlabel - jmp error -.is_ok: - mov esi, token ; Back up this label - mov edi, .tmp_token - call b_string_copy - mov eax, .tmp_token - call b_string_length - mov edi, .tmp_token ; Add ':' char to end for searching - add edi, eax - mov al, ':' - stosb - mov al, 0 - stosb - mov dword eax, [load_point] - mov dword [prog], eax ; Return to start of program to find label -.loop: - call get_token - cmp eax, LABEL - jne .line_loop - mov esi, token - mov edi, .tmp_token - call b_string_compare - jc mainloop -.line_loop: ; Go to end of line - mov dword esi, [prog] - mov byte al, [esi] - inc dword [prog] - cmp al, 10 - jne .line_loop - mov dword eax, [prog] - mov dword ebx, [prog_end] - cmp eax, ebx - jg .past_end - jmp .loop -.past_end: - mov esi, err_label_notfound - jmp error -.tmp_token: times 30 db 0 -; ------------------------------------------------------------------ -; IF -do_if: - call get_token - cmp eax, VARIABLE ; If can only be followed by a variable - je .num_var - cmp eax, STRING_VAR - je near .string_var - mov esi, err_syntax - jmp error -.num_var: - mov eax, 0 - mov byte al, [token] - call get_var - mov edx, eax ; Store value of first part of comparison - call get_token ; Get the delimiter - mov byte al, [token] - cmp al, '=' - je .equals - cmp al, '>' - je .greater - cmp al, '<' - je .less - mov esi, err_syntax ; If not one of the above, error out - jmp error -.equals: - call get_token ; Is this 'X = Y' (equals another variable?) - cmp eax, CHAR - je .equals_char - mov byte al, [token] - call is_letter - jc .equals_var - mov esi, token ; Otherwise it's, eg 'X = 1' (a number) - call b_string_to_int - cmp eax, edx ; On to the THEN bit if 'X = num' matches - je near .on_to_then - jmp .finish_line ; Otherwise skip the rest of the line -.equals_char: - mov eax, 0 - mov byte al, [token] - cmp eax, edx - je near .on_to_then - jmp .finish_line -.equals_var: - mov eax, 0 - mov byte al, [token] - call get_var - cmp eax, edx ; Do the variables match? - je near .on_to_then ; On to the THEN bit if so - jmp .finish_line ; Otherwise skip the rest of the line -.greater: - call get_token ; Greater than a variable or number? - mov byte al, [token] - call is_letter - jc .greater_var - mov esi, token ; Must be a number here... - call b_string_to_int - cmp eax, edx - jl near .on_to_then - jmp .finish_line -.greater_var: ; Variable in this case - mov eax, 0 - mov byte al, [token] - call get_var - cmp eax, edx ; Make the comparison! - jl .on_to_then - jmp .finish_line -.less: - call get_token - mov byte al, [token] - call is_letter - jc .less_var - mov esi, token - call b_string_to_int - cmp eax, edx - jg .on_to_then - jmp .finish_line -.less_var: - mov eax, 0 - mov byte al, [token] - call get_var - cmp eax, edx - jg .on_to_then - jmp .finish_line -.string_var: - mov byte [.tmp_string_var], bl - call get_token - mov byte al, [token] - cmp al, '=' - jne .error - call get_token - cmp eax, STRING_VAR - je .second_is_string_var - cmp eax, QUOTE - jne .error - mov esi, string_vars - mov eax, 128 - mul ebx - add esi, eax - mov edi, token - call b_string_compare - je .on_to_then - jmp .finish_line -.second_is_string_var: - mov esi, string_vars - mov eax, 128 - mul ebx - add esi, eax - mov edi, string_vars - mov ebx, 0 - mov byte bl, [.tmp_string_var] - mov eax, 128 - mul ebx - add edi, eax - call b_string_compare - jc .on_to_then - jmp .finish_line -.on_to_then: - call get_token - mov esi, token - mov edi, then_keyword - call b_string_compare - jc .then_present - mov esi, err_syntax - jmp error -.then_present: ; Continue rest of line like any other command! - jmp mainloop -.finish_line: ; IF wasn't fulfilled, so skip rest of line - mov dword esi, [prog] - mov byte al, [esi] - inc dword [prog] - cmp al, 10 - jne .finish_line - jmp mainloop -.error: - mov esi, err_syntax - jmp error -.tmp_string_var db 0 -; ------------------------------------------------------------------ -; INPUT -do_input: - mov al, 0 ; Clear string from previous usage - mov edi, .tmpstring - mov ecx, 128 - rep stosb - call get_token - cmp eax, VARIABLE ; We can only INPUT to variables! - je .number_var - cmp eax, STRING_VAR - je .string_var - mov esi, err_syntax - jmp error -.number_var: - mov rdi, .tmpstring ; Get input from the user - call b_input_string - mov rsi, .tmpstring - call b_string_length - cmp rcx, 0 - jne .char_entered - mov byte [.tmpstring], '0' ; If enter hit, fill variable with zero - mov byte [.tmpstring + 1], 0 -.char_entered: - mov esi, .tmpstring ; Convert to integer format - call b_string_to_int - mov ebx, eax - mov eax, 0 - mov byte al, [token] ; Get the variable where we're storing it... - call set_var ; ...and store it! - call b_print_newline - jmp mainloop -.string_var: - push rbx - mov rdi, .tmpstring - mov rcx, 120 ; Limit to max of 120 chars - call b_input_string - mov esi, .tmpstring - mov edi, string_vars - pop rbx - mov eax, 128 - mul ebx - add edi, eax - call b_string_copy - call b_print_newline - jmp mainloop -.tmpstring: times 128 db 0 -; ------------------------------------------------------------------ -;; LOAD -;do_load: -; call get_token -; cmp eax, QUOTE -; je .is_quote -; cmp eax, STRING_VAR -; jne .error -; mov esi, string_vars -; mov eax, 128 -; mul ebx -; add esi, eax -; jmp .get_position -;.is_quote: -; mov esi, token -;.get_position: -; mov eax, esi -; call b_file_exists -; jc .file_not_exists -; mov edx, eax ; Store for now -; call get_token -; cmp eax, VARIABLE -; je .second_is_var -; cmp eax, NUMBER -; jne .error -; mov esi, token -; call b_string_to_int -;.load_part: -; mov ecx, eax -; mov eax, edx -; call b_load_file -; mov eax, 0 -; mov byte al, 'S' -; call set_var -; mov eax, 0 -; mov byte al, 'R' -; mov ebx, 0 -; call set_var -; jmp mainloop -;.second_is_var: -; mov eax, 0 -; mov byte al, [token] -; call get_var -; jmp .load_part -;.file_not_exists: -; mov eax, 0 -; mov byte al, 'R' -; mov ebx, 1 -; call set_var -; call get_token ; Skip past the loading point -- unnecessary now -; jmp mainloop -;.error: -; mov esi, err_syntax -; jmp error -; ------------------------------------------------------------------ -; MOVE -do_move: - call get_token - cmp eax, VARIABLE - je .first_is_var - mov esi, token - call b_string_to_int - mov dl, al - jmp .onto_second -.first_is_var: - mov eax, 0 - mov byte al, [token] - call get_var - mov dl, al -.onto_second: - call get_token - cmp eax, VARIABLE - je .second_is_var - mov esi, token - call b_string_to_int - mov dh, al - jmp .finish -.second_is_var: - mov eax, 0 - mov byte al, [token] - call get_var - mov dh, al -.finish: - call b_move_cursor - jmp mainloop -; ------------------------------------------------------------------ -; NEXT -do_next: - call get_token - cmp eax, VARIABLE ; NEXT must be followed by a variable - jne .error - mov eax, 0 - mov byte al, [token] - call get_var - inc eax ; NEXT increments the variable, of course! - mov ebx, eax - mov eax, 0 - mov byte al, [token] - sub al, 65 - mov esi, for_variables - add esi, eax - add esi, eax - lodsw ; Get the target number from the table - inc eax ; (Make the loop inclusive of target number) - cmp eax, ebx ; Do the variable and target match? - je .loop_finished - mov eax, 0 ; If not, store the updated variable - mov byte al, [token] - call set_var - mov eax, 0 ; Find the code point and go back - mov byte al, [token] - sub al, 65 - mov esi, for_code_points - add esi, eax - add esi, eax - lodsw - mov dword [prog], eax - jmp mainloop -.loop_finished: - jmp mainloop -.error: - mov esi, err_syntax - jmp error -; ------------------------------------------------------------------ -; PAUSE -do_pause: - call get_token - cmp eax, VARIABLE - je .is_var - mov esi, token - call b_string_to_int - jmp .finish -.is_var: - mov eax, 0 - mov byte al, [token] - call get_var -.finish: - call b_delay - jmp mainloop -; ------------------------------------------------------------------ -; PEEK -do_peek: - call get_token - cmp eax, VARIABLE - jne .error - mov eax, 0 - mov byte al, [token] - mov byte [.tmp_var], al - call get_token - cmp eax, VARIABLE - je .dereference - cmp eax, NUMBER - jne .error - mov esi, token - call b_string_to_int -.store: - mov esi, eax - mov ebx, 0 - mov byte bl, [esi] - mov eax, 0 - mov byte al, [.tmp_var] - call set_var - jmp mainloop -.dereference: - mov byte al, [token] - call get_var - jmp .store -.error: - mov esi, err_syntax - jmp error -.tmp_var db 0 -; ------------------------------------------------------------------ -; POKE -do_poke: - call get_token - cmp eax, VARIABLE - je .first_is_var - cmp eax, NUMBER - jne .error - mov esi, token - call b_string_to_int - cmp eax, 255 - jg .error - mov byte [.first_value], al - jmp .onto_second -.first_is_var: - mov eax, 0 - mov byte al, [token] - call get_var - mov byte [.first_value], al -.onto_second: - call get_token - cmp eax, VARIABLE - je .second_is_var - cmp eax, NUMBER - jne .error - mov esi, token - call b_string_to_int -.got_value: - mov edi, eax - mov eax, 0 - mov byte al, [.first_value] - mov byte [edi], al - jmp mainloop -.second_is_var: - mov eax, 0 - mov byte al, [token] - call get_var - jmp .got_value -.error: - mov esi, err_syntax - jmp error -.first_value db 0 -; ------------------------------------------------------------------ -; PORT -do_port: - call get_token - mov esi, token - mov edi, .out_cmd - call b_string_compare - jc .do_out_cmd - mov edi, .in_cmd - call b_string_compare - jc .do_in_cmd - jmp .error -.do_out_cmd: - call get_token - cmp eax, NUMBER - jne .error - mov esi, token - call b_string_to_int ; Now EAX = port number - mov edx, eax - call get_token - cmp eax, NUMBER - je .out_is_num - cmp eax, VARIABLE - je .out_is_var - jmp .error -.out_is_num: - mov esi, token - call b_string_to_int -; call b_port_byte_out - jmp mainloop -.out_is_var: - mov eax, 0 - mov byte al, [token] - call get_var -; call b_port_byte_out - jmp mainloop -.do_in_cmd: - call get_token - cmp eax, NUMBER - jne .error - mov esi, token - call b_string_to_int - mov edx, eax - call get_token - cmp eax, VARIABLE - jne .error - mov byte cl, [token] -; call b_port_byte_in - mov ebx, 0 - mov bl, al - mov al, cl - call set_var - jmp mainloop -.error: - mov esi, err_syntax - jmp error -.out_cmd db "OUT", 0 -.in_cmd db "IN", 0 -; ------------------------------------------------------------------ -; PRINT -do_print: - call get_token ; Get part after PRINT - cmp eax, QUOTE ; What type is it? - je .print_quote - cmp eax, VARIABLE ; Numerical variable (eg X) - je .print_var - cmp eax, STRING_VAR ; String variable (eg $1) - je .print_string_var - cmp eax, STRING ; Special keyword (eg CHR or HEX) - je .print_keyword - mov esi, err_print_type ; We only print quoted strings and vars! - jmp error -.print_var: - mov eax, 0 - mov byte al, [token] - call get_var ; Get its value - call b_int_to_string ; Convert to string - mov esi, eax - call b_print_string - jmp .newline_or_not -.print_quote: ; If it's quoted text, print it - mov esi, token - call b_print_string - jmp .newline_or_not -.print_string_var: - mov esi, string_vars - mov eax, 128 - mul ebx - add esi, eax - call b_print_string - jmp .newline_or_not -.print_keyword: - mov esi, token - mov edi, chr_keyword - call b_string_compare - jc .is_chr - mov edi, hex_keyword - call b_string_compare - jc .is_hex - mov esi, err_syntax - jmp error -.is_chr: - call get_token - cmp eax, VARIABLE - jne .error - mov eax, 0 - mov byte al, [token] - call get_var - mov ah, 0Eh - int 10h - jmp .newline_or_not -.is_hex: - call get_token - cmp eax, VARIABLE - jne .error - mov eax, 0 - mov byte al, [token] - call get_var - call b_debug_dump_ax - jmp .newline_or_not -.error: - mov esi, err_syntax - jmp error -.newline_or_not: - ; We want to see if the command ends with ';' -- which means that - ; we shouldn't print a newline after it finishes. So we store the - ; current program location to pop ahead and see if there's the ';' - ; character -- otherwise we put the program location back and resume - ; the main loop -xchg bx, bx - mov dword eax, [prog] - mov dword [.tmp_loc], eax - call get_token - cmp eax, UNKNOWN - jne .ignore - mov eax, 0 - mov al, [token] - cmp al, ';' - jne .ignore - jmp mainloop ; And go back to interpreting the code! -.ignore: - call b_print_newline - mov dword eax, [.tmp_loc] - mov dword [prog], eax - jmp mainloop -.tmp_loc dd 0 -; ------------------------------------------------------------------ -; RAND -do_rand: - call get_token - cmp eax, VARIABLE - jne .error - mov byte al, [token] - mov byte [.tmp], al - call get_token - cmp eax, NUMBER - jne .error - mov esi, token - call b_string_to_int - mov dword [.num1], eax - call get_token - cmp eax, NUMBER - jne .error - mov esi, token - call b_string_to_int - mov dword [.num2], eax - mov dword eax, [.num1] - mov dword ebx, [.num2] - ; call b_get_random - mov ebx, ecx - mov eax, 0 - mov byte al, [.tmp] - call set_var - jmp mainloop -.tmp db 0 -.num1 dd 0 -.num2 dd 0 -.error: - mov esi, err_syntax - jmp error -; ------------------------------------------------------------------ -; REM -do_rem: - mov dword esi, [prog] - mov byte al, [esi] - inc dword [prog] - cmp al, 10 ; Find end of line after REM - jne do_rem - jmp mainloop -; ------------------------------------------------------------------ -; RETURN -do_return: - mov eax, 0 - mov byte al, [gosub_depth] - cmp al, 0 - jne .is_ok - mov esi, err_return - jmp error -.is_ok: - mov esi, gosub_points - add esi, eax ; Table is words (not bytes) - add esi, eax - lodsw - mov dword [prog], eax - dec byte [gosub_depth] - jmp mainloop -; ------------------------------------------------------------------ -;; SAVE -;do_save: -; call get_token -; cmp eax, QUOTE -; je .is_quote -; cmp eax, STRING_VAR -; jne near .error -; mov esi, string_vars -; mov eax, 128 -; mul ebx -; add esi, eax -; jmp .get_position -;.is_quote: -; mov esi, token -;.get_position: -; mov edi, .tmp_filename -; call b_string_copy -; call get_token -; cmp eax, VARIABLE -; je .second_is_var -; cmp eax, NUMBER -; jne .error -; mov esi, token -; call b_string_to_int -;.set_data_loc: -; mov dword [.data_loc], eax -; call get_token -; cmp eax, VARIABLE -; je .third_is_var -; cmp eax, NUMBER -; jne .error -; mov esi, token -; call b_string_to_int -;.set_data_size: -; mov dword [.data_size], eax -; mov dword eax, .tmp_filename -; mov dword ebx, [.data_loc] -; mov dword ecx, [.data_size] -; call b_write_file -; jc .save_failure -; mov eax, 0 -; mov byte al, 'R' -; mov ebx, 0 -; call set_var -; jmp mainloop -;.second_is_var: -; mov eax, 0 -; mov byte al, [token] -; call get_var -; jmp .set_data_loc -;.third_is_var: -; mov eax, 0 -; mov byte al, [token] -; call get_var -; jmp .set_data_size -;.save_failure: -; mov eax, 0 -; mov byte al, 'R' -; mov ebx, 1 -; call set_var -; jmp mainloop -;.error: -; mov esi, err_syntax -; jmp error -;.filename_loc dd 0 -;.data_loc dd 0 -;.data_size dd 0 -;.tmp_filename: times 15 db 0 -; ------------------------------------------------------------------ -; SERIAL -do_serial: - call get_token - mov esi, token - mov edi, .on_cmd - call b_string_compare - jc .do_on_cmd - mov edi, .send_cmd - call b_string_compare - jc .do_send_cmd - mov edi, .rec_cmd - call b_string_compare - jc .do_rec_cmd - jmp .error -.do_on_cmd: - call get_token - cmp eax, NUMBER - je .do_on_cmd_ok - jmp .error -.do_on_cmd_ok: - mov esi, token - call b_string_to_int - cmp eax, 1200 - je .on_cmd_slow_mode - cmp eax, 9600 - je .on_cmd_fast_mode - jmp .error -.on_cmd_fast_mode: - mov eax, 0 - ; call b_serial_port_enable - jmp mainloop -.on_cmd_slow_mode: - mov eax, 1 -; call b_serial_port_enable - jmp mainloop -.do_send_cmd: - call get_token - cmp eax, NUMBER - je .send_number - cmp eax, VARIABLE - je .send_variable - jmp .error -.send_number: - mov esi, token - call b_string_to_int - call b_serial_send - jmp mainloop -.send_variable: - mov eax, 0 - mov byte al, [token] - call get_var - call b_serial_send - jmp mainloop -.do_rec_cmd: - call get_token - cmp eax, VARIABLE - jne .error - mov byte al, [token] - mov ecx, 0 - mov cl, al - call b_serial_recv - mov ebx, 0 - mov bl, al - mov al, cl - call set_var - jmp mainloop -.error: - mov esi, err_syntax - jmp error -.on_cmd db "ON", 0 -.send_cmd db "SEND", 0 -.rec_cmd db "REC", 0 -; ------------------------------------------------------------------ -; SOUND -do_sound: - call get_token - cmp eax, VARIABLE - je .first_is_var - mov esi, token - call b_string_to_int - jmp .done_first -.first_is_var: - mov eax, 0 - mov byte al, [token] - call get_var -.done_first: - call b_speaker_tone - call get_token - cmp eax, VARIABLE - je .second_is_var - mov esi, token - call b_string_to_int - jmp .finish -.second_is_var: - mov eax, 0 - mov byte al, [token] - call get_var -.finish: - call b_delay - call b_speaker_off - jmp mainloop -; ------------------------------------------------------------------ -; WAITKEY -do_waitkey: - call get_token - cmp eax, VARIABLE - je .is_variable - mov esi, err_syntax - jmp error -.is_variable: - mov eax, 0 - mov byte al, [token] - push rax - call b_input_key_wait - cmp eax, 48E0h - je .up_pressed - cmp eax, 50E0h - je .down_pressed - cmp eax, 4BE0h - je .left_pressed - cmp eax, 4DE0h - je .right_pressed -.store: - mov ebx, 0 - mov bl, al - pop rax - call set_var - jmp mainloop -.up_pressed: - mov eax, 1 - jmp .store -.down_pressed: - mov eax, 2 - jmp .store -.left_pressed: - mov eax, 3 - jmp .store -.right_pressed: - mov eax, 4 - jmp .store -; ================================================================== -; INTERNAL ROUTINES FOR INTERPRETER -; ------------------------------------------------------------------ -; Get value of variable character specified in AL (eg 'A') -get_var: - sub al, 65 - mov esi, variables - add esi, eax - add esi, eax - lodsw - ret -; ------------------------------------------------------------------ -; Set value of variable character specified in AL (eg 'A') -; with number specified in EBX -set_var: - mov ah, 0 - sub al, 65 ; Remove ASCII codes before 'A' - mov edi, variables ; Find position in table (of words) - add edi, eax - add edi, eax - mov eax, ebx - stosw - ret -; ------------------------------------------------------------------ -; Get token from current position in prog -get_token: - mov dword esi, [prog] - lodsb - cmp al, 10 - je .newline - cmp al, 13 ;allow for CRLF - je .newline - cmp al, ' ' - je .newline - call is_number - jc get_number_token - cmp al, '"' - je get_quote_token - cmp al, 39 ; Quote mark (') - je get_char_token - cmp al, '$' - je near get_string_var_token - jmp get_string_token -.newline: - inc dword [prog] - jmp get_token -get_number_token: - mov dword esi, [prog] - mov edi, token -.loop: - lodsb - cmp al, 10 - je .done - cmp al, 13 ;allow for CRLF - je .done - cmp al, ' ' - je .done - call is_number - jc .fine - mov esi, err_char_in_num - jmp error -.fine: - stosb - inc dword [prog] - jmp .loop -.done: - mov al, 0 ; Zero-terminate the token - stosb - mov eax, NUMBER ; Pass back the token type - ret -get_char_token: - inc dword [prog] ; Move past first quote (') - mov dword esi, [prog] - lodsb - mov byte [token], al - lodsb - cmp al, 39 ; Needs to finish with another quote - je .is_ok - mov esi, err_quote_term - jmp error -.is_ok: - inc dword [prog] - inc dword [prog] - mov eax, CHAR - ret -get_quote_token: - inc dword [prog] ; Move past first quote (") char - mov dword esi, [prog] - mov edi, token -.loop: - lodsb - cmp al, '"' - je .done - cmp al, 10 - je .error - stosb - inc dword [prog] - jmp .loop -.done: - mov al, 0 ; Zero-terminate the token - stosb - inc dword [prog] ; Move past final quote - mov eax, QUOTE ; Pass back token type - ret -.error: - mov esi, err_quote_term - jmp error -get_string_var_token: - lodsb - mov ebx, 0 ; If it's a string var, pass number of string in EBX - mov bl, al - sub bl, 49 - inc dword [prog] - inc dword [prog] - mov eax, STRING_VAR - ret - -get_string_token: - mov dword esi, [prog] - mov edi, token -.loop: - lodsb - cmp al, 10 - je .done - cmp al, 13 ;allow for CRLF - je .done - cmp al, ' ' - je .done - stosb - inc dword [prog] - jmp .loop -.done: - mov al, 0 ; Zero-terminate the token - stosb - mov eax, token - call b_string_uppercase - mov eax, token - call b_string_length ; How long was the token? - cmp eax, 1 ; If 1 char, it's a variable or delimiter - je .is_not_string - mov esi, token ; If the token ends with ':', it's a label - add esi, eax - dec esi - lodsb - cmp al, ':' - je .is_label - mov eax, STRING ; Otherwise it's a general string of characters - ret -.is_label: - mov eax, LABEL - ret -.is_not_string: - mov byte al, [token] - call is_letter - jc .is_var - mov eax, UNKNOWN - ret -.is_var: - mov eax, VARIABLE ; Otherwise probably a variable - ret -; ------------------------------------------------------------------ -; Set carry flag if AL contains ASCII number -is_number: - cmp al, 48 - jl .not_number - cmp al, 57 - jg .not_number - stc - ret -.not_number: - clc - ret -; ------------------------------------------------------------------ -; Set carry flag if AL contains ASCII letter -is_letter: - cmp al, 65 - jl .not_letter - cmp al, 90 - jg .not_letter - stc - ret -.not_letter: - clc - ret -; ------------------------------------------------------------------ -; Print error message and quit out -error: - call b_print_newline - call b_print_string ; Print error message - call b_print_newline - mov dword esp, [orig_stack] ; Restore the stack to as it was when BASIC started - ret ; And finish -; ------------------------------------------------------------------ - - - - ; Error messages text... -err_char_in_num db "Error: unexpected character in number", 0 -err_quote_term db "Error: quoted string or character not terminated correctly", 0 -err_print_type db "Error: PRINT command not followed by quoted text or variable", 0 -err_cmd_unknown db "Error: unknown command", 0 -err_goto_notlabel db "Error: GOTO or GOSUB not followed by label", 0 -err_label_notfound db "Error: GOTO or GOSUB label not found", 0 -err_return db "Error: RETURN without GOSUB", 0 -err_nest_limit db "Error: FOR or GOSUB nest limit exceeded", 0 -err_next db "Error: NEXT without FOR", 0 -err_syntax db "Error: syntax error", 0 -; ================================================================== -; DATA SECTION -orig_stack dd 0 ; Original stack location when BASIC started -prog dd 0 ; Pointer to current location in BASIC code -prog_end dd 0 ; Pointer to final byte of BASIC code -load_point dd 0 -token_type db 0 ; Type of last token read (eg NUMBER, VARIABLE) -token: times 255 db 0 ; Storage space for the token -variables: times 26 dd 0 ; Storage space for variables A to Z -for_variables: times 26 dd 0 ; Storage for FOR loops -for_code_points: times 26 dd 0 ; Storage for code positions where FOR loops start -alert_cmd db "ALERT", 0 -call_cmd db "CALL", 0 -cls_cmd db "CLS", 0 -cursor_cmd db "CURSOR", 0 -curschar_cmd db "CURSCHAR", 0 -end_cmd db "END", 0 -for_cmd db "FOR", 0 -gosub_cmd db "GOSUB", 0 -goto_cmd db "GOTO", 0 -getkey_cmd db "GETKEY", 0 -if_cmd db "IF", 0 -input_cmd db "INPUT", 0 -load_cmd db "LOAD", 0 -move_cmd db "MOVE", 0 -next_cmd db "NEXT", 0 -pause_cmd db "PAUSE", 0 -peek_cmd db "PEEK", 0 -poke_cmd db "POKE", 0 -port_cmd db "PORT", 0 -print_cmd db "PRINT", 0 -rem_cmd db "REM", 0 -rand_cmd db "RAND", 0 -return_cmd db "RETURN", 0 -save_cmd db "SAVE", 0 -serial_cmd db "SERIAL", 0 -sound_cmd db "SOUND", 0 -waitkey_cmd db "WAITKEY", 0 -then_keyword db "THEN", 0 -chr_keyword db "CHR", 0 -hex_keyword db "HEX", 0 -progstart_keyword db "PROGSTART", 0 -ramstart_keyword db "RAMSTART", 0 -gosub_depth db 0 -gosub_points: times 10 dd 0 ; Points in code to RETURN to -string_vars: times 1024 db 0 ; 8 * 128 byte strings -; ------------------------------------------------------------------ -basic_prog: - DB 'CLS',13,10 - DB 'PRINT "Please type your name: ";',13,10 - DB 'INPUT $N',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT "Hello "',13,10 - DB 'PRINT $N',13,10 - DB 'PRINT ", welcome to MikeOS Basic!"',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT "It supports FOR...NEXT loops and simple integer maths..."',13,10 - DB 'PRINT ""',13,10 - DB 'FOR I = 1 TO 15',13,10 - DB 'J = I * I',13,10 - DB 'K = J * I',13,10 - DB 'L = K * I',13,10 - DB 'PRINT I',13,10 - DB 'PRINT " "',13,10 - DB 'PRINT J',13,10 - DB 'PRINT " "',13,10 - DB 'PRINT K',13,10 - DB 'PRINT " "',13,10 - DB 'PRINT L',13,10 - DB 'NEXT I',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT " ...and IF...THEN and GOSUB and lots of other stuff. Bye!"',13,10 - DB 'END',13,10 +; ================================================================== +; basic.asm - BASIC Interpreter for BareMetal OS +; Ported by Ian Seyler +; +; Based on the "OS-independent" version of MIBASIC by Neville Watkin +; which is based on MIKEOS BASIC by Mike Saunders +; ================================================================== + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +; ------------------------------------------------------------------ +; Token types +VARIABLE equ 1 +STRING_VAR equ 2 +NUMBER equ 3 +STRING equ 4 +QUOTE equ 5 +CHAR equ 6 +UNKNOWN equ 7 +LABEL equ 8 + +; ------------------------------------------------------------------ +; The BASIC intepreter execution starts here... + +os_run_basic: + mov dword [orig_stack], esp ; Save stack pointer -- we might jump to the + ; error printing code and quit in the middle + ; some nested loops, and we want to preserve + ; the stack + mov eax, basic_prog ;embedded test program for a quick DOS test + mov ebx, 8192 ;default size for test program (not critical) + mov dword [load_point], eax ; EAX was passed as starting location of code + mov dword [prog], eax ; prog = pointer to current execution point in code + add ebx, eax ; We were passed the .BAS byte size in BX + dec ebx + dec ebx + mov dword [prog_end], ebx ; Make note of program end point + call clear_ram ; Clear variables etc. from previous run + ; of a BASIC program +mainloop: + call get_token ; Get a token from the start of the line + cmp eax, STRING ; Is the type a string of characters? + je .keyword ; If so, let's see if it's a keyword to process + cmp eax, VARIABLE ; If it's a variable at the start of the line, + je near assign ; this is an assign (eg "X = Y + 5") + cmp eax, STRING_VAR ; Same for a string variable (eg $1) + je near assign + cmp eax, LABEL ; Don't need to do anything here - skip + je mainloop + mov esi, err_syntax ; Otherwise show an error and quit + jmp error +.keyword: + mov esi, token ; Start trying to match commands + mov edi, alert_cmd + call b_string_compare + jc near do_alert + mov edi, call_cmd + call b_string_compare + jc near do_call + mov edi, cls_cmd + call b_string_compare + jc near do_cls + mov edi, cursor_cmd + call b_string_compare + jc near do_cursor + mov edi, curschar_cmd + call b_string_compare + jc near do_curschar + mov edi, end_cmd + call b_string_compare + jc near do_end + mov edi, for_cmd + call b_string_compare + jc near do_for + mov edi, getkey_cmd + call b_string_compare + jc near do_getkey + mov edi, gosub_cmd + call b_string_compare + jc near do_gosub + mov edi, goto_cmd + call b_string_compare + jc near do_goto + mov edi, input_cmd + call b_string_compare + jc near do_input + mov edi, if_cmd + call b_string_compare + jc near do_if +; mov edi, load_cmd +; call b_string_compare +; jc near do_load + mov edi, move_cmd + call b_string_compare + jc near do_move + mov edi, next_cmd + call b_string_compare + jc near do_next + mov edi, pause_cmd + call b_string_compare + jc near do_pause + mov edi, peek_cmd + call b_string_compare + jc near do_peek + mov edi, poke_cmd + call b_string_compare + jc near do_poke + mov edi, port_cmd + call b_string_compare + jc near do_port + mov edi, print_cmd + call b_string_compare + jc near do_print + mov edi, rand_cmd + call b_string_compare + jc near do_rand + mov edi, rem_cmd + call b_string_compare + jc near do_rem + mov edi, return_cmd + call b_string_compare + jc near do_return +; mov edi, save_cmd +; call b_string_compare +; jc near do_save + mov edi, serial_cmd + call b_string_compare + jc near do_serial + mov edi, sound_cmd + call b_string_compare + jc near do_sound + mov edi, waitkey_cmd + call b_string_compare + jc near do_waitkey + mov esi, err_cmd_unknown ; Command not found? + jmp error + +; ------------------------------------------------------------------ +; CLEAR RAM +clear_ram: + mov al, 0 + mov edi, variables + mov ecx, 52 + rep stosb + mov edi, for_variables + mov ecx, 52 + rep stosb + mov edi, for_code_points + mov ecx, 52 + rep stosb + mov byte [gosub_depth], 0 + mov edi, gosub_points + mov ecx, 20 + rep stosb + mov edi, string_vars + mov ecx, 1024 + rep stosb + ret +; ------------------------------------------------------------------ +; ASSIGNMENT +assign: + cmp eax, VARIABLE ; Are we starting with a number var? + je .do_num_var + mov edi, string_vars ; Otherwise it's a string var + mov eax, 128 + mul ebx ; (EBX = string number, passed back from get_token) + add edi, eax + push rdi + call get_token + mov byte al, [token] + cmp al, '=' + jne near .error + call get_token + cmp eax, QUOTE + je .second_is_quote + cmp eax, STRING_VAR + jne near .error + mov esi, string_vars ; Otherwise it's a string var + mov eax, 128 + mul ebx ; (EBX = string number, passed back from get_token) + add esi, eax + pop rdi + call b_string_copy + jmp mainloop +.second_is_quote: + mov esi, token + pop rdi + call b_string_copy + jmp mainloop +.do_num_var: + mov eax, 0 + mov byte al, [token] + mov byte [.tmp], al + call get_token + mov byte al, [token] + cmp al, '=' + jne near .error + call get_token + cmp eax, NUMBER + je .second_is_num + cmp eax, VARIABLE + je .second_is_variable + cmp eax, STRING + je near .second_is_string + cmp eax, UNKNOWN + jne near .error + mov byte al, [token] ; Address of string var? + cmp al, '&' + jne near .error + call get_token ; Let's see if there's a string var + cmp eax, STRING_VAR + jne near .error + mov edi, string_vars + mov eax, 128 + mul ebx + add edi, eax + mov ebx, edi + mov byte al, [.tmp] + call set_var + jmp mainloop +.second_is_variable: + mov eax, 0 + mov byte al, [token] + call get_var + mov ebx, eax + mov byte al, [.tmp] + call set_var + jmp .check_for_more +.second_is_num: + mov esi, token + call b_string_to_int + mov ebx, eax ; Number to insert in variable table + mov eax, 0 + mov byte al, [.tmp] + call set_var + ; The assignment could be simply "X = 5" etc. Or it could be + ; "X = Y + 5" -- ie more complicated. So here we check to see if + ; there's a delimiter... +.check_for_more: + mov dword eax, [prog] ; Save code location in case there's no delimiter + mov dword [.tmp_loc], eax + call get_token ; Any more to deal with in this assignment? + mov byte al, [token] + cmp al, '+' + je .theres_more + cmp al, '-' + je .theres_more + cmp al, '*' + je .theres_more + cmp al, '/' + je .theres_more + cmp al, '%' + je .theres_more + mov dword eax, [.tmp_loc] ; Not a delimiter, so step back before the token + mov dword [prog], eax ; that we just grabbed + jmp mainloop ; And go back to the code interpreter! +.theres_more: + mov byte [.delim], al + call get_token + cmp eax, VARIABLE + je .handle_variable + mov esi, token + call b_string_to_int + mov ebx, eax + mov eax, 0 + mov byte al, [.tmp] + call get_var ; This also points ESI at right place in variable table + cmp byte [.delim], '+' + jne .not_plus + add eax, ebx + jmp .finish +.not_plus: + cmp byte [.delim], '-' + jne .not_minus + sub eax, ebx + jmp .finish +.not_minus: + cmp byte [.delim], '*' + jne .not_times + mul ebx + jmp .finish +.not_times: + cmp byte [.delim], '/' + jne .not_divide + mov edx, 0 + div ebx + jmp .finish +.not_divide: + mov edx, 0 + div ebx + mov eax, edx ; Get remainder +.finish: + mov ebx, eax + mov byte al, [.tmp] + call set_var + jmp .check_for_more +.handle_variable: + mov eax, 0 + mov byte al, [token] + call get_var + mov ebx, eax + mov eax, 0 + mov byte al, [.tmp] + call get_var + cmp byte [.delim], '+' + jne .vnot_plus + add eax, ebx + jmp .vfinish +.vnot_plus: + cmp byte [.delim], '-' + jne .vnot_minus + sub eax, ebx + jmp .vfinish +.vnot_minus: + cmp byte [.delim], '*' + jne .vnot_times + mul ebx + jmp .vfinish +.vnot_times: + cmp byte [.delim], '/' + jne .vnot_divide + mov edx, 0 + div ebx + jmp .finish +.vnot_divide: + mov edx, 0 + div ebx + mov eax, edx ; Get remainder +.vfinish: + mov ebx, eax + mov byte al, [.tmp] + call set_var + jmp .check_for_more +.second_is_string: + mov edi, token + mov esi, progstart_keyword + call b_string_compare + je .is_progstart + mov esi, ramstart_keyword + call b_string_compare + je .is_ramstart + jmp .error +.is_progstart: + mov eax, 0 + mov byte al, [.tmp] + mov dword ebx, [load_point] + call set_var + jmp mainloop +.is_ramstart: + mov eax, 0 + mov byte al, [.tmp] + mov dword ebx, [prog_end] + inc ebx + inc ebx + inc ebx + call set_var + jmp mainloop +.error: + mov esi, err_syntax + jmp error +.tmp db 0 +.tmp_loc dd 0 +.delim db 0 +; ================================================================== +; SPECIFIC COMMAND CODE STARTS HERE +; ------------------------------------------------------------------ +; ALERT +do_alert: + call get_token + cmp eax, QUOTE + je .is_quote + mov esi, err_syntax + jmp error +.is_quote: + mov eax, token ; First string for alert box + mov ebx, 0 ; Others are blank + mov ecx, 0 + mov edx, 0 ; One-choice box +; call b_dialog_box + jmp mainloop +; ------------------------------------------------------------------ +; CALL +do_call: + call get_token + cmp eax, NUMBER + je .is_number + xor eax, eax + mov byte al, [token] + call get_var + jmp .execute_call +.is_number: + mov esi, token + call b_string_to_int +.execute_call: + mov ebx, 0 + mov ecx, 0 + mov edx, 0 + mov edi, 0 + mov esi, 0 + call rax + jmp mainloop +; ------------------------------------------------------------------ +; CLS +do_cls: + call b_screen_clear + jmp mainloop +; ------------------------------------------------------------------ +; CURSOR +do_cursor: + call get_token + mov esi, token + mov edi, .on_str + call b_string_compare + jc .turn_on + mov esi, token + mov edi, .off_str + call b_string_compare + jc .turn_off + mov esi, err_syntax + jmp error +.turn_on: + call b_show_cursor + jmp mainloop +.turn_off: + call b_hide_cursor + jmp mainloop +.on_str db "ON", 0 +.off_str db "OFF", 0 +; ------------------------------------------------------------------ +; CURSCHAR +do_curschar: + call get_token + cmp eax, VARIABLE + je .is_ok + mov esi, err_syntax + jmp error +.is_ok: + mov eax, 0 + mov byte al, [token] + push rax ; Store variable we're going to use + mov ah, 08h + mov ebx, 0 +; int 10h ; Get char at current cursor location + mov ebx, 0 ; We only want the lower byte (the char, not attribute) + mov bl, al + pop rax ; Get the variable back + call set_var ; And store the value + jmp mainloop +; ------------------------------------------------------------------ +; END +do_end: + mov dword esp, [orig_stack] + ret +; ------------------------------------------------------------------ +; FOR +do_for: + call get_token ; Get the variable we're using in this loop + cmp eax, VARIABLE + jne near .error + mov eax, 0 + mov byte al, [token] + mov byte [.tmp_var], al ; Store it in a temporary location for now + call get_token + mov eax, 0 ; Check it's followed up with '=' + mov byte al, [token] + cmp al, '=' + jne .error + call get_token ; Next we want a number + cmp eax, NUMBER + jne .error + mov esi, token ; Convert it + call b_string_to_int + ; At this stage, we've read something like "FOR X = 1" + ; so let's store that 1 in the variable table + mov ebx, eax + mov eax, 0 + mov byte al, [.tmp_var] + call set_var + call get_token ; Next we're looking for "TO" + cmp eax, STRING + jne .error + mov eax, token + call b_string_uppercase + mov esi, token + mov edi, .to_string + call b_string_compare + jnc .error + ; So now we're at "FOR X = 1 TO" + call get_token + cmp eax, NUMBER + jne .error + mov esi, token ; Get target number + call b_string_to_int + mov ebx, eax + mov eax, 0 + mov byte al, [.tmp_var] + sub al, 65 ; Store target number in table + mov edi, for_variables + add edi, eax + add edi, eax + mov eax, ebx + stosw + ; So we've got the variable, assigned it the starting number, and put into + ; our table the limit it should reach. But we also need to store the point in + ; code after the FOR line we should return to if NEXT X doesn't complete the loop... + mov eax, 0 + mov byte al, [.tmp_var] + sub al, 65 ; Store code position to return to in table + mov edi, for_code_points + add edi, eax + add edi, eax + mov dword eax, [prog] + stosw + jmp mainloop +.error: + mov esi, err_syntax + jmp error +.tmp_var db 0 +.to_string db 'TO', 0 +; ------------------------------------------------------------------ +; GETKEY +do_getkey: + call get_token + cmp eax, VARIABLE + je .is_variable + mov esi, err_syntax + jmp error +.is_variable: + mov eax, 0 + mov byte al, [token] + push rax + call b_input_key_check + mov ebx, 0 + mov bl, al + pop rax + call set_var + jmp mainloop +; ------------------------------------------------------------------ +; GOSUB +do_gosub: + call get_token ; Get the number (label) + cmp eax, STRING + je .is_ok + mov esi, err_goto_notlabel + jmp error +.is_ok: + mov esi, token ; Back up this label + mov edi, .tmp_token + call b_string_copy + mov eax, .tmp_token + call b_string_length + mov edi, .tmp_token ; Add ':' char to end for searching + add edi, eax + mov al, ':' + stosb + mov al, 0 + stosb + inc byte [gosub_depth] + mov eax, 0 + mov byte al, [gosub_depth] ; Get current GOSUB nest level + cmp al, 9 + jle .within_limit + mov esi, err_nest_limit + jmp error +.within_limit: + mov edi, gosub_points ; Move into our table of pointers + add edi, eax ; Table is words (not bytes) + add edi, eax + mov dword eax, [prog] + stosw ; Store current location before jump + mov dword eax, [load_point] + mov dword [prog], eax ; Return to start of program to find label +.loop: + call get_token + cmp eax, LABEL + jne .line_loop + mov esi, token + mov edi, .tmp_token + call b_string_compare + jc mainloop +.line_loop: ; Go to end of line + mov dword esi, [prog] + mov byte al, [esi] + inc dword [prog] + cmp al, 10 + jne .line_loop + mov dword eax, [prog] + mov dword ebx, [prog_end] + cmp eax, ebx + jg .past_end + jmp .loop +.past_end: + mov esi, err_label_notfound + jmp error +.tmp_token: times 30 db 0 +; ------------------------------------------------------------------ +; GOTO +do_goto: + call get_token ; Get the next token + cmp eax, STRING + je .is_ok + mov esi, err_goto_notlabel + jmp error +.is_ok: + mov esi, token ; Back up this label + mov edi, .tmp_token + call b_string_copy + mov eax, .tmp_token + call b_string_length + mov edi, .tmp_token ; Add ':' char to end for searching + add edi, eax + mov al, ':' + stosb + mov al, 0 + stosb + mov dword eax, [load_point] + mov dword [prog], eax ; Return to start of program to find label +.loop: + call get_token + cmp eax, LABEL + jne .line_loop + mov esi, token + mov edi, .tmp_token + call b_string_compare + jc mainloop +.line_loop: ; Go to end of line + mov dword esi, [prog] + mov byte al, [esi] + inc dword [prog] + cmp al, 10 + jne .line_loop + mov dword eax, [prog] + mov dword ebx, [prog_end] + cmp eax, ebx + jg .past_end + jmp .loop +.past_end: + mov esi, err_label_notfound + jmp error +.tmp_token: times 30 db 0 +; ------------------------------------------------------------------ +; IF +do_if: + call get_token + cmp eax, VARIABLE ; If can only be followed by a variable + je .num_var + cmp eax, STRING_VAR + je near .string_var + mov esi, err_syntax + jmp error +.num_var: + mov eax, 0 + mov byte al, [token] + call get_var + mov edx, eax ; Store value of first part of comparison + call get_token ; Get the delimiter + mov byte al, [token] + cmp al, '=' + je .equals + cmp al, '>' + je .greater + cmp al, '<' + je .less + mov esi, err_syntax ; If not one of the above, error out + jmp error +.equals: + call get_token ; Is this 'X = Y' (equals another variable?) + cmp eax, CHAR + je .equals_char + mov byte al, [token] + call is_letter + jc .equals_var + mov esi, token ; Otherwise it's, eg 'X = 1' (a number) + call b_string_to_int + cmp eax, edx ; On to the THEN bit if 'X = num' matches + je near .on_to_then + jmp .finish_line ; Otherwise skip the rest of the line +.equals_char: + mov eax, 0 + mov byte al, [token] + cmp eax, edx + je near .on_to_then + jmp .finish_line +.equals_var: + mov eax, 0 + mov byte al, [token] + call get_var + cmp eax, edx ; Do the variables match? + je near .on_to_then ; On to the THEN bit if so + jmp .finish_line ; Otherwise skip the rest of the line +.greater: + call get_token ; Greater than a variable or number? + mov byte al, [token] + call is_letter + jc .greater_var + mov esi, token ; Must be a number here... + call b_string_to_int + cmp eax, edx + jl near .on_to_then + jmp .finish_line +.greater_var: ; Variable in this case + mov eax, 0 + mov byte al, [token] + call get_var + cmp eax, edx ; Make the comparison! + jl .on_to_then + jmp .finish_line +.less: + call get_token + mov byte al, [token] + call is_letter + jc .less_var + mov esi, token + call b_string_to_int + cmp eax, edx + jg .on_to_then + jmp .finish_line +.less_var: + mov eax, 0 + mov byte al, [token] + call get_var + cmp eax, edx + jg .on_to_then + jmp .finish_line +.string_var: + mov byte [.tmp_string_var], bl + call get_token + mov byte al, [token] + cmp al, '=' + jne .error + call get_token + cmp eax, STRING_VAR + je .second_is_string_var + cmp eax, QUOTE + jne .error + mov esi, string_vars + mov eax, 128 + mul ebx + add esi, eax + mov edi, token + call b_string_compare + je .on_to_then + jmp .finish_line +.second_is_string_var: + mov esi, string_vars + mov eax, 128 + mul ebx + add esi, eax + mov edi, string_vars + mov ebx, 0 + mov byte bl, [.tmp_string_var] + mov eax, 128 + mul ebx + add edi, eax + call b_string_compare + jc .on_to_then + jmp .finish_line +.on_to_then: + call get_token + mov esi, token + mov edi, then_keyword + call b_string_compare + jc .then_present + mov esi, err_syntax + jmp error +.then_present: ; Continue rest of line like any other command! + jmp mainloop +.finish_line: ; IF wasn't fulfilled, so skip rest of line + mov dword esi, [prog] + mov byte al, [esi] + inc dword [prog] + cmp al, 10 + jne .finish_line + jmp mainloop +.error: + mov esi, err_syntax + jmp error +.tmp_string_var db 0 +; ------------------------------------------------------------------ +; INPUT +do_input: + mov al, 0 ; Clear string from previous usage + mov edi, .tmpstring + mov ecx, 128 + rep stosb + call get_token + cmp eax, VARIABLE ; We can only INPUT to variables! + je .number_var + cmp eax, STRING_VAR + je .string_var + mov esi, err_syntax + jmp error +.number_var: + mov rdi, .tmpstring ; Get input from the user + call b_input_string + mov rsi, .tmpstring + call b_string_length + cmp rcx, 0 + jne .char_entered + mov byte [.tmpstring], '0' ; If enter hit, fill variable with zero + mov byte [.tmpstring + 1], 0 +.char_entered: + mov esi, .tmpstring ; Convert to integer format + call b_string_to_int + mov ebx, eax + mov eax, 0 + mov byte al, [token] ; Get the variable where we're storing it... + call set_var ; ...and store it! + call b_print_newline + jmp mainloop +.string_var: + push rbx + mov rdi, .tmpstring + mov rcx, 120 ; Limit to max of 120 chars + call b_input_string + mov esi, .tmpstring + mov edi, string_vars + pop rbx + mov eax, 128 + mul ebx + add edi, eax + call b_string_copy + call b_print_newline + jmp mainloop +.tmpstring: times 128 db 0 +; ------------------------------------------------------------------ +;; LOAD +;do_load: +; call get_token +; cmp eax, QUOTE +; je .is_quote +; cmp eax, STRING_VAR +; jne .error +; mov esi, string_vars +; mov eax, 128 +; mul ebx +; add esi, eax +; jmp .get_position +;.is_quote: +; mov esi, token +;.get_position: +; mov eax, esi +; call b_file_exists +; jc .file_not_exists +; mov edx, eax ; Store for now +; call get_token +; cmp eax, VARIABLE +; je .second_is_var +; cmp eax, NUMBER +; jne .error +; mov esi, token +; call b_string_to_int +;.load_part: +; mov ecx, eax +; mov eax, edx +; call b_load_file +; mov eax, 0 +; mov byte al, 'S' +; call set_var +; mov eax, 0 +; mov byte al, 'R' +; mov ebx, 0 +; call set_var +; jmp mainloop +;.second_is_var: +; mov eax, 0 +; mov byte al, [token] +; call get_var +; jmp .load_part +;.file_not_exists: +; mov eax, 0 +; mov byte al, 'R' +; mov ebx, 1 +; call set_var +; call get_token ; Skip past the loading point -- unnecessary now +; jmp mainloop +;.error: +; mov esi, err_syntax +; jmp error +; ------------------------------------------------------------------ +; MOVE +do_move: + call get_token + cmp eax, VARIABLE + je .first_is_var + mov esi, token + call b_string_to_int + mov dl, al + jmp .onto_second +.first_is_var: + mov eax, 0 + mov byte al, [token] + call get_var + mov dl, al +.onto_second: + call get_token + cmp eax, VARIABLE + je .second_is_var + mov esi, token + call b_string_to_int + mov dh, al + jmp .finish +.second_is_var: + mov eax, 0 + mov byte al, [token] + call get_var + mov dh, al +.finish: + call b_move_cursor + jmp mainloop +; ------------------------------------------------------------------ +; NEXT +do_next: + call get_token + cmp eax, VARIABLE ; NEXT must be followed by a variable + jne .error + mov eax, 0 + mov byte al, [token] + call get_var + inc eax ; NEXT increments the variable, of course! + mov ebx, eax + mov eax, 0 + mov byte al, [token] + sub al, 65 + mov esi, for_variables + add esi, eax + add esi, eax + lodsw ; Get the target number from the table + inc eax ; (Make the loop inclusive of target number) + cmp eax, ebx ; Do the variable and target match? + je .loop_finished + mov eax, 0 ; If not, store the updated variable + mov byte al, [token] + call set_var + mov eax, 0 ; Find the code point and go back + mov byte al, [token] + sub al, 65 + mov esi, for_code_points + add esi, eax + add esi, eax + lodsw + mov dword [prog], eax + jmp mainloop +.loop_finished: + jmp mainloop +.error: + mov esi, err_syntax + jmp error +; ------------------------------------------------------------------ +; PAUSE +do_pause: + call get_token + cmp eax, VARIABLE + je .is_var + mov esi, token + call b_string_to_int + jmp .finish +.is_var: + mov eax, 0 + mov byte al, [token] + call get_var +.finish: + call b_delay + jmp mainloop +; ------------------------------------------------------------------ +; PEEK +do_peek: + call get_token + cmp eax, VARIABLE + jne .error + mov eax, 0 + mov byte al, [token] + mov byte [.tmp_var], al + call get_token + cmp eax, VARIABLE + je .dereference + cmp eax, NUMBER + jne .error + mov esi, token + call b_string_to_int +.store: + mov esi, eax + mov ebx, 0 + mov byte bl, [esi] + mov eax, 0 + mov byte al, [.tmp_var] + call set_var + jmp mainloop +.dereference: + mov byte al, [token] + call get_var + jmp .store +.error: + mov esi, err_syntax + jmp error +.tmp_var db 0 +; ------------------------------------------------------------------ +; POKE +do_poke: + call get_token + cmp eax, VARIABLE + je .first_is_var + cmp eax, NUMBER + jne .error + mov esi, token + call b_string_to_int + cmp eax, 255 + jg .error + mov byte [.first_value], al + jmp .onto_second +.first_is_var: + mov eax, 0 + mov byte al, [token] + call get_var + mov byte [.first_value], al +.onto_second: + call get_token + cmp eax, VARIABLE + je .second_is_var + cmp eax, NUMBER + jne .error + mov esi, token + call b_string_to_int +.got_value: + mov edi, eax + mov eax, 0 + mov byte al, [.first_value] + mov byte [edi], al + jmp mainloop +.second_is_var: + mov eax, 0 + mov byte al, [token] + call get_var + jmp .got_value +.error: + mov esi, err_syntax + jmp error +.first_value db 0 +; ------------------------------------------------------------------ +; PORT +do_port: + call get_token + mov esi, token + mov edi, .out_cmd + call b_string_compare + jc .do_out_cmd + mov edi, .in_cmd + call b_string_compare + jc .do_in_cmd + jmp .error +.do_out_cmd: + call get_token + cmp eax, NUMBER + jne .error + mov esi, token + call b_string_to_int ; Now EAX = port number + mov edx, eax + call get_token + cmp eax, NUMBER + je .out_is_num + cmp eax, VARIABLE + je .out_is_var + jmp .error +.out_is_num: + mov esi, token + call b_string_to_int +; call b_port_byte_out + jmp mainloop +.out_is_var: + mov eax, 0 + mov byte al, [token] + call get_var +; call b_port_byte_out + jmp mainloop +.do_in_cmd: + call get_token + cmp eax, NUMBER + jne .error + mov esi, token + call b_string_to_int + mov edx, eax + call get_token + cmp eax, VARIABLE + jne .error + mov byte cl, [token] +; call b_port_byte_in + mov ebx, 0 + mov bl, al + mov al, cl + call set_var + jmp mainloop +.error: + mov esi, err_syntax + jmp error +.out_cmd db "OUT", 0 +.in_cmd db "IN", 0 +; ------------------------------------------------------------------ +; PRINT +do_print: + call get_token ; Get part after PRINT + cmp eax, QUOTE ; What type is it? + je .print_quote + cmp eax, VARIABLE ; Numerical variable (eg X) + je .print_var + cmp eax, STRING_VAR ; String variable (eg $1) + je .print_string_var + cmp eax, STRING ; Special keyword (eg CHR or HEX) + je .print_keyword + mov esi, err_print_type ; We only print quoted strings and vars! + jmp error +.print_var: + mov eax, 0 + mov byte al, [token] + call get_var ; Get its value + call b_int_to_string ; Convert to string + mov esi, eax + call b_print_string + jmp .newline_or_not +.print_quote: ; If it's quoted text, print it + mov esi, token + call b_print_string + jmp .newline_or_not +.print_string_var: + mov esi, string_vars + mov eax, 128 + mul ebx + add esi, eax + call b_print_string + jmp .newline_or_not +.print_keyword: + mov esi, token + mov edi, chr_keyword + call b_string_compare + jc .is_chr + mov edi, hex_keyword + call b_string_compare + jc .is_hex + mov esi, err_syntax + jmp error +.is_chr: + call get_token + cmp eax, VARIABLE + jne .error + mov eax, 0 + mov byte al, [token] + call get_var + mov ah, 0Eh + int 10h + jmp .newline_or_not +.is_hex: + call get_token + cmp eax, VARIABLE + jne .error + mov eax, 0 + mov byte al, [token] + call get_var + call b_debug_dump_ax + jmp .newline_or_not +.error: + mov esi, err_syntax + jmp error +.newline_or_not: + ; We want to see if the command ends with ';' -- which means that + ; we shouldn't print a newline after it finishes. So we store the + ; current program location to pop ahead and see if there's the ';' + ; character -- otherwise we put the program location back and resume + ; the main loop +xchg bx, bx + mov dword eax, [prog] + mov dword [.tmp_loc], eax + call get_token + cmp eax, UNKNOWN + jne .ignore + mov eax, 0 + mov al, [token] + cmp al, ';' + jne .ignore + jmp mainloop ; And go back to interpreting the code! +.ignore: + call b_print_newline + mov dword eax, [.tmp_loc] + mov dword [prog], eax + jmp mainloop +.tmp_loc dd 0 +; ------------------------------------------------------------------ +; RAND +do_rand: + call get_token + cmp eax, VARIABLE + jne .error + mov byte al, [token] + mov byte [.tmp], al + call get_token + cmp eax, NUMBER + jne .error + mov esi, token + call b_string_to_int + mov dword [.num1], eax + call get_token + cmp eax, NUMBER + jne .error + mov esi, token + call b_string_to_int + mov dword [.num2], eax + mov dword eax, [.num1] + mov dword ebx, [.num2] + ; call b_get_random + mov ebx, ecx + mov eax, 0 + mov byte al, [.tmp] + call set_var + jmp mainloop +.tmp db 0 +.num1 dd 0 +.num2 dd 0 +.error: + mov esi, err_syntax + jmp error +; ------------------------------------------------------------------ +; REM +do_rem: + mov dword esi, [prog] + mov byte al, [esi] + inc dword [prog] + cmp al, 10 ; Find end of line after REM + jne do_rem + jmp mainloop +; ------------------------------------------------------------------ +; RETURN +do_return: + mov eax, 0 + mov byte al, [gosub_depth] + cmp al, 0 + jne .is_ok + mov esi, err_return + jmp error +.is_ok: + mov esi, gosub_points + add esi, eax ; Table is words (not bytes) + add esi, eax + lodsw + mov dword [prog], eax + dec byte [gosub_depth] + jmp mainloop +; ------------------------------------------------------------------ +;; SAVE +;do_save: +; call get_token +; cmp eax, QUOTE +; je .is_quote +; cmp eax, STRING_VAR +; jne near .error +; mov esi, string_vars +; mov eax, 128 +; mul ebx +; add esi, eax +; jmp .get_position +;.is_quote: +; mov esi, token +;.get_position: +; mov edi, .tmp_filename +; call b_string_copy +; call get_token +; cmp eax, VARIABLE +; je .second_is_var +; cmp eax, NUMBER +; jne .error +; mov esi, token +; call b_string_to_int +;.set_data_loc: +; mov dword [.data_loc], eax +; call get_token +; cmp eax, VARIABLE +; je .third_is_var +; cmp eax, NUMBER +; jne .error +; mov esi, token +; call b_string_to_int +;.set_data_size: +; mov dword [.data_size], eax +; mov dword eax, .tmp_filename +; mov dword ebx, [.data_loc] +; mov dword ecx, [.data_size] +; call b_write_file +; jc .save_failure +; mov eax, 0 +; mov byte al, 'R' +; mov ebx, 0 +; call set_var +; jmp mainloop +;.second_is_var: +; mov eax, 0 +; mov byte al, [token] +; call get_var +; jmp .set_data_loc +;.third_is_var: +; mov eax, 0 +; mov byte al, [token] +; call get_var +; jmp .set_data_size +;.save_failure: +; mov eax, 0 +; mov byte al, 'R' +; mov ebx, 1 +; call set_var +; jmp mainloop +;.error: +; mov esi, err_syntax +; jmp error +;.filename_loc dd 0 +;.data_loc dd 0 +;.data_size dd 0 +;.tmp_filename: times 15 db 0 +; ------------------------------------------------------------------ +; SERIAL +do_serial: + call get_token + mov esi, token + mov edi, .on_cmd + call b_string_compare + jc .do_on_cmd + mov edi, .send_cmd + call b_string_compare + jc .do_send_cmd + mov edi, .rec_cmd + call b_string_compare + jc .do_rec_cmd + jmp .error +.do_on_cmd: + call get_token + cmp eax, NUMBER + je .do_on_cmd_ok + jmp .error +.do_on_cmd_ok: + mov esi, token + call b_string_to_int + cmp eax, 1200 + je .on_cmd_slow_mode + cmp eax, 9600 + je .on_cmd_fast_mode + jmp .error +.on_cmd_fast_mode: + mov eax, 0 + ; call b_serial_port_enable + jmp mainloop +.on_cmd_slow_mode: + mov eax, 1 +; call b_serial_port_enable + jmp mainloop +.do_send_cmd: + call get_token + cmp eax, NUMBER + je .send_number + cmp eax, VARIABLE + je .send_variable + jmp .error +.send_number: + mov esi, token + call b_string_to_int + call b_serial_send + jmp mainloop +.send_variable: + mov eax, 0 + mov byte al, [token] + call get_var + call b_serial_send + jmp mainloop +.do_rec_cmd: + call get_token + cmp eax, VARIABLE + jne .error + mov byte al, [token] + mov ecx, 0 + mov cl, al + call b_serial_recv + mov ebx, 0 + mov bl, al + mov al, cl + call set_var + jmp mainloop +.error: + mov esi, err_syntax + jmp error +.on_cmd db "ON", 0 +.send_cmd db "SEND", 0 +.rec_cmd db "REC", 0 +; ------------------------------------------------------------------ +; SOUND +do_sound: + call get_token + cmp eax, VARIABLE + je .first_is_var + mov esi, token + call b_string_to_int + jmp .done_first +.first_is_var: + mov eax, 0 + mov byte al, [token] + call get_var +.done_first: + call b_speaker_tone + call get_token + cmp eax, VARIABLE + je .second_is_var + mov esi, token + call b_string_to_int + jmp .finish +.second_is_var: + mov eax, 0 + mov byte al, [token] + call get_var +.finish: + call b_delay + call b_speaker_off + jmp mainloop +; ------------------------------------------------------------------ +; WAITKEY +do_waitkey: + call get_token + cmp eax, VARIABLE + je .is_variable + mov esi, err_syntax + jmp error +.is_variable: + mov eax, 0 + mov byte al, [token] + push rax + call b_input_key_wait + cmp eax, 48E0h + je .up_pressed + cmp eax, 50E0h + je .down_pressed + cmp eax, 4BE0h + je .left_pressed + cmp eax, 4DE0h + je .right_pressed +.store: + mov ebx, 0 + mov bl, al + pop rax + call set_var + jmp mainloop +.up_pressed: + mov eax, 1 + jmp .store +.down_pressed: + mov eax, 2 + jmp .store +.left_pressed: + mov eax, 3 + jmp .store +.right_pressed: + mov eax, 4 + jmp .store +; ================================================================== +; INTERNAL ROUTINES FOR INTERPRETER +; ------------------------------------------------------------------ +; Get value of variable character specified in AL (eg 'A') +get_var: + sub al, 65 + mov esi, variables + add esi, eax + add esi, eax + lodsw + ret +; ------------------------------------------------------------------ +; Set value of variable character specified in AL (eg 'A') +; with number specified in EBX +set_var: + mov ah, 0 + sub al, 65 ; Remove ASCII codes before 'A' + mov edi, variables ; Find position in table (of words) + add edi, eax + add edi, eax + mov eax, ebx + stosw + ret +; ------------------------------------------------------------------ +; Get token from current position in prog +get_token: + mov dword esi, [prog] + lodsb + cmp al, 10 + je .newline + cmp al, 13 ;allow for CRLF + je .newline + cmp al, ' ' + je .newline + call is_number + jc get_number_token + cmp al, '"' + je get_quote_token + cmp al, 39 ; Quote mark (') + je get_char_token + cmp al, '$' + je near get_string_var_token + jmp get_string_token +.newline: + inc dword [prog] + jmp get_token +get_number_token: + mov dword esi, [prog] + mov edi, token +.loop: + lodsb + cmp al, 10 + je .done + cmp al, 13 ;allow for CRLF + je .done + cmp al, ' ' + je .done + call is_number + jc .fine + mov esi, err_char_in_num + jmp error +.fine: + stosb + inc dword [prog] + jmp .loop +.done: + mov al, 0 ; Zero-terminate the token + stosb + mov eax, NUMBER ; Pass back the token type + ret +get_char_token: + inc dword [prog] ; Move past first quote (') + mov dword esi, [prog] + lodsb + mov byte [token], al + lodsb + cmp al, 39 ; Needs to finish with another quote + je .is_ok + mov esi, err_quote_term + jmp error +.is_ok: + inc dword [prog] + inc dword [prog] + mov eax, CHAR + ret +get_quote_token: + inc dword [prog] ; Move past first quote (") char + mov dword esi, [prog] + mov edi, token +.loop: + lodsb + cmp al, '"' + je .done + cmp al, 10 + je .error + stosb + inc dword [prog] + jmp .loop +.done: + mov al, 0 ; Zero-terminate the token + stosb + inc dword [prog] ; Move past final quote + mov eax, QUOTE ; Pass back token type + ret +.error: + mov esi, err_quote_term + jmp error +get_string_var_token: + lodsb + mov ebx, 0 ; If it's a string var, pass number of string in EBX + mov bl, al + sub bl, 49 + inc dword [prog] + inc dword [prog] + mov eax, STRING_VAR + ret + +get_string_token: + mov dword esi, [prog] + mov edi, token +.loop: + lodsb + cmp al, 10 + je .done + cmp al, 13 ;allow for CRLF + je .done + cmp al, ' ' + je .done + stosb + inc dword [prog] + jmp .loop +.done: + mov al, 0 ; Zero-terminate the token + stosb + mov eax, token + call b_string_uppercase + mov eax, token + call b_string_length ; How long was the token? + cmp eax, 1 ; If 1 char, it's a variable or delimiter + je .is_not_string + mov esi, token ; If the token ends with ':', it's a label + add esi, eax + dec esi + lodsb + cmp al, ':' + je .is_label + mov eax, STRING ; Otherwise it's a general string of characters + ret +.is_label: + mov eax, LABEL + ret +.is_not_string: + mov byte al, [token] + call is_letter + jc .is_var + mov eax, UNKNOWN + ret +.is_var: + mov eax, VARIABLE ; Otherwise probably a variable + ret +; ------------------------------------------------------------------ +; Set carry flag if AL contains ASCII number +is_number: + cmp al, 48 + jl .not_number + cmp al, 57 + jg .not_number + stc + ret +.not_number: + clc + ret +; ------------------------------------------------------------------ +; Set carry flag if AL contains ASCII letter +is_letter: + cmp al, 65 + jl .not_letter + cmp al, 90 + jg .not_letter + stc + ret +.not_letter: + clc + ret +; ------------------------------------------------------------------ +; Print error message and quit out +error: + call b_print_newline + call b_print_string ; Print error message + call b_print_newline + mov dword esp, [orig_stack] ; Restore the stack to as it was when BASIC started + ret ; And finish +; ------------------------------------------------------------------ + + + + ; Error messages text... +err_char_in_num db "Error: unexpected character in number", 0 +err_quote_term db "Error: quoted string or character not terminated correctly", 0 +err_print_type db "Error: PRINT command not followed by quoted text or variable", 0 +err_cmd_unknown db "Error: unknown command", 0 +err_goto_notlabel db "Error: GOTO or GOSUB not followed by label", 0 +err_label_notfound db "Error: GOTO or GOSUB label not found", 0 +err_return db "Error: RETURN without GOSUB", 0 +err_nest_limit db "Error: FOR or GOSUB nest limit exceeded", 0 +err_next db "Error: NEXT without FOR", 0 +err_syntax db "Error: syntax error", 0 +; ================================================================== +; DATA SECTION +orig_stack dd 0 ; Original stack location when BASIC started +prog dd 0 ; Pointer to current location in BASIC code +prog_end dd 0 ; Pointer to final byte of BASIC code +load_point dd 0 +token_type db 0 ; Type of last token read (eg NUMBER, VARIABLE) +token: times 255 db 0 ; Storage space for the token +variables: times 26 dd 0 ; Storage space for variables A to Z +for_variables: times 26 dd 0 ; Storage for FOR loops +for_code_points: times 26 dd 0 ; Storage for code positions where FOR loops start +alert_cmd db "ALERT", 0 +call_cmd db "CALL", 0 +cls_cmd db "CLS", 0 +cursor_cmd db "CURSOR", 0 +curschar_cmd db "CURSCHAR", 0 +end_cmd db "END", 0 +for_cmd db "FOR", 0 +gosub_cmd db "GOSUB", 0 +goto_cmd db "GOTO", 0 +getkey_cmd db "GETKEY", 0 +if_cmd db "IF", 0 +input_cmd db "INPUT", 0 +load_cmd db "LOAD", 0 +move_cmd db "MOVE", 0 +next_cmd db "NEXT", 0 +pause_cmd db "PAUSE", 0 +peek_cmd db "PEEK", 0 +poke_cmd db "POKE", 0 +port_cmd db "PORT", 0 +print_cmd db "PRINT", 0 +rem_cmd db "REM", 0 +rand_cmd db "RAND", 0 +return_cmd db "RETURN", 0 +save_cmd db "SAVE", 0 +serial_cmd db "SERIAL", 0 +sound_cmd db "SOUND", 0 +waitkey_cmd db "WAITKEY", 0 +then_keyword db "THEN", 0 +chr_keyword db "CHR", 0 +hex_keyword db "HEX", 0 +progstart_keyword db "PROGSTART", 0 +ramstart_keyword db "RAMSTART", 0 +gosub_depth db 0 +gosub_points: times 10 dd 0 ; Points in code to RETURN to +string_vars: times 1024 db 0 ; 8 * 128 byte strings +; ------------------------------------------------------------------ +basic_prog: + DB 'CLS',13,10 + DB 'PRINT "Please type your name: ";',13,10 + DB 'INPUT $N',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT "Hello "',13,10 + DB 'PRINT $N',13,10 + DB 'PRINT ", welcome to MikeOS Basic!"',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT "It supports FOR...NEXT loops and simple integer maths..."',13,10 + DB 'PRINT ""',13,10 + DB 'FOR I = 1 TO 15',13,10 + DB 'J = I * I',13,10 + DB 'K = J * I',13,10 + DB 'L = K * I',13,10 + DB 'PRINT I',13,10 + DB 'PRINT " "',13,10 + DB 'PRINT J',13,10 + DB 'PRINT " "',13,10 + DB 'PRINT K',13,10 + DB 'PRINT " "',13,10 + DB 'PRINT L',13,10 + DB 'NEXT I',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT " ...and IF...THEN and GOSUB and lots of other stuff. Bye!"',13,10 + DB 'END',13,10 diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bf.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bf.asm index 0530659e..85dfdf03 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bf.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bf.asm @@ -1,115 +1,115 @@ -; ============================================================================= -; Brainf*ck -- A 64-bit Brainf*ck interpreter -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; http://en.wikipedia.org/wiki/Brainfuck -; ============================================================================= - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -bf_start: - ; clear memory here - -bf_run: - mov rsi, [codepointer] - lodsb - add qword [codepointer], 1 - cmp al, '>' - je incptr - cmp al, '<' - je decptr - cmp al, '+' - je incdata - cmp al, '-' - je decdata - cmp al, '.' - je outchar - cmp al, ',' - je inchar - cmp al, '[' - je startloop - cmp al, ']' - je endloop - ret - -incptr: - add qword [datapointer], 8 - jmp bf_run - -decptr: - sub qword [datapointer], 8 - jmp bf_run - -incdata: - mov rax, [datapointer] - mov rsi, rax - mov rdi, rax - lodsq - add rax, 1 - stosq - jmp bf_run - -decdata: - mov rax, [datapointer] - mov rsi, rax - mov rdi, rax - lodsq - sub rax, 1 - stosq - jmp bf_run - -outchar: - mov rsi, [datapointer] - lodsq - call b_print_char - jmp bf_run - -inchar: - mov rdi, [datapointer] - xor rax, rax - call b_input_key_wait - stosq - jmp bf_run - -startloop: - mov rsi, [datapointer] - lodsq - cmp rax, 0 - jne bf_run - mov rsi, [codepointer] -startloop_next: - lodsb - cmp al, ']' - jne startloop_next - mov qword [codepointer], rsi - jmp bf_run - -endloop: - xchg bx, bx - mov rsi, [datapointer] - lodsq - cmp rax, 0 - je bf_run - mov rsi, [codepointer] - std -endloop_next: - lodsb - cmp al, '[' - jne endloop_next - add rsi, 1 - mov qword [codepointer], rsi - cld - jmp bf_run - -align 16 -datapointer: dq data -codepointer: dq code - -code: -db '>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.', 0 - -align 16 +; ============================================================================= +; Brainf*ck -- A 64-bit Brainf*ck interpreter +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; http://en.wikipedia.org/wiki/Brainfuck +; ============================================================================= + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +bf_start: + ; clear memory here + +bf_run: + mov rsi, [codepointer] + lodsb + add qword [codepointer], 1 + cmp al, '>' + je incptr + cmp al, '<' + je decptr + cmp al, '+' + je incdata + cmp al, '-' + je decdata + cmp al, '.' + je outchar + cmp al, ',' + je inchar + cmp al, '[' + je startloop + cmp al, ']' + je endloop + ret + +incptr: + add qword [datapointer], 8 + jmp bf_run + +decptr: + sub qword [datapointer], 8 + jmp bf_run + +incdata: + mov rax, [datapointer] + mov rsi, rax + mov rdi, rax + lodsq + add rax, 1 + stosq + jmp bf_run + +decdata: + mov rax, [datapointer] + mov rsi, rax + mov rdi, rax + lodsq + sub rax, 1 + stosq + jmp bf_run + +outchar: + mov rsi, [datapointer] + lodsq + call b_print_char + jmp bf_run + +inchar: + mov rdi, [datapointer] + xor rax, rax + call b_input_key_wait + stosq + jmp bf_run + +startloop: + mov rsi, [datapointer] + lodsq + cmp rax, 0 + jne bf_run + mov rsi, [codepointer] +startloop_next: + lodsb + cmp al, ']' + jne startloop_next + mov qword [codepointer], rsi + jmp bf_run + +endloop: + xchg bx, bx + mov rsi, [datapointer] + lodsq + cmp rax, 0 + je bf_run + mov rsi, [codepointer] + std +endloop_next: + lodsb + cmp al, '[' + jne endloop_next + add rsi, 1 + mov qword [codepointer], rsi + cld + jmp bf_run + +align 16 +datapointer: dq data +codepointer: dq code + +code: +db '>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.', 0 + +align 16 data: \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bmdev.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bmdev.asm index 4072e7eb..181fa2c6 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bmdev.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/bmdev.asm @@ -1,86 +1,86 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Include file for Bare Metal program development (API version 2.0) -; ============================================================================= - - -b_print_string equ 0x0000000000100010 ; Displays text. IN: RSI = message location (zero-terminated string) -b_print_char equ 0x0000000000100020 ; Displays a char. IN: AL = char to display -b_print_char_hex equ 0x0000000000100030 ; Displays a char in hex mode. IN: AL = char to display -b_print_newline equ 0x0000000000100040 ; Print a new line -b_input_key_check equ 0x0000000000100050 ; Scans keyboard for input, but doesn't wait. OUT: AL = ASCII code or 0 if no key pressed -b_input_key_wait equ 0x0000000000100060 ; Waits for keypress and returns key. OUT: AL = key pressed -b_input_string equ 0x0000000000100070 ; Take string from keyboard entry. IN: RDI = location where string will be stored. RCX = max chars to accept -b_delay equ 0x0000000000100080 ; Pause for a set time. IN: RAX = Time in hundredths of a second -b_speaker_tone equ 0x0000000000100090 ; Generate PC speaker tone (call b_speaker_off after). IN: RAX = note frequency -b_speaker_off equ 0x00000000001000A0 ; Shut off the PC speaker -b_speaker_beep equ 0x00000000001000B0 ; Play a standard beep noise -b_move_cursor equ 0x00000000001000C0 ; Move the cursor on screen. IN: AL = column, AH = row -b_string_length equ 0x00000000001000D0 ; Return the length of a string. IN: RSI = string address. OUT: RCX = string length -b_find_char_in_string equ 0x00000000001000E0 ; Find first location of character in a string. IN: RSI = string location, AL = character to find. OUT: RAX = location in string, or 0 if char not present -b_string_copy equ 0x00000000001000F0 ; Copy the contents of one string into another. IN: RSI = source, RDI = destination -b_string_truncate equ 0x0000000000100100 ; Chop string down to specified number of characters. IN: RSI = string location, RAX = number of characters -b_string_join equ 0x0000000000100110 ; Join two strings into a third string. IN: RAX = string one, RBX = string two, RDI = destination string -b_string_chomp equ 0x0000000000100120 ; Strip leading and trailing spaces from a string. IN: RSI = string location -b_string_strip equ 0x0000000000100130 ; Removes specified character from a string. IN: RSI = string location, AL = character to remove -b_string_compare equ 0x0000000000100140 ; See if two strings match. IN: RSI = string one, RDI = string two. OUT: Carry flag set if same -b_string_uppercase equ 0x0000000000100150 ; Convert a string to all uppercase characters. IN: RSI = string address -b_string_lowercase equ 0x0000000000100160 ; Convert a string to all lowercase characters. IN: RSI = string address -b_int_to_string equ 0x0000000000100170 ; Convert an integer to a string. IN: RAX = interger. OUT: RDI = destination string -b_string_to_int equ 0x0000000000100180 ; Convert a string to an interger. IN: RSI = source string. OUT: RAX = interger -b_debug_dump_reg equ 0x0000000000100190 ; Dump the registers to the screen -b_debug_dump_mem equ 0x00000000001001A0 ; Dump contents of memory to the screen. IN: RSI = Start of memory address to dump, RCX = number of bytes to dump -b_debug_dump_rax equ 0x00000000001001B0 ; Dump the content of RAX (64-bit) to the screen -b_debug_dump_eax equ 0x00000000001001C0 ; Dump the content of EAX (32-bit) to the screen -b_debug_dump_ax equ 0x00000000001001D0 ; Dump the content of AX (16-bit) to the screen -b_debug_dump_al equ 0x00000000001001E0 ; Dump the content of AL (8-bit) to the screen -b_smp_reset equ 0x00000000001001F0 ; Resets a CPU/Core. IN: AL = CPU # -b_smp_get_id equ 0x0000000000100200 ; Returns the APIC ID of the CPU that ran this function. OUT: RAX = CPU's APIC ID number -b_smp_enqueue equ 0x0000000000100210 ; Add a workload to the processing queue. IN: RAX = Code to execute, RBX = Variable/Data to work on -b_smp_dequeue equ 0x0000000000100220 ; Dequeue a workload from the processing queue. OUT: RAX = Code to execute, RBX = Variable/Data to work on -b_serial_send equ 0x0000000000100230 ; Send a byte over the primary serial port. IN: AL = Byte to send over serial port -b_serial_recv equ 0x0000000000100240 ; Receive a byte from the primary serial port. OUT: AL = Byte recevied, Carry flag is set if a byte was received (otherwise AL is trashed) -b_string_parse equ 0x0000000000100250 ; Parse a string into individual words. IN: RSI = Address of string. OUT: RCX = word count -b_get_argc equ 0x0000000000100260 ; Return the number arguments passed to the program. OUT: AL = Number of arguments -b_get_argv equ 0x0000000000100270 ; Get the value of an argument that was passed to the program. IN: AL = Argument number. OUT: RSI = Start of numbered argument string -b_smp_queuelen equ 0x0000000000100280 ; Returns the number of items in the processing queue. OUT: RAX = number of items in processing queue -b_smp_wait equ 0x0000000000100290 ; Wait until all other CPU Cores are finished processing -b_get_timecounter equ 0x00000000001002A0 ; Get the current RTC clock couter value. OUT: RAX = Time in eights of a second since clock started -b_string_append equ 0x00000000001002B0 ; Append a string to an existing string. IN: RSI = String to be appended, RDI = Destination string -b_int_to_hex_string equ 0x00000000001002C0 ; Convert an integer to a hex string. IN: RAX = Integer value. RDI = location to store string -b_hex_string_to_int equ 0x00000000001002D0 ; Convert up to 8 hexascii to bin. IN: RSI = Location of hex asciiz string. OUT: RAX = binary value of hex string -b_string_change_char equ 0x00000000001002E0 ; Change all instances of a character in a string. IN: RSI = string location, AL = character to replace, BL = replacement character -b_is_digit equ 0x00000000001002F0 ; Check if character is a digit. IN: AL = ASCII char. OUT: EQ flag set if numeric -b_is_alpha equ 0x0000000000100300 ; Check if character is a letter. IN: AL = ASCII char. OUT: EQ flag set if alpha -b_file_read equ 0x0000000000100310 ; Read a file from disk into memory. IN: RSI = Address of filename string, RDI = Memory location where file will be loaded to. OUT: Carry is set if the file was not found or an error occured -b_file_write equ 0x0000000000100320 ; Write memory to a file on disk. IN: RSI = Memory location of data to be written, RDI = Address of filename string, RCX = Number of bytes to write. OUT: Carry is set if an error occured -b_file_delete equ 0x0000000000100330 ; Delete a file from disk. IN: RSI = Memory location of file name to delete. OUT: Carry is set if the file was not found or an error occured -b_file_get_list equ 0x0000000000100340 ; Generate a list of files on disk. IN: RDI = Location to store list. OUT: RDI = pointer to end of list -b_smp_run equ 0x0000000000100350 ; Call the function address in RAX. IN: RAX = Memory location of code to run -b_smp_lock equ 0x0000000000100360 ; Lock a variable. IN: RAX = Memory address of variable -b_smp_unlock equ 0x0000000000100370 ; Unlock a variable. IN: RAX = Memory address of variable -b_print_string_with_color equ 0x0000000000100380 ; Displays text in colour. IN: RSI = message location (zero-terminated string), BL = colour -b_print_char_with_color equ 0x0000000000100390 ; Displays a char in colour. IN: AL = char to display, BL = colour -b_ethernet_tx equ 0x00000000001003A0 ; Transmit a packet via Ethernet. IN: RSI = Memory location where data is stored, RDI = Pointer to 48 bit destination address, BX = Type of packet (If set to 0 then the EtherType will be set to the length of data), CX = Length of data -b_ethernet_rx equ 0x00000000001003B0 ; Polls the Ethernet card for received data. IN: RDI = Memory location where packet will be stored. OUT: RCX = Length of packet -b_mem_allocate equ 0x00000000001003C0 ; Allocates the requested number of 2 MiB pages. IN: RCX = Number of pages to allocate. OUT: RAX = Starting address, RCX = Number of pages allocated (Set to the value asked for or 0 on failure) -b_mem_release equ 0x00000000001003D0 ; Frees the requested number of 2 MiB pages. IN: RAX = Starting address, RCX = Number of pages to free. OUT: RCX = Number of pages freed -b_mem_get_free equ 0x00000000001003E0 ; Returns the number of 2 MiB pages that are available. OUT: RCX = Number of free 2 MiB pages -b_smp_numcores equ 0x00000000001003F0 ; Returns the number of cores in this computer. OUT: RAX = number of cores in this computer -b_file_get_size equ 0x0000000000100400 ; Return the size of a file on disk. IN: RSI = Address of filename string. OUT: RCX = Size in bytes, Carry is set if the file was not found or an error occured -b_ethernet_avail equ 0x0000000000100410 ; Check if Ethernet is available. IN: Nothing. OUT: RAX = Set to 1 if Ethernet is enabled on host -b_print_char_hex_with_color equ 0x0000000000100420 ; Displays a char in hex mode with color. IN: AL = char to display, BL = colour -b_screen_clear equ 0x0000000000100440 ; Clear the screen -b_show_cursor equ 0x0000000000100450 ; Turns on cursor in text mode -b_hide_cursor equ 0x0000000000100460 ; Turns off cursor in text mode -b_show_statusbar equ 0x0000000000100470 ; Show the system status bar -b_hide_statusbar equ 0x0000000000100480 ; Hide the system status bar -b_screen_update equ 0x0000000000100490 ; Manually refresh the screen from the frame buffer -b_print_chars equ 0x00000000001004A0 ; Displays text. IN: RSI = message location (A string, not zero-terminated), RCX = number of chars to print -b_print_chars_with_color equ 0x00000000001004B0 ; Displays text with color. IN: RSI = message location (A string, not zero-terminated), BL = color, RCX = number of chars to print - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Include file for Bare Metal program development (API version 2.0) +; ============================================================================= + + +b_print_string equ 0x0000000000100010 ; Displays text. IN: RSI = message location (zero-terminated string) +b_print_char equ 0x0000000000100020 ; Displays a char. IN: AL = char to display +b_print_char_hex equ 0x0000000000100030 ; Displays a char in hex mode. IN: AL = char to display +b_print_newline equ 0x0000000000100040 ; Print a new line +b_input_key_check equ 0x0000000000100050 ; Scans keyboard for input, but doesn't wait. OUT: AL = ASCII code or 0 if no key pressed +b_input_key_wait equ 0x0000000000100060 ; Waits for keypress and returns key. OUT: AL = key pressed +b_input_string equ 0x0000000000100070 ; Take string from keyboard entry. IN: RDI = location where string will be stored. RCX = max chars to accept +b_delay equ 0x0000000000100080 ; Pause for a set time. IN: RAX = Time in hundredths of a second +b_speaker_tone equ 0x0000000000100090 ; Generate PC speaker tone (call b_speaker_off after). IN: RAX = note frequency +b_speaker_off equ 0x00000000001000A0 ; Shut off the PC speaker +b_speaker_beep equ 0x00000000001000B0 ; Play a standard beep noise +b_move_cursor equ 0x00000000001000C0 ; Move the cursor on screen. IN: AL = column, AH = row +b_string_length equ 0x00000000001000D0 ; Return the length of a string. IN: RSI = string address. OUT: RCX = string length +b_find_char_in_string equ 0x00000000001000E0 ; Find first location of character in a string. IN: RSI = string location, AL = character to find. OUT: RAX = location in string, or 0 if char not present +b_string_copy equ 0x00000000001000F0 ; Copy the contents of one string into another. IN: RSI = source, RDI = destination +b_string_truncate equ 0x0000000000100100 ; Chop string down to specified number of characters. IN: RSI = string location, RAX = number of characters +b_string_join equ 0x0000000000100110 ; Join two strings into a third string. IN: RAX = string one, RBX = string two, RDI = destination string +b_string_chomp equ 0x0000000000100120 ; Strip leading and trailing spaces from a string. IN: RSI = string location +b_string_strip equ 0x0000000000100130 ; Removes specified character from a string. IN: RSI = string location, AL = character to remove +b_string_compare equ 0x0000000000100140 ; See if two strings match. IN: RSI = string one, RDI = string two. OUT: Carry flag set if same +b_string_uppercase equ 0x0000000000100150 ; Convert a string to all uppercase characters. IN: RSI = string address +b_string_lowercase equ 0x0000000000100160 ; Convert a string to all lowercase characters. IN: RSI = string address +b_int_to_string equ 0x0000000000100170 ; Convert an integer to a string. IN: RAX = interger. OUT: RDI = destination string +b_string_to_int equ 0x0000000000100180 ; Convert a string to an interger. IN: RSI = source string. OUT: RAX = interger +b_debug_dump_reg equ 0x0000000000100190 ; Dump the registers to the screen +b_debug_dump_mem equ 0x00000000001001A0 ; Dump contents of memory to the screen. IN: RSI = Start of memory address to dump, RCX = number of bytes to dump +b_debug_dump_rax equ 0x00000000001001B0 ; Dump the content of RAX (64-bit) to the screen +b_debug_dump_eax equ 0x00000000001001C0 ; Dump the content of EAX (32-bit) to the screen +b_debug_dump_ax equ 0x00000000001001D0 ; Dump the content of AX (16-bit) to the screen +b_debug_dump_al equ 0x00000000001001E0 ; Dump the content of AL (8-bit) to the screen +b_smp_reset equ 0x00000000001001F0 ; Resets a CPU/Core. IN: AL = CPU # +b_smp_get_id equ 0x0000000000100200 ; Returns the APIC ID of the CPU that ran this function. OUT: RAX = CPU's APIC ID number +b_smp_enqueue equ 0x0000000000100210 ; Add a workload to the processing queue. IN: RAX = Code to execute, RBX = Variable/Data to work on +b_smp_dequeue equ 0x0000000000100220 ; Dequeue a workload from the processing queue. OUT: RAX = Code to execute, RBX = Variable/Data to work on +b_serial_send equ 0x0000000000100230 ; Send a byte over the primary serial port. IN: AL = Byte to send over serial port +b_serial_recv equ 0x0000000000100240 ; Receive a byte from the primary serial port. OUT: AL = Byte recevied, Carry flag is set if a byte was received (otherwise AL is trashed) +b_string_parse equ 0x0000000000100250 ; Parse a string into individual words. IN: RSI = Address of string. OUT: RCX = word count +b_get_argc equ 0x0000000000100260 ; Return the number arguments passed to the program. OUT: AL = Number of arguments +b_get_argv equ 0x0000000000100270 ; Get the value of an argument that was passed to the program. IN: AL = Argument number. OUT: RSI = Start of numbered argument string +b_smp_queuelen equ 0x0000000000100280 ; Returns the number of items in the processing queue. OUT: RAX = number of items in processing queue +b_smp_wait equ 0x0000000000100290 ; Wait until all other CPU Cores are finished processing +b_get_timecounter equ 0x00000000001002A0 ; Get the current RTC clock couter value. OUT: RAX = Time in eights of a second since clock started +b_string_append equ 0x00000000001002B0 ; Append a string to an existing string. IN: RSI = String to be appended, RDI = Destination string +b_int_to_hex_string equ 0x00000000001002C0 ; Convert an integer to a hex string. IN: RAX = Integer value. RDI = location to store string +b_hex_string_to_int equ 0x00000000001002D0 ; Convert up to 8 hexascii to bin. IN: RSI = Location of hex asciiz string. OUT: RAX = binary value of hex string +b_string_change_char equ 0x00000000001002E0 ; Change all instances of a character in a string. IN: RSI = string location, AL = character to replace, BL = replacement character +b_is_digit equ 0x00000000001002F0 ; Check if character is a digit. IN: AL = ASCII char. OUT: EQ flag set if numeric +b_is_alpha equ 0x0000000000100300 ; Check if character is a letter. IN: AL = ASCII char. OUT: EQ flag set if alpha +b_file_read equ 0x0000000000100310 ; Read a file from disk into memory. IN: RSI = Address of filename string, RDI = Memory location where file will be loaded to. OUT: Carry is set if the file was not found or an error occured +b_file_write equ 0x0000000000100320 ; Write memory to a file on disk. IN: RSI = Memory location of data to be written, RDI = Address of filename string, RCX = Number of bytes to write. OUT: Carry is set if an error occured +b_file_delete equ 0x0000000000100330 ; Delete a file from disk. IN: RSI = Memory location of file name to delete. OUT: Carry is set if the file was not found or an error occured +b_file_get_list equ 0x0000000000100340 ; Generate a list of files on disk. IN: RDI = Location to store list. OUT: RDI = pointer to end of list +b_smp_run equ 0x0000000000100350 ; Call the function address in RAX. IN: RAX = Memory location of code to run +b_smp_lock equ 0x0000000000100360 ; Lock a variable. IN: RAX = Memory address of variable +b_smp_unlock equ 0x0000000000100370 ; Unlock a variable. IN: RAX = Memory address of variable +b_print_string_with_color equ 0x0000000000100380 ; Displays text in colour. IN: RSI = message location (zero-terminated string), BL = colour +b_print_char_with_color equ 0x0000000000100390 ; Displays a char in colour. IN: AL = char to display, BL = colour +b_ethernet_tx equ 0x00000000001003A0 ; Transmit a packet via Ethernet. IN: RSI = Memory location where data is stored, RDI = Pointer to 48 bit destination address, BX = Type of packet (If set to 0 then the EtherType will be set to the length of data), CX = Length of data +b_ethernet_rx equ 0x00000000001003B0 ; Polls the Ethernet card for received data. IN: RDI = Memory location where packet will be stored. OUT: RCX = Length of packet +b_mem_allocate equ 0x00000000001003C0 ; Allocates the requested number of 2 MiB pages. IN: RCX = Number of pages to allocate. OUT: RAX = Starting address, RCX = Number of pages allocated (Set to the value asked for or 0 on failure) +b_mem_release equ 0x00000000001003D0 ; Frees the requested number of 2 MiB pages. IN: RAX = Starting address, RCX = Number of pages to free. OUT: RCX = Number of pages freed +b_mem_get_free equ 0x00000000001003E0 ; Returns the number of 2 MiB pages that are available. OUT: RCX = Number of free 2 MiB pages +b_smp_numcores equ 0x00000000001003F0 ; Returns the number of cores in this computer. OUT: RAX = number of cores in this computer +b_file_get_size equ 0x0000000000100400 ; Return the size of a file on disk. IN: RSI = Address of filename string. OUT: RCX = Size in bytes, Carry is set if the file was not found or an error occured +b_ethernet_avail equ 0x0000000000100410 ; Check if Ethernet is available. IN: Nothing. OUT: RAX = Set to 1 if Ethernet is enabled on host +b_print_char_hex_with_color equ 0x0000000000100420 ; Displays a char in hex mode with color. IN: AL = char to display, BL = colour +b_screen_clear equ 0x0000000000100440 ; Clear the screen +b_show_cursor equ 0x0000000000100450 ; Turns on cursor in text mode +b_hide_cursor equ 0x0000000000100460 ; Turns off cursor in text mode +b_show_statusbar equ 0x0000000000100470 ; Show the system status bar +b_hide_statusbar equ 0x0000000000100480 ; Hide the system status bar +b_screen_update equ 0x0000000000100490 ; Manually refresh the screen from the frame buffer +b_print_chars equ 0x00000000001004A0 ; Displays text. IN: RSI = message location (A string, not zero-terminated), RCX = number of chars to print +b_print_chars_with_color equ 0x00000000001004B0 ; Displays text with color. IN: RSI = message location (A string, not zero-terminated), BL = color, RCX = number of chars to print + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/ethtool.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/ethtool.asm index e83151ad..dacadebe 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/ethtool.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/ethtool.asm @@ -1,72 +1,72 @@ -; ----------------------------------------------------------------- -; EthTool v0.1 - Ethernet debugging tool -; Ian Seyler @ Return Infinity -; ----------------------------------------------------------------- - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -ethtool: - - mov rsi, startstring - call b_print_string - -ethtool_command: - call b_input_key_wait - or al, 00100000b ; Convert character to lowercase if it is not already - - cmp al, 's' - je ethtool_send - cmp al, 'r' - je ethtool_receive - cmp al, 'q' - je ethtool_finish - jmp ethtool_command ; Didn't get any key we were expecting so try again. - -ethtool_finish: - call b_print_newline - ret ; Back to OS - -ethtool_send: - mov rsi, sendstring - call b_print_string - mov rdi, broadcastaddress - mov rsi, startstring - mov rbx, 0xABBA - mov rcx, 63 - call b_ethernet_tx - mov rsi, sentstring - call b_print_string - jmp ethtool_command - -ethtool_receive: - mov rsi, receivestring - call b_print_string - mov rdi, EthernetBuffer - call b_ethernet_rx - cmp rcx, 0 - je ethtool_receive_nopacket - mov rsi, receiveddata - call b_print_string - mov rsi, EthernetBuffer - call b_debug_dump_mem - jmp ethtool_command - -ethtool_receive_nopacket: - mov rsi, receivednothingstring - call b_print_string - jmp ethtool_command - -; ----------------------------------------------------------------- - -startstring: db 'EthTool: S to send a packet, R to recieve a packet, Q to quit.', 0 -sendstring: db 13, 'Sending packet, ', 0 -sentstring: db 'Sent', 0 -receivestring: db 13, 'Receiving packet, ', 0 -receivednothingstring: db 'Nothing there', 0 -receiveddata: db 'Data received', 13, 0 -broadcastaddress: db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 +; ----------------------------------------------------------------- +; EthTool v0.1 - Ethernet debugging tool +; Ian Seyler @ Return Infinity +; ----------------------------------------------------------------- + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +ethtool: + + mov rsi, startstring + call b_print_string + +ethtool_command: + call b_input_key_wait + or al, 00100000b ; Convert character to lowercase if it is not already + + cmp al, 's' + je ethtool_send + cmp al, 'r' + je ethtool_receive + cmp al, 'q' + je ethtool_finish + jmp ethtool_command ; Didn't get any key we were expecting so try again. + +ethtool_finish: + call b_print_newline + ret ; Back to OS + +ethtool_send: + mov rsi, sendstring + call b_print_string + mov rdi, broadcastaddress + mov rsi, startstring + mov rbx, 0xABBA + mov rcx, 63 + call b_ethernet_tx + mov rsi, sentstring + call b_print_string + jmp ethtool_command + +ethtool_receive: + mov rsi, receivestring + call b_print_string + mov rdi, EthernetBuffer + call b_ethernet_rx + cmp rcx, 0 + je ethtool_receive_nopacket + mov rsi, receiveddata + call b_print_string + mov rsi, EthernetBuffer + call b_debug_dump_mem + jmp ethtool_command + +ethtool_receive_nopacket: + mov rsi, receivednothingstring + call b_print_string + jmp ethtool_command + +; ----------------------------------------------------------------- + +startstring: db 'EthTool: S to send a packet, R to recieve a packet, Q to quit.', 0 +sendstring: db 13, 'Sending packet, ', 0 +sentstring: db 'Sent', 0 +receivestring: db 13, 'Receiving packet, ', 0 +receivednothingstring: db 'Nothing there', 0 +receiveddata: db 'Data received', 13, 0 +broadcastaddress: db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 EthernetBuffer: db 0 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/filetest.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/filetest.asm index 01a9ef24..868cd323 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/filetest.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/filetest.asm @@ -1,61 +1,61 @@ -; ----------------------------------------------------------------- -; EthTool v0.1 - Ethernet debugging tool -; Ian Seyler @ Return Infinity -; ----------------------------------------------------------------- - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -filetest: - mov rsi, startstring - call b_print_string - - mov rcx, 4000000 - mov rsi, DataBuffer - mov rdi, file1 - call b_file_write - mov rsi, file1 - call b_print_string - call b_print_newline - - mov rcx, 4000000 - mov rsi, DataBuffer - mov rdi, file2 - call b_file_write - mov rsi, file2 - call b_print_string - call b_print_newline - - mov rcx, 4000000 - mov rsi, DataBuffer - mov rdi, file3 - call b_file_write - mov rsi, file3 - call b_print_string - call b_print_newline - - mov rcx, 4000000 - mov rsi, DataBuffer - mov rdi, file4 - call b_file_write - mov rsi, file4 - call b_print_string - call b_print_newline - - mov rsi, endstring - call b_print_string - -ret -; ----------------------------------------------------------------- - -startstring: db 'Start', 13, 0 -endstring: db 'End', 13, 0 -file1: db 'tst1.app', 0 -file2: db 'tst2.app', 0 -file3: db 'tst3.app', 0 -file4: db 'tst4.app', 0 - +; ----------------------------------------------------------------- +; EthTool v0.1 - Ethernet debugging tool +; Ian Seyler @ Return Infinity +; ----------------------------------------------------------------- + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +filetest: + mov rsi, startstring + call b_print_string + + mov rcx, 4000000 + mov rsi, DataBuffer + mov rdi, file1 + call b_file_write + mov rsi, file1 + call b_print_string + call b_print_newline + + mov rcx, 4000000 + mov rsi, DataBuffer + mov rdi, file2 + call b_file_write + mov rsi, file2 + call b_print_string + call b_print_newline + + mov rcx, 4000000 + mov rsi, DataBuffer + mov rdi, file3 + call b_file_write + mov rsi, file3 + call b_print_string + call b_print_newline + + mov rcx, 4000000 + mov rsi, DataBuffer + mov rdi, file4 + call b_file_write + mov rsi, file4 + call b_print_string + call b_print_newline + + mov rsi, endstring + call b_print_string + +ret +; ----------------------------------------------------------------- + +startstring: db 'Start', 13, 0 +endstring: db 'End', 13, 0 +file1: db 'tst1.app', 0 +file2: db 'tst2.app', 0 +file3: db 'tst3.app', 0 +file4: db 'tst4.app', 0 + DataBuffer: db 0xCA, 0xFE \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/hello.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/hello.asm index c5892469..d2d34e86 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/hello.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/hello.asm @@ -1,20 +1,20 @@ -; Hello World Assembly Test Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm hello.asm -o hello.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - mov rsi, hello_message ; Load RSI with memory address of string - call b_print_string ; Print the string that RSI points to - -ret ; Return to OS - -hello_message: db 'Hello, world!', 13, 0 +; Hello World Assembly Test Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm hello.asm -o hello.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + mov rsi, hello_message ; Load RSI with memory address of string + call b_print_string ; Print the string that RSI points to + +ret ; Return to OS + +hello_message: db 'Hello, world!', 13, 0 diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/keyboard.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/keyboard.asm index 0830aeac..8480d99e 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/keyboard.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/keyboard.asm @@ -1,111 +1,111 @@ -; ----------------------------------------------------------------- -; Music keyboard -; Based on keyboard.asm from MikeOS -; Use Z key rightwards for an octave -; ----------------------------------------------------------------- - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -music_keyboard: - - mov rsi, startstring - call b_print_string - call b_print_newline - -.retry: - call b_input_key_wait - -; And start matching keys with notes - - cmp al, 'z' - jne .x - mov al, 'C' - call b_print_char ; Print note - mov ax, 4000 - jmp .playnote - -.x: - cmp al, 'x' - jne .c - mov al, 'D' - call b_print_char ; Print note - mov ax, 3600 - jmp .playnote - -.c: - cmp al, 'c' - jne .v - mov al, 'E' - call b_print_char ; Print note - mov ax, 3200 - jmp .playnote - -.v: - cmp al, 'v' - jne .b - mov al, 'F' - call b_print_char ; Print note - mov ax, 3000 - jmp .playnote - -.b: - cmp al, 'b' - jne .n - mov al, 'G' - call b_print_char ; Print note - mov ax, 2700 - jmp .playnote - -.n: - cmp al, 'n' - jne .m - mov al, 'A' - call b_print_char ; Print note - mov ax, 2400 - jmp .playnote - -.m: - cmp al, 'm' - jne .comma - mov al, 'B' - call b_print_char - mov ax, 2100 - jmp .playnote - -.comma: - cmp al, ',' - jne .space - mov al, 'C' - call b_print_char - mov ax, 2000 - jmp .playnote - -.space: - cmp al, ' ' - jne .q - call b_speaker_off - jmp .retry - -.playnote: - call b_speaker_tone - jmp .retry - -.q: - cmp al, 'q' - je .end - cmp al, 'Q' - je .end - jmp .retry ; Didn't get any key we were expecting so try again. - -.end: - call b_speaker_off - call b_print_newline - ret ; Back to OS - -; ----------------------------------------------------------------- - +; ----------------------------------------------------------------- +; Music keyboard +; Based on keyboard.asm from MikeOS +; Use Z key rightwards for an octave +; ----------------------------------------------------------------- + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +music_keyboard: + + mov rsi, startstring + call b_print_string + call b_print_newline + +.retry: + call b_input_key_wait + +; And start matching keys with notes + + cmp al, 'z' + jne .x + mov al, 'C' + call b_print_char ; Print note + mov ax, 4000 + jmp .playnote + +.x: + cmp al, 'x' + jne .c + mov al, 'D' + call b_print_char ; Print note + mov ax, 3600 + jmp .playnote + +.c: + cmp al, 'c' + jne .v + mov al, 'E' + call b_print_char ; Print note + mov ax, 3200 + jmp .playnote + +.v: + cmp al, 'v' + jne .b + mov al, 'F' + call b_print_char ; Print note + mov ax, 3000 + jmp .playnote + +.b: + cmp al, 'b' + jne .n + mov al, 'G' + call b_print_char ; Print note + mov ax, 2700 + jmp .playnote + +.n: + cmp al, 'n' + jne .m + mov al, 'A' + call b_print_char ; Print note + mov ax, 2400 + jmp .playnote + +.m: + cmp al, 'm' + jne .comma + mov al, 'B' + call b_print_char + mov ax, 2100 + jmp .playnote + +.comma: + cmp al, ',' + jne .space + mov al, 'C' + call b_print_char + mov ax, 2000 + jmp .playnote + +.space: + cmp al, ' ' + jne .q + call b_speaker_off + jmp .retry + +.playnote: + call b_speaker_tone + jmp .retry + +.q: + cmp al, 'q' + je .end + cmp al, 'Q' + je .end + jmp .retry ; Didn't get any key we were expecting so try again. + +.end: + call b_speaker_off + call b_print_newline + ret ; Back to OS + +; ----------------------------------------------------------------- + startstring: db 'Musical keyboard. Use "Z"-"," to play notes. Space to stop the note. Q to quit.', 0 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/libBareMetal.h b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/libBareMetal.h index d786541f..6bed50c8 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/libBareMetal.h +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/libBareMetal.h @@ -1,75 +1,75 @@ -// ============================================================================= -// BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -// Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -// -// The BareMetal OS C library header. -// -// Version 2.0 -// -// This allows for a C program to access OS functions available in BareMetal OS -// ============================================================================= - - -void b_print_string(char *str); -void b_print_char(char chr); -void b_print_char_hex(char chr); -void b_print_newline(void); -void b_print_string_with_color(char *str, unsigned char clr); -void b_print_char_with_color(char chr, unsigned char clr); -void b_print_char_hex_with_color(char chr, unsigned char clr); - - -unsigned char b_input_get_key(void); -unsigned char b_input_wait_for_key(void); -unsigned long b_input_string(unsigned char *str, unsigned long nbr); - - -unsigned long b_string_length(unsigned char *str); -unsigned long b_string_find_char(unsigned char *str, unsigned char chr); -void b_os_string_copy(unsigned char *dst, unsigned char *src); -void b_int_to_string(unsigned long nbr, unsigned char *str); -unsigned long b_string_to_int(unsigned char *str); - - -void b_delay(unsigned long nbr); -unsigned long b_get_argc(); -char* b_get_argv(unsigned char nbr); -unsigned long b_get_timercounter(void); - - -void b_debug_dump_mem(void *data, unsigned int size); - - -void b_serial_send(unsigned char chr); -unsigned char b_serial_recv(void); - - -void b_file_read(unsigned char *name, void *mem); -void b_file_write(void *data, unsigned char *name, unsigned int size); -void b_file_delete(unsigned char *name); - - -unsigned long b_smp_enqueue(void *ptr, unsigned long var); -unsigned long b_smp_dequeue(unsigned long *var); -void b_smp_run(unsigned long ptr); -unsigned long b_smp_queuelen(void); -void b_smp_wait(void); -void b_smp_lock(unsigned long ptr); -void b_smp_unlock(unsigned long ptr); -unsigned long b_smp_get_id(void); -unsigned long b_smp_numcores(void); - - -void b_speaker_tone(unsigned long nbr); -void b_speaker_off(void); -void b_speaker_beep(void); - - -void b_ethernet_tx(void *mem, void *dest, unsigned short type, unsigned short len); -void b_ethernet_tx_raw(void *mem, unsigned short len); -unsigned long b_ethernet_rx(void *mem); -unsigned long b_ethernet_avail(); - - -// ============================================================================= -// EOF +// ============================================================================= +// BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +// Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +// +// The BareMetal OS C library header. +// +// Version 2.0 +// +// This allows for a C program to access OS functions available in BareMetal OS +// ============================================================================= + + +void b_print_string(char *str); +void b_print_char(char chr); +void b_print_char_hex(char chr); +void b_print_newline(void); +void b_print_string_with_color(char *str, unsigned char clr); +void b_print_char_with_color(char chr, unsigned char clr); +void b_print_char_hex_with_color(char chr, unsigned char clr); + + +unsigned char b_input_get_key(void); +unsigned char b_input_wait_for_key(void); +unsigned long b_input_string(unsigned char *str, unsigned long nbr); + + +unsigned long b_string_length(unsigned char *str); +unsigned long b_string_find_char(unsigned char *str, unsigned char chr); +void b_os_string_copy(unsigned char *dst, unsigned char *src); +void b_int_to_string(unsigned long nbr, unsigned char *str); +unsigned long b_string_to_int(unsigned char *str); + + +void b_delay(unsigned long nbr); +unsigned long b_get_argc(); +char* b_get_argv(unsigned char nbr); +unsigned long b_get_timercounter(void); + + +void b_debug_dump_mem(void *data, unsigned int size); + + +void b_serial_send(unsigned char chr); +unsigned char b_serial_recv(void); + + +void b_file_read(unsigned char *name, void *mem); +void b_file_write(void *data, unsigned char *name, unsigned int size); +void b_file_delete(unsigned char *name); + + +unsigned long b_smp_enqueue(void *ptr, unsigned long var); +unsigned long b_smp_dequeue(unsigned long *var); +void b_smp_run(unsigned long ptr); +unsigned long b_smp_queuelen(void); +void b_smp_wait(void); +void b_smp_lock(unsigned long ptr); +void b_smp_unlock(unsigned long ptr); +unsigned long b_smp_get_id(void); +unsigned long b_smp_numcores(void); + + +void b_speaker_tone(unsigned long nbr); +void b_speaker_off(void); +void b_speaker_beep(void); + + +void b_ethernet_tx(void *mem, void *dest, unsigned short type, unsigned short len); +void b_ethernet_tx_raw(void *mem, unsigned short len); +unsigned long b_ethernet_rx(void *mem); +unsigned long b_ethernet_avail(); + + +// ============================================================================= +// EOF diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/mbasic.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/mbasic.asm index 385a460c..e83564b3 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/mbasic.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/mbasic.asm @@ -1,2436 +1,2436 @@ -; ================================================================== -; MikeOS -- The Mike Operating System kernel -; Copyright (C) 2006 - 2011 MikeOS Developers -- see doc/LICENSE.TXT -; -; BASIC CODE INTERPRETER -; ================================================================== - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -; ------------------------------------------------------------------ -; Token types - -%DEFINE VARIABLE 1 -%DEFINE STRING_VAR 2 -%DEFINE NUMBER 3 -%DEFINE STRING 4 -%DEFINE QUOTE 5 -%DEFINE CHAR 6 -%DEFINE UNKNOWN 7 -%DEFINE LABEL 8 - - -; ------------------------------------------------------------------ -; The BASIC interpreter execution starts here... - -b_run_basic: - mov [orig_stack], rsp ; Save stack pointer -- we might jump to the - ; error printing code and quit in the middle - ; some nested loops, and we want to preserve - ; the stack - mov rax, basic_prog ;embedded test program for a quick DOS test - mov rbx, 8192 ;default size for test program (not critical) - mov [load_point], rax ; rax was passed as starting location of code - - mov [prog], rax ; prog = pointer to current execution point in code - - add rbx, rax ; We were passed the .BAS byte size in rbx - sub rbx, 2 - mov [prog_end], rbx ; Make note of program end point - - - call clear_ram ; Clear variables etc. from previous run - ; of a BASIC program - - - -mainloop: - call get_token ; Get a token from the start of the line - - cmp rax, STRING ; Is the type a string of characters? - je .keyword ; If so, let's see if it's a keyword to process - - cmp rax, VARIABLE ; If it's a variable at the start of the line, - je near assign ; this is an assign (eg "X = Y + 5") - - cmp rax, STRING_VAR ; Same for a string variable (eg $1) - je near assign - - cmp rax, LABEL ; Don't need to do anything here - skip - je mainloop - - mov rsi, err_syntax ; Otherwise show an error and quit - jmp error - - -.keyword: - mov rsi, token ; Start trying to match commands - - mov rdi, alert_cmd - call b_string_compare - jc near do_alert - - mov rdi, call_cmd - call b_string_compare - jc near do_call - - mov rdi, cls_cmd - call b_string_compare - jc near do_cls - - mov rdi, cursor_cmd - call b_string_compare - jc near do_cursor - - mov rdi, curschar_cmd - call b_string_compare - jc near do_curschar - - mov rdi, end_cmd - call b_string_compare - jc near do_end - - mov rdi, for_cmd - call b_string_compare - jc near do_for - - mov rdi, getkey_cmd - call b_string_compare - jc near do_getkey - - mov rdi, gosub_cmd - call b_string_compare - jc near do_gosub - - mov rdi, goto_cmd - call b_string_compare - jc near do_goto - - mov rdi, input_cmd - call b_string_compare - jc near do_input - - mov rdi, if_cmd - call b_string_compare - jc near do_if - - mov rdi, load_cmd - call b_string_compare - jc near do_load - - mov rdi, move_cmd - call b_string_compare - jc near do_move - - mov rdi, next_cmd - call b_string_compare - jc near do_next - - mov rdi, pause_cmd - call b_string_compare - jc near do_pause - - mov rdi, peek_cmd - call b_string_compare - jc near do_peek - - mov rdi, poke_cmd - call b_string_compare - jc near do_poke - - mov rdi, port_cmd - call b_string_compare - jc near do_port - - mov rdi, print_cmd - call b_string_compare - jc near do_print - - mov rdi, rand_cmd - call b_string_compare - jc near do_rand - - mov rdi, rem_cmd - call b_string_compare - jc near do_rem - - mov rdi, return_cmd - call b_string_compare - jc near do_return - - mov rdi, save_cmd - call b_string_compare - jc near do_save - - mov rdi, serial_cmd - call b_string_compare - jc near do_serial - - mov rdi, sound_cmd - call b_string_compare - jc near do_sound - - mov rdi, waitkey_cmd - call b_string_compare - jc near do_waitkey - - mov rsi, err_cmd_unknown ; Command not found? - jmp error - - -; ------------------------------------------------------------------ -; CLEAR RAM - -clear_ram: - xor eax, eax - - mov rdi, variables - mov rcx, 52 - rep stosb - - mov rdi, for_variables - mov rcx, 52 - rep stosb - - mov rdi, for_code_points - mov rcx, 52 - rep stosb - - mov byte [gosub_depth], 0 - - mov rdi, gosub_points - mov rcx, 20 - rep stosb - - mov rdi, string_vars - mov rcx, 1024 - rep stosb - - ret - - -; ------------------------------------------------------------------ -; ASSIGNMENT - -assign: - cmp rax, VARIABLE ; Are we starting with a number var? - je .do_num_var - - mov rdi, string_vars ; Otherwise it's a string var - mov rax, 128 - mul rbx ; (rbx = string number, passed back from get_token) - add rdi, rax - - push rdi - - call get_token - mov byte al, [token] - cmp al, '=' - jne near .error - - call get_token - cmp rax, QUOTE - je .second_is_quote - - cmp rax, STRING_VAR - jne near .error - - mov rsi, string_vars ; Otherwise it's a string var - mov rax, 128 - mul rbx ; (rbx = string number, passed back from get_token) - add rsi, rax - - pop rdi - call b_string_copy - - jmp mainloop - - -.second_is_quote: - mov rsi, token - pop rdi - call b_string_copy - - jmp mainloop - - -.do_num_var: - xor rax, rax - mov byte al, [token] - mov byte [.tmp], al - - call get_token - mov byte al, [token] - cmp al, '=' - jne near .error - - call get_token - cmp rax, NUMBER - je .second_is_num - - cmp rax, VARIABLE - je .second_is_variable - - cmp rax, STRING - je near .second_is_string - - cmp rax, UNKNOWN - jne near .error - - mov byte al, [token] ; Address of string var? - cmp al, '&' - jne near .error - - call get_token ; Let's see if there's a string var - cmp rax, STRING_VAR - jne near .error - - mov rdi, string_vars - mov rax, 128 - mul rbx - add rdi, rax - - mov rbx, rdi - - mov byte al, [.tmp] - call set_var - - jmp mainloop - - -.second_is_variable: - xor rax, rax - mov byte al, [token] - - call get_var - mov rbx, rax - mov byte al, [.tmp] - call set_var - - jmp .check_for_more - - -.second_is_num: - mov rsi, token - call b_string_to_int - - mov rbx, rax ; Number to insert in variable table - - xor rax, rax - mov byte al, [.tmp] - - call set_var - - - ; The assignment could be simply "X = 5" etc. Or it could be - ; "X = Y + 5" -- ie more complicated. So here we check to see if - ; there's a delimiter... - -.check_for_more: - mov rax, [prog] ; Save code location in case there's no delimiter - mov [.tmp_loc], rax - - call get_token ; Any more to deal with in this assignment? - mov byte al, [token] - cmp al, '+' - je .theres_more - cmp al, '-' - je .theres_more - cmp al, '*' - je .theres_more - cmp al, '/' - je .theres_more - cmp al, '%' - je .theres_more - - mov rax, [.tmp_loc] ; Not a delimiter, so step back before the token - mov [prog], rax ; that we just grabbed - - jmp mainloop ; And go back to the code interpreter! - - -.theres_more: - mov byte [.delim], al - - call get_token - cmp rax, VARIABLE - je .handle_variable - - mov rsi, token - call b_string_to_int - mov rbx, rax - - xor rax, rax - mov byte al, [.tmp] - - call get_var ; This also points rsi at right place in variable table - - cmp byte [.delim], '+' - jne .not_plus - - add rax, rbx - jmp .finish - -.not_plus: - cmp byte [.delim], '-' - jne .not_minus - - sub rax, rbx - jmp .finish - -.not_minus: - cmp byte [.delim], '*' - jne .not_times - - mul rbx - jmp .finish - -.not_times: - cmp byte [.delim], '/' - jne .not_divide - - xor rdx, rdx - div rbx - jmp .finish - -.not_divide: - xor rdx, rdx - div rbx - mov rax, rdx ; Get remainder - -.finish: - mov rbx, rax - mov byte al, [.tmp] - call set_var - - jmp .check_for_more - - -.handle_variable: - xor rax, rax - mov byte al, [token] - - call get_var - - mov rbx, rax - - xor rax, rax - mov byte al, [.tmp] - - call get_var - - cmp byte [.delim], '+' - jne .vnot_plus - - add rax, rbx - jmp .vfinish - -.vnot_plus: - cmp byte [.delim], '-' - jne .vnot_minus - - sub rax, rbx - jmp .vfinish - -.vnot_minus: - cmp byte [.delim], '*' - jne .vnot_times - - mul rbx - jmp .vfinish - -.vnot_times: - cmp byte [.delim], '/' - jne .vnot_divide - - mov dx, 0 - div rbx - jmp .finish - -.vnot_divide: - mov dx, 0 - div rbx - mov rax, rdx ; Get remainder - -.vfinish: - mov rbx, rax - mov byte al, [.tmp] - call set_var - - jmp .check_for_more - - -.second_is_string: - mov rdi, token - mov rsi, progstart_keyword - call b_string_compare - je .is_progstart - - mov rsi, ramstart_keyword - call b_string_compare - je .is_ramstart - - jmp .error - -.is_progstart: - xor rax, rax - mov byte al, [.tmp] - - mov rbx, [load_point] - call set_var - - jmp mainloop - - - -.is_ramstart: - xor rax, rax - mov byte al, [.tmp] - - mov rbx, [prog_end] - inc rbx - inc rbx - inc rbx - call set_var - - jmp mainloop - - -.error: - mov rsi, err_syntax - jmp error - - - .tmp db 0 - .tmp_loc dq 0 - .delim db 0 - - -; ================================================================== -; SPECIFIC COMMAND CODE STARTS HERE - -; ------------------------------------------------------------------ -; ALERT - -do_alert: - call get_token - - cmp rax, QUOTE - je .is_quote - - mov rsi, err_syntax - jmp error - -.is_quote: - mov rax, token ; First string for alert box - xor rbx, rbx ; Others are blank - xor rcx, rcx - mov dx, 0 ; One-choice box - jmp mainloop - - -; ------------------------------------------------------------------ -; CALL - -do_call: - call get_token - cmp rax, NUMBER - je .is_number - - xor rax, rax - mov byte al, [token] - call get_var - jmp .execute_call - -.is_number: - mov rsi, token - call b_string_to_int - -.execute_call: - xor rbx, rbx - xor rcx, rcx - mov dx, 0 - mov rdi, 0 - mov rsi, 0 - - call rax - - jmp mainloop - - - -; ------------------------------------------------------------------ -; CLS - -do_cls: - call b_screen_clear - jmp mainloop - - -; ------------------------------------------------------------------ -; CURSOR - -do_cursor: - call get_token - - mov rsi, token - mov rdi, .on_str - call b_string_compare - jc .turn_on - - mov rsi, token - mov rdi, .off_str - call b_string_compare - jc .turn_off - - mov rsi, err_syntax - jmp error - -.turn_on: - call b_show_cursor - jmp mainloop - -.turn_off: - call b_hide_cursor - jmp mainloop - - - .on_str db "ON", 0 - .off_str db "OFF", 0 - - -; ------------------------------------------------------------------ -; CURSCHAR - -do_curschar: - call get_token - - cmp rax, VARIABLE - je .is_ok - - mov rsi, err_syntax - jmp error - -.is_ok: - xor rax, rax - mov byte al, [token] - - push rax ; Store variable we're going to use - -; mov ah, 08h -; xor rbx, rbx -; int 10h ; Get char at current cursor location - - xor rbx, rbx ; We only want the lower byte (the char, not attribute) - mov bl, al - - pop rax ; Get the variable back - - call set_var ; And store the value - - jmp mainloop - - -; ------------------------------------------------------------------ -; END - -do_end: - mov rsp, [orig_stack] - ret - - -; ------------------------------------------------------------------ -; FOR - -do_for: - call get_token ; Get the variable we're using in this loop - - cmp rax, VARIABLE - jne near .error - - xor rax, rax - mov byte al, [token] - mov byte [.tmp_var], al ; Store it in a temporary location for now - - call get_token - - xor rax, rax ; Check it's followed up with '=' - mov byte al, [token] - cmp al, '=' - jne .error - - call get_token ; Next we want a number - - cmp rax, NUMBER - jne .error - - mov rsi, token ; Convert it - call b_string_to_int - - - ; At this stage, we've read something like "FOR X = 1" - ; so let's store that 1 in the variable table - - mov rbx, rax - xor rax, rax - mov byte al, [.tmp_var] - call set_var - - - call get_token ; Next we're looking for "TO" - - cmp rax, STRING - jne .error - - mov rax, token - call b_string_uppercase - - mov rsi, token - mov rdi, .to_string - call b_string_compare - jnc .error - - ; So now we're at "FOR X = 1 TO" - - call get_token - - cmp rax, NUMBER - jne .error - - mov rsi, token ; Get target number - call b_string_to_int - - mov rbx, rax - - xor rax, rax - mov byte al, [.tmp_var] - - sub al, 65 ; Store target number in table - mov rdi, for_variables - add rdi, rax - add rdi, rax - mov rax, rbx - stosw - - - ; So we've got the variable, assigned it the starting number, and put into - ; our table the limit it should reach. But we also need to store the point in - ; code after the FOR line we should return to if NEXT X doesn't complete the loop... -; xor rax, rax - xor rax, rax -; xor eax, eax - mov byte al, [.tmp_var] - - sub al, 65 ; Store code position to return to in table - mov rdi, for_code_points -; add rdi, rax -; add rdi, rax - shl rax, 3 - add rdi, rax - mov rax, [prog] - stosq - - jmp mainloop - - -.error: - mov rsi, err_syntax - jmp error - - - .tmp_var db 0 - .to_string db 'TO', 0 - - -; ------------------------------------------------------------------ -; GETKEY - -do_getkey: - call get_token - cmp rax, VARIABLE - je .is_variable - - mov rsi, err_syntax - jmp error - -.is_variable: - xor rax, rax - mov byte al, [token] - - push rax - - call b_input_key_check - - xor rbx, rbx - mov bl, al - - pop rax - - call set_var - - jmp mainloop - - -; ------------------------------------------------------------------ -; GOSUB - -do_gosub: - call get_token ; Get the number (label) - - cmp rax, STRING - je .is_ok - - mov rsi, err_goto_notlabel - jmp error - -.is_ok: - mov rsi, token ; Back up this label - mov rdi, .tmp_token - call b_string_copy - - mov rax, .tmp_token - call b_string_length - - mov rdi, .tmp_token ; Add ':' char to end for searching - add rdi, rax - mov al, ':' - stosb - mov al, 0 - stosb - - inc byte [gosub_depth] - - xor rax, rax - mov byte al, [gosub_depth] ; Get current GOSUB nest level - - cmp al, 9 - jle .within_limit - - mov rsi, err_nest_limit - jmp error - -.within_limit: - mov rdi, gosub_points ; Move into our table of pointers - add rdi, rax ; Table is words (not bytes) - add rdi, rax - mov rax, [prog] - stosw ; Store current location before jump - - - mov rax, [load_point] - mov [prog], rax ; Return to start of program to find label - -.loop: - call get_token - - cmp rax, LABEL - jne .line_loop - - mov rsi, token - mov rdi, .tmp_token - call b_string_compare - jc mainloop - -.line_loop: ; Go to end of line - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - cmp al, 10 - jne .line_loop - - mov rax, [prog] - mov rbx, [prog_end] - cmp rax, rbx - jg .past_end - - jmp .loop - -.past_end: - mov rsi, err_label_notfound - jmp error - - .tmp_token times 30 db 0 - - -; ------------------------------------------------------------------ -; GOTO - -do_goto: - call get_token ; Get the next token - - cmp rax, STRING - je .is_ok - - mov rsi, err_goto_notlabel - jmp error - -.is_ok: - mov rsi, token ; Back up this label - mov rdi, .tmp_token - call b_string_copy - - mov rax, .tmp_token - call b_string_length - - mov rdi, .tmp_token ; Add ':' char to end for searching - add rdi, rax - mov al, ':' - stosb - mov al, 0 - stosb - - mov rax, [load_point] - mov [prog], rax ; Return to start of program to find label - -.loop: - call get_token - - cmp rax, LABEL - jne .line_loop - - mov rsi, token - mov rdi, .tmp_token - call b_string_compare - jc mainloop - -.line_loop: ; Go to end of line - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - - cmp al, 10 - jne .line_loop - - mov rax, [prog] - mov rbx, [prog_end] - cmp rax, rbx - jg .past_end - - jmp .loop - -.past_end: - mov rsi, err_label_notfound - jmp error - - .tmp_token times 30 db 0 - - -; ------------------------------------------------------------------ -; IF - -do_if: - call get_token - - cmp rax, VARIABLE ; If can only be followed by a variable - je .num_var - - cmp rax, STRING_VAR - je near .string_var - - mov rsi, err_syntax - jmp error - -.num_var: - xor rax, rax - mov byte al, [token] - call get_var - - mov rdx, rax ; Store value of first part of comparison - - call get_token ; Get the delimiter - mov byte al, [token] - cmp al, '=' - je .equals - cmp al, '>' - je .greater - cmp al, '<' - je .less - - mov rsi, err_syntax ; If not one of the above, error out - jmp error - -.equals: - call get_token ; Is this 'X = Y' (equals another variable?) - - cmp rax, CHAR - je .equals_char - - mov byte al, [token] - call is_letter - jc .equals_var - - mov rsi, token ; Otherwise it's, eg 'X = 1' (a number) - call b_string_to_int - - cmp rax, rdx ; On to the THEN bit if 'X = num' matches - je near .on_to_then - - jmp .finish_line ; Otherwise skip the rest of the line - -.equals_char: - xor rax, rax - mov byte al, [token] - - cmp rax, rdx - je near .on_to_then - - jmp .finish_line - -.equals_var: - xor rax, rax - mov byte al, [token] - - call get_var - - cmp rax, rdx ; Do the variables match? - je near .on_to_then ; On to the THEN bit if so - - jmp .finish_line ; Otherwise skip the rest of the line - -.greater: - call get_token ; Greater than a variable or number? - mov byte al, [token] - call is_letter - jc .greater_var - - mov rsi, token ; Must be a number here... - call b_string_to_int - - cmp rax, rdx - jl near .on_to_then - - jmp .finish_line - -.greater_var: ; Variable in this case - xor rax, rax - mov byte al, [token] - - call get_var - - cmp rax, rdx ; Make the comparison! - jl .on_to_then - - jmp .finish_line - -.less: - call get_token - mov byte al, [token] - call is_letter - jc .less_var - - mov rsi, token - call b_string_to_int - - cmp rax, rdx - jg .on_to_then - - jmp .finish_line - -.less_var: - xor rax, rax - mov byte al, [token] - - call get_var - - cmp rax, rdx - jg .on_to_then - - jmp .finish_line - -.string_var: - mov byte [.tmp_string_var], bl - - call get_token - - mov byte al, [token] - cmp al, '=' - jne .error - - call get_token - cmp rax, STRING_VAR - je .second_is_string_var - - cmp rax, QUOTE - jne .error - - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - mov rdi, token - call b_string_compare - je .on_to_then - - jmp .finish_line - -.second_is_string_var: - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - - mov rdi, string_vars - xor rbx, rbx - mov byte bl, [.tmp_string_var] - mov rax, 128 - mul rbx - add rdi, rax - - call b_string_compare - jc .on_to_then - - jmp .finish_line - -.on_to_then: - call get_token - - mov rsi, token - mov rdi, then_keyword - call b_string_compare - - jc .then_present - - mov rsi, err_syntax - jmp error - -.then_present: ; Continue rest of line like any other command! - jmp mainloop - -.finish_line: ; IF wasn't fulfilled, so skip rest of line - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - cmp al, 10 - jne .finish_line - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - .tmp_string_var db 0 - - -; ------------------------------------------------------------------ -; INPUT - -do_input: - mov al, 0 ; Clear string from previous usage - mov rdi, .tmpstring - mov rcx, 128 - rep stosb - - call get_token - - cmp rax, VARIABLE ; We can only INPUT to variables! - je .number_var - - cmp rax, STRING_VAR - je .string_var - - mov rsi, err_syntax - jmp error - -.number_var: - mov rdi, .tmpstring ; Get input from the user - mov rcx, 50 - call b_input_string - - mov rsi, .tmpstring - call b_string_length - cmp rcx, 0 - jne .char_entered - - mov byte [.tmpstring], '0' ; If enter hit, fill variable with zero - mov byte [.tmpstring + 1], 0 - -.char_entered: - mov rsi, .tmpstring ; Convert to integer format - call b_string_to_int - mov rbx, rax - - xor rax, rax - mov byte al, [token] ; Get the variable where we're storing it... - call set_var ; ...and store it! - - call b_print_newline - - jmp mainloop - -.string_var: - push rbx - - mov rdi, .tmpstring - mov rcx, 50 - call b_input_string - - mov rsi, .tmpstring - mov rdi, string_vars - - pop rbx - - mov rax, 128 - mul rbx - - add rdi, rax - call b_string_copy - - call b_print_newline - - jmp mainloop - - .tmpstring times 128 db 0 - - -; ------------------------------------------------------------------ -; LOAD - -do_load: - call get_token - cmp rax, QUOTE - je .is_quote - - cmp rax, STRING_VAR - jne .error - - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - jmp .get_position - -.is_quote: - mov rsi, token - -.get_position: - mov rax, rsi -; call b_file_exists - jc .file_not_exists - - mov rdx, rax ; Store for now - - call get_token - - cmp rax, VARIABLE - je .second_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.load_part: - mov rcx, rax - - mov rax, rdx - -; call b_load_file - - xor rax, rax - mov byte al, 'S' - call set_var - - xor rax, rax - mov byte al, 'R' - xor rbx, rbx - call set_var - - jmp mainloop - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .load_part - -.file_not_exists: - xor rax, rax - mov byte al, 'R' - mov rbx, 1 - call set_var - - call get_token ; Skip past the loading point -- unnecessary now - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - -; ------------------------------------------------------------------ -; MOVE - -do_move: - call get_token - - cmp rax, VARIABLE - je .first_is_var - - mov rsi, token - call b_string_to_int - mov dl, al - jmp .onto_second - -.first_is_var: - xor rax, rax - mov byte al, [token] - call get_var - mov dl, al - -.onto_second: - call get_token - - cmp rax, VARIABLE - je .second_is_var - - mov rsi, token - call b_string_to_int - mov dh, al - jmp .finish - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - mov dh, al - -.finish: - call b_move_cursor - - jmp mainloop - - -; ------------------------------------------------------------------ -; NEXT - -do_next: - call get_token - - cmp rax, VARIABLE ; NEXT must be followed by a variable - jne .error - - xor rax, rax - mov byte al, [token] - call get_var - - inc rax ; NEXT increments the variable, of course! - - mov rbx, rax - - xor rax, rax - mov byte al, [token] - - sub al, 65 - mov rsi, for_variables - add rsi, rax - add rsi, rax - lodsw ; Get the target number from the table - - inc rax ; (Make the loop inclusive of target number) - cmp rax, rbx ; Do the variable and target match? - je .loop_finished - - xor rax, rax ; If not, store the updated variable - mov byte al, [token] - call set_var - - xor rax, rax ; Find the code point and go back - mov byte al, [token] - sub al, 65 - mov rsi, for_code_points -; add rsi, rax -; add rsi, rax - shl rax, 3 - add rsi, rax - lodsq - - mov [prog], rax - jmp mainloop - -.loop_finished: - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - -; ------------------------------------------------------------------ -; PAUSE - -do_pause: - call get_token - - cmp rax, VARIABLE - je .is_var - - mov rsi, token - call b_string_to_int - jmp .finish - -.is_var: - xor rax, rax - mov byte al, [token] - call get_var - -.finish: -; call b_pause - jmp mainloop - - -; ------------------------------------------------------------------ -; PEEK - -do_peek: - call get_token - - cmp rax, VARIABLE - jne .error - - xor rax, rax - mov byte al, [token] - mov byte [.tmp_var], al - - call get_token - - cmp rax, VARIABLE - je .dereference - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.store: - mov rsi, rax - xor rbx, rbx - mov byte bl, [rsi] - xor rax, rax - mov byte al, [.tmp_var] - call set_var - - jmp mainloop - -.dereference: - mov byte al, [token] - call get_var - jmp .store - -.error: - mov rsi, err_syntax - jmp error - - - .tmp_var db 0 - - -; ------------------------------------------------------------------ -; POKE - -do_poke: - call get_token - - cmp rax, VARIABLE - je .first_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - - cmp rax, 255 - jg .error - - mov byte [.first_value], al - jmp .onto_second - - -.first_is_var: - xor rax, rax - mov byte al, [token] - call get_var - - mov byte [.first_value], al - -.onto_second: - call get_token - - cmp rax, VARIABLE - je .second_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.got_value: - mov rdi, rax - xor rax, rax - mov byte al, [.first_value] - mov byte [rdi], al - - jmp mainloop - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .got_value - -.error: - mov rsi, err_syntax - jmp error - - .first_value db 0 - - -; ------------------------------------------------------------------ -; PORT - -do_port: - call get_token - mov rsi, token - - mov rdi, .out_cmd - call b_string_compare - jc .do_out_cmd - - mov rdi, .in_cmd - call b_string_compare - jc .do_in_cmd - - jmp .error - -.do_out_cmd: - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int ; Now rax = port number - mov rdx, rax - - call get_token - cmp rax, NUMBER - je .out_is_num - - cmp rax, VARIABLE - je .out_is_var - - jmp .error - -.out_is_num: - mov rsi, token - call b_string_to_int -; call b_port_byte_out - jmp mainloop - -.out_is_var: - xor rax, rax - mov byte al, [token] - call get_var - -; call b_port_byte_out - jmp mainloop - -.do_in_cmd: - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - mov rdx, rax - - call get_token - cmp rax, VARIABLE - jne .error - - mov byte cl, [token] - -; call b_port_byte_in - xor rbx, rbx - mov bl, al - - mov al, cl - call set_var - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - - .out_cmd db "OUT", 0 - .in_cmd db "IN", 0 - - -; ------------------------------------------------------------------ -; PRINT - -do_print: - call get_token ; Get part after PRINT - - cmp rax, QUOTE ; What type is it? - je .print_quote - - cmp rax, VARIABLE ; Numerical variable (eg X) - je .print_var - - cmp rax, STRING_VAR ; String variable (eg $1) - je .print_string_var - - cmp rax, STRING ; Special keyword (eg CHR or HEX) - je .print_keyword - - mov rsi, err_print_type ; We only print quoted strings and vars! - jmp error - -.print_var: - xor rax, rax - mov byte al, [token] - call get_var ; Get its value - mov rdi, tstring - mov rsi, rdi - call b_int_to_string ; Convert to string - call b_print_string - - jmp .newline_or_not - -.print_quote: ; If it's quoted text, print it - mov rsi, token - call b_print_string - - jmp .newline_or_not - -.print_string_var: - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - call b_print_string - - jmp .newline_or_not - -.print_keyword: - mov rsi, token - mov rdi, chr_keyword - call b_string_compare - jc .is_chr - - mov rdi, hex_keyword - call b_string_compare - jc .is_hex - - mov rsi, err_syntax - jmp error - -.is_chr: - call get_token - - cmp rax, VARIABLE - jne .error - - xor rax, rax - mov byte al, [token] - call get_var - -; mov ah, 0Eh -; int 10h - - jmp .newline_or_not - -.is_hex: - call get_token - - cmp rax, VARIABLE - jne .error - - xor rax, rax - mov byte al, [token] - call get_var - - call b_debug_dump_al ;print_2hex - - jmp .newline_or_not - -.error: - mov rsi, err_syntax - jmp error - -.newline_or_not: - ; We want to see if the command ends with ';' -- which means that - ; we shouldn't print a newline after it finishes. So we store the - ; current program location to pop ahead and see if there's the ';' - ; character -- otherwise we put the program location back and resume - ; the main loop - mov rax, [prog] - mov [.tmp_loc], rax - - call get_token - cmp rax, UNKNOWN - jne .ignore - - xor rax, rax - mov al, [token] - cmp al, ';' - jne .ignore - - jmp mainloop ; And go back to interpreting the code! - -.ignore: - call b_print_newline - - mov rax, [.tmp_loc] - mov [prog], rax - - jmp mainloop - - .tmp_loc dq 0 - - -; ------------------------------------------------------------------ -; RAND - -do_rand: - call get_token - cmp rax, VARIABLE - jne .error - - mov byte al, [token] - mov byte [.tmp], al - - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - mov [.num1], rax - - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - mov [.num2], rax - - mov rax, [.num1] - mov rbx, [.num2] -; call b_get_random - - mov rbx, rcx - xor rax, rax - mov byte al, [.tmp] - call set_var - - jmp mainloop - - .tmp db 0 - .num1 dq 0 - .num2 dq 0 - -.error: - mov rsi, err_syntax - jmp error - - -; ------------------------------------------------------------------ -; REM - -do_rem: - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - cmp al, 10 ; Find end of line after REM - jne do_rem - - jmp mainloop - - -; ------------------------------------------------------------------ -; RETURN - -do_return: - xor rax, rax - mov byte al, [gosub_depth] - cmp al, 0 - jne .is_ok - - mov rsi, err_return - jmp error - -.is_ok: - mov rsi, gosub_points - add rsi, rax ; Table is words (not bytes) - add rsi, rax - lodsw - mov [prog], rax - dec byte [gosub_depth] - - jmp mainloop - - -; ------------------------------------------------------------------ -; SAVE - -do_save: - call get_token - cmp rax, QUOTE - je .is_quote - - cmp rax, STRING_VAR - jne near .error - - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - jmp .get_position - -.is_quote: - mov rsi, token - -.get_position: - mov rdi, .tmp_filename - call b_string_copy - - call get_token - - cmp rax, VARIABLE - je .second_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.set_data_loc: - mov [.data_loc], rax - - call get_token - - cmp rax, VARIABLE - je .third_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.set_data_size: - mov [.data_size], rax - - mov rax, .tmp_filename - mov rbx, [.data_loc] - mov rcx, [.data_size] - -; call b_write_file - jc .save_failure - - xor rax, rax - mov byte al, 'R' - xor rbx, rbx - call set_var - - jmp mainloop - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .set_data_loc - -.third_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .set_data_size - -.save_failure: - xor rax, rax - mov byte al, 'R' - mov rbx, 1 - call set_var - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - - .filename_loc dw 0 - .data_loc dw 0 - .data_size dw 0 - - .tmp_filename times 15 db 0 - - -; ------------------------------------------------------------------ -; SERIAL - -do_serial: - call get_token - mov rsi, token - - mov rdi, .on_cmd - call b_string_compare - jc .do_on_cmd - - mov rdi, .send_cmd - call b_string_compare - jc .do_send_cmd - - mov rdi, .rec_cmd - call b_string_compare - jc .do_rec_cmd - - jmp .error - -.do_on_cmd: - call get_token - cmp rax, NUMBER - je .do_on_cmd_ok - jmp .error - -.do_on_cmd_ok: - mov rsi, token - call b_string_to_int - cmp rax, 1200 - je .on_cmd_slow_mode - cmp rax, 9600 - je .on_cmd_fast_mode - - jmp .error - -.on_cmd_fast_mode: - xor rax, rax -; call b_serial_port_enable - jmp mainloop - -.on_cmd_slow_mode: - mov rax, 1 -; call b_serial_port_enable - jmp mainloop - -.do_send_cmd: - call get_token - cmp rax, NUMBER - je .send_number - - cmp rax, VARIABLE - je .send_variable - - jmp .error - -.send_number: - mov rsi, token - call b_string_to_int -; call b_send_via_serial - jmp mainloop - -.send_variable: - xor rax, rax - mov byte al, [token] - call get_var -; call b_send_via_serial - jmp mainloop - -.do_rec_cmd: - call get_token - cmp rax, VARIABLE - jne .error - - mov byte al, [token] - - xor rcx, rcx - mov cl, al -; call b_get_via_serial - - xor rbx, rbx - mov bl, al - mov al, cl - call set_var - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - .on_cmd db "ON", 0 - .send_cmd db "SEND", 0 - .rec_cmd db "REC", 0 - - -; ------------------------------------------------------------------ -; SOUND - -do_sound: - call get_token - - cmp rax, VARIABLE - je .first_is_var - - mov rsi, token - call b_string_to_int - jmp .done_first - -.first_is_var: - xor rax, rax - mov byte al, [token] - call get_var - -.done_first: - call b_speaker_tone - - call get_token - - cmp rax, VARIABLE - je .second_is_var - - mov rsi, token - call b_string_to_int - jmp .finish - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - -.finish: -; call b_pause - call b_speaker_off - - jmp mainloop - - -; ------------------------------------------------------------------ -; WAITKEY - -do_waitkey: - call get_token - cmp rax, VARIABLE - je .is_variable - - mov rsi, err_syntax - jmp error - -.is_variable: - xor rax, rax - mov byte al, [token] - - push rax - - call b_input_key_wait - - cmp rax, 48E0h - je .up_pressed - - cmp rax, 50E0h - je .down_pressed - - cmp rax, 4BE0h - je .left_pressed - - cmp rax, 4DE0h - je .right_pressed - -.store: - xor rbx, rbx - mov bl, al - - pop rax - - call set_var - - jmp mainloop - -.up_pressed: - mov rax, 1 - jmp .store - -.down_pressed: - mov rax, 2 - jmp .store - -.left_pressed: - mov rax, 3 - jmp .store - -.right_pressed: - mov rax, 4 - jmp .store - - -; ================================================================== -; INTERNAL ROUTINES FOR INTERPRETER - -; ------------------------------------------------------------------ -; Get value of variable character specified in AL (eg 'A') - -get_var: - sub al, 65 - mov rsi, variables - add rsi, rax - add rsi, rax - lodsw - ret - - -; ------------------------------------------------------------------ -; Set value of variable character specified in AL (eg 'A') -; with number specified in rbx - -set_var: - mov ah, 0 - sub al, 65 ; Remove ASCII codes before 'A' - - mov rdi, variables ; Find position in table (of words) - add rdi, rax - add rdi, rax - mov rax, rbx - stosw - ret - - -; ------------------------------------------------------------------ -; Get token from current position in prog - -get_token: - mov rsi, [prog] - lodsb - - cmp al, 13 - je .newline - - cmp al, 10 - je .newline - - cmp al, ' ' - je .newline - - call is_number - jc get_number_token - - cmp al, '"' - je get_quote_token - - cmp al, 39 ; Quote mark (') - je get_char_token - - cmp al, '$' - je near get_string_var_token - - jmp get_string_token - -.newline: - inc qword [prog] - jmp get_token - -get_number_token: - mov rsi, [prog] - mov rdi, token - -.loop: - lodsb - cmp al, 13 - je .done - cmp al, 10 - je .done - cmp al, ' ' - je .done - call is_number - jc .fine - - mov rsi, err_char_in_num - jmp error - -.fine: - stosb - inc qword [prog] - jmp .loop - -.done: - mov al, 0 ; Zero-terminate the token - stosb - - mov rax, NUMBER ; Pass back the token type - ret - -get_char_token: - inc qword [prog] ; Move past first quote (') - - mov rsi, [prog] - lodsb - - mov byte [token], al - - lodsb - cmp al, 39 ; Needs to finish with another quote - je .is_ok - - mov rsi, err_quote_term - jmp error - -.is_ok: - inc qword [prog] - inc qword [prog] - - mov rax, CHAR - ret - -get_quote_token: - inc qword [prog] ; Move past first quote (") char - mov qword rsi, [prog] - mov rdi, token -.loop: - lodsb - cmp al, '"' - je .done - cmp al, 10 - je .error - stosb - inc qword [prog] - jmp .loop - -.done: - mov al, 0 ; Zero-terminate the token - stosb - inc qword [prog] ; Move past final quote - - mov rax, QUOTE ; Pass back token type - ret - -.error: - mov rsi, err_quote_term - jmp error - -get_string_var_token: - lodsb - xor rbx, rbx ; If it's a string var, pass number of string in rbx - mov bl, al - sub bl, 49 - - inc qword [prog] - inc qword [prog] - - mov rax, STRING_VAR - ret - -get_string_token: - mov qword rsi, [prog] - mov rdi, token -.loop: - lodsb - cmp al, 13 - je .done - cmp al, 10 - je .done - cmp al, ' ' - je .done - stosb - inc qword [prog] - jmp .loop -.done: - mov al, 0 ; Zero-terminate the token - stosb - - mov rax, token - call b_string_uppercase - - mov rsi, token - call b_string_length ; How long was the token? - cmp rcx, 1 ; If 1 char, it's a variable or delimiter - je .is_not_string - - mov rsi, token ; If the token ends with ':', it's a label - add rsi, rax - dec rsi - lodsb - cmp al, ':' - je .is_label - - mov rax, STRING ; Otherwise it's a general string of characters - ret - -.is_label: - mov rax, LABEL - ret - -.is_not_string: - mov byte al, [token] - call is_letter - jc .is_var - - mov rax, UNKNOWN - ret - -.is_var: - mov rax, VARIABLE ; Otherwise probably a variable - ret - - -; ------------------------------------------------------------------ -; Set carry flag if AL contains ASCII number - -is_number: - cmp al, 48 - jl .not_number - cmp al, 57 - jg .not_number - stc - ret -.not_number: - clc - ret - - -; ------------------------------------------------------------------ -; Set carry flag if AL contains ASCII letter - -is_letter: - cmp al, 65 - jl .not_letter - cmp al, 90 - jg .not_letter - stc - ret - -.not_letter: - clc - ret - - -; ------------------------------------------------------------------ -; Print error message and quit out - -error: - call b_print_newline - call b_print_string ; Print error message - call b_print_newline - - mov rsp, [orig_stack] ; Restore the stack to as it was when BASIC started - - ret ; And finish - - - ; Error messages text... - - err_char_in_num db "Error: unexpected character in number", 0 - err_quote_term db "Error: quoted string or character not terminated correctly", 0 - err_print_type db "Error: PRINT command not followed by quoted text or variable", 0 - err_cmd_unknown db "Error: unknown command", 0 - err_goto_notlabel db "Error: GOTO or GOSUB not followed by label", 0 - err_label_notfound db "Error: GOTO or GOSUB label not found", 0 - err_return db "Error: RETURN without GOSUB", 0 - err_nest_limit db "Error: FOR or GOSUB nest limit exceeded", 0 - err_next db "Error: NEXT without FOR", 0 - err_syntax db "Error: syntax error", 0 - - - -; ================================================================== -; DATA SECTION - - orig_stack dq 0 ; Original stack location when BASIC started - - prog dq 0 ; Pointer to current location in BASIC code - prog_end dq 0 ; Pointer to final byte of BASIC code - - load_point dq 0 - - token_type db 0 ; Type of last token read (eg NUMBER, VARIABLE) - token times 255 db 0 ; Storage space for the token - tstring times 255 db 0 - -align 16 - variables times 26 dq 0 ; Storage space for variables A to Z -align 16 - for_variables times 26 dq 0 ; Storage for FOR loops -align 16 - for_code_points times 26 dq 0 ; Storage for code positions where FOR loops start - - alert_cmd db "ALERT", 0 - call_cmd db "CALL", 0 - cls_cmd db "CLS", 0 - cursor_cmd db "CURSOR", 0 - curschar_cmd db "CURSCHAR", 0 - end_cmd db "END", 0 - for_cmd db "FOR", 0 - gosub_cmd db "GOSUB", 0 - goto_cmd db "GOTO", 0 - getkey_cmd db "GETKEY", 0 - if_cmd db "IF", 0 - input_cmd db "INPUT", 0 - load_cmd db "LOAD", 0 - move_cmd db "MOVE", 0 - next_cmd db "NEXT", 0 - pause_cmd db "PAUSE", 0 - peek_cmd db "PEEK", 0 - poke_cmd db "POKE", 0 - port_cmd db "PORT", 0 - print_cmd db "PRINT", 0 - rem_cmd db "REM", 0 - rand_cmd db "RAND", 0 - return_cmd db "RETURN", 0 - save_cmd db "SAVE", 0 - serial_cmd db "SERIAL", 0 - sound_cmd db "SOUND", 0 - waitkey_cmd db "WAITKEY", 0 - - then_keyword db "THEN", 0 - chr_keyword db "CHR", 0 - hex_keyword db "HEX", 0 - - progstart_keyword db "PROGSTART", 0 - ramstart_keyword db "RAMSTART", 0 - - gosub_depth db 0 - gosub_points times 10 dq 0 ; Points in code to RETURN to - - string_vars times 1024 db 0 ; 8 * 128 byte strings - - -; ------------------------------------------------------------------ -basic_prog: - DB 'CLS',13,10 - DB 'PRINT "Please type your name: ";',13,10 - DB 'INPUT $N',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT "Hello ";',13,10 - DB 'PRINT $N;',13,10 - DB 'PRINT ", welcome to MikeOS Basic (in 64-bit mode)!"',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT "It supports FOR...NEXT loops and simple integer maths..."',13,10 - DB 'PRINT ""',13,10 - DB 'FOR I = 1 TO 15',13,10 - DB 'J = I * I',13,10 - DB 'K = J * I',13,10 - DB 'L = K * I',13,10 - DB 'PRINT I ;',13,10 - DB 'PRINT " ";',13,10 - DB 'PRINT J ;',13,10 - DB 'PRINT " ";',13,10 - DB 'PRINT K ;',13,10 - DB 'PRINT " ";',13,10 - DB 'PRINT L',13,10 - DB 'NEXT I',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT " ...and IF...THEN and GOSUB and lots of other stuff. Bye!"',13,10 - DB 'END',13,10 +; ================================================================== +; MikeOS -- The Mike Operating System kernel +; Copyright (C) 2006 - 2011 MikeOS Developers -- see doc/LICENSE.TXT +; +; BASIC CODE INTERPRETER +; ================================================================== + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +; ------------------------------------------------------------------ +; Token types + +%DEFINE VARIABLE 1 +%DEFINE STRING_VAR 2 +%DEFINE NUMBER 3 +%DEFINE STRING 4 +%DEFINE QUOTE 5 +%DEFINE CHAR 6 +%DEFINE UNKNOWN 7 +%DEFINE LABEL 8 + + +; ------------------------------------------------------------------ +; The BASIC interpreter execution starts here... + +b_run_basic: + mov [orig_stack], rsp ; Save stack pointer -- we might jump to the + ; error printing code and quit in the middle + ; some nested loops, and we want to preserve + ; the stack + mov rax, basic_prog ;embedded test program for a quick DOS test + mov rbx, 8192 ;default size for test program (not critical) + mov [load_point], rax ; rax was passed as starting location of code + + mov [prog], rax ; prog = pointer to current execution point in code + + add rbx, rax ; We were passed the .BAS byte size in rbx + sub rbx, 2 + mov [prog_end], rbx ; Make note of program end point + + + call clear_ram ; Clear variables etc. from previous run + ; of a BASIC program + + + +mainloop: + call get_token ; Get a token from the start of the line + + cmp rax, STRING ; Is the type a string of characters? + je .keyword ; If so, let's see if it's a keyword to process + + cmp rax, VARIABLE ; If it's a variable at the start of the line, + je near assign ; this is an assign (eg "X = Y + 5") + + cmp rax, STRING_VAR ; Same for a string variable (eg $1) + je near assign + + cmp rax, LABEL ; Don't need to do anything here - skip + je mainloop + + mov rsi, err_syntax ; Otherwise show an error and quit + jmp error + + +.keyword: + mov rsi, token ; Start trying to match commands + + mov rdi, alert_cmd + call b_string_compare + jc near do_alert + + mov rdi, call_cmd + call b_string_compare + jc near do_call + + mov rdi, cls_cmd + call b_string_compare + jc near do_cls + + mov rdi, cursor_cmd + call b_string_compare + jc near do_cursor + + mov rdi, curschar_cmd + call b_string_compare + jc near do_curschar + + mov rdi, end_cmd + call b_string_compare + jc near do_end + + mov rdi, for_cmd + call b_string_compare + jc near do_for + + mov rdi, getkey_cmd + call b_string_compare + jc near do_getkey + + mov rdi, gosub_cmd + call b_string_compare + jc near do_gosub + + mov rdi, goto_cmd + call b_string_compare + jc near do_goto + + mov rdi, input_cmd + call b_string_compare + jc near do_input + + mov rdi, if_cmd + call b_string_compare + jc near do_if + + mov rdi, load_cmd + call b_string_compare + jc near do_load + + mov rdi, move_cmd + call b_string_compare + jc near do_move + + mov rdi, next_cmd + call b_string_compare + jc near do_next + + mov rdi, pause_cmd + call b_string_compare + jc near do_pause + + mov rdi, peek_cmd + call b_string_compare + jc near do_peek + + mov rdi, poke_cmd + call b_string_compare + jc near do_poke + + mov rdi, port_cmd + call b_string_compare + jc near do_port + + mov rdi, print_cmd + call b_string_compare + jc near do_print + + mov rdi, rand_cmd + call b_string_compare + jc near do_rand + + mov rdi, rem_cmd + call b_string_compare + jc near do_rem + + mov rdi, return_cmd + call b_string_compare + jc near do_return + + mov rdi, save_cmd + call b_string_compare + jc near do_save + + mov rdi, serial_cmd + call b_string_compare + jc near do_serial + + mov rdi, sound_cmd + call b_string_compare + jc near do_sound + + mov rdi, waitkey_cmd + call b_string_compare + jc near do_waitkey + + mov rsi, err_cmd_unknown ; Command not found? + jmp error + + +; ------------------------------------------------------------------ +; CLEAR RAM + +clear_ram: + xor eax, eax + + mov rdi, variables + mov rcx, 52 + rep stosb + + mov rdi, for_variables + mov rcx, 52 + rep stosb + + mov rdi, for_code_points + mov rcx, 52 + rep stosb + + mov byte [gosub_depth], 0 + + mov rdi, gosub_points + mov rcx, 20 + rep stosb + + mov rdi, string_vars + mov rcx, 1024 + rep stosb + + ret + + +; ------------------------------------------------------------------ +; ASSIGNMENT + +assign: + cmp rax, VARIABLE ; Are we starting with a number var? + je .do_num_var + + mov rdi, string_vars ; Otherwise it's a string var + mov rax, 128 + mul rbx ; (rbx = string number, passed back from get_token) + add rdi, rax + + push rdi + + call get_token + mov byte al, [token] + cmp al, '=' + jne near .error + + call get_token + cmp rax, QUOTE + je .second_is_quote + + cmp rax, STRING_VAR + jne near .error + + mov rsi, string_vars ; Otherwise it's a string var + mov rax, 128 + mul rbx ; (rbx = string number, passed back from get_token) + add rsi, rax + + pop rdi + call b_string_copy + + jmp mainloop + + +.second_is_quote: + mov rsi, token + pop rdi + call b_string_copy + + jmp mainloop + + +.do_num_var: + xor rax, rax + mov byte al, [token] + mov byte [.tmp], al + + call get_token + mov byte al, [token] + cmp al, '=' + jne near .error + + call get_token + cmp rax, NUMBER + je .second_is_num + + cmp rax, VARIABLE + je .second_is_variable + + cmp rax, STRING + je near .second_is_string + + cmp rax, UNKNOWN + jne near .error + + mov byte al, [token] ; Address of string var? + cmp al, '&' + jne near .error + + call get_token ; Let's see if there's a string var + cmp rax, STRING_VAR + jne near .error + + mov rdi, string_vars + mov rax, 128 + mul rbx + add rdi, rax + + mov rbx, rdi + + mov byte al, [.tmp] + call set_var + + jmp mainloop + + +.second_is_variable: + xor rax, rax + mov byte al, [token] + + call get_var + mov rbx, rax + mov byte al, [.tmp] + call set_var + + jmp .check_for_more + + +.second_is_num: + mov rsi, token + call b_string_to_int + + mov rbx, rax ; Number to insert in variable table + + xor rax, rax + mov byte al, [.tmp] + + call set_var + + + ; The assignment could be simply "X = 5" etc. Or it could be + ; "X = Y + 5" -- ie more complicated. So here we check to see if + ; there's a delimiter... + +.check_for_more: + mov rax, [prog] ; Save code location in case there's no delimiter + mov [.tmp_loc], rax + + call get_token ; Any more to deal with in this assignment? + mov byte al, [token] + cmp al, '+' + je .theres_more + cmp al, '-' + je .theres_more + cmp al, '*' + je .theres_more + cmp al, '/' + je .theres_more + cmp al, '%' + je .theres_more + + mov rax, [.tmp_loc] ; Not a delimiter, so step back before the token + mov [prog], rax ; that we just grabbed + + jmp mainloop ; And go back to the code interpreter! + + +.theres_more: + mov byte [.delim], al + + call get_token + cmp rax, VARIABLE + je .handle_variable + + mov rsi, token + call b_string_to_int + mov rbx, rax + + xor rax, rax + mov byte al, [.tmp] + + call get_var ; This also points rsi at right place in variable table + + cmp byte [.delim], '+' + jne .not_plus + + add rax, rbx + jmp .finish + +.not_plus: + cmp byte [.delim], '-' + jne .not_minus + + sub rax, rbx + jmp .finish + +.not_minus: + cmp byte [.delim], '*' + jne .not_times + + mul rbx + jmp .finish + +.not_times: + cmp byte [.delim], '/' + jne .not_divide + + xor rdx, rdx + div rbx + jmp .finish + +.not_divide: + xor rdx, rdx + div rbx + mov rax, rdx ; Get remainder + +.finish: + mov rbx, rax + mov byte al, [.tmp] + call set_var + + jmp .check_for_more + + +.handle_variable: + xor rax, rax + mov byte al, [token] + + call get_var + + mov rbx, rax + + xor rax, rax + mov byte al, [.tmp] + + call get_var + + cmp byte [.delim], '+' + jne .vnot_plus + + add rax, rbx + jmp .vfinish + +.vnot_plus: + cmp byte [.delim], '-' + jne .vnot_minus + + sub rax, rbx + jmp .vfinish + +.vnot_minus: + cmp byte [.delim], '*' + jne .vnot_times + + mul rbx + jmp .vfinish + +.vnot_times: + cmp byte [.delim], '/' + jne .vnot_divide + + mov dx, 0 + div rbx + jmp .finish + +.vnot_divide: + mov dx, 0 + div rbx + mov rax, rdx ; Get remainder + +.vfinish: + mov rbx, rax + mov byte al, [.tmp] + call set_var + + jmp .check_for_more + + +.second_is_string: + mov rdi, token + mov rsi, progstart_keyword + call b_string_compare + je .is_progstart + + mov rsi, ramstart_keyword + call b_string_compare + je .is_ramstart + + jmp .error + +.is_progstart: + xor rax, rax + mov byte al, [.tmp] + + mov rbx, [load_point] + call set_var + + jmp mainloop + + + +.is_ramstart: + xor rax, rax + mov byte al, [.tmp] + + mov rbx, [prog_end] + inc rbx + inc rbx + inc rbx + call set_var + + jmp mainloop + + +.error: + mov rsi, err_syntax + jmp error + + + .tmp db 0 + .tmp_loc dq 0 + .delim db 0 + + +; ================================================================== +; SPECIFIC COMMAND CODE STARTS HERE + +; ------------------------------------------------------------------ +; ALERT + +do_alert: + call get_token + + cmp rax, QUOTE + je .is_quote + + mov rsi, err_syntax + jmp error + +.is_quote: + mov rax, token ; First string for alert box + xor rbx, rbx ; Others are blank + xor rcx, rcx + mov dx, 0 ; One-choice box + jmp mainloop + + +; ------------------------------------------------------------------ +; CALL + +do_call: + call get_token + cmp rax, NUMBER + je .is_number + + xor rax, rax + mov byte al, [token] + call get_var + jmp .execute_call + +.is_number: + mov rsi, token + call b_string_to_int + +.execute_call: + xor rbx, rbx + xor rcx, rcx + mov dx, 0 + mov rdi, 0 + mov rsi, 0 + + call rax + + jmp mainloop + + + +; ------------------------------------------------------------------ +; CLS + +do_cls: + call b_screen_clear + jmp mainloop + + +; ------------------------------------------------------------------ +; CURSOR + +do_cursor: + call get_token + + mov rsi, token + mov rdi, .on_str + call b_string_compare + jc .turn_on + + mov rsi, token + mov rdi, .off_str + call b_string_compare + jc .turn_off + + mov rsi, err_syntax + jmp error + +.turn_on: + call b_show_cursor + jmp mainloop + +.turn_off: + call b_hide_cursor + jmp mainloop + + + .on_str db "ON", 0 + .off_str db "OFF", 0 + + +; ------------------------------------------------------------------ +; CURSCHAR + +do_curschar: + call get_token + + cmp rax, VARIABLE + je .is_ok + + mov rsi, err_syntax + jmp error + +.is_ok: + xor rax, rax + mov byte al, [token] + + push rax ; Store variable we're going to use + +; mov ah, 08h +; xor rbx, rbx +; int 10h ; Get char at current cursor location + + xor rbx, rbx ; We only want the lower byte (the char, not attribute) + mov bl, al + + pop rax ; Get the variable back + + call set_var ; And store the value + + jmp mainloop + + +; ------------------------------------------------------------------ +; END + +do_end: + mov rsp, [orig_stack] + ret + + +; ------------------------------------------------------------------ +; FOR + +do_for: + call get_token ; Get the variable we're using in this loop + + cmp rax, VARIABLE + jne near .error + + xor rax, rax + mov byte al, [token] + mov byte [.tmp_var], al ; Store it in a temporary location for now + + call get_token + + xor rax, rax ; Check it's followed up with '=' + mov byte al, [token] + cmp al, '=' + jne .error + + call get_token ; Next we want a number + + cmp rax, NUMBER + jne .error + + mov rsi, token ; Convert it + call b_string_to_int + + + ; At this stage, we've read something like "FOR X = 1" + ; so let's store that 1 in the variable table + + mov rbx, rax + xor rax, rax + mov byte al, [.tmp_var] + call set_var + + + call get_token ; Next we're looking for "TO" + + cmp rax, STRING + jne .error + + mov rax, token + call b_string_uppercase + + mov rsi, token + mov rdi, .to_string + call b_string_compare + jnc .error + + ; So now we're at "FOR X = 1 TO" + + call get_token + + cmp rax, NUMBER + jne .error + + mov rsi, token ; Get target number + call b_string_to_int + + mov rbx, rax + + xor rax, rax + mov byte al, [.tmp_var] + + sub al, 65 ; Store target number in table + mov rdi, for_variables + add rdi, rax + add rdi, rax + mov rax, rbx + stosw + + + ; So we've got the variable, assigned it the starting number, and put into + ; our table the limit it should reach. But we also need to store the point in + ; code after the FOR line we should return to if NEXT X doesn't complete the loop... +; xor rax, rax + xor rax, rax +; xor eax, eax + mov byte al, [.tmp_var] + + sub al, 65 ; Store code position to return to in table + mov rdi, for_code_points +; add rdi, rax +; add rdi, rax + shl rax, 3 + add rdi, rax + mov rax, [prog] + stosq + + jmp mainloop + + +.error: + mov rsi, err_syntax + jmp error + + + .tmp_var db 0 + .to_string db 'TO', 0 + + +; ------------------------------------------------------------------ +; GETKEY + +do_getkey: + call get_token + cmp rax, VARIABLE + je .is_variable + + mov rsi, err_syntax + jmp error + +.is_variable: + xor rax, rax + mov byte al, [token] + + push rax + + call b_input_key_check + + xor rbx, rbx + mov bl, al + + pop rax + + call set_var + + jmp mainloop + + +; ------------------------------------------------------------------ +; GOSUB + +do_gosub: + call get_token ; Get the number (label) + + cmp rax, STRING + je .is_ok + + mov rsi, err_goto_notlabel + jmp error + +.is_ok: + mov rsi, token ; Back up this label + mov rdi, .tmp_token + call b_string_copy + + mov rax, .tmp_token + call b_string_length + + mov rdi, .tmp_token ; Add ':' char to end for searching + add rdi, rax + mov al, ':' + stosb + mov al, 0 + stosb + + inc byte [gosub_depth] + + xor rax, rax + mov byte al, [gosub_depth] ; Get current GOSUB nest level + + cmp al, 9 + jle .within_limit + + mov rsi, err_nest_limit + jmp error + +.within_limit: + mov rdi, gosub_points ; Move into our table of pointers + add rdi, rax ; Table is words (not bytes) + add rdi, rax + mov rax, [prog] + stosw ; Store current location before jump + + + mov rax, [load_point] + mov [prog], rax ; Return to start of program to find label + +.loop: + call get_token + + cmp rax, LABEL + jne .line_loop + + mov rsi, token + mov rdi, .tmp_token + call b_string_compare + jc mainloop + +.line_loop: ; Go to end of line + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + cmp al, 10 + jne .line_loop + + mov rax, [prog] + mov rbx, [prog_end] + cmp rax, rbx + jg .past_end + + jmp .loop + +.past_end: + mov rsi, err_label_notfound + jmp error + + .tmp_token times 30 db 0 + + +; ------------------------------------------------------------------ +; GOTO + +do_goto: + call get_token ; Get the next token + + cmp rax, STRING + je .is_ok + + mov rsi, err_goto_notlabel + jmp error + +.is_ok: + mov rsi, token ; Back up this label + mov rdi, .tmp_token + call b_string_copy + + mov rax, .tmp_token + call b_string_length + + mov rdi, .tmp_token ; Add ':' char to end for searching + add rdi, rax + mov al, ':' + stosb + mov al, 0 + stosb + + mov rax, [load_point] + mov [prog], rax ; Return to start of program to find label + +.loop: + call get_token + + cmp rax, LABEL + jne .line_loop + + mov rsi, token + mov rdi, .tmp_token + call b_string_compare + jc mainloop + +.line_loop: ; Go to end of line + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + + cmp al, 10 + jne .line_loop + + mov rax, [prog] + mov rbx, [prog_end] + cmp rax, rbx + jg .past_end + + jmp .loop + +.past_end: + mov rsi, err_label_notfound + jmp error + + .tmp_token times 30 db 0 + + +; ------------------------------------------------------------------ +; IF + +do_if: + call get_token + + cmp rax, VARIABLE ; If can only be followed by a variable + je .num_var + + cmp rax, STRING_VAR + je near .string_var + + mov rsi, err_syntax + jmp error + +.num_var: + xor rax, rax + mov byte al, [token] + call get_var + + mov rdx, rax ; Store value of first part of comparison + + call get_token ; Get the delimiter + mov byte al, [token] + cmp al, '=' + je .equals + cmp al, '>' + je .greater + cmp al, '<' + je .less + + mov rsi, err_syntax ; If not one of the above, error out + jmp error + +.equals: + call get_token ; Is this 'X = Y' (equals another variable?) + + cmp rax, CHAR + je .equals_char + + mov byte al, [token] + call is_letter + jc .equals_var + + mov rsi, token ; Otherwise it's, eg 'X = 1' (a number) + call b_string_to_int + + cmp rax, rdx ; On to the THEN bit if 'X = num' matches + je near .on_to_then + + jmp .finish_line ; Otherwise skip the rest of the line + +.equals_char: + xor rax, rax + mov byte al, [token] + + cmp rax, rdx + je near .on_to_then + + jmp .finish_line + +.equals_var: + xor rax, rax + mov byte al, [token] + + call get_var + + cmp rax, rdx ; Do the variables match? + je near .on_to_then ; On to the THEN bit if so + + jmp .finish_line ; Otherwise skip the rest of the line + +.greater: + call get_token ; Greater than a variable or number? + mov byte al, [token] + call is_letter + jc .greater_var + + mov rsi, token ; Must be a number here... + call b_string_to_int + + cmp rax, rdx + jl near .on_to_then + + jmp .finish_line + +.greater_var: ; Variable in this case + xor rax, rax + mov byte al, [token] + + call get_var + + cmp rax, rdx ; Make the comparison! + jl .on_to_then + + jmp .finish_line + +.less: + call get_token + mov byte al, [token] + call is_letter + jc .less_var + + mov rsi, token + call b_string_to_int + + cmp rax, rdx + jg .on_to_then + + jmp .finish_line + +.less_var: + xor rax, rax + mov byte al, [token] + + call get_var + + cmp rax, rdx + jg .on_to_then + + jmp .finish_line + +.string_var: + mov byte [.tmp_string_var], bl + + call get_token + + mov byte al, [token] + cmp al, '=' + jne .error + + call get_token + cmp rax, STRING_VAR + je .second_is_string_var + + cmp rax, QUOTE + jne .error + + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + mov rdi, token + call b_string_compare + je .on_to_then + + jmp .finish_line + +.second_is_string_var: + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + + mov rdi, string_vars + xor rbx, rbx + mov byte bl, [.tmp_string_var] + mov rax, 128 + mul rbx + add rdi, rax + + call b_string_compare + jc .on_to_then + + jmp .finish_line + +.on_to_then: + call get_token + + mov rsi, token + mov rdi, then_keyword + call b_string_compare + + jc .then_present + + mov rsi, err_syntax + jmp error + +.then_present: ; Continue rest of line like any other command! + jmp mainloop + +.finish_line: ; IF wasn't fulfilled, so skip rest of line + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + cmp al, 10 + jne .finish_line + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + .tmp_string_var db 0 + + +; ------------------------------------------------------------------ +; INPUT + +do_input: + mov al, 0 ; Clear string from previous usage + mov rdi, .tmpstring + mov rcx, 128 + rep stosb + + call get_token + + cmp rax, VARIABLE ; We can only INPUT to variables! + je .number_var + + cmp rax, STRING_VAR + je .string_var + + mov rsi, err_syntax + jmp error + +.number_var: + mov rdi, .tmpstring ; Get input from the user + mov rcx, 50 + call b_input_string + + mov rsi, .tmpstring + call b_string_length + cmp rcx, 0 + jne .char_entered + + mov byte [.tmpstring], '0' ; If enter hit, fill variable with zero + mov byte [.tmpstring + 1], 0 + +.char_entered: + mov rsi, .tmpstring ; Convert to integer format + call b_string_to_int + mov rbx, rax + + xor rax, rax + mov byte al, [token] ; Get the variable where we're storing it... + call set_var ; ...and store it! + + call b_print_newline + + jmp mainloop + +.string_var: + push rbx + + mov rdi, .tmpstring + mov rcx, 50 + call b_input_string + + mov rsi, .tmpstring + mov rdi, string_vars + + pop rbx + + mov rax, 128 + mul rbx + + add rdi, rax + call b_string_copy + + call b_print_newline + + jmp mainloop + + .tmpstring times 128 db 0 + + +; ------------------------------------------------------------------ +; LOAD + +do_load: + call get_token + cmp rax, QUOTE + je .is_quote + + cmp rax, STRING_VAR + jne .error + + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + jmp .get_position + +.is_quote: + mov rsi, token + +.get_position: + mov rax, rsi +; call b_file_exists + jc .file_not_exists + + mov rdx, rax ; Store for now + + call get_token + + cmp rax, VARIABLE + je .second_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.load_part: + mov rcx, rax + + mov rax, rdx + +; call b_load_file + + xor rax, rax + mov byte al, 'S' + call set_var + + xor rax, rax + mov byte al, 'R' + xor rbx, rbx + call set_var + + jmp mainloop + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .load_part + +.file_not_exists: + xor rax, rax + mov byte al, 'R' + mov rbx, 1 + call set_var + + call get_token ; Skip past the loading point -- unnecessary now + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + +; ------------------------------------------------------------------ +; MOVE + +do_move: + call get_token + + cmp rax, VARIABLE + je .first_is_var + + mov rsi, token + call b_string_to_int + mov dl, al + jmp .onto_second + +.first_is_var: + xor rax, rax + mov byte al, [token] + call get_var + mov dl, al + +.onto_second: + call get_token + + cmp rax, VARIABLE + je .second_is_var + + mov rsi, token + call b_string_to_int + mov dh, al + jmp .finish + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + mov dh, al + +.finish: + call b_move_cursor + + jmp mainloop + + +; ------------------------------------------------------------------ +; NEXT + +do_next: + call get_token + + cmp rax, VARIABLE ; NEXT must be followed by a variable + jne .error + + xor rax, rax + mov byte al, [token] + call get_var + + inc rax ; NEXT increments the variable, of course! + + mov rbx, rax + + xor rax, rax + mov byte al, [token] + + sub al, 65 + mov rsi, for_variables + add rsi, rax + add rsi, rax + lodsw ; Get the target number from the table + + inc rax ; (Make the loop inclusive of target number) + cmp rax, rbx ; Do the variable and target match? + je .loop_finished + + xor rax, rax ; If not, store the updated variable + mov byte al, [token] + call set_var + + xor rax, rax ; Find the code point and go back + mov byte al, [token] + sub al, 65 + mov rsi, for_code_points +; add rsi, rax +; add rsi, rax + shl rax, 3 + add rsi, rax + lodsq + + mov [prog], rax + jmp mainloop + +.loop_finished: + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + +; ------------------------------------------------------------------ +; PAUSE + +do_pause: + call get_token + + cmp rax, VARIABLE + je .is_var + + mov rsi, token + call b_string_to_int + jmp .finish + +.is_var: + xor rax, rax + mov byte al, [token] + call get_var + +.finish: +; call b_pause + jmp mainloop + + +; ------------------------------------------------------------------ +; PEEK + +do_peek: + call get_token + + cmp rax, VARIABLE + jne .error + + xor rax, rax + mov byte al, [token] + mov byte [.tmp_var], al + + call get_token + + cmp rax, VARIABLE + je .dereference + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.store: + mov rsi, rax + xor rbx, rbx + mov byte bl, [rsi] + xor rax, rax + mov byte al, [.tmp_var] + call set_var + + jmp mainloop + +.dereference: + mov byte al, [token] + call get_var + jmp .store + +.error: + mov rsi, err_syntax + jmp error + + + .tmp_var db 0 + + +; ------------------------------------------------------------------ +; POKE + +do_poke: + call get_token + + cmp rax, VARIABLE + je .first_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + + cmp rax, 255 + jg .error + + mov byte [.first_value], al + jmp .onto_second + + +.first_is_var: + xor rax, rax + mov byte al, [token] + call get_var + + mov byte [.first_value], al + +.onto_second: + call get_token + + cmp rax, VARIABLE + je .second_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.got_value: + mov rdi, rax + xor rax, rax + mov byte al, [.first_value] + mov byte [rdi], al + + jmp mainloop + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .got_value + +.error: + mov rsi, err_syntax + jmp error + + .first_value db 0 + + +; ------------------------------------------------------------------ +; PORT + +do_port: + call get_token + mov rsi, token + + mov rdi, .out_cmd + call b_string_compare + jc .do_out_cmd + + mov rdi, .in_cmd + call b_string_compare + jc .do_in_cmd + + jmp .error + +.do_out_cmd: + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int ; Now rax = port number + mov rdx, rax + + call get_token + cmp rax, NUMBER + je .out_is_num + + cmp rax, VARIABLE + je .out_is_var + + jmp .error + +.out_is_num: + mov rsi, token + call b_string_to_int +; call b_port_byte_out + jmp mainloop + +.out_is_var: + xor rax, rax + mov byte al, [token] + call get_var + +; call b_port_byte_out + jmp mainloop + +.do_in_cmd: + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + mov rdx, rax + + call get_token + cmp rax, VARIABLE + jne .error + + mov byte cl, [token] + +; call b_port_byte_in + xor rbx, rbx + mov bl, al + + mov al, cl + call set_var + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + + .out_cmd db "OUT", 0 + .in_cmd db "IN", 0 + + +; ------------------------------------------------------------------ +; PRINT + +do_print: + call get_token ; Get part after PRINT + + cmp rax, QUOTE ; What type is it? + je .print_quote + + cmp rax, VARIABLE ; Numerical variable (eg X) + je .print_var + + cmp rax, STRING_VAR ; String variable (eg $1) + je .print_string_var + + cmp rax, STRING ; Special keyword (eg CHR or HEX) + je .print_keyword + + mov rsi, err_print_type ; We only print quoted strings and vars! + jmp error + +.print_var: + xor rax, rax + mov byte al, [token] + call get_var ; Get its value + mov rdi, tstring + mov rsi, rdi + call b_int_to_string ; Convert to string + call b_print_string + + jmp .newline_or_not + +.print_quote: ; If it's quoted text, print it + mov rsi, token + call b_print_string + + jmp .newline_or_not + +.print_string_var: + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + call b_print_string + + jmp .newline_or_not + +.print_keyword: + mov rsi, token + mov rdi, chr_keyword + call b_string_compare + jc .is_chr + + mov rdi, hex_keyword + call b_string_compare + jc .is_hex + + mov rsi, err_syntax + jmp error + +.is_chr: + call get_token + + cmp rax, VARIABLE + jne .error + + xor rax, rax + mov byte al, [token] + call get_var + +; mov ah, 0Eh +; int 10h + + jmp .newline_or_not + +.is_hex: + call get_token + + cmp rax, VARIABLE + jne .error + + xor rax, rax + mov byte al, [token] + call get_var + + call b_debug_dump_al ;print_2hex + + jmp .newline_or_not + +.error: + mov rsi, err_syntax + jmp error + +.newline_or_not: + ; We want to see if the command ends with ';' -- which means that + ; we shouldn't print a newline after it finishes. So we store the + ; current program location to pop ahead and see if there's the ';' + ; character -- otherwise we put the program location back and resume + ; the main loop + mov rax, [prog] + mov [.tmp_loc], rax + + call get_token + cmp rax, UNKNOWN + jne .ignore + + xor rax, rax + mov al, [token] + cmp al, ';' + jne .ignore + + jmp mainloop ; And go back to interpreting the code! + +.ignore: + call b_print_newline + + mov rax, [.tmp_loc] + mov [prog], rax + + jmp mainloop + + .tmp_loc dq 0 + + +; ------------------------------------------------------------------ +; RAND + +do_rand: + call get_token + cmp rax, VARIABLE + jne .error + + mov byte al, [token] + mov byte [.tmp], al + + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + mov [.num1], rax + + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + mov [.num2], rax + + mov rax, [.num1] + mov rbx, [.num2] +; call b_get_random + + mov rbx, rcx + xor rax, rax + mov byte al, [.tmp] + call set_var + + jmp mainloop + + .tmp db 0 + .num1 dq 0 + .num2 dq 0 + +.error: + mov rsi, err_syntax + jmp error + + +; ------------------------------------------------------------------ +; REM + +do_rem: + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + cmp al, 10 ; Find end of line after REM + jne do_rem + + jmp mainloop + + +; ------------------------------------------------------------------ +; RETURN + +do_return: + xor rax, rax + mov byte al, [gosub_depth] + cmp al, 0 + jne .is_ok + + mov rsi, err_return + jmp error + +.is_ok: + mov rsi, gosub_points + add rsi, rax ; Table is words (not bytes) + add rsi, rax + lodsw + mov [prog], rax + dec byte [gosub_depth] + + jmp mainloop + + +; ------------------------------------------------------------------ +; SAVE + +do_save: + call get_token + cmp rax, QUOTE + je .is_quote + + cmp rax, STRING_VAR + jne near .error + + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + jmp .get_position + +.is_quote: + mov rsi, token + +.get_position: + mov rdi, .tmp_filename + call b_string_copy + + call get_token + + cmp rax, VARIABLE + je .second_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.set_data_loc: + mov [.data_loc], rax + + call get_token + + cmp rax, VARIABLE + je .third_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.set_data_size: + mov [.data_size], rax + + mov rax, .tmp_filename + mov rbx, [.data_loc] + mov rcx, [.data_size] + +; call b_write_file + jc .save_failure + + xor rax, rax + mov byte al, 'R' + xor rbx, rbx + call set_var + + jmp mainloop + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .set_data_loc + +.third_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .set_data_size + +.save_failure: + xor rax, rax + mov byte al, 'R' + mov rbx, 1 + call set_var + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + + .filename_loc dw 0 + .data_loc dw 0 + .data_size dw 0 + + .tmp_filename times 15 db 0 + + +; ------------------------------------------------------------------ +; SERIAL + +do_serial: + call get_token + mov rsi, token + + mov rdi, .on_cmd + call b_string_compare + jc .do_on_cmd + + mov rdi, .send_cmd + call b_string_compare + jc .do_send_cmd + + mov rdi, .rec_cmd + call b_string_compare + jc .do_rec_cmd + + jmp .error + +.do_on_cmd: + call get_token + cmp rax, NUMBER + je .do_on_cmd_ok + jmp .error + +.do_on_cmd_ok: + mov rsi, token + call b_string_to_int + cmp rax, 1200 + je .on_cmd_slow_mode + cmp rax, 9600 + je .on_cmd_fast_mode + + jmp .error + +.on_cmd_fast_mode: + xor rax, rax +; call b_serial_port_enable + jmp mainloop + +.on_cmd_slow_mode: + mov rax, 1 +; call b_serial_port_enable + jmp mainloop + +.do_send_cmd: + call get_token + cmp rax, NUMBER + je .send_number + + cmp rax, VARIABLE + je .send_variable + + jmp .error + +.send_number: + mov rsi, token + call b_string_to_int +; call b_send_via_serial + jmp mainloop + +.send_variable: + xor rax, rax + mov byte al, [token] + call get_var +; call b_send_via_serial + jmp mainloop + +.do_rec_cmd: + call get_token + cmp rax, VARIABLE + jne .error + + mov byte al, [token] + + xor rcx, rcx + mov cl, al +; call b_get_via_serial + + xor rbx, rbx + mov bl, al + mov al, cl + call set_var + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + .on_cmd db "ON", 0 + .send_cmd db "SEND", 0 + .rec_cmd db "REC", 0 + + +; ------------------------------------------------------------------ +; SOUND + +do_sound: + call get_token + + cmp rax, VARIABLE + je .first_is_var + + mov rsi, token + call b_string_to_int + jmp .done_first + +.first_is_var: + xor rax, rax + mov byte al, [token] + call get_var + +.done_first: + call b_speaker_tone + + call get_token + + cmp rax, VARIABLE + je .second_is_var + + mov rsi, token + call b_string_to_int + jmp .finish + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + +.finish: +; call b_pause + call b_speaker_off + + jmp mainloop + + +; ------------------------------------------------------------------ +; WAITKEY + +do_waitkey: + call get_token + cmp rax, VARIABLE + je .is_variable + + mov rsi, err_syntax + jmp error + +.is_variable: + xor rax, rax + mov byte al, [token] + + push rax + + call b_input_key_wait + + cmp rax, 48E0h + je .up_pressed + + cmp rax, 50E0h + je .down_pressed + + cmp rax, 4BE0h + je .left_pressed + + cmp rax, 4DE0h + je .right_pressed + +.store: + xor rbx, rbx + mov bl, al + + pop rax + + call set_var + + jmp mainloop + +.up_pressed: + mov rax, 1 + jmp .store + +.down_pressed: + mov rax, 2 + jmp .store + +.left_pressed: + mov rax, 3 + jmp .store + +.right_pressed: + mov rax, 4 + jmp .store + + +; ================================================================== +; INTERNAL ROUTINES FOR INTERPRETER + +; ------------------------------------------------------------------ +; Get value of variable character specified in AL (eg 'A') + +get_var: + sub al, 65 + mov rsi, variables + add rsi, rax + add rsi, rax + lodsw + ret + + +; ------------------------------------------------------------------ +; Set value of variable character specified in AL (eg 'A') +; with number specified in rbx + +set_var: + mov ah, 0 + sub al, 65 ; Remove ASCII codes before 'A' + + mov rdi, variables ; Find position in table (of words) + add rdi, rax + add rdi, rax + mov rax, rbx + stosw + ret + + +; ------------------------------------------------------------------ +; Get token from current position in prog + +get_token: + mov rsi, [prog] + lodsb + + cmp al, 13 + je .newline + + cmp al, 10 + je .newline + + cmp al, ' ' + je .newline + + call is_number + jc get_number_token + + cmp al, '"' + je get_quote_token + + cmp al, 39 ; Quote mark (') + je get_char_token + + cmp al, '$' + je near get_string_var_token + + jmp get_string_token + +.newline: + inc qword [prog] + jmp get_token + +get_number_token: + mov rsi, [prog] + mov rdi, token + +.loop: + lodsb + cmp al, 13 + je .done + cmp al, 10 + je .done + cmp al, ' ' + je .done + call is_number + jc .fine + + mov rsi, err_char_in_num + jmp error + +.fine: + stosb + inc qword [prog] + jmp .loop + +.done: + mov al, 0 ; Zero-terminate the token + stosb + + mov rax, NUMBER ; Pass back the token type + ret + +get_char_token: + inc qword [prog] ; Move past first quote (') + + mov rsi, [prog] + lodsb + + mov byte [token], al + + lodsb + cmp al, 39 ; Needs to finish with another quote + je .is_ok + + mov rsi, err_quote_term + jmp error + +.is_ok: + inc qword [prog] + inc qword [prog] + + mov rax, CHAR + ret + +get_quote_token: + inc qword [prog] ; Move past first quote (") char + mov qword rsi, [prog] + mov rdi, token +.loop: + lodsb + cmp al, '"' + je .done + cmp al, 10 + je .error + stosb + inc qword [prog] + jmp .loop + +.done: + mov al, 0 ; Zero-terminate the token + stosb + inc qword [prog] ; Move past final quote + + mov rax, QUOTE ; Pass back token type + ret + +.error: + mov rsi, err_quote_term + jmp error + +get_string_var_token: + lodsb + xor rbx, rbx ; If it's a string var, pass number of string in rbx + mov bl, al + sub bl, 49 + + inc qword [prog] + inc qword [prog] + + mov rax, STRING_VAR + ret + +get_string_token: + mov qword rsi, [prog] + mov rdi, token +.loop: + lodsb + cmp al, 13 + je .done + cmp al, 10 + je .done + cmp al, ' ' + je .done + stosb + inc qword [prog] + jmp .loop +.done: + mov al, 0 ; Zero-terminate the token + stosb + + mov rax, token + call b_string_uppercase + + mov rsi, token + call b_string_length ; How long was the token? + cmp rcx, 1 ; If 1 char, it's a variable or delimiter + je .is_not_string + + mov rsi, token ; If the token ends with ':', it's a label + add rsi, rax + dec rsi + lodsb + cmp al, ':' + je .is_label + + mov rax, STRING ; Otherwise it's a general string of characters + ret + +.is_label: + mov rax, LABEL + ret + +.is_not_string: + mov byte al, [token] + call is_letter + jc .is_var + + mov rax, UNKNOWN + ret + +.is_var: + mov rax, VARIABLE ; Otherwise probably a variable + ret + + +; ------------------------------------------------------------------ +; Set carry flag if AL contains ASCII number + +is_number: + cmp al, 48 + jl .not_number + cmp al, 57 + jg .not_number + stc + ret +.not_number: + clc + ret + + +; ------------------------------------------------------------------ +; Set carry flag if AL contains ASCII letter + +is_letter: + cmp al, 65 + jl .not_letter + cmp al, 90 + jg .not_letter + stc + ret + +.not_letter: + clc + ret + + +; ------------------------------------------------------------------ +; Print error message and quit out + +error: + call b_print_newline + call b_print_string ; Print error message + call b_print_newline + + mov rsp, [orig_stack] ; Restore the stack to as it was when BASIC started + + ret ; And finish + + + ; Error messages text... + + err_char_in_num db "Error: unexpected character in number", 0 + err_quote_term db "Error: quoted string or character not terminated correctly", 0 + err_print_type db "Error: PRINT command not followed by quoted text or variable", 0 + err_cmd_unknown db "Error: unknown command", 0 + err_goto_notlabel db "Error: GOTO or GOSUB not followed by label", 0 + err_label_notfound db "Error: GOTO or GOSUB label not found", 0 + err_return db "Error: RETURN without GOSUB", 0 + err_nest_limit db "Error: FOR or GOSUB nest limit exceeded", 0 + err_next db "Error: NEXT without FOR", 0 + err_syntax db "Error: syntax error", 0 + + + +; ================================================================== +; DATA SECTION + + orig_stack dq 0 ; Original stack location when BASIC started + + prog dq 0 ; Pointer to current location in BASIC code + prog_end dq 0 ; Pointer to final byte of BASIC code + + load_point dq 0 + + token_type db 0 ; Type of last token read (eg NUMBER, VARIABLE) + token times 255 db 0 ; Storage space for the token + tstring times 255 db 0 + +align 16 + variables times 26 dq 0 ; Storage space for variables A to Z +align 16 + for_variables times 26 dq 0 ; Storage for FOR loops +align 16 + for_code_points times 26 dq 0 ; Storage for code positions where FOR loops start + + alert_cmd db "ALERT", 0 + call_cmd db "CALL", 0 + cls_cmd db "CLS", 0 + cursor_cmd db "CURSOR", 0 + curschar_cmd db "CURSCHAR", 0 + end_cmd db "END", 0 + for_cmd db "FOR", 0 + gosub_cmd db "GOSUB", 0 + goto_cmd db "GOTO", 0 + getkey_cmd db "GETKEY", 0 + if_cmd db "IF", 0 + input_cmd db "INPUT", 0 + load_cmd db "LOAD", 0 + move_cmd db "MOVE", 0 + next_cmd db "NEXT", 0 + pause_cmd db "PAUSE", 0 + peek_cmd db "PEEK", 0 + poke_cmd db "POKE", 0 + port_cmd db "PORT", 0 + print_cmd db "PRINT", 0 + rem_cmd db "REM", 0 + rand_cmd db "RAND", 0 + return_cmd db "RETURN", 0 + save_cmd db "SAVE", 0 + serial_cmd db "SERIAL", 0 + sound_cmd db "SOUND", 0 + waitkey_cmd db "WAITKEY", 0 + + then_keyword db "THEN", 0 + chr_keyword db "CHR", 0 + hex_keyword db "HEX", 0 + + progstart_keyword db "PROGSTART", 0 + ramstart_keyword db "RAMSTART", 0 + + gosub_depth db 0 + gosub_points times 10 dq 0 ; Points in code to RETURN to + + string_vars times 1024 db 0 ; 8 * 128 byte strings + + +; ------------------------------------------------------------------ +basic_prog: + DB 'CLS',13,10 + DB 'PRINT "Please type your name: ";',13,10 + DB 'INPUT $N',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT "Hello ";',13,10 + DB 'PRINT $N;',13,10 + DB 'PRINT ", welcome to MikeOS Basic (in 64-bit mode)!"',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT "It supports FOR...NEXT loops and simple integer maths..."',13,10 + DB 'PRINT ""',13,10 + DB 'FOR I = 1 TO 15',13,10 + DB 'J = I * I',13,10 + DB 'K = J * I',13,10 + DB 'L = K * I',13,10 + DB 'PRINT I ;',13,10 + DB 'PRINT " ";',13,10 + DB 'PRINT J ;',13,10 + DB 'PRINT " ";',13,10 + DB 'PRINT K ;',13,10 + DB 'PRINT " ";',13,10 + DB 'PRINT L',13,10 + DB 'NEXT I',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT " ...and IF...THEN and GOSUB and lots of other stuff. Bye!"',13,10 + DB 'END',13,10 diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/nibbles.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/nibbles.asm index 4c425a1e..b5b5d462 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/nibbles.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/nibbles.asm @@ -1,116 +1,116 @@ -; The classic game of Nibbles -; Written by Ian Seyler -; -; BareMetal compile: -; nasm argtest.asm -o argtest.app - -; Game field is surrounded by a border. Play area is 38 x 23 - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - call b_hide_statusbar - call b_hide_cursor - call b_screen_clear - - mov rdi, os_screen ; Screen framebuffer - - mov eax, 0x15DB15DB - mov rcx, 41 - rep stosd ; Draw the top wall - - mov rcx, 23 -nextside: ; Draw the side walls - add rdi, 152 - stosd - stosd - sub rcx, 1 - cmp rcx, 0 - jne nextside - - mov rcx, 39 - rep stosd ; Draw the bottom wall - - call b_screen_update ; Copy the screen buffer to video memory - - - -gameloop: - cmp byte [direction], 1 - je move_up - cmp byte [direction], 2 - je move_right - cmp byte [direction], 3 - je move_down - cmp byte [direction], 4 - je move_left - jmp fin ; Fatal error - -move_up: - sub byte [head_x], 1 - jmp drawworm -move_right: - add byte [head_y], 1 - jmp drawworm -move_down: - add byte [head_x], 1 - jmp drawworm -move_left: - sub byte [head_y], 1 - jmp drawworm - -drawworm: - mov rax, 1 - call b_delay - mov ah, byte [head_y] - shl ah, 1 - mov al, byte [head_x] - call b_move_cursor - mov al, 219 - call b_print_char - call b_print_char - call b_input_key_check - cmp al, 'w' - je go_up - cmp al, 'a' - je go_left - cmp al, 's' - je go_down - cmp al, 'd' - je go_right - cmp al, 'q' - je fin - jmp gameloop - -go_up: - mov byte [direction], 1 - jmp gameloop - -go_left: - mov byte [direction], 4 - jmp gameloop - -go_down: - mov byte [direction], 3 - jmp gameloop - -go_right: - mov byte [direction], 2 - jmp gameloop - -fin: - call b_screen_clear - mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner - call b_move_cursor - call b_show_cursor - call b_show_statusbar - ret ; Return to OS - -head_x: db 5 -head_y: db 5 -direction: db 2 ; 1 up, 2 right, 3 down, 4 left - -os_screen: equ 0x0000000000180000 ; This is the address for the text screen frame buffer. It gets copied to video memory via b_update_screen +; The classic game of Nibbles +; Written by Ian Seyler +; +; BareMetal compile: +; nasm argtest.asm -o argtest.app + +; Game field is surrounded by a border. Play area is 38 x 23 + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + call b_hide_statusbar + call b_hide_cursor + call b_screen_clear + + mov rdi, os_screen ; Screen framebuffer + + mov eax, 0x15DB15DB + mov rcx, 41 + rep stosd ; Draw the top wall + + mov rcx, 23 +nextside: ; Draw the side walls + add rdi, 152 + stosd + stosd + sub rcx, 1 + cmp rcx, 0 + jne nextside + + mov rcx, 39 + rep stosd ; Draw the bottom wall + + call b_screen_update ; Copy the screen buffer to video memory + + + +gameloop: + cmp byte [direction], 1 + je move_up + cmp byte [direction], 2 + je move_right + cmp byte [direction], 3 + je move_down + cmp byte [direction], 4 + je move_left + jmp fin ; Fatal error + +move_up: + sub byte [head_x], 1 + jmp drawworm +move_right: + add byte [head_y], 1 + jmp drawworm +move_down: + add byte [head_x], 1 + jmp drawworm +move_left: + sub byte [head_y], 1 + jmp drawworm + +drawworm: + mov rax, 1 + call b_delay + mov ah, byte [head_y] + shl ah, 1 + mov al, byte [head_x] + call b_move_cursor + mov al, 219 + call b_print_char + call b_print_char + call b_input_key_check + cmp al, 'w' + je go_up + cmp al, 'a' + je go_left + cmp al, 's' + je go_down + cmp al, 'd' + je go_right + cmp al, 'q' + je fin + jmp gameloop + +go_up: + mov byte [direction], 1 + jmp gameloop + +go_left: + mov byte [direction], 4 + jmp gameloop + +go_down: + mov byte [direction], 3 + jmp gameloop + +go_right: + mov byte [direction], 2 + jmp gameloop + +fin: + call b_screen_clear + mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner + call b_move_cursor + call b_show_cursor + call b_show_statusbar + ret ; Return to OS + +head_x: db 5 +head_y: db 5 +direction: db 2 ; 1 up, 2 right, 3 down, 4 left + +os_screen: equ 0x0000000000180000 ; This is the address for the text screen frame buffer. It gets copied to video memory via b_update_screen diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/primeasm.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/primeasm.asm index 4c1d5b32..8d4ebec8 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/primeasm.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/primeasm.asm @@ -1,44 +1,44 @@ -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -primestart: ; Start of program label - - call b_get_timecounter - mov [start], rax - -; Calc -; xor ecx, ecx -;loop1: - -;The DIV instruction returns the quotient in AX and the remainder in DX. The modulus is the remainder. - -; mov ecx, 2 - -; div rax, rcx -; test rdx, rdx -; jz meh -; add rcx, 1 -; cmp rcx, blah -; jne loop1 -; add qword [primes], 1 - - -; cmp rcx, [maxn] -; add rcx, 1 -; jle loop1 - - - call b_get_timecounter - mov [finish], rax - -ret ; Return to OS - - -i: dq 0 -j: dq 0 -maxn: dq 400000 -primes: dq 0 -start: dq 0 +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +primestart: ; Start of program label + + call b_get_timecounter + mov [start], rax + +; Calc +; xor ecx, ecx +;loop1: + +;The DIV instruction returns the quotient in AX and the remainder in DX. The modulus is the remainder. + +; mov ecx, 2 + +; div rax, rcx +; test rdx, rdx +; jz meh +; add rcx, 1 +; cmp rcx, blah +; jne loop1 +; add qword [primes], 1 + + +; cmp rcx, [maxn] +; add rcx, 1 +; jle loop1 + + + call b_get_timecounter + mov [finish], rax + +ret ; Return to OS + + +i: dq 0 +j: dq 0 +maxn: dq 400000 +primes: dq 0 +start: dq 0 finish: dq 0 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/smptest.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/smptest.asm index 90b4a4b3..2678dd38 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/smptest.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/smptest.asm @@ -1,64 +1,64 @@ -; SMP Test Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm smptest.asm -o smptest.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - mov rax, ap_print_id ; Our code to run on all CPUs - xor rbx, rbx ; Clear RBX as there is no argument - mov rcx, 64 ; Number of instances to spawn - -spawn: - call b_smp_enqueue - sub rcx, 1 - cmp rcx, 0 - jne spawn - -bsp: - call b_smp_dequeue ; Try to dequeue a workload - jc emptyqueue ; If carry is set then the queue is empty - call b_smp_run ; Otherwise run the workload - jne bsp ; If it is not empty try to do another workload - -emptyqueue: - call b_smp_wait ; Wait for all other processors to finish - call b_print_newline - -ret ; Return to OS - - -; This procedure will be executed by each of the processors -; It requires mutually exclusive access while it creates the string and prints to the screen -; We must insure that only one CPU at a time can execute this code, so we employ a 'spinlock'. -ap_print_id: - mov rcx, 0x1FFFFF -delay: - dec rcx - cmp rcx, 0 - jne delay - -grablock: - bt word [mutex], 0 ; Check if the mutex is free - jnc grablock ; If not check it again - - lock ; The mutex was free, lock the bus - btr word [mutex], 0 ; Try to grab the mutex - jnc grablock ; Jump if we were unsuccessful - - call b_smp_get_id ; Get the local APIC ID - call b_debug_dump_al ; Print the APIC ID - mov al, ' ' - call b_print_char - - bts word [mutex], 0 ; Release the mutex -ret - - mutex dw 1 ; The MUTual-EXclustion flag +; SMP Test Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm smptest.asm -o smptest.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + mov rax, ap_print_id ; Our code to run on all CPUs + xor rbx, rbx ; Clear RBX as there is no argument + mov rcx, 64 ; Number of instances to spawn + +spawn: + call b_smp_enqueue + sub rcx, 1 + cmp rcx, 0 + jne spawn + +bsp: + call b_smp_dequeue ; Try to dequeue a workload + jc emptyqueue ; If carry is set then the queue is empty + call b_smp_run ; Otherwise run the workload + jne bsp ; If it is not empty try to do another workload + +emptyqueue: + call b_smp_wait ; Wait for all other processors to finish + call b_print_newline + +ret ; Return to OS + + +; This procedure will be executed by each of the processors +; It requires mutually exclusive access while it creates the string and prints to the screen +; We must insure that only one CPU at a time can execute this code, so we employ a 'spinlock'. +ap_print_id: + mov rcx, 0x1FFFFF +delay: + dec rcx + cmp rcx, 0 + jne delay + +grablock: + bt word [mutex], 0 ; Check if the mutex is free + jnc grablock ; If not check it again + + lock ; The mutex was free, lock the bus + btr word [mutex], 0 ; Try to grab the mutex + jnc grablock ; Jump if we were unsuccessful + + call b_smp_get_id ; Get the local APIC ID + call b_debug_dump_al ; Print the APIC ID + mov al, ' ' + call b_print_char + + bts word [mutex], 0 ; Release the mutex +ret + + mutex dw 1 ; The MUTual-EXclustion flag diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/sysinfo.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/sysinfo.asm index 9294a412..a7f8c22d 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/sysinfo.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/sysinfo.asm @@ -1,235 +1,235 @@ -; System Information Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm sysinfo.asm -o sysinfo.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - mov rsi, startmessage ; Load RSI with memory address of string - call b_print_string ; Print the string that RSI points to - -;Get processor brand string - xor rax, rax - mov rdi, tstring - mov eax, 0x80000002 - cpuid - stosd - mov eax, ebx - stosd - mov eax, ecx - stosd - mov eax, edx - stosd - mov eax, 0x80000003 - cpuid - stosd - mov eax, ebx - stosd - mov eax, ecx - stosd - mov eax, edx - stosd - mov eax, 0x80000004 - cpuid - stosd - mov eax, ebx - stosd - mov eax, ecx - stosd - mov eax, edx - stosd - xor al, al - stosb ; Terminate the string - mov rsi, tstring - call b_string_parse - mov rsi, cpustringmsg - call b_print_string - mov rsi, tstring - call b_print_string - -; Number of cores - call b_print_newline - mov rsi, numcoresmsg - call b_print_string - xor rax, rax - mov rsi, 0x5012 - lodsw - mov rdi, tstring - call b_int_to_string - mov rsi, tstring - call b_print_string - -; Speed - call b_print_newline - mov rsi, speedmsg - call b_print_string - xor rax, rax - mov rsi, 0x5010 - lodsw - mov rdi, tstring - call b_int_to_string - mov rsi, tstring - call b_print_string - mov rsi, mhzmsg - call b_print_string - -; L1 code/data cache info - call b_print_newline - mov eax, 0x80000005 ; L1 cache info - cpuid - mov eax, edx ; EDX bits 31 - 24 store code L1 cache size in KBs - shr eax, 24 - mov rdi, tstring - call b_int_to_string - mov rsi, l1ccachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - call b_print_newline - mov eax, ecx ; ECX bits 31 - 24 store data L1 cache size in KBs - shr eax, 24 - mov rdi, tstring - call b_int_to_string - mov rsi, l1dcachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - -; L2/L3 cache info - call b_print_newline - mov eax, 0x80000006 ; L2/L3 cache info - cpuid - mov eax, ecx ; ecx bits 31 - 16 store unified L2 cache size in KBs - shr eax, 16 - mov rdi, tstring - call b_int_to_string - mov rsi, l2ucachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - - call b_print_newline - mov eax, edx ; edx bits 31 - 18 store unified L3 cache size in 512 KB chunks - shr eax, 18 - and eax, 0x3FFFF ; Clear bits 18 - 31 - shl eax, 9 ; Convert the value for 512 KB chunks to KBs (Multiply by 512) - mov rdi, tstring - call b_int_to_string - mov rsi, l3ucachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - -;CPU features - call b_print_newline - mov rsi, cpufeatures - call b_print_string - mov rax, 1 - cpuid - -checksse: - test edx, 00000010000000000000000000000000b - jz checksse2 - mov rsi, sse - call b_print_string - -checksse2: - test edx, 00000100000000000000000000000000b - jz checksse3 - mov rsi, sse2 - call b_print_string - -checksse3: - test ecx, 00000000000000000000000000000001b - jz checkssse3 - mov rsi, sse3 - call b_print_string - -checkssse3: - test ecx, 00000000000000000000001000000000b - jz checksse41 - mov rsi, ssse3 - call b_print_string - -checksse41: - test ecx, 00000000000010000000000000000000b - jz checksse42 - mov rsi, sse41 - call b_print_string - -checksse42: - test ecx, 00000000000100000000000000000000b - jz checkaes - mov rsi, sse42 - call b_print_string - -checkaes: - test ecx, 00000010000000000000000000000000b - jz checkavx - mov rsi, aes - call b_print_string - -checkavx: - test ecx, 00010000000000000000000000000000b - jz endit - mov rsi, avx - call b_print_string - -endit: -;RAM - call b_print_newline - mov rsi, memmessage - call b_print_string - xor rax, rax - mov rsi, 0x5020 - lodsw - mov rdi, tstring - call b_int_to_string - mov rsi, tstring - call b_print_string - mov rsi, mbmsg - call b_print_string - - - call b_print_newline - -ret ; Return to OS - -startmessage: db 'System Information:', 13, 0 -cpustringmsg: db 'CPU String: ', 0 -numcoresmsg: db 'Number of cores: ', 0 -speedmsg: db 'Detected speed: ', 0 -l1ccachemsg: db 'L1 code cache: ', 0 -l1dcachemsg: db 'L1 data cache: ', 0 -l2ucachemsg: db 'L2 unified cache: ', 0 -l3ucachemsg: db 'L3 unified cache: ', 0 -cpufeatures: db 'CPU features: ', 0 -kbmsg: db ' KiB', 0 -mbmsg: db ' MiB', 0 -mhzmsg: db ' MHz', 0 -sse: db 'SSE ', 0 -sse2: db 'SSE2 ', 0 -sse3: db 'SSE3 ', 0 -ssse3: db 'SSSE3 ', 0 -sse41: db 'SSE4.1 ', 0 -sse42: db 'SSE4.2 ', 0 -aes: db 'AES ', 0 -avx: db 'AVX ', 0 -memmessage: db 'RAM: ', 0 - +; System Information Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm sysinfo.asm -o sysinfo.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + mov rsi, startmessage ; Load RSI with memory address of string + call b_print_string ; Print the string that RSI points to + +;Get processor brand string + xor rax, rax + mov rdi, tstring + mov eax, 0x80000002 + cpuid + stosd + mov eax, ebx + stosd + mov eax, ecx + stosd + mov eax, edx + stosd + mov eax, 0x80000003 + cpuid + stosd + mov eax, ebx + stosd + mov eax, ecx + stosd + mov eax, edx + stosd + mov eax, 0x80000004 + cpuid + stosd + mov eax, ebx + stosd + mov eax, ecx + stosd + mov eax, edx + stosd + xor al, al + stosb ; Terminate the string + mov rsi, tstring + call b_string_parse + mov rsi, cpustringmsg + call b_print_string + mov rsi, tstring + call b_print_string + +; Number of cores + call b_print_newline + mov rsi, numcoresmsg + call b_print_string + xor rax, rax + mov rsi, 0x5012 + lodsw + mov rdi, tstring + call b_int_to_string + mov rsi, tstring + call b_print_string + +; Speed + call b_print_newline + mov rsi, speedmsg + call b_print_string + xor rax, rax + mov rsi, 0x5010 + lodsw + mov rdi, tstring + call b_int_to_string + mov rsi, tstring + call b_print_string + mov rsi, mhzmsg + call b_print_string + +; L1 code/data cache info + call b_print_newline + mov eax, 0x80000005 ; L1 cache info + cpuid + mov eax, edx ; EDX bits 31 - 24 store code L1 cache size in KBs + shr eax, 24 + mov rdi, tstring + call b_int_to_string + mov rsi, l1ccachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + call b_print_newline + mov eax, ecx ; ECX bits 31 - 24 store data L1 cache size in KBs + shr eax, 24 + mov rdi, tstring + call b_int_to_string + mov rsi, l1dcachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + +; L2/L3 cache info + call b_print_newline + mov eax, 0x80000006 ; L2/L3 cache info + cpuid + mov eax, ecx ; ecx bits 31 - 16 store unified L2 cache size in KBs + shr eax, 16 + mov rdi, tstring + call b_int_to_string + mov rsi, l2ucachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + + call b_print_newline + mov eax, edx ; edx bits 31 - 18 store unified L3 cache size in 512 KB chunks + shr eax, 18 + and eax, 0x3FFFF ; Clear bits 18 - 31 + shl eax, 9 ; Convert the value for 512 KB chunks to KBs (Multiply by 512) + mov rdi, tstring + call b_int_to_string + mov rsi, l3ucachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + +;CPU features + call b_print_newline + mov rsi, cpufeatures + call b_print_string + mov rax, 1 + cpuid + +checksse: + test edx, 00000010000000000000000000000000b + jz checksse2 + mov rsi, sse + call b_print_string + +checksse2: + test edx, 00000100000000000000000000000000b + jz checksse3 + mov rsi, sse2 + call b_print_string + +checksse3: + test ecx, 00000000000000000000000000000001b + jz checkssse3 + mov rsi, sse3 + call b_print_string + +checkssse3: + test ecx, 00000000000000000000001000000000b + jz checksse41 + mov rsi, ssse3 + call b_print_string + +checksse41: + test ecx, 00000000000010000000000000000000b + jz checksse42 + mov rsi, sse41 + call b_print_string + +checksse42: + test ecx, 00000000000100000000000000000000b + jz checkaes + mov rsi, sse42 + call b_print_string + +checkaes: + test ecx, 00000010000000000000000000000000b + jz checkavx + mov rsi, aes + call b_print_string + +checkavx: + test ecx, 00010000000000000000000000000000b + jz endit + mov rsi, avx + call b_print_string + +endit: +;RAM + call b_print_newline + mov rsi, memmessage + call b_print_string + xor rax, rax + mov rsi, 0x5020 + lodsw + mov rdi, tstring + call b_int_to_string + mov rsi, tstring + call b_print_string + mov rsi, mbmsg + call b_print_string + + + call b_print_newline + +ret ; Return to OS + +startmessage: db 'System Information:', 13, 0 +cpustringmsg: db 'CPU String: ', 0 +numcoresmsg: db 'Number of cores: ', 0 +speedmsg: db 'Detected speed: ', 0 +l1ccachemsg: db 'L1 code cache: ', 0 +l1dcachemsg: db 'L1 data cache: ', 0 +l2ucachemsg: db 'L2 unified cache: ', 0 +l3ucachemsg: db 'L3 unified cache: ', 0 +cpufeatures: db 'CPU features: ', 0 +kbmsg: db ' KiB', 0 +mbmsg: db ' MiB', 0 +mhzmsg: db ' MHz', 0 +sse: db 'SSE ', 0 +sse2: db 'SSE2 ', 0 +sse3: db 'SSE3 ', 0 +ssse3: db 'SSSE3 ', 0 +sse41: db 'SSE4.1 ', 0 +sse42: db 'SSE4.2 ', 0 +aes: db 'AES ', 0 +avx: db 'AVX ', 0 +memmessage: db 'RAM: ', 0 + tstring: times 50 db 0 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/test.asm b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/test.asm index 9360e551..7a6637b3 100644 --- a/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/test.asm +++ b/amd64/bareMetalOS-0.5.2/baremetal0.5.2/programs/test.asm @@ -1,63 +1,63 @@ -[bits 64] -[org 0x0000000000200000] -%include "bmdev.asm" - -start: - mov rsi, corecnt - call b_print_string - call b_smp_numcores - mov rdi, buffer - call b_int_to_string - mov rsi, buffer - call b_print_string - call b_print_newline - call task - mov rbx, 14 - -cycle: - push rbx - mov rax, task - call b_smp_enqueue - pop rbx - dec rbx - or rbx, rbx - jnz cycle - - call b_smp_wait - call b_print_newline - mov rsi, finmsg - call b_print_string - ret - -task: - call b_print_newline - mov rsi, corenum - call b_print_string - - call b_smp_get_id - mov rdi, buffer - call b_int_to_string - mov rsi, buffer - call b_print_string - - mov rsi, separator - call b_print_string - - inc qword [number] - mov rax, [number] - mov rdi, buffer - call b_int_to_string - mov rsi, buffer - call b_print_string - - mov rcx, 24 - call b_delay - - ret - -corecnt db "Total Available Cores:",0 -corenum db "Core:",0 -finmsg db "Finished.", 0 -separator db " ",0 -number db 0,0,0,0,0,0,0,0 +[bits 64] +[org 0x0000000000200000] +%include "bmdev.asm" + +start: + mov rsi, corecnt + call b_print_string + call b_smp_numcores + mov rdi, buffer + call b_int_to_string + mov rsi, buffer + call b_print_string + call b_print_newline + call task + mov rbx, 14 + +cycle: + push rbx + mov rax, task + call b_smp_enqueue + pop rbx + dec rbx + or rbx, rbx + jnz cycle + + call b_smp_wait + call b_print_newline + mov rsi, finmsg + call b_print_string + ret + +task: + call b_print_newline + mov rsi, corenum + call b_print_string + + call b_smp_get_id + mov rdi, buffer + call b_int_to_string + mov rsi, buffer + call b_print_string + + mov rsi, separator + call b_print_string + + inc qword [number] + mov rax, [number] + mov rdi, buffer + call b_int_to_string + mov rsi, buffer + call b_print_string + + mov rcx, 24 + call b_delay + + ret + +corecnt db "Total Available Cores:",0 +corenum db "Core:",0 +finmsg db "Finished.", 0 +separator db " ",0 +number db 0,0,0,0,0,0,0,0 buffer resb 64 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/README.TXT b/amd64/bareMetalOS-0.5.2/pure64.boot0/README.TXT index 39f3b194..78f549f6 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/README.TXT +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/README.TXT @@ -1,18 +1,18 @@ -=============================================================================== -Pure64 v0.4.9 Distribution -Copyright (C) 2007-2011 www.returninfinity.com -=============================================================================== - -Pure64 is a second stage bootloader for 64-bit PC's with compatible Intel or -AMD processors. The loader gets the computer into a full 64-bit state with no -legacy compatibility layers. Pure64 also enables and configures all available -Cores/CPUs in the computer. An information table is stored in memory after -Pure64 is finished that stores important details about the computer. - -This distribution contains the Pure64 second stage boot loader. It also -contains some example software that Pure64 can load as well as the FAT16 -bootsector that loads Pure64. - -For documentation please see www.returninfinity.com/pure64.html - -=============================================================================== +=============================================================================== +Pure64 v0.4.9 Distribution +Copyright (C) 2007-2011 www.returninfinity.com +=============================================================================== + +Pure64 is a second stage bootloader for 64-bit PC's with compatible Intel or +AMD processors. The loader gets the computer into a full 64-bit state with no +legacy compatibility layers. Pure64 also enables and configures all available +Cores/CPUs in the computer. An information table is stored in memory after +Pure64 is finished that stores important details about the computer. + +This distribution contains the Pure64 second stage boot loader. It also +contains some example software that Pure64 can load as well as the FAT16 +bootsector that loads Pure64. + +For documentation please see www.returninfinity.com/pure64.html + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/boot16b.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/boot16b.asm index b2a8c1e2..47ec2ce9 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/boot16b.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/boot16b.asm @@ -1,251 +1,251 @@ -USE16 -org 0x7C00 - -entry: - jmp short begin - nop - -%define bsOemName bp+0x03 ; OEM label (8) -%define bsBytesPerSec bp+0x0B ; bytes/sector (dw) -%define bsSecsPerClust bp+0x0D ; sectors/allocation unit (db) -%define bsResSectors bp+0x0E ; # reserved sectors (dw) -%define bsFATs bp+0x10 ; # of fats (db) -%define bsRootDirEnts bp+0x11 ; Max # of root dir entries (dw) -%define bsSectors bp+0x13 ; # sectors total in image (dw) -%define bsMedia bp+0x15 ; media descriptor (db) -%define bsSecsPerFat bp+0x16 ; # sectors in a fat (dw) -%define bsSecsPerTrack bp+0x18 ; # sectors/track -%define bsHeads bp+0x1A ; # heads (dw) -%define bsHidden bp+0x1C ; # hidden sectors (dd) -%define bsSectorHuge bp+0x20 ; # sectors if > 65536 (dd) -%define bsDriveNumber bp+0x24 ; (dw) -%define bsSigniture bp+0x26 ; (db) -%define bsVolumeSerial bp+0x27 ; (dd) -%define bsVolumeLabel bp+0x2B ; (11) -%define bsSysID bp+0x36 ; (8) - -times 0x3B db 0 ; Code starts at offset 0x3E - -begin: - mov [bsDriveNumber], dl ; BIOS passes drive number in DL - xor eax, eax - xor esi, esi - xor edi, edi - mov ds, ax - mov es, ax - mov bp, 0x7c00 - -; Make sure the screen is set to 80x25 color text mode - mov ax, 0x0003 ; Set to normal (80x25 text) video mode - int 0x10 - -; Print message - mov si, msg_Load - call print_string_16 - -; read in the root cluster -; check for the filename -; if found save the starting cluster -; if not then error - -;fatstart = bsResSectors - -;rootcluster = bsResSectors + (bsFATs * bsSecsPerFat) -; 4 + (2 * 254) = sector 512 - -;datastart = bsResSectors + (bsFATs * bsSecsPerFat) + ((bsRootDirEnts * 32) / bsBytesPerSec) -; 4 + (2 * 254) + ((512 * 32) / 512) = sector 544 - -;cluster X starting sector -; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart - -; 0x7C5C as of Jan 6, 2010 -getoffset: - xor eax, eax - mov bx, 0x8000 - call readsector ; Read the MBR to 0x8000 - mov eax, [0x81C6] ; Grab the dword at 0x01C6 (num of sectors between MBR and first sector in partition) - mov [secoffset], eax ; Save it for later use - xor eax, eax - -ff: - mov ax, [bsSecsPerFat] - shl ax, 1 ; quick multiply by two - add ax, [bsResSectors] - mov [rootstart], ax - - mov bx, [bsRootDirEnts] - shr bx, 4 ; bx = (bx * 32) / 512 - add bx, ax ; BX now holds the datastart sector number - mov [datastart], bx - -ff_next_sector: - mov bx, 0x8000 - mov si, bx - mov di, bx - add eax, [secoffset] - call readsector - -; Search for file name, and find start cluster. -ff_next_entry: - mov cx, 11 - mov si, filename - repe cmpsb - jz ff_done ; note that di now is at dirent+11 - - add di, byte 0x20 - and di, byte -0x20 - cmp di, [bsBytesPerSec] - jnz ff_next_entry - ; load next sector - dec dx ; next sector in cluster - jnz ff_next_sector - -ff_done: - add di, 15 - mov ax, [di] ; AX now holds the starting cluster # - -; At this point we have found the file we want and know the cluster where the file starts - - mov bx, 0x8000 ; We want to load to 0x0000:0x8000 -loadfile: - call readcluster - cmp ax, 0xFFF8 ; Have we reached the end cluster marker? - jg loadfile ; If not then load another - - jmp 0x0000:0x8000 - - - -;------------------------------------------------------------------------------ -; Read a sector from a disk, using LBA -; input: EAX - 32-bit DOS sector number -; ES:BX - destination buffer -; output: ES:BX points one byte after the last byte read -; EAX - next sector -readsector: - push dx - push si - push di - -read_it: - push eax ; Save the sector number - mov di, sp ; remember parameter block end - - push byte 0 ; other half of the 32 bits at [C] - push byte 0 ; [C] sector number high 32bit - push eax ; [8] sector number low 32bit - push es ; [6] buffer segment - push bx ; [4] buffer offset - push byte 1 ; [2] 1 sector (word) - push byte 16 ; [0] size of parameter block (word) - - mov si, sp - mov dl, [bsDriveNumber] - mov ah, 42h ; EXTENDED READ - int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 - - mov sp, di ; remove parameter block from stack - pop eax ; Restore the sector number - - jnc read_ok ; jump if no error - - push ax - xor ah, ah ; else, reset and retry - int 0x13 - pop ax - jmp read_it - -read_ok: - inc eax ; next sector - add bx, 512 ; Add bytes per sector - jnc no_incr_es ; if overflow... - -incr_es: - mov dx, es - add dh, 0x10 ; ...add 1000h to ES - mov es, dx - -no_incr_es: - pop di - pop si - pop dx - ret -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; Read a cluster from a disk partition, using LBA -; input: AX - 16-bit cluster number -; ES:BX - destination buffer -; output: ES:BX points one byte after the last byte read -; AX - next cluster -readcluster: - push cx - mov [tcluster], ax ; save our cluster value -;cluster X starting sector -; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart - xor cx, cx - sub ax, 2 - mov cl, byte [bsSecsPerClust] - imul cx ; EAX now holds starting sector - add ax, word [datastart] ; add the datastart offset - - xor cx, cx - mov cl, byte [bsSecsPerClust] - add eax, [secoffset] -readcluster_nextsector: - call readsector - dec cx - cmp cx, 0 - jne readcluster_nextsector - -; Great! We read a cluster.. now find out where the next cluster is - push bx ; save our memory pointer - mov bx, 0x7E00 ; load a sector from the root cluster here - push bx - mov ax, [bsResSectors] - add eax, [secoffset] - call readsector - pop bx ; bx points to 0x7e00 again - mov ax, [tcluster] ; ax holds the cluster # we just read - shl ax, 1 ; multipy by 2 - add bx, ax - mov ax, [bx] - - pop bx ; restore our memory pointer - pop cx - - ret -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; 16-bit Function to print a sting to the screen -; input: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -.repeat: - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - - -msg_Load db "Loading... ", 0 -msg_Error db "No " -filename db "PURE64 SYS", 0 -datastart dw 0x0000 -rootstart dw 0x0000 -tcluster dw 0x0000 -secoffset dd 0x00000000 - -times 510-$+$$ db 0 - -sign dw 0xAA55 +USE16 +org 0x7C00 + +entry: + jmp short begin + nop + +%define bsOemName bp+0x03 ; OEM label (8) +%define bsBytesPerSec bp+0x0B ; bytes/sector (dw) +%define bsSecsPerClust bp+0x0D ; sectors/allocation unit (db) +%define bsResSectors bp+0x0E ; # reserved sectors (dw) +%define bsFATs bp+0x10 ; # of fats (db) +%define bsRootDirEnts bp+0x11 ; Max # of root dir entries (dw) +%define bsSectors bp+0x13 ; # sectors total in image (dw) +%define bsMedia bp+0x15 ; media descriptor (db) +%define bsSecsPerFat bp+0x16 ; # sectors in a fat (dw) +%define bsSecsPerTrack bp+0x18 ; # sectors/track +%define bsHeads bp+0x1A ; # heads (dw) +%define bsHidden bp+0x1C ; # hidden sectors (dd) +%define bsSectorHuge bp+0x20 ; # sectors if > 65536 (dd) +%define bsDriveNumber bp+0x24 ; (dw) +%define bsSigniture bp+0x26 ; (db) +%define bsVolumeSerial bp+0x27 ; (dd) +%define bsVolumeLabel bp+0x2B ; (11) +%define bsSysID bp+0x36 ; (8) + +times 0x3B db 0 ; Code starts at offset 0x3E + +begin: + mov [bsDriveNumber], dl ; BIOS passes drive number in DL + xor eax, eax + xor esi, esi + xor edi, edi + mov ds, ax + mov es, ax + mov bp, 0x7c00 + +; Make sure the screen is set to 80x25 color text mode + mov ax, 0x0003 ; Set to normal (80x25 text) video mode + int 0x10 + +; Print message + mov si, msg_Load + call print_string_16 + +; read in the root cluster +; check for the filename +; if found save the starting cluster +; if not then error + +;fatstart = bsResSectors + +;rootcluster = bsResSectors + (bsFATs * bsSecsPerFat) +; 4 + (2 * 254) = sector 512 + +;datastart = bsResSectors + (bsFATs * bsSecsPerFat) + ((bsRootDirEnts * 32) / bsBytesPerSec) +; 4 + (2 * 254) + ((512 * 32) / 512) = sector 544 + +;cluster X starting sector +; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart + +; 0x7C5C as of Jan 6, 2010 +getoffset: + xor eax, eax + mov bx, 0x8000 + call readsector ; Read the MBR to 0x8000 + mov eax, [0x81C6] ; Grab the dword at 0x01C6 (num of sectors between MBR and first sector in partition) + mov [secoffset], eax ; Save it for later use + xor eax, eax + +ff: + mov ax, [bsSecsPerFat] + shl ax, 1 ; quick multiply by two + add ax, [bsResSectors] + mov [rootstart], ax + + mov bx, [bsRootDirEnts] + shr bx, 4 ; bx = (bx * 32) / 512 + add bx, ax ; BX now holds the datastart sector number + mov [datastart], bx + +ff_next_sector: + mov bx, 0x8000 + mov si, bx + mov di, bx + add eax, [secoffset] + call readsector + +; Search for file name, and find start cluster. +ff_next_entry: + mov cx, 11 + mov si, filename + repe cmpsb + jz ff_done ; note that di now is at dirent+11 + + add di, byte 0x20 + and di, byte -0x20 + cmp di, [bsBytesPerSec] + jnz ff_next_entry + ; load next sector + dec dx ; next sector in cluster + jnz ff_next_sector + +ff_done: + add di, 15 + mov ax, [di] ; AX now holds the starting cluster # + +; At this point we have found the file we want and know the cluster where the file starts + + mov bx, 0x8000 ; We want to load to 0x0000:0x8000 +loadfile: + call readcluster + cmp ax, 0xFFF8 ; Have we reached the end cluster marker? + jg loadfile ; If not then load another + + jmp 0x0000:0x8000 + + + +;------------------------------------------------------------------------------ +; Read a sector from a disk, using LBA +; input: EAX - 32-bit DOS sector number +; ES:BX - destination buffer +; output: ES:BX points one byte after the last byte read +; EAX - next sector +readsector: + push dx + push si + push di + +read_it: + push eax ; Save the sector number + mov di, sp ; remember parameter block end + + push byte 0 ; other half of the 32 bits at [C] + push byte 0 ; [C] sector number high 32bit + push eax ; [8] sector number low 32bit + push es ; [6] buffer segment + push bx ; [4] buffer offset + push byte 1 ; [2] 1 sector (word) + push byte 16 ; [0] size of parameter block (word) + + mov si, sp + mov dl, [bsDriveNumber] + mov ah, 42h ; EXTENDED READ + int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 + + mov sp, di ; remove parameter block from stack + pop eax ; Restore the sector number + + jnc read_ok ; jump if no error + + push ax + xor ah, ah ; else, reset and retry + int 0x13 + pop ax + jmp read_it + +read_ok: + inc eax ; next sector + add bx, 512 ; Add bytes per sector + jnc no_incr_es ; if overflow... + +incr_es: + mov dx, es + add dh, 0x10 ; ...add 1000h to ES + mov es, dx + +no_incr_es: + pop di + pop si + pop dx + ret +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; Read a cluster from a disk partition, using LBA +; input: AX - 16-bit cluster number +; ES:BX - destination buffer +; output: ES:BX points one byte after the last byte read +; AX - next cluster +readcluster: + push cx + mov [tcluster], ax ; save our cluster value +;cluster X starting sector +; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart + xor cx, cx + sub ax, 2 + mov cl, byte [bsSecsPerClust] + imul cx ; EAX now holds starting sector + add ax, word [datastart] ; add the datastart offset + + xor cx, cx + mov cl, byte [bsSecsPerClust] + add eax, [secoffset] +readcluster_nextsector: + call readsector + dec cx + cmp cx, 0 + jne readcluster_nextsector + +; Great! We read a cluster.. now find out where the next cluster is + push bx ; save our memory pointer + mov bx, 0x7E00 ; load a sector from the root cluster here + push bx + mov ax, [bsResSectors] + add eax, [secoffset] + call readsector + pop bx ; bx points to 0x7e00 again + mov ax, [tcluster] ; ax holds the cluster # we just read + shl ax, 1 ; multipy by 2 + add bx, ax + mov ax, [bx] + + pop bx ; restore our memory pointer + pop cx + + ret +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; 16-bit Function to print a sting to the screen +; input: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +.repeat: + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + + +msg_Load db "Loading... ", 0 +msg_Error db "No " +filename db "PURE64 SYS", 0 +datastart dw 0x0000 +rootstart dw 0x0000 +tcluster dw 0x0000 +secoffset dd 0x00000000 + +times 510-$+$$ db 0 + +sign dw 0xAA55 diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/fat16mbr.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/fat16mbr.asm index 17a80979..ecc99084 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/fat16mbr.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/fat16mbr.asm @@ -1,131 +1,131 @@ -USE16 -org 0x7C00 - -entry: - cli - mov [DriveNumber], dl ; BIOS passes drive number in DL - xor ax, ax - mov ss, ax - mov sp, 0x7C00 - mov si, sp - push ax - pop es - push ax - pop ds - sti - -; Copy MBR sector to 0x0600 and jump there - cld - mov di, 0x0600 - mov cx, 0x0100 - repne movsw - jmp 0x0000:0x0621 -; 0x0621 - -; Print message - mov si, msg_Load - call print_string_16 - - mov si, 0x07BE - cmp byte [si], 0x80 - jne NoActivePartition - - mov ecx, [0x07C6] - mov bx, 0x7C00 - xor esi, esi - xor edi, edi - mov si, bx - mov di, bx - add eax, ecx - call readsector - jmp 0x0000:0x7C00 - -NoActivePartition: - mov si, msg_NoPartition - call print_string_16 - jmp $ - - -;------------------------------------------------------------------------------ -; Read a sector from a disk, using LBA -; input: EAX - 32-bit DOS sector number -; ES:BX - destination buffer -; output: ES:BX points one byte after the last byte read -; EAX - next sector -readsector: - push dx - push si - push di - -read_it: - push eax ; Save the sector number - mov di, sp ; remember parameter block end - - push byte 0 ; other half of the 32 bits at [C] - push byte 0 ; [C] sector number high 32bit - push eax ; [8] sector number low 32bit - push es ; [6] buffer segment - push bx ; [4] buffer offset - push byte 1 ; [2] 1 sector (word) - push byte 16 ; [0] size of parameter block (word) - - mov si, sp - mov dl, [DriveNumber] - mov ah, 42h ; EXTENDED READ - int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 - - mov sp, di ; remove parameter block from stack - pop eax ; Restore the sector number - - jnc read_ok ; jump if no error - - push ax - xor ah, ah ; else, reset and retry - int 0x13 - pop ax - jmp read_it - -read_ok: - inc eax ; next sector - add bx, 512 ; Add bytes per sector - jnc no_incr_es ; if overflow... - -incr_es: - mov dx, es - add dh, 0x10 ; ...add 1000h to ES - mov es, dx - -no_incr_es: - pop di - pop si - pop dx - ret -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; 16-bit Function to print a sting to the screen -; input: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -.repeat: - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - -msg_Load db "Loading... ", 0 -msg_NoPartition db "No active partition found" -DriveNumber db 0x00 - -times 446-$+$$ db 0 - -tables db "XXXXXXXXXXXXXXXX DO NOT OVERWRITE THIS AREA!!! XXXXXXXXXXXXXXXX" ; 64 bytes in length - -sign dw 0xAA55 +USE16 +org 0x7C00 + +entry: + cli + mov [DriveNumber], dl ; BIOS passes drive number in DL + xor ax, ax + mov ss, ax + mov sp, 0x7C00 + mov si, sp + push ax + pop es + push ax + pop ds + sti + +; Copy MBR sector to 0x0600 and jump there + cld + mov di, 0x0600 + mov cx, 0x0100 + repne movsw + jmp 0x0000:0x0621 +; 0x0621 + +; Print message + mov si, msg_Load + call print_string_16 + + mov si, 0x07BE + cmp byte [si], 0x80 + jne NoActivePartition + + mov ecx, [0x07C6] + mov bx, 0x7C00 + xor esi, esi + xor edi, edi + mov si, bx + mov di, bx + add eax, ecx + call readsector + jmp 0x0000:0x7C00 + +NoActivePartition: + mov si, msg_NoPartition + call print_string_16 + jmp $ + + +;------------------------------------------------------------------------------ +; Read a sector from a disk, using LBA +; input: EAX - 32-bit DOS sector number +; ES:BX - destination buffer +; output: ES:BX points one byte after the last byte read +; EAX - next sector +readsector: + push dx + push si + push di + +read_it: + push eax ; Save the sector number + mov di, sp ; remember parameter block end + + push byte 0 ; other half of the 32 bits at [C] + push byte 0 ; [C] sector number high 32bit + push eax ; [8] sector number low 32bit + push es ; [6] buffer segment + push bx ; [4] buffer offset + push byte 1 ; [2] 1 sector (word) + push byte 16 ; [0] size of parameter block (word) + + mov si, sp + mov dl, [DriveNumber] + mov ah, 42h ; EXTENDED READ + int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 + + mov sp, di ; remove parameter block from stack + pop eax ; Restore the sector number + + jnc read_ok ; jump if no error + + push ax + xor ah, ah ; else, reset and retry + int 0x13 + pop ax + jmp read_it + +read_ok: + inc eax ; next sector + add bx, 512 ; Add bytes per sector + jnc no_incr_es ; if overflow... + +incr_es: + mov dx, es + add dh, 0x10 ; ...add 1000h to ES + mov es, dx + +no_incr_es: + pop di + pop si + pop dx + ret +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; 16-bit Function to print a sting to the screen +; input: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +.repeat: + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + +msg_Load db "Loading... ", 0 +msg_NoPartition db "No active partition found" +DriveNumber db 0x00 + +times 446-$+$$ db 0 + +tables db "XXXXXXXXXXXXXXXX DO NOT OVERWRITE THIS AREA!!! XXXXXXXXXXXXXXXX" ; 64 bytes in length + +sign dw 0xAA55 diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/pxestart.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/pxestart.asm index 0aa36306..eef160a4 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/pxestart.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/bootsector/pxestart.asm @@ -1,67 +1,67 @@ -; ============================================================================= -; Pure64 PXE Start -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; This is a stub file for chainloading Pure64 and a Kernel via PXE. -; -; You will need to uncomment the Chainloading lines in pure64.asm -; -; Windows - copy /b pxestart.bin + pure64.sys + kernel64.sys pxeboot.bin -; Unix - cat pxestart.bin pure64.sys kernel64.sys > pxeboot.bin -; -; Max size of the resulting pxeboot.bin is 32768 bytes. PXE loads the file to -; address 0x00007C00 (Just like a boot sector). -; -; File Sizes -; pxestart.bin 1024 bytes -; pure64.sys 6144 bytes -; kernel64.sys 16384 bytes (or so) -; ============================================================================= - - -USE16 -org 0x7C00 - -start: - xor eax, eax - xor esi, esi - xor edi, edi - mov ds, ax - mov es, ax - mov bp, 0x7c00 - -; Make sure the screen is set to 80x25 color text mode - mov ax, 0x0003 ; Set to normal (80x25 text) video mode - int 0x10 - -; Print message - mov si, msg_Load - call print_string_16 - - jmp 0x0000:0x8000 - -;------------------------------------------------------------------------------ -; 16-bit Function to print a sting to the screen -; input: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -.repeat: - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - - -msg_Load db "Loading via PXE... ", 0 - -times 510-$+$$ db 0 ; Pad out for a normal boot sector - -sign dw 0xAA55 - +; ============================================================================= +; Pure64 PXE Start -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; This is a stub file for chainloading Pure64 and a Kernel via PXE. +; +; You will need to uncomment the Chainloading lines in pure64.asm +; +; Windows - copy /b pxestart.bin + pure64.sys + kernel64.sys pxeboot.bin +; Unix - cat pxestart.bin pure64.sys kernel64.sys > pxeboot.bin +; +; Max size of the resulting pxeboot.bin is 32768 bytes. PXE loads the file to +; address 0x00007C00 (Just like a boot sector). +; +; File Sizes +; pxestart.bin 1024 bytes +; pure64.sys 6144 bytes +; kernel64.sys 16384 bytes (or so) +; ============================================================================= + + +USE16 +org 0x7C00 + +start: + xor eax, eax + xor esi, esi + xor edi, edi + mov ds, ax + mov es, ax + mov bp, 0x7c00 + +; Make sure the screen is set to 80x25 color text mode + mov ax, 0x0003 ; Set to normal (80x25 text) video mode + int 0x10 + +; Print message + mov si, msg_Load + call print_string_16 + + jmp 0x0000:0x8000 + +;------------------------------------------------------------------------------ +; 16-bit Function to print a sting to the screen +; input: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +.repeat: + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + + +msg_Load db "Loading via PXE... ", 0 + +times 510-$+$$ db 0 ; Pad out for a normal boot sector + +sign dw 0xAA55 + times 1024-$+$$ db 0 ; Padding so that Pure64 will be aligned at 0x8000 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/CREDITS.TXT b/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/CREDITS.TXT index d38d057c..b3966976 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/CREDITS.TXT +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/CREDITS.TXT @@ -1,17 +1,17 @@ -=============================================================================== -Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -=============================================================================== - - -PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) - - * Ian Seyler -- ian.seyler@returninfinity.com - - -DEVELOPMENT AND TESTING - - * Members of OSDev.org - - -=============================================================================== +=============================================================================== +Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +=============================================================================== + + +PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) + + * Ian Seyler -- ian.seyler@returninfinity.com + + +DEVELOPMENT AND TESTING + + * Members of OSDev.org + + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/LICENSE.TXT b/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/LICENSE.TXT index 3d745531..b21a64af 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/LICENSE.TXT +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/docs/LICENSE.TXT @@ -1,35 +1,35 @@ -=============================================================================== -Pure64 -- License -=============================================================================== - -Copyright (C) 2008-2011 Return Infinity -- http://www.returninfinity.com - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name Pure64 nor the names of any Pure64 contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -=============================================================================== +=============================================================================== +Pure64 -- License +=============================================================================== + +Copyright (C) 2008-2011 Return Infinity -- http://www.returninfinity.com + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name Pure64 nor the names of any Pure64 contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/kernel_asm/kernel64.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/kernel_asm/kernel64.asm index 29b3f8c5..95693e05 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/kernel_asm/kernel64.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/kernel_asm/kernel64.asm @@ -1,20 +1,20 @@ -; ============================================================================= -; 64-bit Assembly example for Pure64 -; Written by Ian Seyler (www.returninfinity.com) -; -; Assemble with NASM or YASM -; ============================================================================= - - -USE64 -[ORG 0x0000000000100000] - -start: - -; put your code here - -end: -jmp end - -; ============================================================================= -; EOF +; ============================================================================= +; 64-bit Assembly example for Pure64 +; Written by Ian Seyler (www.returninfinity.com) +; +; Assemble with NASM or YASM +; ============================================================================= + + +USE64 +[ORG 0x0000000000100000] + +start: + +; put your code here + +end: +jmp end + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/fat16.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/fat16.asm index 449ca820..fda9b6bc 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/fat16.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/fat16.asm @@ -1,144 +1,144 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; FAT16 functions -; ============================================================================= - - -; ----------------------------------------------------------------------------- -; readcluster -- Read a cluster from the FAT16 partition -; IN: AX - (cluster) -; RDI - (memory location to store at least 32KB) -; OUT: AX - (next cluster) -; RDI - points one byte after the last byte read -readcluster: - push rsi - push rdx - push rcx - push rbx - - and rax, 0x000000000000FFFF ; Clear the top 48 bits - mov rbx, rax ; Save the cluster number to be used later - - cmp ax, 2 ; If less than 2 then bail out... - jl near readcluster_bailout ; as clusters start at 2 - -; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start - xor rcx, rcx - mov cl, byte [fat16_SectorsPerCluster] - push rcx ; Save the number of sectors per cluster - sub ax, 2 - imul cx ; EAX now holds starting sector - add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - - pop rcx ; Restore the number of sectors per cluster - call readsectors ; Read one cluster of sectors - -; Calculate the next cluster -; Psuedo-code -; tint1 = Cluster / 256 <- Dump the remainder -; sector_to_read = tint1 + ReservedSectors -; tint2 = (Cluster - (tint1 * 256)) * 2 - push rdi - mov rdi, hdbuffer1 ; Read to this temporary buffer - mov rsi, rdi ; Copy buffer address to RSI - push rbx ; Save the original cluster value - shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - add rax, rbx ; Add the sector offset - mov rcx, 1 - call readsectors - pop rax ; Get our original cluster value back - shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) - sub rax, rbx ; RAX is now pointed to the offset within the sector - shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) - add rsi, rax - lodsw ; AX now holds the next cluster - pop rdi - - jmp readcluster_end - -readcluster_bailout: - xor ax, ax - -readcluster_end: - pop rbx - pop rcx - pop rdx - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; findfile -- -; IN: RSI(Pointer to file name, must be in 'FILENAMEEXT" format) -; OUT: AX(Staring cluster), 0x0 if not found -; Notes: Only searches the root sector.. not the following sectors. -findfile: - push rsi - push rdi - push rdx - push rcx - push rbx - - clc ; Clear carry - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - -os_fat16_find_file_read_sector: - mov rdi, hdbuffer1 - push rdi - mov rcx, 1 - call readsectors - pop rdi - mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 - -os_fat16_find_file_next_entry: - cmp byte [rdi], 0x00 ; end of records - je os_fat16_find_file_notfound - - mov rcx, 11 - push rsi - repe cmpsb - pop rsi - mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at - jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 - - add rdi, byte 0x20 - and rdi, byte -0x20 - dec rbx - cmp rbx, 0 - jne os_fat16_find_file_next_entry - -; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. - - add rdx, 1 - mov rax, rdx - jmp os_fat16_find_file_read_sector - -os_fat16_find_file_notfound: - stc ; Set carry - xor rax, rax - -os_fat16_find_file_done: - cmp ax, 0x0000 ; BUG HERE - jne wut ; Carry is not being set properly in this function - stc -wut: - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; FAT16 functions +; ============================================================================= + + +; ----------------------------------------------------------------------------- +; readcluster -- Read a cluster from the FAT16 partition +; IN: AX - (cluster) +; RDI - (memory location to store at least 32KB) +; OUT: AX - (next cluster) +; RDI - points one byte after the last byte read +readcluster: + push rsi + push rdx + push rcx + push rbx + + and rax, 0x000000000000FFFF ; Clear the top 48 bits + mov rbx, rax ; Save the cluster number to be used later + + cmp ax, 2 ; If less than 2 then bail out... + jl near readcluster_bailout ; as clusters start at 2 + +; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start + xor rcx, rcx + mov cl, byte [fat16_SectorsPerCluster] + push rcx ; Save the number of sectors per cluster + sub ax, 2 + imul cx ; EAX now holds starting sector + add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + + pop rcx ; Restore the number of sectors per cluster + call readsectors ; Read one cluster of sectors + +; Calculate the next cluster +; Psuedo-code +; tint1 = Cluster / 256 <- Dump the remainder +; sector_to_read = tint1 + ReservedSectors +; tint2 = (Cluster - (tint1 * 256)) * 2 + push rdi + mov rdi, hdbuffer1 ; Read to this temporary buffer + mov rsi, rdi ; Copy buffer address to RSI + push rbx ; Save the original cluster value + shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + add rax, rbx ; Add the sector offset + mov rcx, 1 + call readsectors + pop rax ; Get our original cluster value back + shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) + sub rax, rbx ; RAX is now pointed to the offset within the sector + shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) + add rsi, rax + lodsw ; AX now holds the next cluster + pop rdi + + jmp readcluster_end + +readcluster_bailout: + xor ax, ax + +readcluster_end: + pop rbx + pop rcx + pop rdx + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; findfile -- +; IN: RSI(Pointer to file name, must be in 'FILENAMEEXT" format) +; OUT: AX(Staring cluster), 0x0 if not found +; Notes: Only searches the root sector.. not the following sectors. +findfile: + push rsi + push rdi + push rdx + push rcx + push rbx + + clc ; Clear carry + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + +os_fat16_find_file_read_sector: + mov rdi, hdbuffer1 + push rdi + mov rcx, 1 + call readsectors + pop rdi + mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 + +os_fat16_find_file_next_entry: + cmp byte [rdi], 0x00 ; end of records + je os_fat16_find_file_notfound + + mov rcx, 11 + push rsi + repe cmpsb + pop rsi + mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at + jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 + + add rdi, byte 0x20 + and rdi, byte -0x20 + dec rbx + cmp rbx, 0 + jne os_fat16_find_file_next_entry + +; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. + + add rdx, 1 + mov rax, rdx + jmp os_fat16_find_file_read_sector + +os_fat16_find_file_notfound: + stc ; Set carry + xor rax, rax + +os_fat16_find_file_done: + cmp ax, 0x0000 ; BUG HERE + jne wut ; Carry is not being set properly in this function + stc +wut: + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_cpu.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_cpu.asm index eb6043e0..c4c1b389 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_cpu.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_cpu.asm @@ -1,144 +1,144 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT CPU -; ============================================================================= - - -init_cpu: - -; Check for Prefetcher and L2 Cache support - mov r15b, 1 ; Set MSR support to 1 - xor eax, eax - mov al, 1 ; Access CPUID leaf 1 - cpuid - shr rax, 8 ; Family now in AL (lowest 4 bits) - and al, 0x0F ; Clear the high 4 bits - cmp al, 0x0F - jne init_cpu_msrok ; If Family is not 0xF then jump - mov r15b, 0 ; If it is 0xF (Older P4/Xeon) then set MSR support to 0 -init_cpu_msrok: - -; Disable Cache - mov rax, cr0 - btr rax, 29 ; Clear No Write Thru (Bit 29) - bts rax, 30 ; Set Cache Disable (Bit 30) - mov cr0, rax - -; Flush Cache - wbinvd - -; Diable Paging Global Extensions - mov rax, cr4 - btr rax, 7 ; Clear Paging Global Extensions (Bit 7) - mov cr4, rax - mov rax, cr3 - mov cr3, rax - -; Skip next portion if MSR support doesn't exist -; cmp r15b, 0 -; je init_cpu_skip1 - -; Disable Prefetchers (Not supported on P4 or Atom) -; mov ecx, 0x000001A0 -; rdmsr -; or eax, 0x00080200 ; Set Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) -; or edx, 0x000000A0 ; Set DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) -; wrmsr - -; Disable L2 Cache (Not supported on P4 or Atom) -; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache -; rdmsr -; btr eax, 8 ; Clear L2 Enabled (Bit 8) -; wrmsr - -;init_cpu_skip1: - -; Disable MTRRs and Configure default memory type to UC - mov ecx, 0x000002FF - rdmsr - and eax, 0xFFFFF300 ; Clear MTRR Enable (Bit 11), Fixed Range MTRR Enable (Bit 10), and Default Memory Type (Bits 7:0) to UC (0x00) - wrmsr - -; Setup variable-size address ranges -; Cache 0-64 MiB as type 6 (WB) cache -; See example in Intel Volume 3A. Example Base and Mask Calculations -; mov ecx, 0x00000200 ; MTRR_Phys_Base_MSR(0) -; mov edx, 0x00000000 ; Base is EDX:EAX, 0x0000000000000006 -; mov eax, 0x00000006 ; Type 6 (write-back cache) -; wrmsr -; mov ecx, 0x00000201 ; MTRR_Phys_Mask_MSR(0) -;; mov edx, 0x00000000 ; Mask is EDX:EAX, 0x0000000001000800 (Because bochs sucks) -;; mov eax, 0x01000800 ; Bit 11 set for Valid -; mov edx, 0x0000000F ; Mask is EDX:EAX, 0x0000000F80000800 (2 GiB) -; mov eax, 0x80000800 ; Bit 11 set for Valid -; wrmsr - -; MTRR notes: -; Base 0x0000000000000000 = 0 MiB -; Base 0x0000000080000000 = 2048 MiB, 2048 is 0x800 -; Base 0x0000000100000000 = 4096 MiB, 4096 is 0x1000 -; Mask 0x0000000F80000000 = 2048 MiB, 0xFFFFFFFFF - F80000000 = 7FFFFFFF = 2147483647 (~2 GiB) -; Mask 0x0000000FC0000000 = 1024 MiB, 0xFFFFFFFFF - FC0000000 = 3FFFFFFF = 1073741823 (~1 GiB) -; Mask 0x0000000FFC000000 = 64 MiB, 0xFFFFFFFFF - FFC000000 = 3FFFFFF = 67108863 (~64 MiB) - -; Enable MTRRs - mov ecx, 0x000002FF - rdmsr - bts eax, 11 ; Set MTRR Enable (Bit 11), Only enables Variable Range MTRR's - wrmsr - -; Flush Cache - wbinvd - -; Skip next portion if MSR support doesn't exist -; cmp r15b, 0 -; je init_cpu_skip2 - -; Enable L2 Cache (Not supported on P4 or Atom) -; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache -; rdmsr -; bts eax, 8 ; Set L2 Enabled (Bit 8) -; wrmsr - -; Enable Prefetchers (Not supported on P4 or Atom) -; mov ecx, 0x000001A0 -; rdmsr -; and eax, 0xFFF7FDFF ; Clear Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) -; and edx, 0xFFFFFFAF ; Clear DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) -; wrmsr - -;init_cpu_skip2: - -; Enable Cache - mov rax, cr0 - btr rax, 29 ; Clear No Write Thru (Bit 29) - btr rax, 30 ; Clear CD (Bit 30) - mov cr0, rax - -; Enable Paging Global Extensions - mov rax, cr4 - bts rax, 7 ; Set Paging Global Extensions (Bit 7) - mov cr4, rax - -; Enable Floating Point - mov rax, cr0 - bts rax, 1 ; Set Monitor co-processor (Bit 1) - btr rax, 2 ; Clear Emulation (Bit 2) - mov cr0, rax - -; Enable SSE - mov rax, cr4 - bts rax, 9 ; Set Operating System Support for FXSAVE and FXSTOR instructions (Bit 9) - bts rax, 10 ; Set Operating System Support for Unmasked SIMD Floating-Point Exceptions (Bit 10) - mov cr4, rax - -; Enable Math Co-processor - finit - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT CPU +; ============================================================================= + + +init_cpu: + +; Check for Prefetcher and L2 Cache support + mov r15b, 1 ; Set MSR support to 1 + xor eax, eax + mov al, 1 ; Access CPUID leaf 1 + cpuid + shr rax, 8 ; Family now in AL (lowest 4 bits) + and al, 0x0F ; Clear the high 4 bits + cmp al, 0x0F + jne init_cpu_msrok ; If Family is not 0xF then jump + mov r15b, 0 ; If it is 0xF (Older P4/Xeon) then set MSR support to 0 +init_cpu_msrok: + +; Disable Cache + mov rax, cr0 + btr rax, 29 ; Clear No Write Thru (Bit 29) + bts rax, 30 ; Set Cache Disable (Bit 30) + mov cr0, rax + +; Flush Cache + wbinvd + +; Diable Paging Global Extensions + mov rax, cr4 + btr rax, 7 ; Clear Paging Global Extensions (Bit 7) + mov cr4, rax + mov rax, cr3 + mov cr3, rax + +; Skip next portion if MSR support doesn't exist +; cmp r15b, 0 +; je init_cpu_skip1 + +; Disable Prefetchers (Not supported on P4 or Atom) +; mov ecx, 0x000001A0 +; rdmsr +; or eax, 0x00080200 ; Set Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) +; or edx, 0x000000A0 ; Set DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) +; wrmsr + +; Disable L2 Cache (Not supported on P4 or Atom) +; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache +; rdmsr +; btr eax, 8 ; Clear L2 Enabled (Bit 8) +; wrmsr + +;init_cpu_skip1: + +; Disable MTRRs and Configure default memory type to UC + mov ecx, 0x000002FF + rdmsr + and eax, 0xFFFFF300 ; Clear MTRR Enable (Bit 11), Fixed Range MTRR Enable (Bit 10), and Default Memory Type (Bits 7:0) to UC (0x00) + wrmsr + +; Setup variable-size address ranges +; Cache 0-64 MiB as type 6 (WB) cache +; See example in Intel Volume 3A. Example Base and Mask Calculations +; mov ecx, 0x00000200 ; MTRR_Phys_Base_MSR(0) +; mov edx, 0x00000000 ; Base is EDX:EAX, 0x0000000000000006 +; mov eax, 0x00000006 ; Type 6 (write-back cache) +; wrmsr +; mov ecx, 0x00000201 ; MTRR_Phys_Mask_MSR(0) +;; mov edx, 0x00000000 ; Mask is EDX:EAX, 0x0000000001000800 (Because bochs sucks) +;; mov eax, 0x01000800 ; Bit 11 set for Valid +; mov edx, 0x0000000F ; Mask is EDX:EAX, 0x0000000F80000800 (2 GiB) +; mov eax, 0x80000800 ; Bit 11 set for Valid +; wrmsr + +; MTRR notes: +; Base 0x0000000000000000 = 0 MiB +; Base 0x0000000080000000 = 2048 MiB, 2048 is 0x800 +; Base 0x0000000100000000 = 4096 MiB, 4096 is 0x1000 +; Mask 0x0000000F80000000 = 2048 MiB, 0xFFFFFFFFF - F80000000 = 7FFFFFFF = 2147483647 (~2 GiB) +; Mask 0x0000000FC0000000 = 1024 MiB, 0xFFFFFFFFF - FC0000000 = 3FFFFFFF = 1073741823 (~1 GiB) +; Mask 0x0000000FFC000000 = 64 MiB, 0xFFFFFFFFF - FFC000000 = 3FFFFFF = 67108863 (~64 MiB) + +; Enable MTRRs + mov ecx, 0x000002FF + rdmsr + bts eax, 11 ; Set MTRR Enable (Bit 11), Only enables Variable Range MTRR's + wrmsr + +; Flush Cache + wbinvd + +; Skip next portion if MSR support doesn't exist +; cmp r15b, 0 +; je init_cpu_skip2 + +; Enable L2 Cache (Not supported on P4 or Atom) +; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache +; rdmsr +; bts eax, 8 ; Set L2 Enabled (Bit 8) +; wrmsr + +; Enable Prefetchers (Not supported on P4 or Atom) +; mov ecx, 0x000001A0 +; rdmsr +; and eax, 0xFFF7FDFF ; Clear Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) +; and edx, 0xFFFFFFAF ; Clear DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) +; wrmsr + +;init_cpu_skip2: + +; Enable Cache + mov rax, cr0 + btr rax, 29 ; Clear No Write Thru (Bit 29) + btr rax, 30 ; Clear CD (Bit 30) + mov cr0, rax + +; Enable Paging Global Extensions + mov rax, cr4 + bts rax, 7 ; Set Paging Global Extensions (Bit 7) + mov cr4, rax + +; Enable Floating Point + mov rax, cr0 + bts rax, 1 ; Set Monitor co-processor (Bit 1) + btr rax, 2 ; Clear Emulation (Bit 2) + mov cr0, rax + +; Enable SSE + mov rax, cr4 + bts rax, 9 ; Set Operating System Support for FXSAVE and FXSTOR instructions (Bit 9) + bts rax, 10 ; Set Operating System Support for Unmasked SIMD Floating-Point Exceptions (Bit 10) + mov cr4, rax + +; Enable Math Co-processor + finit + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_hdd.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_hdd.asm index 89c4be66..68a8d02c 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_hdd.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_hdd.asm @@ -1,178 +1,178 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT HDD -; ============================================================================= - - -hdd_setup: -; Read first sector of HDD into memory - xor rax, rax - mov rdi, hdbuffer - push rdi - mov rcx, 1 - call readsectors - pop rdi - - cmp byte [cfg_mbr], 0x01 ; Did we boot from a MBR drive - jne hdd_setup_no_mbr ; If not then we already have the correct sector - -; Grab the partition offset value for the first partition - mov eax, [rdi+0x01C6] - mov [fat16_PartitionOffset], eax - -; Read the first sector of the first partition - mov rdi, hdbuffer - push rdi - mov rcx, 1 - call readsectors - pop rdi - -hdd_setup_no_mbr: -; Get the values we need to start using fat16 - mov ax, [rdi+0x0b] - mov [fat16_BytesPerSector], ax ; This will probably be 512 - mov al, [rdi+0x0d] - mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) - mov ax, [rdi+0x0e] - mov [fat16_ReservedSectors], ax - mov [fat16_FatStart], eax - mov al, [rdi+0x10] - mov [fat16_Fats], al ; This will probably be 2 - mov ax, [rdi+0x11] - mov [fat16_RootDirEnts], ax - mov ax, [rdi+0x16] - mov [fat16_SectorsPerFat], ax - -; Find out how many sectors are on the disk - xor eax, eax - mov ax, [rdi+0x13] - cmp ax, 0x0000 - jne lessthan65536sectors - mov eax, [rdi+0x20] -lessthan65536sectors: - mov [fat16_TotalSectors], eax - -; Calculate the size in MiB - xor rax, rax - mov eax, [fat16_TotalSectors] - mov [hd1_maxlba], rax - shr rax, 11 ; rax = rax * 512 / 1048576 - mov [hd1_size], eax ; in mebibytes (MiB) - -; Create a string of the harddrive size - mov rdi, hdtempstring - call os_int_to_string - - xor rax, rax - xor rbx, rbx - mov ax, [fat16_SectorsPerFat] - shl ax, 1 ; quick multiply by two - add ax, [fat16_ReservedSectors] - mov [fat16_RootStart], eax - mov bx, [fat16_RootDirEnts] - shr ebx, 4 ; bx = (bx * 32) / 512 - add ebx, eax ; BX now holds the datastart sector number - mov [fat16_DataStart], ebx - -ret - - -; ----------------------------------------------------------------------------- -; readsectors -- Read sectors on the hard drive -; IN: RAX = starting sector to read -; RCX = number of sectors to read (1 - 256) -; RDI = memory location to store sectors -; OUT: RAX = RAX + number of sectors that were read -; RCX = number of sectors that were read (0 on error) -; RDI = RDI + (number of sectors * 512) -; All other registers preserved -readsectors: - push rdx - push rcx - push rbx - push rax - - push rcx ; Save RCX for use in the read loop - mov rbx, rcx ; Store number of sectors to read - cmp rcx, 256 - jg readsectors_fail ; Over 256? Fail! - jne readsectors_skip ; Not 256? No need to modify CL - xor rcx, rcx ; 0 translates to 256 -readsectors_skip: - - push rax ; Save RAX since we are about to overwrite it - mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 - mov al, cl ; Read CL sectors - out dx, al - pop rax ; Restore RAX which is our sector number - inc dx ; 0x01F3 - LBA Low Port 7:0 - out dx, al - inc dx ; 0x01F4 - LBA Mid Port 15:8 - shr rax, 8 - out dx, al - inc dx ; 0x01F5 - LBA High Port 23:16 - shr rax, 8 - out dx, al - inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) - shr rax, 8 - and al, 00001111b ; Clear bits 4-7 just to be safe - or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) - out dx, al - inc dx ; 0x01F7 - Command Port - mov al, 0x20 ; Read sector(s). 0x24 if LBA48 - out dx, al - - mov rcx, 4 -readsectors_wait: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_retry - test al, 0x08 ; DRQ set? - jne readsectors_dataready -readsectors_retry: - dec rcx - jg readsectors_wait -readsectors_nextsector: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_nextsector - test al, 0x21 ; ERR or DF set? - jne readsectors_fail - -readsectors_dataready: - sub dx, 7 ; Data port (0x1F0) - mov rcx, 256 ; Read - rep insw ; Copy a 512 byte sector to RDI - add dx, 7 ; Set DX back to status register (0x01F7) - in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ - in al, dx - in al, dx - in al, dx - - dec rbx ; RBX is the "sectors to read" counter - cmp rbx, 0 - jne readsectors_nextsector - - pop rcx - pop rax - pop rbx - add rax, rcx - pop rcx - pop rdx -ret - -readsectors_fail: - pop rcx - pop rax - pop rbx - pop rcx - pop rdx - xor rcx, rcx ; Set RCX to 0 since nothing was read -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT HDD +; ============================================================================= + + +hdd_setup: +; Read first sector of HDD into memory + xor rax, rax + mov rdi, hdbuffer + push rdi + mov rcx, 1 + call readsectors + pop rdi + + cmp byte [cfg_mbr], 0x01 ; Did we boot from a MBR drive + jne hdd_setup_no_mbr ; If not then we already have the correct sector + +; Grab the partition offset value for the first partition + mov eax, [rdi+0x01C6] + mov [fat16_PartitionOffset], eax + +; Read the first sector of the first partition + mov rdi, hdbuffer + push rdi + mov rcx, 1 + call readsectors + pop rdi + +hdd_setup_no_mbr: +; Get the values we need to start using fat16 + mov ax, [rdi+0x0b] + mov [fat16_BytesPerSector], ax ; This will probably be 512 + mov al, [rdi+0x0d] + mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) + mov ax, [rdi+0x0e] + mov [fat16_ReservedSectors], ax + mov [fat16_FatStart], eax + mov al, [rdi+0x10] + mov [fat16_Fats], al ; This will probably be 2 + mov ax, [rdi+0x11] + mov [fat16_RootDirEnts], ax + mov ax, [rdi+0x16] + mov [fat16_SectorsPerFat], ax + +; Find out how many sectors are on the disk + xor eax, eax + mov ax, [rdi+0x13] + cmp ax, 0x0000 + jne lessthan65536sectors + mov eax, [rdi+0x20] +lessthan65536sectors: + mov [fat16_TotalSectors], eax + +; Calculate the size in MiB + xor rax, rax + mov eax, [fat16_TotalSectors] + mov [hd1_maxlba], rax + shr rax, 11 ; rax = rax * 512 / 1048576 + mov [hd1_size], eax ; in mebibytes (MiB) + +; Create a string of the harddrive size + mov rdi, hdtempstring + call os_int_to_string + + xor rax, rax + xor rbx, rbx + mov ax, [fat16_SectorsPerFat] + shl ax, 1 ; quick multiply by two + add ax, [fat16_ReservedSectors] + mov [fat16_RootStart], eax + mov bx, [fat16_RootDirEnts] + shr ebx, 4 ; bx = (bx * 32) / 512 + add ebx, eax ; BX now holds the datastart sector number + mov [fat16_DataStart], ebx + +ret + + +; ----------------------------------------------------------------------------- +; readsectors -- Read sectors on the hard drive +; IN: RAX = starting sector to read +; RCX = number of sectors to read (1 - 256) +; RDI = memory location to store sectors +; OUT: RAX = RAX + number of sectors that were read +; RCX = number of sectors that were read (0 on error) +; RDI = RDI + (number of sectors * 512) +; All other registers preserved +readsectors: + push rdx + push rcx + push rbx + push rax + + push rcx ; Save RCX for use in the read loop + mov rbx, rcx ; Store number of sectors to read + cmp rcx, 256 + jg readsectors_fail ; Over 256? Fail! + jne readsectors_skip ; Not 256? No need to modify CL + xor rcx, rcx ; 0 translates to 256 +readsectors_skip: + + push rax ; Save RAX since we are about to overwrite it + mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 + mov al, cl ; Read CL sectors + out dx, al + pop rax ; Restore RAX which is our sector number + inc dx ; 0x01F3 - LBA Low Port 7:0 + out dx, al + inc dx ; 0x01F4 - LBA Mid Port 15:8 + shr rax, 8 + out dx, al + inc dx ; 0x01F5 - LBA High Port 23:16 + shr rax, 8 + out dx, al + inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) + shr rax, 8 + and al, 00001111b ; Clear bits 4-7 just to be safe + or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) + out dx, al + inc dx ; 0x01F7 - Command Port + mov al, 0x20 ; Read sector(s). 0x24 if LBA48 + out dx, al + + mov rcx, 4 +readsectors_wait: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_retry + test al, 0x08 ; DRQ set? + jne readsectors_dataready +readsectors_retry: + dec rcx + jg readsectors_wait +readsectors_nextsector: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_nextsector + test al, 0x21 ; ERR or DF set? + jne readsectors_fail + +readsectors_dataready: + sub dx, 7 ; Data port (0x1F0) + mov rcx, 256 ; Read + rep insw ; Copy a 512 byte sector to RDI + add dx, 7 ; Set DX back to status register (0x01F7) + in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ + in al, dx + in al, dx + in al, dx + + dec rbx ; RBX is the "sectors to read" counter + cmp rbx, 0 + jne readsectors_nextsector + + pop rcx + pop rax + pop rbx + add rax, rcx + pop rcx + pop rdx +ret + +readsectors_fail: + pop rcx + pop rax + pop rbx + pop rcx + pop rdx + xor rcx, rcx ; Set RCX to 0 since nothing was read +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_isa.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_isa.asm index a04e4476..141804e3 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_isa.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_isa.asm @@ -1,178 +1,178 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT ISA -; ============================================================================= - - -isa_setup: - - mov edi, 0x00004000 - xor eax, eax - mov ecx, 2048 - rep stosd - -; Get the BIOS E820 Memory Map -; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map -; inputs: es:di -> destination buffer for 24 byte entries -; outputs: bp = entry count, trashes all registers except esi -do_e820: - mov edi, 0x00004000 ; location that memory map will be stored to - xor ebx, ebx ; ebx must be 0 to start - xor bp, bp ; keep an entry count in bp - mov edx, 0x0534D4150 ; Place "SMAP" into edx - mov eax, 0xe820 - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes - int 0x15 - jc nomemmap ; carry set on first call means "unsupported function" - mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? - cmp eax, edx ; on success, eax must have been reset to "SMAP" - jne nomemmap - test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) - je nomemmap - jmp jmpin -e820lp: - mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes again - int 0x15 - jc memmapend ; carry set means "end of list already reached" - mov edx, 0x0534D4150 ; repair potentially trashed register -jmpin: - jcxz skipent ; skip any 0 length entries - cmp cl, 20 ; got a 24 byte ACPI 3.X response? - jbe notext - test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? - je skipent -notext: - mov ecx, [es:di + 8] ; get lower dword of memory region length - test ecx, ecx ; is the qword == 0? - jne goodent - mov ecx, [es:di + 12] ; get upper dword of memory region length - jecxz skipent ; if length qword is 0, skip entry -goodent: - inc bp ; got a good entry: ++count, move to next storage spot - add di, 32 -skipent: - test ebx, ebx ; if ebx resets to 0, list is complete - jne e820lp -nomemmap: - mov byte [cfg_e820], 0 ; No memory map function -memmapend: - xor eax, eax ; Create a blank record for termination (32 bytes) - mov ecx, 8 - rep stosd - -; Enable the A20 gate -set_A20: - in al, 0x64 - test al, 0x02 - jnz set_A20 - mov al, 0xD1 - out 0x64, al -check_A20: - in al, 0x64 - test al, 0x02 - jnz check_A20 - mov al, 0xDF - out 0x60, al - -; Configure serial port 1 - mov dx, 0 - mov al, 11100011b ; 9600 baud, no parity, 8 data bits, 1 stop bit - mov ah, 0 - int 14h - -; Set PIT Channel 0 to fire at 1000Hz (Divisor = 1193180 / hz) - mov al, 0x36 ; Set Timer - out 0x43, al - mov al, 0xA9 ; We want 100MHz so 0x2E9B - out 0x40, al ; 1000MHz would be 0x04A9 - mov al, 0x04 - out 0x40, al - -; Set keyboard repeat rate to max - mov al, 0xf3 - out 0x60, al ; Set Typematic Rate/Delay - xor al, al - out 0x60, al ; 30 cps and .25 second delay - mov al, 0xed - out 0x60, al ; Set/Reset LEDs - xor al, al - out 0x60, al ; all off - -; Set up RTC - mov al, 0x0B - out 0x70, al - in al, 0x71 - or al, 00000010b ; Bit 2 (0) Data Mode to BCD, Bit 1 (1) 24 hour mode - push ax - mov al, 0x0B - out 0x70, al - pop ax - out 0x71, al - -; VBE init - cmp byte [cfg_vesa], 1 ; Check if VESA should be enabled - jne VBEdone ; If not then skip VESA init - mov edi, VBEModeInfoBlock ; VBE data will be stored at this address - mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm - ; CX queries the mode, it should be in the form 0x41XX as bit 14 is set for LFB and bit 8 is set for VESA mode - ; 0x4112 is 640x480x24bit 0x4129 is 640x480x32bit - ; 0x4115 is 800x600x24bit 0x412E is 800x600x32bit - ; 0x4118 is 1024x768x24bit 0x4138 is 1024x768x32bit - ; 0x411B is 1280x1024x24bit 0x413D is 1280x1024x32bit - mov cx, 0x4112 ; Put your desired mode here - mov bx, cx ; Mode is saved to BX for the set command later - int 0x10 - - cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful - jne VBEfail - cmp byte[VBEModeInfoBlock.BitsPerPixel], 24 ; Make sure this matches the number of bits for the mode! - jne VBEfail ; If set bit mode was unsucessful then bail out - - mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm - int 0x10 - cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful - jne VBEfail - - jmp VBEdone - -VBEfail: - mov byte [cfg_vesa], 0 ; Clear the VESA config as it was not sucessful - -VBEdone: - -; Remap IRQ's -; As heard on an episode of Jerry Springer.. "It's time to lose the zero (8259 PIC) and get with a hero (IOAPIC)". -; http://osdever.net/tutorials/apicarticle.php - mov al, 00010001b ; begin PIC 1 initialization - out 0x20, al - mov al, 00010001b ; begin PIC 2 initialization - out 0xA0, al - mov al, 0x20 ; IRQ 0-7: interrupts 20h-27h - out 0x21, al - mov al, 0x28 ; IRQ 8-15: interrupts 28h-2Fh - out 0xA1, al - mov al, 4 - out 0x21, al - mov al, 2 - out 0xA1, al - mov al, 1 - out 0x21, al - out 0xA1, al - - in al, 0x21 - mov al, 11111110b ; Disable all IRQs except for timer - out 0x21, al - in al, 0xA1 - mov al, 11111111b - out 0xA1, al - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT ISA +; ============================================================================= + + +isa_setup: + + mov edi, 0x00004000 + xor eax, eax + mov ecx, 2048 + rep stosd + +; Get the BIOS E820 Memory Map +; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map +; inputs: es:di -> destination buffer for 24 byte entries +; outputs: bp = entry count, trashes all registers except esi +do_e820: + mov edi, 0x00004000 ; location that memory map will be stored to + xor ebx, ebx ; ebx must be 0 to start + xor bp, bp ; keep an entry count in bp + mov edx, 0x0534D4150 ; Place "SMAP" into edx + mov eax, 0xe820 + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes + int 0x15 + jc nomemmap ; carry set on first call means "unsupported function" + mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? + cmp eax, edx ; on success, eax must have been reset to "SMAP" + jne nomemmap + test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) + je nomemmap + jmp jmpin +e820lp: + mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes again + int 0x15 + jc memmapend ; carry set means "end of list already reached" + mov edx, 0x0534D4150 ; repair potentially trashed register +jmpin: + jcxz skipent ; skip any 0 length entries + cmp cl, 20 ; got a 24 byte ACPI 3.X response? + jbe notext + test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? + je skipent +notext: + mov ecx, [es:di + 8] ; get lower dword of memory region length + test ecx, ecx ; is the qword == 0? + jne goodent + mov ecx, [es:di + 12] ; get upper dword of memory region length + jecxz skipent ; if length qword is 0, skip entry +goodent: + inc bp ; got a good entry: ++count, move to next storage spot + add di, 32 +skipent: + test ebx, ebx ; if ebx resets to 0, list is complete + jne e820lp +nomemmap: + mov byte [cfg_e820], 0 ; No memory map function +memmapend: + xor eax, eax ; Create a blank record for termination (32 bytes) + mov ecx, 8 + rep stosd + +; Enable the A20 gate +set_A20: + in al, 0x64 + test al, 0x02 + jnz set_A20 + mov al, 0xD1 + out 0x64, al +check_A20: + in al, 0x64 + test al, 0x02 + jnz check_A20 + mov al, 0xDF + out 0x60, al + +; Configure serial port 1 + mov dx, 0 + mov al, 11100011b ; 9600 baud, no parity, 8 data bits, 1 stop bit + mov ah, 0 + int 14h + +; Set PIT Channel 0 to fire at 1000Hz (Divisor = 1193180 / hz) + mov al, 0x36 ; Set Timer + out 0x43, al + mov al, 0xA9 ; We want 100MHz so 0x2E9B + out 0x40, al ; 1000MHz would be 0x04A9 + mov al, 0x04 + out 0x40, al + +; Set keyboard repeat rate to max + mov al, 0xf3 + out 0x60, al ; Set Typematic Rate/Delay + xor al, al + out 0x60, al ; 30 cps and .25 second delay + mov al, 0xed + out 0x60, al ; Set/Reset LEDs + xor al, al + out 0x60, al ; all off + +; Set up RTC + mov al, 0x0B + out 0x70, al + in al, 0x71 + or al, 00000010b ; Bit 2 (0) Data Mode to BCD, Bit 1 (1) 24 hour mode + push ax + mov al, 0x0B + out 0x70, al + pop ax + out 0x71, al + +; VBE init + cmp byte [cfg_vesa], 1 ; Check if VESA should be enabled + jne VBEdone ; If not then skip VESA init + mov edi, VBEModeInfoBlock ; VBE data will be stored at this address + mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm + ; CX queries the mode, it should be in the form 0x41XX as bit 14 is set for LFB and bit 8 is set for VESA mode + ; 0x4112 is 640x480x24bit 0x4129 is 640x480x32bit + ; 0x4115 is 800x600x24bit 0x412E is 800x600x32bit + ; 0x4118 is 1024x768x24bit 0x4138 is 1024x768x32bit + ; 0x411B is 1280x1024x24bit 0x413D is 1280x1024x32bit + mov cx, 0x4112 ; Put your desired mode here + mov bx, cx ; Mode is saved to BX for the set command later + int 0x10 + + cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful + jne VBEfail + cmp byte[VBEModeInfoBlock.BitsPerPixel], 24 ; Make sure this matches the number of bits for the mode! + jne VBEfail ; If set bit mode was unsucessful then bail out + + mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm + int 0x10 + cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful + jne VBEfail + + jmp VBEdone + +VBEfail: + mov byte [cfg_vesa], 0 ; Clear the VESA config as it was not sucessful + +VBEdone: + +; Remap IRQ's +; As heard on an episode of Jerry Springer.. "It's time to lose the zero (8259 PIC) and get with a hero (IOAPIC)". +; http://osdever.net/tutorials/apicarticle.php + mov al, 00010001b ; begin PIC 1 initialization + out 0x20, al + mov al, 00010001b ; begin PIC 2 initialization + out 0xA0, al + mov al, 0x20 ; IRQ 0-7: interrupts 20h-27h + out 0x21, al + mov al, 0x28 ; IRQ 8-15: interrupts 28h-2Fh + out 0xA1, al + mov al, 4 + out 0x21, al + mov al, 2 + out 0xA1, al + mov al, 1 + out 0x21, al + out 0xA1, al + + in al, 0x21 + mov al, 11111110b ; Disable all IRQs except for timer + out 0x21, al + in al, 0xA1 + mov al, 11111111b + out 0xA1, al + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp.asm index 73f1651b..2b65f9e0 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp.asm @@ -1,232 +1,232 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT SMP -; ============================================================================= - -;MP_debugmsg: db 'MP_CODE!', 0 - - -smp_setup: - sti ; Enable the timer - mov al, '3' ; Start of MP init - mov [0x000B809C], al - mov al, '0' - mov [0x000B809E], al - -; Step 1: Get APIC Information via ACPI -smp_check_for_acpi: ; Look for the Root System Description Pointer Structure - mov rsi, 0x00000000000E0000 ; We want to start looking here - mov rbx, 'RSD PTR ' ; This in the Signature for the ACPI Structure Table (0x2052545020445352) -searchingforACPI: - lodsq ; Load a quad word from RSI and store in RAX, then increment RSI by 8 - cmp rax, rbx - je foundACPI - cmp rsi, 0x00000000000FFFFF ; Keep looking until we get here - jge noMP ; We can't find ACPI either.. bail out and default to single cpu mode - jmp searchingforACPI - - mov al, '3' ; ACPI tables detected - mov [0x000B809C], al - mov al, '2' - mov [0x000B809E], al - -foundACPI: - jmp init_smp_acpi - -makempgonow: - mov al, '3' ; ACPI tables parsed - mov [0x000B809C], al - mov al, '6' - mov [0x000B809E], al - -; Step 2: Enable Local APIC on BSP - mov rsi, [os_LocalAPICAddress] - cmp rsi, 0x00000000 - je noMP ; Skip MP init if we didn't get a valid LAPIC address - add rsi, 0xf0 ; Offset to Spurious Interrupt Register - mov rdi, rsi - lodsd - or eax, 0000000100000000b - stosd - -; Check if we want the AP's to be enabled.. if not then skip to end -; cmp byte [cfg_smpinit], 1 ; Check if SMP should be enabled -; jne noMP ; If not then skip SMP init - -; Step 3: Start the AP's one by one - xor eax, eax - xor ecx, ecx - xor edx, edx - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the BSP CPU's APIC ID - mov dl, al ; Store BSP APIC ID in DL - mov rsi, 0x0000000000005800 - xor eax, eax - -nextcore: - cmp rsi, 0x0000000000005900 - je done - lodsb - cmp al, 1 ; Is it enabled? - jne skipcore - -; push rax ; Debug - display APIC ID -; mov al, cl -; add al, 48 -; call os_print_char -; pop rax - - cmp cl, dl ; Is it the BSP? - je skipcore - -; Broadcast 'INIT' IPI to APIC ID in AL - mov al, cl - shl eax, 24 - mov rdi, [os_LocalAPICAddress] - add rdi, 0x310 - stosd - mov eax, 0x00004500 - mov rdi, [os_LocalAPICAddress] - add rdi, 0x300 - stosd - push rsi -verifyinit: - mov rsi, [os_LocalAPICAddress] - add rsi, 0x300 - lodsd - bt eax, 12 ; Verify that the command completed - jc verifyinit - pop rsi - - mov rax, [os_Counter] - add rax, 10 -wait1: - mov rbx, [os_Counter] - cmp rax, rbx - jg wait1 - -; Broadcast 'Startup' IPI to destination using vector 0x08 to specify entry-point is at the memory-address 0x00008000 - mov al, cl - shl eax, 24 - mov rdi, [os_LocalAPICAddress] - add rdi, 0x310 - stosd - mov eax, 0x00004608 ; Vector 0x08 - mov rdi, [os_LocalAPICAddress] - add rdi, 0x300 - stosd - push rsi -verifystartup1: - mov rsi, [os_LocalAPICAddress] - add rsi, 0x300 - lodsd - bt eax, 12 ; Verify that the command completed - jc verifystartup1 - pop rsi - - mov rax, [os_Counter] - add rax, 2 -wait2: - mov rbx, [os_Counter] - cmp rax, rbx - jg wait2 - -skipcore: - inc cl - jmp nextcore - -done: - - mov al, '3' - mov [0x000B809C], al - mov al, '8' - mov [0x000B809E], al - -; Let things settle (Give the AP's some time to finish) - mov rax, [os_Counter] - add rax, 10 -wait3: - mov rbx, [os_Counter] - cmp rax, rbx - jg wait3 - -; Step 4: Prepare the IOAPIC -; To be coded... - -; Step 5: Finish up - -noMP: - lock - inc word [cpu_activated] ; BSP adds one here - - xor eax, eax - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) - mov rdi, 0x00005700 ; The location where the cpu values are stored - add rdi, rax ; RDI points to infomap CPU area + APIC ID. ex F701 would be APIC ID 1 - mov al, 3 ; This is the BSP so bits 0 and 1 are set - stosb - - mov al, '3' - mov [0x000B809C], al - mov al, 'A' - mov [0x000B809E], al - -; Calculate speed of CPU (At this point the timer is firing at 1000Hz) - xchg bx, bx - cpuid - xor edx, edx - xor eax, eax - mov rcx, [os_Counter] - add rcx, 10 - rdtsc - push rax -speedtest: - mov rbx, [os_Counter] - cmp rbx, rcx - jl speedtest - rdtsc - pop rdx - sub rax, rdx - xor edx, edx - mov rcx, 10000 - div rcx - mov [cpu_speed], ax - - mov al, '3' - mov [0x000B809C], al - mov al, 'C' - mov [0x000B809E], al - - cli ; Disable the timer - -; Set PIT Channel 0 to fire at 100Hz (Divisor = 1193180 / hz) - mov al, 0x36 ; Set Timer - out 0x43, al - mov al, 0x9B ; We want 100MHz so 0x2E9B - out 0x40, al - mov al, 0x2E - out 0x40, al - -; Disable all IRQs - in al, 0x21 - mov al, 11111111b - out 0x21, al - in al, 0xA1 - mov al, 11111111b - out 0xA1, al - -ret - - -%include "init_smp_acpi.asm" - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT SMP +; ============================================================================= + +;MP_debugmsg: db 'MP_CODE!', 0 + + +smp_setup: + sti ; Enable the timer + mov al, '3' ; Start of MP init + mov [0x000B809C], al + mov al, '0' + mov [0x000B809E], al + +; Step 1: Get APIC Information via ACPI +smp_check_for_acpi: ; Look for the Root System Description Pointer Structure + mov rsi, 0x00000000000E0000 ; We want to start looking here + mov rbx, 'RSD PTR ' ; This in the Signature for the ACPI Structure Table (0x2052545020445352) +searchingforACPI: + lodsq ; Load a quad word from RSI and store in RAX, then increment RSI by 8 + cmp rax, rbx + je foundACPI + cmp rsi, 0x00000000000FFFFF ; Keep looking until we get here + jge noMP ; We can't find ACPI either.. bail out and default to single cpu mode + jmp searchingforACPI + + mov al, '3' ; ACPI tables detected + mov [0x000B809C], al + mov al, '2' + mov [0x000B809E], al + +foundACPI: + jmp init_smp_acpi + +makempgonow: + mov al, '3' ; ACPI tables parsed + mov [0x000B809C], al + mov al, '6' + mov [0x000B809E], al + +; Step 2: Enable Local APIC on BSP + mov rsi, [os_LocalAPICAddress] + cmp rsi, 0x00000000 + je noMP ; Skip MP init if we didn't get a valid LAPIC address + add rsi, 0xf0 ; Offset to Spurious Interrupt Register + mov rdi, rsi + lodsd + or eax, 0000000100000000b + stosd + +; Check if we want the AP's to be enabled.. if not then skip to end +; cmp byte [cfg_smpinit], 1 ; Check if SMP should be enabled +; jne noMP ; If not then skip SMP init + +; Step 3: Start the AP's one by one + xor eax, eax + xor ecx, ecx + xor edx, edx + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the BSP CPU's APIC ID + mov dl, al ; Store BSP APIC ID in DL + mov rsi, 0x0000000000005800 + xor eax, eax + +nextcore: + cmp rsi, 0x0000000000005900 + je done + lodsb + cmp al, 1 ; Is it enabled? + jne skipcore + +; push rax ; Debug - display APIC ID +; mov al, cl +; add al, 48 +; call os_print_char +; pop rax + + cmp cl, dl ; Is it the BSP? + je skipcore + +; Broadcast 'INIT' IPI to APIC ID in AL + mov al, cl + shl eax, 24 + mov rdi, [os_LocalAPICAddress] + add rdi, 0x310 + stosd + mov eax, 0x00004500 + mov rdi, [os_LocalAPICAddress] + add rdi, 0x300 + stosd + push rsi +verifyinit: + mov rsi, [os_LocalAPICAddress] + add rsi, 0x300 + lodsd + bt eax, 12 ; Verify that the command completed + jc verifyinit + pop rsi + + mov rax, [os_Counter] + add rax, 10 +wait1: + mov rbx, [os_Counter] + cmp rax, rbx + jg wait1 + +; Broadcast 'Startup' IPI to destination using vector 0x08 to specify entry-point is at the memory-address 0x00008000 + mov al, cl + shl eax, 24 + mov rdi, [os_LocalAPICAddress] + add rdi, 0x310 + stosd + mov eax, 0x00004608 ; Vector 0x08 + mov rdi, [os_LocalAPICAddress] + add rdi, 0x300 + stosd + push rsi +verifystartup1: + mov rsi, [os_LocalAPICAddress] + add rsi, 0x300 + lodsd + bt eax, 12 ; Verify that the command completed + jc verifystartup1 + pop rsi + + mov rax, [os_Counter] + add rax, 2 +wait2: + mov rbx, [os_Counter] + cmp rax, rbx + jg wait2 + +skipcore: + inc cl + jmp nextcore + +done: + + mov al, '3' + mov [0x000B809C], al + mov al, '8' + mov [0x000B809E], al + +; Let things settle (Give the AP's some time to finish) + mov rax, [os_Counter] + add rax, 10 +wait3: + mov rbx, [os_Counter] + cmp rax, rbx + jg wait3 + +; Step 4: Prepare the IOAPIC +; To be coded... + +; Step 5: Finish up + +noMP: + lock + inc word [cpu_activated] ; BSP adds one here + + xor eax, eax + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) + mov rdi, 0x00005700 ; The location where the cpu values are stored + add rdi, rax ; RDI points to infomap CPU area + APIC ID. ex F701 would be APIC ID 1 + mov al, 3 ; This is the BSP so bits 0 and 1 are set + stosb + + mov al, '3' + mov [0x000B809C], al + mov al, 'A' + mov [0x000B809E], al + +; Calculate speed of CPU (At this point the timer is firing at 1000Hz) + xchg bx, bx + cpuid + xor edx, edx + xor eax, eax + mov rcx, [os_Counter] + add rcx, 10 + rdtsc + push rax +speedtest: + mov rbx, [os_Counter] + cmp rbx, rcx + jl speedtest + rdtsc + pop rdx + sub rax, rdx + xor edx, edx + mov rcx, 10000 + div rcx + mov [cpu_speed], ax + + mov al, '3' + mov [0x000B809C], al + mov al, 'C' + mov [0x000B809E], al + + cli ; Disable the timer + +; Set PIT Channel 0 to fire at 100Hz (Divisor = 1193180 / hz) + mov al, 0x36 ; Set Timer + out 0x43, al + mov al, 0x9B ; We want 100MHz so 0x2E9B + out 0x40, al + mov al, 0x2E + out 0x40, al + +; Disable all IRQs + in al, 0x21 + mov al, 11111111b + out 0x21, al + in al, 0xA1 + mov al, 11111111b + out 0xA1, al + +ret + + +%include "init_smp_acpi.asm" + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_acpi.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_acpi.asm index b0f09f95..21babc9a 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_acpi.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_acpi.asm @@ -1,167 +1,167 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT SMP ACPI -; ============================================================================= - - -init_smp_acpi: - lodsb ; Checksum - lodsd ; OEMID (First 4 bytes) - lodsw ; OEMID (Last 2 bytes) - lodsb ; Grab the Revision value (0 is v1.0, 1 is v2.0, 2 is v3.0, etc) - add al, 49 - mov [0x000B8098], al ; Print the ACPI version number - sub al, 49 - cmp al, 0 - je foundACPIv1 ; If AL is 0 then the system is using ACPI v1.0 - jmp foundACPIv2 ; Otherwise it is v2.0 or higher - -foundACPIv1: - xor eax, eax - lodsd ; Grab the 32 bit physical address of the RSDT (Offset 16). - mov rsi, rax ; RSI now points to the RSDT - lodsd ; Grab the Signiture - cmp eax, 'RSDT' ; Make sure the signiture is valid - jne novalidacpi ; Not the same? Bail out - sub rsi, 4 - mov [os_ACPITableAddress], rsi ; Save the RSDT Table Address - add rsi, 4 - xor eax, eax - lodsd ; Length - add rsi, 28 ; Skip to the Entry offset - sub eax, 36 ; EAX holds the table size. Subtract the preamble - shr eax, 2 ; Divide by 4 - mov rdx, rax ; RDX is the entry count - xor ecx, ecx -foundACPIv1_nextentry: - lodsd - push rax - add ecx, 1 - cmp ecx, edx - je findAPICTable - jmp foundACPIv1_nextentry - -foundACPIv2: - lodsd ; RSDT Address - lodsd ; Length - lodsq ; Grab the 64 bit physical address of the XSDT (Offset 24). - mov rsi, rax ; RSI now points to the XSDT - lodsd ; Grab the Signiture - cmp eax, 'XSDT' ; Make sure the signiture is valid - jne novalidacpi ; Not the same? Bail out - sub rsi, 4 - mov [os_ACPITableAddress], rsi ; Save the XSDT Table Address - add rsi, 4 - xor eax, eax - lodsd ; Length - add rsi, 28 ; Skip to the start of the Entries (offset 36) - sub eax, 36 ; EAX holds the table size. Subtract the preamble - shr eax, 3 ; Divide by 8 - mov rdx, rax ; RDX is the entry count - xor ecx, ecx -foundACPIv2_nextentry: - lodsq - push rax - add ecx, 1 - cmp ecx, edx - jne foundACPIv2_nextentry - -findAPICTable: - mov al, '3' ; Search for the APIC table - mov [0x000B809C], al - mov al, '4' - mov [0x000B809E], al - mov ebx, 'APIC' - xor ecx, ecx -searchingforAPIC: - pop rsi - lodsd - add ecx, 1 - cmp eax, ebx - je foundAPICTable - cmp ecx, edx - jne searchingforAPIC - jmp noMP - -fixstack: - pop rax - add ecx, 1 - -foundAPICTable: - ; fix the stack - cmp ecx, edx - jne fixstack - - lodsd ; Length of MADT in bytes - mov ecx, eax - xor ebx, ebx - lodsb ; Revision - lodsb ; Checksum - lodsd ; OEMID (First 4 bytes) - lodsw ; OEMID (Last 2 bytes) - lodsq ; OEM Table ID - lodsd ; OEM Revision - lodsd ; Creator ID - lodsd ; Creator Revision - xor eax, eax - lodsd ; Local APIC Address - mov [os_LocalAPICAddress], rax ; Save the Address of the Local APIC - lodsd ; Flags - add ebx, 44 - mov rdi, 0x0000000000005800 - -readAPICstructures: - cmp ebx, ecx - jge init_smp_acpi_done - lodsb ; APIC Structure Type - cmp al, 0 - je APICcpu - cmp al, 1 - je APICioapic - jmp APICignore - -APICcpu: - inc word [cpu_detected] - xor eax, eax - lodsb ; Length (will be set to 8) - add ebx, eax - lodsb ; ACPI Processor ID - lodsb ; APIC ID - push rdi - add rdi, rax - lodsd ; Flags - stosb - pop rdi - jmp readAPICstructures ; Read the next structure - -APICioapic: - xor eax, eax - lodsb ; Length (will be set to 12) - add ebx, eax - lodsb ; IO APIC ID - lodsb ; Reserved - xor eax, eax - lodsd ; IO APIC Address - mov [os_IOAPICAddress], rax - lodsd ; System Vector Base - jmp readAPICstructures ; Read the next structure - -APICignore: - xor eax, eax - lodsb ; We have a type that we ignore, read the next byte - add ebx, eax - add rsi, rax - sub rsi, 2 ; For the two bytes just read - jmp readAPICstructures ; Read the next structure - -init_smp_acpi_done: - jmp makempgonow - -novalidacpi: - mov al, 'X' - mov [0x000B809A], al - jmp $ -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT SMP ACPI +; ============================================================================= + + +init_smp_acpi: + lodsb ; Checksum + lodsd ; OEMID (First 4 bytes) + lodsw ; OEMID (Last 2 bytes) + lodsb ; Grab the Revision value (0 is v1.0, 1 is v2.0, 2 is v3.0, etc) + add al, 49 + mov [0x000B8098], al ; Print the ACPI version number + sub al, 49 + cmp al, 0 + je foundACPIv1 ; If AL is 0 then the system is using ACPI v1.0 + jmp foundACPIv2 ; Otherwise it is v2.0 or higher + +foundACPIv1: + xor eax, eax + lodsd ; Grab the 32 bit physical address of the RSDT (Offset 16). + mov rsi, rax ; RSI now points to the RSDT + lodsd ; Grab the Signiture + cmp eax, 'RSDT' ; Make sure the signiture is valid + jne novalidacpi ; Not the same? Bail out + sub rsi, 4 + mov [os_ACPITableAddress], rsi ; Save the RSDT Table Address + add rsi, 4 + xor eax, eax + lodsd ; Length + add rsi, 28 ; Skip to the Entry offset + sub eax, 36 ; EAX holds the table size. Subtract the preamble + shr eax, 2 ; Divide by 4 + mov rdx, rax ; RDX is the entry count + xor ecx, ecx +foundACPIv1_nextentry: + lodsd + push rax + add ecx, 1 + cmp ecx, edx + je findAPICTable + jmp foundACPIv1_nextentry + +foundACPIv2: + lodsd ; RSDT Address + lodsd ; Length + lodsq ; Grab the 64 bit physical address of the XSDT (Offset 24). + mov rsi, rax ; RSI now points to the XSDT + lodsd ; Grab the Signiture + cmp eax, 'XSDT' ; Make sure the signiture is valid + jne novalidacpi ; Not the same? Bail out + sub rsi, 4 + mov [os_ACPITableAddress], rsi ; Save the XSDT Table Address + add rsi, 4 + xor eax, eax + lodsd ; Length + add rsi, 28 ; Skip to the start of the Entries (offset 36) + sub eax, 36 ; EAX holds the table size. Subtract the preamble + shr eax, 3 ; Divide by 8 + mov rdx, rax ; RDX is the entry count + xor ecx, ecx +foundACPIv2_nextentry: + lodsq + push rax + add ecx, 1 + cmp ecx, edx + jne foundACPIv2_nextentry + +findAPICTable: + mov al, '3' ; Search for the APIC table + mov [0x000B809C], al + mov al, '4' + mov [0x000B809E], al + mov ebx, 'APIC' + xor ecx, ecx +searchingforAPIC: + pop rsi + lodsd + add ecx, 1 + cmp eax, ebx + je foundAPICTable + cmp ecx, edx + jne searchingforAPIC + jmp noMP + +fixstack: + pop rax + add ecx, 1 + +foundAPICTable: + ; fix the stack + cmp ecx, edx + jne fixstack + + lodsd ; Length of MADT in bytes + mov ecx, eax + xor ebx, ebx + lodsb ; Revision + lodsb ; Checksum + lodsd ; OEMID (First 4 bytes) + lodsw ; OEMID (Last 2 bytes) + lodsq ; OEM Table ID + lodsd ; OEM Revision + lodsd ; Creator ID + lodsd ; Creator Revision + xor eax, eax + lodsd ; Local APIC Address + mov [os_LocalAPICAddress], rax ; Save the Address of the Local APIC + lodsd ; Flags + add ebx, 44 + mov rdi, 0x0000000000005800 + +readAPICstructures: + cmp ebx, ecx + jge init_smp_acpi_done + lodsb ; APIC Structure Type + cmp al, 0 + je APICcpu + cmp al, 1 + je APICioapic + jmp APICignore + +APICcpu: + inc word [cpu_detected] + xor eax, eax + lodsb ; Length (will be set to 8) + add ebx, eax + lodsb ; ACPI Processor ID + lodsb ; APIC ID + push rdi + add rdi, rax + lodsd ; Flags + stosb + pop rdi + jmp readAPICstructures ; Read the next structure + +APICioapic: + xor eax, eax + lodsb ; Length (will be set to 12) + add ebx, eax + lodsb ; IO APIC ID + lodsb ; Reserved + xor eax, eax + lodsd ; IO APIC Address + mov [os_IOAPICAddress], rax + lodsd ; System Vector Base + jmp readAPICstructures ; Read the next structure + +APICignore: + xor eax, eax + lodsb ; We have a type that we ignore, read the next byte + add ebx, eax + add rsi, rax + sub rsi, 2 ; For the two bytes just read + jmp readAPICstructures ; Read the next structure + +init_smp_acpi_done: + jmp makempgonow + +novalidacpi: + mov al, 'X' + mov [0x000B809A], al + jmp $ +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_ap.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_ap.asm index f00d89d7..634511b5 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_ap.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/init_smp_ap.asm @@ -1,178 +1,178 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; INIT SMP AP -; ============================================================================= - -USE16 - -mp_ap_setup: - nop - jmp 0x0000:clearcs_ap - -clearcs_ap: - -; Enable the A20 gate -set_A20_ap: - in al, 0x64 - test al, 0x02 - jnz set_A20_ap - mov al, 0xD1 - out 0x64, al -check_A20_ap: - in al, 0x64 - test al, 0x02 - jnz check_A20_ap - mov al, 0xDF - out 0x60, al - -; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. - lgdt [cs:GDTR32] ; load GDT register - - mov eax, cr0 ; switch to 32-bit protected mode - or al, 1 - mov cr0, eax - - jmp 8:startap32 - -align 16 - - -; ============================================================================= -; 32-bit mode -USE32 - -startap32: - mov eax, 16 ; load 4 GB data descriptor - mov ds, ax ; to all data segment registers - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor esi, esi - xor edi, edi - xor ebp, ebp - mov esp, 0x8000 ; Set a known free location for the stack - -; Load the GDT - lgdt [GDTR64] - -; Enable physical-address extensions (set CR4.PAE=1) - mov eax, cr4 - or eax, 0x000000020 ; PAE (Bit 5) - mov cr4, eax - -; Point cr3 at PML4 - mov eax, 0x00002008 ; Write-thru (Bit 3) - mov cr3, eax - -; Enable long mode (set EFER.LME=1) - mov ecx, 0xC0000080 ; EFER MSR number - rdmsr ; Read EFER - or eax, 0x00000100 ; LME (Bit 8) - wrmsr ; Write EFER - -; Enable paging to activate long mode (set CR0.PG=1) - mov eax, cr0 - or eax, 0x80000000 ; PG (Bit 31) - mov cr0, eax - -; Make the jump directly from 16-bit real mode to 64-bit long mode - jmp SYS64_CODE_SEL:startap64 - -align 16 - - -; ============================================================================= -; 64-bit mode -USE64 - -startap64: - xor rax, rax ; aka r0 - xor rbx, rbx ; aka r3 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor rbp, rbp ; aka r5 - xor rsp, rsp ; aka r4 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - mov ds, ax ; Clear the legacy segment registers - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - - mov rax, clearcs64_ap - jmp rax - nop -clearcs64_ap: - xor rax, rax - - ; Reset the stack. Each CPU gets a 1024-byte unique stack location - mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... - add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. - lodsd ; Load a 32-bit value. We only want the high 8 bits - shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID - shl rax, 10 ; shift left 10 bits for a 1024byte stack - add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in - mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that - - lgdt [GDTR64] ; Load the GDT - lidt [IDTR64] ; load IDT register - -; Enable Local APIC on AP - mov rsi, [os_LocalAPICAddress] - add rsi, 0x00f0 ; Offset to Spurious Interrupt Register - mov rdi, rsi - lodsd - or eax, 0000000100000000b - stosd - - call init_cpu ; Setup CPU - -; Make sure exceptions are working. -; xor rax, rax -; xor rbx, rbx -; xor rcx, rcx -; xor rdx, rdx -; div rax - - lock - inc word [cpu_activated] - xor eax, eax - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) - mov rdi, 0x00005700 ; The location where the cpu values are stored - add rdi, rax ; RDI points to infomap CPU area + APIC ID. ex F701 would be APIC ID 1 - mov al, 1 - stosb - sti ; Activate interrupts for SMP - jmp ap_sleep - -align 16 -.apmsg db 'THE_AP_SPIN_ZONE' -align 16 - -ap_sleep: - hlt ; Suspend CPU until an interrupt is received. opcode for hlt is 0xF4 - jmp ap_sleep ; just-in-case of an NMI - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; INIT SMP AP +; ============================================================================= + +USE16 + +mp_ap_setup: + nop + jmp 0x0000:clearcs_ap + +clearcs_ap: + +; Enable the A20 gate +set_A20_ap: + in al, 0x64 + test al, 0x02 + jnz set_A20_ap + mov al, 0xD1 + out 0x64, al +check_A20_ap: + in al, 0x64 + test al, 0x02 + jnz check_A20_ap + mov al, 0xDF + out 0x60, al + +; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. + lgdt [cs:GDTR32] ; load GDT register + + mov eax, cr0 ; switch to 32-bit protected mode + or al, 1 + mov cr0, eax + + jmp 8:startap32 + +align 16 + + +; ============================================================================= +; 32-bit mode +USE32 + +startap32: + mov eax, 16 ; load 4 GB data descriptor + mov ds, ax ; to all data segment registers + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + xor eax, eax + xor ebx, ebx + xor ecx, ecx + xor edx, edx + xor esi, esi + xor edi, edi + xor ebp, ebp + mov esp, 0x8000 ; Set a known free location for the stack + +; Load the GDT + lgdt [GDTR64] + +; Enable physical-address extensions (set CR4.PAE=1) + mov eax, cr4 + or eax, 0x000000020 ; PAE (Bit 5) + mov cr4, eax + +; Point cr3 at PML4 + mov eax, 0x00002008 ; Write-thru (Bit 3) + mov cr3, eax + +; Enable long mode (set EFER.LME=1) + mov ecx, 0xC0000080 ; EFER MSR number + rdmsr ; Read EFER + or eax, 0x00000100 ; LME (Bit 8) + wrmsr ; Write EFER + +; Enable paging to activate long mode (set CR0.PG=1) + mov eax, cr0 + or eax, 0x80000000 ; PG (Bit 31) + mov cr0, eax + +; Make the jump directly from 16-bit real mode to 64-bit long mode + jmp SYS64_CODE_SEL:startap64 + +align 16 + + +; ============================================================================= +; 64-bit mode +USE64 + +startap64: + xor rax, rax ; aka r0 + xor rbx, rbx ; aka r3 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor rbp, rbp ; aka r5 + xor rsp, rsp ; aka r4 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + mov ds, ax ; Clear the legacy segment registers + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + mov rax, clearcs64_ap + jmp rax + nop +clearcs64_ap: + xor rax, rax + + ; Reset the stack. Each CPU gets a 1024-byte unique stack location + mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... + add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. + lodsd ; Load a 32-bit value. We only want the high 8 bits + shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID + shl rax, 10 ; shift left 10 bits for a 1024byte stack + add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in + mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that + + lgdt [GDTR64] ; Load the GDT + lidt [IDTR64] ; load IDT register + +; Enable Local APIC on AP + mov rsi, [os_LocalAPICAddress] + add rsi, 0x00f0 ; Offset to Spurious Interrupt Register + mov rdi, rsi + lodsd + or eax, 0000000100000000b + stosd + + call init_cpu ; Setup CPU + +; Make sure exceptions are working. +; xor rax, rax +; xor rbx, rbx +; xor rcx, rcx +; xor rdx, rdx +; div rax + + lock + inc word [cpu_activated] + xor eax, eax + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) + mov rdi, 0x00005700 ; The location where the cpu values are stored + add rdi, rax ; RDI points to infomap CPU area + APIC ID. ex F701 would be APIC ID 1 + mov al, 1 + stosb + sti ; Activate interrupts for SMP + jmp ap_sleep + +align 16 +.apmsg db 'THE_AP_SPIN_ZONE' +align 16 + +ap_sleep: + hlt ; Suspend CPU until an interrupt is received. opcode for hlt is 0xF4 + jmp ap_sleep ; just-in-case of an NMI + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/interrupt.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/interrupt.asm index f36665f9..4f910b99 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/interrupt.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/interrupt.asm @@ -1,164 +1,164 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Interrupts -; ============================================================================= - - -; ----------------------------------------------------------------------------- -; Default exception handler -exception_gate: - mov rsi, int_string - call os_print_string - mov rsi, exc_string - call os_print_string - jmp $ ; hang -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Default interrupt handler -interrupt_gate: ; handler for all other interrupts - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Real-time clock interrupt. IRQ 0x00, INT 0x20 -align 16 -timer: - add qword [os_Counter], 1 ; 64-bit counter started at bootup - mov al, 0x20 ; Acknowledge the IRQ - out 0x20, al - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; CPU Exception Gates -exception_gate_00: - mov al, 0x00 - jmp exception_gate_main - -exception_gate_01: - mov al, 0x01 - jmp exception_gate_main - -exception_gate_02: - mov al, 0x02 - jmp exception_gate_main - -exception_gate_03: - mov al, 0x03 - jmp exception_gate_main - -exception_gate_04: - mov al, 0x04 - jmp exception_gate_main - -exception_gate_05: - mov al, 0x05 - jmp exception_gate_main - -exception_gate_06: - mov al, 0x06 - jmp exception_gate_main - -exception_gate_07: - mov al, 0x07 - jmp exception_gate_main - -exception_gate_08: - mov al, 0x08 - jmp exception_gate_main - -exception_gate_09: - mov al, 0x09 - jmp exception_gate_main - -exception_gate_10: - mov al, 0x0A - jmp exception_gate_main - -exception_gate_11: - mov al, 0x0B - jmp exception_gate_main - -exception_gate_12: - mov al, 0x0C - jmp exception_gate_main - -exception_gate_13: - mov al, 0x0D - jmp exception_gate_main - -exception_gate_14: - mov al, 0x0E - jmp exception_gate_main - -exception_gate_15: - mov al, 0x0F - jmp exception_gate_main - -exception_gate_16: - mov al, 0x10 - jmp exception_gate_main - -exception_gate_17: - mov al, 0x11 - jmp exception_gate_main - -exception_gate_18: - mov al, 0x12 - jmp exception_gate_main - -exception_gate_19: - mov al, 0x13 - jmp exception_gate_main - -exception_gate_main: - call os_print_newline - mov rsi, int_string - call os_print_string - mov rsi, exc_string00 - and rax, 0xFF ; Clear out everything in RAX except for AL - mov bl, 8 - mul bl ; AX = AL x BL - add rsi, rax ; Use the value in RAX as an offset to get to the right message - call os_print_string - call os_print_newline - call os_dump_regs - -exception_gate_main_hang: - nop - jmp exception_gate_main_hang ; Hang. User must reset machine at this point - -; Strings for the error messages -int_string db 'Pure64 - Interrupt ', 0 -exc_string db '?? - Unknown Fatal Exception!', 0 -align 16 -exc_string00 db '00 - DE', 0 -exc_string01 db '01 - DB', 0 -exc_string02 db '02 ', 0 -exc_string03 db '03 - BP', 0 -exc_string04 db '04 - OF', 0 -exc_string05 db '05 - BR', 0 -exc_string06 db '06 - UD', 0 -exc_string07 db '07 - NM', 0 -exc_string08 db '08 - DF', 0 -exc_string09 db '09 ', 0 ; No longer generated on new CPU's -exc_string10 db '10 - TS', 0 -exc_string11 db '11 - NP', 0 -exc_string12 db '12 - SS', 0 -exc_string13 db '13 - GP', 0 -exc_string14 db '14 - PF', 0 -exc_string15 db '15 ', 0 -exc_string16 db '16 - MF', 0 -exc_string17 db '17 - AC', 0 -exc_string18 db '18 - MC', 0 -exc_string19 db '19 - XM', 0 - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Interrupts +; ============================================================================= + + +; ----------------------------------------------------------------------------- +; Default exception handler +exception_gate: + mov rsi, int_string + call os_print_string + mov rsi, exc_string + call os_print_string + jmp $ ; hang +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Default interrupt handler +interrupt_gate: ; handler for all other interrupts + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Real-time clock interrupt. IRQ 0x00, INT 0x20 +align 16 +timer: + add qword [os_Counter], 1 ; 64-bit counter started at bootup + mov al, 0x20 ; Acknowledge the IRQ + out 0x20, al + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; CPU Exception Gates +exception_gate_00: + mov al, 0x00 + jmp exception_gate_main + +exception_gate_01: + mov al, 0x01 + jmp exception_gate_main + +exception_gate_02: + mov al, 0x02 + jmp exception_gate_main + +exception_gate_03: + mov al, 0x03 + jmp exception_gate_main + +exception_gate_04: + mov al, 0x04 + jmp exception_gate_main + +exception_gate_05: + mov al, 0x05 + jmp exception_gate_main + +exception_gate_06: + mov al, 0x06 + jmp exception_gate_main + +exception_gate_07: + mov al, 0x07 + jmp exception_gate_main + +exception_gate_08: + mov al, 0x08 + jmp exception_gate_main + +exception_gate_09: + mov al, 0x09 + jmp exception_gate_main + +exception_gate_10: + mov al, 0x0A + jmp exception_gate_main + +exception_gate_11: + mov al, 0x0B + jmp exception_gate_main + +exception_gate_12: + mov al, 0x0C + jmp exception_gate_main + +exception_gate_13: + mov al, 0x0D + jmp exception_gate_main + +exception_gate_14: + mov al, 0x0E + jmp exception_gate_main + +exception_gate_15: + mov al, 0x0F + jmp exception_gate_main + +exception_gate_16: + mov al, 0x10 + jmp exception_gate_main + +exception_gate_17: + mov al, 0x11 + jmp exception_gate_main + +exception_gate_18: + mov al, 0x12 + jmp exception_gate_main + +exception_gate_19: + mov al, 0x13 + jmp exception_gate_main + +exception_gate_main: + call os_print_newline + mov rsi, int_string + call os_print_string + mov rsi, exc_string00 + and rax, 0xFF ; Clear out everything in RAX except for AL + mov bl, 8 + mul bl ; AX = AL x BL + add rsi, rax ; Use the value in RAX as an offset to get to the right message + call os_print_string + call os_print_newline + call os_dump_regs + +exception_gate_main_hang: + nop + jmp exception_gate_main_hang ; Hang. User must reset machine at this point + +; Strings for the error messages +int_string db 'Pure64 - Interrupt ', 0 +exc_string db '?? - Unknown Fatal Exception!', 0 +align 16 +exc_string00 db '00 - DE', 0 +exc_string01 db '01 - DB', 0 +exc_string02 db '02 ', 0 +exc_string03 db '03 - BP', 0 +exc_string04 db '04 - OF', 0 +exc_string05 db '05 - BR', 0 +exc_string06 db '06 - UD', 0 +exc_string07 db '07 - NM', 0 +exc_string08 db '08 - DF', 0 +exc_string09 db '09 ', 0 ; No longer generated on new CPU's +exc_string10 db '10 - TS', 0 +exc_string11 db '11 - NP', 0 +exc_string12 db '12 - SS', 0 +exc_string13 db '13 - GP', 0 +exc_string14 db '14 - PF', 0 +exc_string15 db '15 ', 0 +exc_string16 db '16 - MF', 0 +exc_string17 db '17 - AC', 0 +exc_string18 db '18 - MC', 0 +exc_string19 db '19 - XM', 0 + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/pure64.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/pure64.asm index f4b034b5..ea06e1ff 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/pure64.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/pure64.asm @@ -1,685 +1,685 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Loaded from the first stage. Gather information about the system while -; in 16-bit mode (BIOS is still accessable), setup a minimal 64-bit -; enviroment, load the 64-bit kernel from the filesystem into memory and -; jump to it! -; ============================================================================= - - -USE16 -ORG 0x00008000 -start: - cli ; Disable all interrupts - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor esi, esi - xor edi, edi - xor ebp, ebp - mov ds, ax - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - mov esp, 0x8000 ; Set a known free location for the stack - -align 16 - jmp start16 ; This command will be overwritten with 'NOP's before the AP's are started - -%include "init_smp_ap.asm" ; Our AP code is at 0x8000 - -align 16 -db '16' -align 16 - -USE16 -start16: - jmp 0x0000:clearcs - -clearcs: - mov ax, [0x07FE] ; MBR sector is copied to 0x0600 - cmp ax, 0xAA55 ; Check if the word at 0x07FE is set to 0xAA55 (Boot sector marker) - jne no_mbr - mov byte [cfg_mbr], 1 ; Set for booting from a disk with a MBR -no_mbr: - -; Make sure the screen is set to 80x25 color text mode - mov ax, 0x0003 ; Set to normal (80x25 text) video mode - int 0x10 - -; Hide the cursor -; mov ax, 0x0100 -; mov cx, 0x200F -; int 0x10 - -; Print message - mov si, initStartupMsg - call print_string_16 - -; Check to make sure the CPU supports 64-bit mode... If not then bail out - mov eax, 0x80000000 ; Extended-function 8000000h. - cpuid ; Is largest extended function - cmp eax, 0x80000000 ; any function > 80000000h? - jbe near no_long_mode ; If not, no long mode. - mov eax, 0x80000001 ; Extended-function 8000001h. - cpuid ; Now EDX = extended-features flags. - bt edx, 29 ; Test if long mode is supported. - jnc near no_long_mode ; Exit if not supported. - - call isa_setup ; Setup legacy hardware - -; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. - lgdt [cs:GDTR32] ; Load GDT register - - mov eax, cr0 - or al, 0x01 ; Set protected mode bit - mov cr0, eax - - jmp 8:start32 ; Jump to 32-bit protected mode - -; 16-bit Function to print a sting to the screen -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -.repeat: - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp short .repeat -.done: - popa - ret - -; Display an error message that the CPU does not support 64-bit mode -no_long_mode: - mov si, no64msg - call print_string_16 - jmp $ - -%include "init_isa.asm" - -align 16 -GDTR32: ; Global Descriptors Table Register -dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) -dq gdt32 ; linear address of GDT - -align 16 -gdt32: -dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null desciptor -dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code desciptor -dw 0xFFFF, 0x0000, 0x9200, 0x008F ; 32-bit data desciptor -gdt32_end: - -align 16 -db '32' -align 16 - - -; ============================================================================= -; 32-bit mode -USE32 - -start32: - mov eax, 16 ; load 4 GB data descriptor - mov ds, ax ; to all data segment registers - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor esi, esi - xor edi, edi - xor ebp, ebp - mov esp, 0x8000 ; Set a known free location for the stack - -; Debug - mov al, '1' ; Now in 32-bit protected mode - mov [0x000B809C], al - mov al, '0' - mov [0x000B809E], al - -; Clear out the first 4096 bytes of memory. This will store the 64-bit IDT, GDT, PML4, and PDP - mov ecx, 1024 - xor eax, eax - mov edi, eax - rep stosd - -; Clear memory for the Page Descriptor Entries (0x10000 - 0x4FFFF) - mov edi, 0x00010000 - mov ecx, 65536 - rep stosd - -; Copy the GDT to its final location in memory - mov esi, gdt64 - mov edi, 0x00001000 ; GDT address - mov ecx, (gdt64_end - gdt64) - rep movsb ; Move it to final pos. - -; Create the Level 4 Page Map. (Maps 4GBs of 2MB pages) -; First create a PML4 entry. -; PML4 is stored at 0x0000000000002000, create the first entry there -; A single PML4 entry can map 512GB with 2MB pages. - cld - mov edi, 0x00002000 ; Create a PML4 entry for the first 4GB of RAM - mov eax, 0x00003007 - stosd - xor eax, eax - stosd - - mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) - mov eax, 0x00003007 ; The higher half is identity mapped to the lower half - stosd - xor eax, eax - stosd - -; Create the PDP entries. -; The first PDP is stored at 0x0000000000003000, create the first entries there -; A single PDP entry can map 1GB with 2MB pages - mov ecx, 64 ; number of PDPE's to make.. each PDPE maps 1GB of physical memory - mov edi, 0x00003000 - mov eax, 0x00010007 ; location of first PD -create_pdpe: - stosd - push eax - xor eax, eax - stosd - pop eax - add eax, 0x00001000 ; 4K later (512 records x 8 bytes) - dec ecx - cmp ecx, 0 - jne create_pdpe - -; Create the PD entries. -; PD entries are stored starting at 0x0000000000010000 and ending at 0x000000000004FFFF (256 KiB) -; This gives us room to map 64 GiB with 2 MiB pages - mov edi, 0x00010000 - mov eax, 0x0000008F ; Bit 7 must be set to 1 as we have 2 MiB pages - xor ecx, ecx -pd_again: ; Create a 2 MiB page - stosd - push eax - xor eax, eax - stosd - pop eax - add eax, 0x00200000 - inc ecx - cmp ecx, 2048 - jne pd_again ; Create 2048 2 MiB page maps. - -; Load the GDT - lgdt [GDTR64] - -; Enable physical-address extensions (set CR4.PAE=1) - mov eax, cr4 - or eax, 0x000000020 ; PAE (Bit 5) - mov cr4, eax - -; Point cr3 at PML4 - mov eax, 0x00002008 ; Write-thru (Bit 3) - mov cr3, eax - -; Enable long mode (set EFER.LME=1) - mov ecx, 0xC0000080 ; EFER MSR number - rdmsr ; Read EFER - or eax, 0x00000100 ; LME (Bit 8) - wrmsr ; Write EFER - -; Debug - mov al, '1' ; About to make the jump into 64-bit mode - mov [0x000B809C], al - mov al, 'E' - mov [0x000B809E], al - -; Enable paging to activate long mode (set CR0.PG=1) - mov eax, cr0 - or eax, 0x80000000 ; PG (Bit 31) - mov cr0, eax - - jmp SYS64_CODE_SEL:start64 ; Jump to 64-bit mode - -align 16 -db '64' -align 16 - - -; ============================================================================= -; 64-bit mode -USE64 - -start64: -; Debug - mov al, '2' ; Now in 64-bit mode - mov [0x000B809C], al - mov al, '0' - mov [0x000B809E], al - - mov al, 2 - mov ah, 22 - call os_move_cursor - - xor rax, rax ; aka r0 - xor rbx, rbx ; aka r3 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor rbp, rbp ; aka r5 - mov rsp, 0x8000 ; aka r4 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - mov ds, ax ; Clear the legacy segment registers - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - - mov rax, clearcs64 ; Do a proper 64-bit jump. Should not be needed as the ... - jmp rax ; ... jmp SYS64_CODE_SEL:start64 would have sent us ... - nop ; .. out of compatibilty mode and into 64-bit mode -clearcs64: - xor rax, rax - - lgdt [GDTR64] ; Reload the GDT - -; Debug - mov al, '2' - mov [0x000B809C], al - mov al, '2' - mov [0x000B809E], al - -; Patch Pure64 AP code ; The AP's will be told to start execution at 0x8000 - mov edi, 0x00008030 ; We need to remove the BSP Jump call to get the AP's - mov eax, 0x90909090 ; to fall through to the AP Init code - stosd - -; Build the rest of the page tables (4GiB+) - mov rcx, 0x0000000000000000 - mov rax, 0x000000010000008F - mov rdi, 0x0000000000014000 -buildem: - stosq - add rax, 0x0000000000200000 - add rcx, 1 - cmp rcx, 30720 ; Another 60 GiB (We already mapped 4 GiB) - jne buildem - ; We have 64 GiB mapped now - -; Build a temporary IDT - xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) - - mov rcx, 32 -make_exception_gates: ; make gates for exception handlers - mov rax, exception_gate - push rax ; save the exception gate to the stack for later use - stosw ; store the low word (15..0) of the address - mov ax, SYS64_CODE_SEL - stosw ; store the segment selector - mov ax, 0x8E00 - stosw ; store exception gate marker - pop rax ; get the exception gate back - shr rax, 16 - stosw ; store the high word (31..16) of the address - shr rax, 16 - stosd ; store the extra high dword (63..32) of the address. - xor rax, rax - stosd ; reserved - dec rcx - jnz make_exception_gates - - mov rcx, 256-32 -make_interrupt_gates: ; make gates for the other interrupts - mov rax, interrupt_gate - push rax ; save the interrupt gate to the stack for later use - stosw ; store the low word (15..0) of the address - mov ax, SYS64_CODE_SEL - stosw ; store the segment selector - mov ax, 0x8F00 - stosw ; store interrupt gate marker - pop rax ; get the interrupt gate back - shr rax, 16 - stosw ; store the high word (31..16) of the address - shr rax, 16 - stosd ; store the extra high dword (63..32) of the address. - xor rax, rax - stosd ; reserved - dec rcx - jnz make_interrupt_gates - - ; Set up the exception gates for all of the CPU exceptions - ; The following code will be seriously busted if the exception gates are moved above 16MB - mov word [0x00*16], exception_gate_00 - mov word [0x01*16], exception_gate_01 - mov word [0x02*16], exception_gate_02 - mov word [0x03*16], exception_gate_03 - mov word [0x04*16], exception_gate_04 - mov word [0x05*16], exception_gate_05 - mov word [0x06*16], exception_gate_06 - mov word [0x07*16], exception_gate_07 - mov word [0x08*16], exception_gate_08 - mov word [0x09*16], exception_gate_09 - mov word [0x0A*16], exception_gate_10 - mov word [0x0B*16], exception_gate_11 - mov word [0x0C*16], exception_gate_12 - mov word [0x0D*16], exception_gate_13 - mov word [0x0E*16], exception_gate_14 - mov word [0x0F*16], exception_gate_15 - mov word [0x10*16], exception_gate_16 - mov word [0x11*16], exception_gate_17 - mov word [0x12*16], exception_gate_18 - mov word [0x13*16], exception_gate_19 - - mov rdi, 0x20 ; Set up Timer IRQ handler - mov rax, timer - call create_gate - - lidt [IDTR64] ; load IDT register - -; Debug - mov al, '2' - mov [0x000B809C], al - mov al, '4' - mov [0x000B809E], al - -; Clear memory 0xf000 - 0xf7ff for the infomap (2048 bytes) - xor rax, rax - mov rcx, 256 - mov rdi, 0x000000000000F000 -clearmapnext: - stosq - dec rcx - cmp rcx, 0 - jne clearmapnext - - call init_cpu ; Setup CPU - -; Debug - mov al, '2' ; CPU Init complete - mov [0x000B809C], al - mov al, '6' - mov [0x000B809E], al - -; Make sure exceptions are working. -; xor rax, rax -; xor rbx, rbx -; xor rcx, rcx -; xor rdx, rdx -; div rax - - call hdd_setup ; Gather Hard Drive information - -; Debug - mov al, '2' ; HDD Init complete - mov [0x000B809C], al - mov al, '8' - mov [0x000B809E], al - -; Find init64.cfg -; mov rbx, configname -; call findfile -; cmp rbx, 0 -; je near noconfig ; If the config file was not found we just use the default settings. - mov al, 1 - mov byte [cfg_default], al ; We have a config file - -; Read in the first cluster of init64.cfg -; mov rdi, 0x0000000000100000 -; call readcluster - -; Parse init64.cfg -; Get Kernel name -; get SMP setting - -; noconfig: - -; Init of SMP - call smp_setup - -; Reset the stack to the proper location (was set to 0x8000 previously) - mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... - add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. - lodsd ; Load a 32-bit value. We only want the high 8 bits - shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID - shl rax, 10 ; shift left 10 bits for a 1024byte stack - add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in - mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that - -; Debug - mov al, '3' ; SMP Init complete - mov [0x000B809C], al - mov al, 'E' - mov [0x000B809E], al - -; Calculate amount of usable RAM from Memory Map - xor rcx, rcx - mov rsi, 0x0000000000004000 ; E820 Map location -readnextrecord: - lodsq - lodsq - lodsd - cmp eax, 0 ; Are we at the end? - je endmemcalc - cmp eax, 1 ; Usuable RAM - je goodmem - cmp eax, 3 ; ACPI Reclaimable - je goodmem - cmp eax, 6 ; BIOS Reclaimable - je goodmem - lodsd - lodsq - jmp readnextrecord -goodmem: - sub rsi, 12 - lodsq - add rcx, rax - lodsq - lodsq - jmp readnextrecord - -endmemcalc: - shr rcx, 20 ; Value is in bytes so do a quick divide by 1048576 to get MiB's - add cx, 1 ; The BIOS will usually report actual memory minus 1 - and cx, 0xFFFE ; Make sure it is an even number (in case we added 1 to an even number) - mov word [mem_amount], cx - -; Convert CPU speed value to string - xor rax, rax - mov ax, [cpu_speed] - mov rdi, speedtempstring - call os_int_to_string - -; Convert CPU amount value to string - xor rax, rax - mov ax, [cpu_activated] - mov rdi, cpu_amount_string - call os_int_to_string - -; Convert RAM amount value to string - xor rax, rax - mov ax, [mem_amount] - mov rdi, memtempstring - call os_int_to_string - -; Build the infomap - mov rdi, 0x0000000000005000 - mov rax, [os_LocalAPICAddress] - stosq - mov rax, [os_IOAPICAddress] - stosq - - mov rdi, 0x0000000000005010 - mov ax, [cpu_speed] - stosw - mov ax, [cpu_activated] - stosw - mov ax, [cpu_detected] - stosw - - mov rdi, 0x0000000000005020 - mov ax, [mem_amount] - stosw - - mov rdi, 0x0000000000005030 - mov al, [cfg_mbr] - stosb - - mov rdi, 0x0000000000005040 - mov rax, [os_ACPITableAddress] - stosq - - mov rdi, 0x0000000000005050 - mov eax, [VBEModeInfoBlock.PhysBasePtr] - stosd - mov ax, [VBEModeInfoBlock.XResolution] - stosw - mov ax, [VBEModeInfoBlock.YResolution] - stosw - -; Initialization is now complete... write a message to the screen - mov rsi, msg_done - call os_print_string - -; Write an extra message if we are using the default config - cmp byte [cfg_default], 1 - je nodefaultconfig - mov al, 2 - mov ah, 28 - call os_move_cursor - mov rsi, msg_noconfig - call os_print_string -nodefaultconfig: - -; Print info on CPU, MEM, and HD - mov ax, 0x0004 - call os_move_cursor - mov rsi, msg_CPU - call os_print_string - mov rsi, speedtempstring - call os_print_string - mov rsi, msg_mhz - call os_print_string - mov rsi, cpu_amount_string - call os_print_string - - mov rsi, msg_MEM - call os_print_string - mov rsi, memtempstring - call os_print_string - mov rsi, msg_mb - call os_print_string - - mov rsi, msg_HDD - call os_print_string - mov rsi, hdtempstring - call os_print_string - mov rsi, msg_mb - call os_print_string - -; ============================================================================= -; Chainload the kernel attached to the end of the pure64.sys binary -; Windows - copy /b pure64.sys + kernel64.sys -; Unix - cat pure64.sys kernel64.sys > pure64.sys -; Max size of the resulting pure64.sys is 28672 bytes -; Uncomment the following 5 lines if you are chainloading -; mov rsi, 0x8000+6144 ; Memory offset to end of pure64.sys -; mov rdi, 0x100000 ; Destination address at the 1MiB mark -; mov rcx, 0x800 ; For a 16KiB kernel (2048 x 8) -; rep movsq ; Copy 8 bytes at a time -; jmp fini ; Print starting message and jump to kernel -; ============================================================================= - -; Print a message that the kernel is being loaded - mov ax, 0x0006 - call os_move_cursor - mov rsi, msg_loadingkernel - call os_print_string - -; Find the kernel file - mov rsi, kernelname - call findfile - cmp ax, 0x0000 - je near nokernel - -; Load 64-bit kernel from drive to 0x0000000000010000 - mov rdi, 0x0000000000100000 -readfile_getdata: -; push rax -; mov al, '.' ; Show loading progress -; call os_print_char -; pop rax - call readcluster ; store in memory - cmp ax, 0xFFFF ; Value for end of cluster chain. - jne readfile_getdata ; Are there more clusters? If so then read again.. if not fall through. - -; Print a message that the kernel has been loaded - mov rsi, msg_done - call os_print_string - -fini: ; For chainloading - -; Print a message that the kernel is being started - mov ax, 0x0008 - call os_move_cursor - mov rsi, msg_startingkernel - call os_print_string - -; Debug - mov al, ' ' ; Clear the debug messages - mov [0x000B809A], al - mov [0x000B809C], al - mov [0x000B809E], al - -; Clear all registers (skip the stack pointer) - xor rax, rax ; aka r0 - xor rbx, rbx ; aka r3 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor rbp, rbp ; aka r5 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - jmp 0x0000000000100000 ; Jump to the kernel - -nokernel: - mov al, 6 - mov ah, 0 - call os_move_cursor - mov rsi, kernelerror - call os_print_string - jmp $ - -%include "init_cpu.asm" -%include "init_hdd.asm" -%include "init_smp.asm" -%include "syscalls.asm" -%include "interrupt.asm" -%include "fat16.asm" -%include "sysvar.asm" - -; Pad to an even KB file (6 KiB) -times 6144-($-$$) db 0x90 - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Loaded from the first stage. Gather information about the system while +; in 16-bit mode (BIOS is still accessable), setup a minimal 64-bit +; enviroment, load the 64-bit kernel from the filesystem into memory and +; jump to it! +; ============================================================================= + + +USE16 +ORG 0x00008000 +start: + cli ; Disable all interrupts + xor eax, eax + xor ebx, ebx + xor ecx, ecx + xor edx, edx + xor esi, esi + xor edi, edi + xor ebp, ebp + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + mov esp, 0x8000 ; Set a known free location for the stack + +align 16 + jmp start16 ; This command will be overwritten with 'NOP's before the AP's are started + +%include "init_smp_ap.asm" ; Our AP code is at 0x8000 + +align 16 +db '16' +align 16 + +USE16 +start16: + jmp 0x0000:clearcs + +clearcs: + mov ax, [0x07FE] ; MBR sector is copied to 0x0600 + cmp ax, 0xAA55 ; Check if the word at 0x07FE is set to 0xAA55 (Boot sector marker) + jne no_mbr + mov byte [cfg_mbr], 1 ; Set for booting from a disk with a MBR +no_mbr: + +; Make sure the screen is set to 80x25 color text mode + mov ax, 0x0003 ; Set to normal (80x25 text) video mode + int 0x10 + +; Hide the cursor +; mov ax, 0x0100 +; mov cx, 0x200F +; int 0x10 + +; Print message + mov si, initStartupMsg + call print_string_16 + +; Check to make sure the CPU supports 64-bit mode... If not then bail out + mov eax, 0x80000000 ; Extended-function 8000000h. + cpuid ; Is largest extended function + cmp eax, 0x80000000 ; any function > 80000000h? + jbe near no_long_mode ; If not, no long mode. + mov eax, 0x80000001 ; Extended-function 8000001h. + cpuid ; Now EDX = extended-features flags. + bt edx, 29 ; Test if long mode is supported. + jnc near no_long_mode ; Exit if not supported. + + call isa_setup ; Setup legacy hardware + +; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. + lgdt [cs:GDTR32] ; Load GDT register + + mov eax, cr0 + or al, 0x01 ; Set protected mode bit + mov cr0, eax + + jmp 8:start32 ; Jump to 32-bit protected mode + +; 16-bit Function to print a sting to the screen +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +.repeat: + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp short .repeat +.done: + popa + ret + +; Display an error message that the CPU does not support 64-bit mode +no_long_mode: + mov si, no64msg + call print_string_16 + jmp $ + +%include "init_isa.asm" + +align 16 +GDTR32: ; Global Descriptors Table Register +dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) +dq gdt32 ; linear address of GDT + +align 16 +gdt32: +dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null desciptor +dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code desciptor +dw 0xFFFF, 0x0000, 0x9200, 0x008F ; 32-bit data desciptor +gdt32_end: + +align 16 +db '32' +align 16 + + +; ============================================================================= +; 32-bit mode +USE32 + +start32: + mov eax, 16 ; load 4 GB data descriptor + mov ds, ax ; to all data segment registers + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + xor eax, eax + xor ebx, ebx + xor ecx, ecx + xor edx, edx + xor esi, esi + xor edi, edi + xor ebp, ebp + mov esp, 0x8000 ; Set a known free location for the stack + +; Debug + mov al, '1' ; Now in 32-bit protected mode + mov [0x000B809C], al + mov al, '0' + mov [0x000B809E], al + +; Clear out the first 4096 bytes of memory. This will store the 64-bit IDT, GDT, PML4, and PDP + mov ecx, 1024 + xor eax, eax + mov edi, eax + rep stosd + +; Clear memory for the Page Descriptor Entries (0x10000 - 0x4FFFF) + mov edi, 0x00010000 + mov ecx, 65536 + rep stosd + +; Copy the GDT to its final location in memory + mov esi, gdt64 + mov edi, 0x00001000 ; GDT address + mov ecx, (gdt64_end - gdt64) + rep movsb ; Move it to final pos. + +; Create the Level 4 Page Map. (Maps 4GBs of 2MB pages) +; First create a PML4 entry. +; PML4 is stored at 0x0000000000002000, create the first entry there +; A single PML4 entry can map 512GB with 2MB pages. + cld + mov edi, 0x00002000 ; Create a PML4 entry for the first 4GB of RAM + mov eax, 0x00003007 + stosd + xor eax, eax + stosd + + mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) + mov eax, 0x00003007 ; The higher half is identity mapped to the lower half + stosd + xor eax, eax + stosd + +; Create the PDP entries. +; The first PDP is stored at 0x0000000000003000, create the first entries there +; A single PDP entry can map 1GB with 2MB pages + mov ecx, 64 ; number of PDPE's to make.. each PDPE maps 1GB of physical memory + mov edi, 0x00003000 + mov eax, 0x00010007 ; location of first PD +create_pdpe: + stosd + push eax + xor eax, eax + stosd + pop eax + add eax, 0x00001000 ; 4K later (512 records x 8 bytes) + dec ecx + cmp ecx, 0 + jne create_pdpe + +; Create the PD entries. +; PD entries are stored starting at 0x0000000000010000 and ending at 0x000000000004FFFF (256 KiB) +; This gives us room to map 64 GiB with 2 MiB pages + mov edi, 0x00010000 + mov eax, 0x0000008F ; Bit 7 must be set to 1 as we have 2 MiB pages + xor ecx, ecx +pd_again: ; Create a 2 MiB page + stosd + push eax + xor eax, eax + stosd + pop eax + add eax, 0x00200000 + inc ecx + cmp ecx, 2048 + jne pd_again ; Create 2048 2 MiB page maps. + +; Load the GDT + lgdt [GDTR64] + +; Enable physical-address extensions (set CR4.PAE=1) + mov eax, cr4 + or eax, 0x000000020 ; PAE (Bit 5) + mov cr4, eax + +; Point cr3 at PML4 + mov eax, 0x00002008 ; Write-thru (Bit 3) + mov cr3, eax + +; Enable long mode (set EFER.LME=1) + mov ecx, 0xC0000080 ; EFER MSR number + rdmsr ; Read EFER + or eax, 0x00000100 ; LME (Bit 8) + wrmsr ; Write EFER + +; Debug + mov al, '1' ; About to make the jump into 64-bit mode + mov [0x000B809C], al + mov al, 'E' + mov [0x000B809E], al + +; Enable paging to activate long mode (set CR0.PG=1) + mov eax, cr0 + or eax, 0x80000000 ; PG (Bit 31) + mov cr0, eax + + jmp SYS64_CODE_SEL:start64 ; Jump to 64-bit mode + +align 16 +db '64' +align 16 + + +; ============================================================================= +; 64-bit mode +USE64 + +start64: +; Debug + mov al, '2' ; Now in 64-bit mode + mov [0x000B809C], al + mov al, '0' + mov [0x000B809E], al + + mov al, 2 + mov ah, 22 + call os_move_cursor + + xor rax, rax ; aka r0 + xor rbx, rbx ; aka r3 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor rbp, rbp ; aka r5 + mov rsp, 0x8000 ; aka r4 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + mov ds, ax ; Clear the legacy segment registers + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + mov rax, clearcs64 ; Do a proper 64-bit jump. Should not be needed as the ... + jmp rax ; ... jmp SYS64_CODE_SEL:start64 would have sent us ... + nop ; .. out of compatibilty mode and into 64-bit mode +clearcs64: + xor rax, rax + + lgdt [GDTR64] ; Reload the GDT + +; Debug + mov al, '2' + mov [0x000B809C], al + mov al, '2' + mov [0x000B809E], al + +; Patch Pure64 AP code ; The AP's will be told to start execution at 0x8000 + mov edi, 0x00008030 ; We need to remove the BSP Jump call to get the AP's + mov eax, 0x90909090 ; to fall through to the AP Init code + stosd + +; Build the rest of the page tables (4GiB+) + mov rcx, 0x0000000000000000 + mov rax, 0x000000010000008F + mov rdi, 0x0000000000014000 +buildem: + stosq + add rax, 0x0000000000200000 + add rcx, 1 + cmp rcx, 30720 ; Another 60 GiB (We already mapped 4 GiB) + jne buildem + ; We have 64 GiB mapped now + +; Build a temporary IDT + xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) + + mov rcx, 32 +make_exception_gates: ; make gates for exception handlers + mov rax, exception_gate + push rax ; save the exception gate to the stack for later use + stosw ; store the low word (15..0) of the address + mov ax, SYS64_CODE_SEL + stosw ; store the segment selector + mov ax, 0x8E00 + stosw ; store exception gate marker + pop rax ; get the exception gate back + shr rax, 16 + stosw ; store the high word (31..16) of the address + shr rax, 16 + stosd ; store the extra high dword (63..32) of the address. + xor rax, rax + stosd ; reserved + dec rcx + jnz make_exception_gates + + mov rcx, 256-32 +make_interrupt_gates: ; make gates for the other interrupts + mov rax, interrupt_gate + push rax ; save the interrupt gate to the stack for later use + stosw ; store the low word (15..0) of the address + mov ax, SYS64_CODE_SEL + stosw ; store the segment selector + mov ax, 0x8F00 + stosw ; store interrupt gate marker + pop rax ; get the interrupt gate back + shr rax, 16 + stosw ; store the high word (31..16) of the address + shr rax, 16 + stosd ; store the extra high dword (63..32) of the address. + xor rax, rax + stosd ; reserved + dec rcx + jnz make_interrupt_gates + + ; Set up the exception gates for all of the CPU exceptions + ; The following code will be seriously busted if the exception gates are moved above 16MB + mov word [0x00*16], exception_gate_00 + mov word [0x01*16], exception_gate_01 + mov word [0x02*16], exception_gate_02 + mov word [0x03*16], exception_gate_03 + mov word [0x04*16], exception_gate_04 + mov word [0x05*16], exception_gate_05 + mov word [0x06*16], exception_gate_06 + mov word [0x07*16], exception_gate_07 + mov word [0x08*16], exception_gate_08 + mov word [0x09*16], exception_gate_09 + mov word [0x0A*16], exception_gate_10 + mov word [0x0B*16], exception_gate_11 + mov word [0x0C*16], exception_gate_12 + mov word [0x0D*16], exception_gate_13 + mov word [0x0E*16], exception_gate_14 + mov word [0x0F*16], exception_gate_15 + mov word [0x10*16], exception_gate_16 + mov word [0x11*16], exception_gate_17 + mov word [0x12*16], exception_gate_18 + mov word [0x13*16], exception_gate_19 + + mov rdi, 0x20 ; Set up Timer IRQ handler + mov rax, timer + call create_gate + + lidt [IDTR64] ; load IDT register + +; Debug + mov al, '2' + mov [0x000B809C], al + mov al, '4' + mov [0x000B809E], al + +; Clear memory 0xf000 - 0xf7ff for the infomap (2048 bytes) + xor rax, rax + mov rcx, 256 + mov rdi, 0x000000000000F000 +clearmapnext: + stosq + dec rcx + cmp rcx, 0 + jne clearmapnext + + call init_cpu ; Setup CPU + +; Debug + mov al, '2' ; CPU Init complete + mov [0x000B809C], al + mov al, '6' + mov [0x000B809E], al + +; Make sure exceptions are working. +; xor rax, rax +; xor rbx, rbx +; xor rcx, rcx +; xor rdx, rdx +; div rax + + call hdd_setup ; Gather Hard Drive information + +; Debug + mov al, '2' ; HDD Init complete + mov [0x000B809C], al + mov al, '8' + mov [0x000B809E], al + +; Find init64.cfg +; mov rbx, configname +; call findfile +; cmp rbx, 0 +; je near noconfig ; If the config file was not found we just use the default settings. + mov al, 1 + mov byte [cfg_default], al ; We have a config file + +; Read in the first cluster of init64.cfg +; mov rdi, 0x0000000000100000 +; call readcluster + +; Parse init64.cfg +; Get Kernel name +; get SMP setting + +; noconfig: + +; Init of SMP + call smp_setup + +; Reset the stack to the proper location (was set to 0x8000 previously) + mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... + add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. + lodsd ; Load a 32-bit value. We only want the high 8 bits + shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID + shl rax, 10 ; shift left 10 bits for a 1024byte stack + add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in + mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that + +; Debug + mov al, '3' ; SMP Init complete + mov [0x000B809C], al + mov al, 'E' + mov [0x000B809E], al + +; Calculate amount of usable RAM from Memory Map + xor rcx, rcx + mov rsi, 0x0000000000004000 ; E820 Map location +readnextrecord: + lodsq + lodsq + lodsd + cmp eax, 0 ; Are we at the end? + je endmemcalc + cmp eax, 1 ; Usuable RAM + je goodmem + cmp eax, 3 ; ACPI Reclaimable + je goodmem + cmp eax, 6 ; BIOS Reclaimable + je goodmem + lodsd + lodsq + jmp readnextrecord +goodmem: + sub rsi, 12 + lodsq + add rcx, rax + lodsq + lodsq + jmp readnextrecord + +endmemcalc: + shr rcx, 20 ; Value is in bytes so do a quick divide by 1048576 to get MiB's + add cx, 1 ; The BIOS will usually report actual memory minus 1 + and cx, 0xFFFE ; Make sure it is an even number (in case we added 1 to an even number) + mov word [mem_amount], cx + +; Convert CPU speed value to string + xor rax, rax + mov ax, [cpu_speed] + mov rdi, speedtempstring + call os_int_to_string + +; Convert CPU amount value to string + xor rax, rax + mov ax, [cpu_activated] + mov rdi, cpu_amount_string + call os_int_to_string + +; Convert RAM amount value to string + xor rax, rax + mov ax, [mem_amount] + mov rdi, memtempstring + call os_int_to_string + +; Build the infomap + mov rdi, 0x0000000000005000 + mov rax, [os_LocalAPICAddress] + stosq + mov rax, [os_IOAPICAddress] + stosq + + mov rdi, 0x0000000000005010 + mov ax, [cpu_speed] + stosw + mov ax, [cpu_activated] + stosw + mov ax, [cpu_detected] + stosw + + mov rdi, 0x0000000000005020 + mov ax, [mem_amount] + stosw + + mov rdi, 0x0000000000005030 + mov al, [cfg_mbr] + stosb + + mov rdi, 0x0000000000005040 + mov rax, [os_ACPITableAddress] + stosq + + mov rdi, 0x0000000000005050 + mov eax, [VBEModeInfoBlock.PhysBasePtr] + stosd + mov ax, [VBEModeInfoBlock.XResolution] + stosw + mov ax, [VBEModeInfoBlock.YResolution] + stosw + +; Initialization is now complete... write a message to the screen + mov rsi, msg_done + call os_print_string + +; Write an extra message if we are using the default config + cmp byte [cfg_default], 1 + je nodefaultconfig + mov al, 2 + mov ah, 28 + call os_move_cursor + mov rsi, msg_noconfig + call os_print_string +nodefaultconfig: + +; Print info on CPU, MEM, and HD + mov ax, 0x0004 + call os_move_cursor + mov rsi, msg_CPU + call os_print_string + mov rsi, speedtempstring + call os_print_string + mov rsi, msg_mhz + call os_print_string + mov rsi, cpu_amount_string + call os_print_string + + mov rsi, msg_MEM + call os_print_string + mov rsi, memtempstring + call os_print_string + mov rsi, msg_mb + call os_print_string + + mov rsi, msg_HDD + call os_print_string + mov rsi, hdtempstring + call os_print_string + mov rsi, msg_mb + call os_print_string + +; ============================================================================= +; Chainload the kernel attached to the end of the pure64.sys binary +; Windows - copy /b pure64.sys + kernel64.sys +; Unix - cat pure64.sys kernel64.sys > pure64.sys +; Max size of the resulting pure64.sys is 28672 bytes +; Uncomment the following 5 lines if you are chainloading +; mov rsi, 0x8000+6144 ; Memory offset to end of pure64.sys +; mov rdi, 0x100000 ; Destination address at the 1MiB mark +; mov rcx, 0x800 ; For a 16KiB kernel (2048 x 8) +; rep movsq ; Copy 8 bytes at a time +; jmp fini ; Print starting message and jump to kernel +; ============================================================================= + +; Print a message that the kernel is being loaded + mov ax, 0x0006 + call os_move_cursor + mov rsi, msg_loadingkernel + call os_print_string + +; Find the kernel file + mov rsi, kernelname + call findfile + cmp ax, 0x0000 + je near nokernel + +; Load 64-bit kernel from drive to 0x0000000000010000 + mov rdi, 0x0000000000100000 +readfile_getdata: +; push rax +; mov al, '.' ; Show loading progress +; call os_print_char +; pop rax + call readcluster ; store in memory + cmp ax, 0xFFFF ; Value for end of cluster chain. + jne readfile_getdata ; Are there more clusters? If so then read again.. if not fall through. + +; Print a message that the kernel has been loaded + mov rsi, msg_done + call os_print_string + +fini: ; For chainloading + +; Print a message that the kernel is being started + mov ax, 0x0008 + call os_move_cursor + mov rsi, msg_startingkernel + call os_print_string + +; Debug + mov al, ' ' ; Clear the debug messages + mov [0x000B809A], al + mov [0x000B809C], al + mov [0x000B809E], al + +; Clear all registers (skip the stack pointer) + xor rax, rax ; aka r0 + xor rbx, rbx ; aka r3 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor rbp, rbp ; aka r5 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + jmp 0x0000000000100000 ; Jump to the kernel + +nokernel: + mov al, 6 + mov ah, 0 + call os_move_cursor + mov rsi, kernelerror + call os_print_string + jmp $ + +%include "init_cpu.asm" +%include "init_hdd.asm" +%include "init_smp.asm" +%include "syscalls.asm" +%include "interrupt.asm" +%include "fat16.asm" +%include "sysvar.asm" + +; Pad to an even KB file (6 KiB) +times 6144-($-$$) db 0x90 + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/syscalls.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/syscalls.asm index e8ef7738..6456b62a 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/syscalls.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/syscalls.asm @@ -1,468 +1,468 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; System Calls -; ================================================================= - - -; ----------------------------------------------------------------------------- -; os_move_cursor -- Moves the virtual cursor in text mode -; IN: AH, AL = row, column -; OUT: Nothing. All registers preserved -os_move_cursor: - push rcx - push rbx - push rax - - mov [screen_cursor_x], ah - mov [screen_cursor_y], al - - and rax, 0x000000000000FFFF ; only keep the low 16 bits - ;calculate the new offset - mov cl, 80 - mul cl ; AX = AL * CL - xor rbx, rbx - mov bl, [screen_cursor_x] - add ax, bx - shl ax, 1 ; multiply by 2 - - add rax, 0x00000000000B8000 - mov [screen_cursor_offset], rax - - pop rax - pop rbx - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_newline -- Reset cursor to start of next line and scroll if needed -; IN: Nothing -; OUT: Nothing, all registers perserved -os_print_newline: - push rax - - mov ah, 0 ; Set the cursor x value to 0 - mov al, [screen_cursor_y] ; Grab the cursor y value - cmp al, 24 ; Compare to see if we are on the last line - je os_print_newline_scroll ; If so then we need to scroll the sreen - - inc al ; If not then we can go ahead an increment the y value - jmp os_print_newline_done - -os_print_newline_scroll: - mov ax, 0x0000 ; If we have reached the end then wrap back to the front - -os_print_newline_done: - call os_move_cursor ; update the cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_string -- Displays text -; IN: RSI = message location (zero-terminated string) -; OUT: Nothing, all registers perserved -os_print_string: - push rsi - push rax - - cld ; Clear the direction flag.. we want to increment through the string - -os_print_string_nextchar: - lodsb ; Get char from string and store in AL - cmp al, 0 ; Strings are Zero terminated. - je os_print_string_done ; If char is Zero then it is the end of the string - - cmp al, 13 ; Check if there was a newline character in the string - je os_print_string_newline ; If so then we print a new line - - call os_print_char - - jmp os_print_string_nextchar - -os_print_string_newline: - call os_print_newline - jmp os_print_string_nextchar - -os_print_string_done: - pop rax - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char -- Displays a char -; IN: AL = char to display -; OUT: Nothing. All registers preserved -os_print_char: - push rdi - - mov rdi, [screen_cursor_offset] - stosb - add qword [screen_cursor_offset], 2 ; Add 2 (1 byte for char and 1 byte for attribute) - - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_hex -- Displays a char in hex mode -; IN: AL = char to display -; OUT: Nothing. All registers preserved -os_print_char_hex: - push rbx - push rax - - mov rbx, hextable - - push rax ; save rax for the next part - shr al, 4 ; we want to work on the high part so shift right by 4 bits - xlatb - call os_print_char - - pop rax - and al, 0x0f ; we want to work on the low part so clear the high part - xlatb - call os_print_char - - pop rax - pop rbx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_copy -- Copy the contents of one string into another -; IN: RSI = source -; RDI = destination -; OUT: Nothing. All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_copy: - push rsi - push rdi - push rax - -os_string_copy_more: - lodsb ; Load a character from the source string - stosb - cmp al, 0 ; If source string is empty, quit out - jne os_string_copy_more - - pop rax - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_compare -- See if two strings match -; IN: RSI = string one -; RDI = string two -; OUT: Carry flag set if same -os_string_compare: - push rsi - push rdi - push rbx - push rax - -os_string_compare_more: - mov al, [rsi] ; Store string contents - mov bl, [rdi] - - cmp al, 0 ; End of first string? - je os_string_compare_terminated - - cmp al, bl - jne os_string_compare_not_same - - inc rsi - inc rdi - jmp os_string_compare_more - -os_string_compare_not_same: - pop rax - pop rbx - pop rdi - pop rsi - clc - ret - -os_string_compare_terminated: - cmp bl, 0 ; End of second string? - jne os_string_compare_not_same - - pop rax - pop rbx - pop rdi - pop rsi - stc - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_uppercase -- Convert zero-terminated string to uppercase -; IN: RSI = string location -; OUT: Nothing. All registers preserved -os_string_uppercase: - push rsi - -os_string_uppercase_more: - cmp byte [rsi], 0x00 ; Zero-termination of string? - je os_string_uppercase_done ; If so, quit - - cmp byte [rsi], 97 ; In the uppercase A to Z range? - jl os_string_uppercase_noatoz - cmp byte [rsi], 122 - jg os_string_uppercase_noatoz - - sub byte [rsi], 0x20 ; If so, convert input char to uppercase - - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_noatoz: - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_done: - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_dump_regs -- Dump the values on the registers to the screen (For debug purposes) -; IN/OUT: Nothing -; FIX: Clean this up.. it could be shorter with loops. -os_dump_regs: - push r15 - push r14 - push r13 - push r12 - push r11 - push r10 - push r9 - push r8 - push rsp - push rbp - push rdi - push rsi - push rdx - push rcx - push rbx - push rax - - mov byte [os_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting - -os_dump_regs_again: - mov rsi, os_dump_reg_string00 - xor rax, rax - xor rbx, rbx - mov al, [os_dump_reg_stage] - mov bl, 5 ; each string is 5 bytes - mul bl ; ax = bl x al - add rsi, rax - call os_print_string ; Print the register name - - mov rdi, os_dump_reg_tstring - pop rax - call os_int_to_hex_string ; Convert the register value to a hex string - mov rsi, os_dump_reg_tstring - call os_print_string ; Print the hex string - - inc byte [os_dump_reg_stage] - cmp byte [os_dump_reg_stage], 0x10 - jne os_dump_regs_again - -; call os_print_newline - -ret - -os_dump_reg_string00: db ' A:', 0 -os_dump_reg_string01: db ' B:', 0 -os_dump_reg_string02: db ' C:', 0 -os_dump_reg_string03: db ' D:', 0 -os_dump_reg_string04: db ' SI:', 0 -os_dump_reg_string05: db ' DI:', 0 -os_dump_reg_string06: db ' BP:', 0 -os_dump_reg_string07: db ' SP:', 0 -os_dump_reg_string08: db ' 8:', 0 -os_dump_reg_string09: db ' 9:', 0 -os_dump_reg_string0A: db ' 10:', 0 -os_dump_reg_string0B: db ' 11:', 0 -os_dump_reg_string0C: db ' 12:', 0 -os_dump_reg_string0D: db ' 13:', 0 -os_dump_reg_string0E: db ' 14:', 0 -os_dump_reg_string0F: db ' 15:', 0 - -os_dump_reg_tstring: times 17 db 0 -os_dump_reg_stage: db 0x00 -; ----------------------------------------------------------------------------- - - - -; ----------------------------------------------------------------------------- -; os_dump_mem -- Dump some memory content to the screen (For debug purposes) -; IN: RSI = memory to dump (512bytes) -;OUT: -os_dump_mem: - push rdx - push rcx - push rbx - push rax - - push rsi - - mov rcx, 512 -dumpit: - lodsb - call os_print_char_hex - dec rcx - cmp rcx, 0 - jne dumpit - - pop rsi - -; call os_print_newline - - pop rax - pop rbx - pop rcx - pop rdx -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_int_to_string -- Convert a binary interger into an string string -; IN: RAX = binary integer -; RDI = location to store string -; OUT: RDI = pointer to end of string -; All other registers preserved -; Min return value is 0 and max return value is 18446744073709551615 so your -; string needs to be able to store at least 21 characters (20 for the number -; and 1 for the string terminator). -; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s -os_int_to_string: - push rdx - push rcx - push rbx - push rax - - mov rbx, 10 ; base of the decimal system - xor rcx, rcx ; number of digits generated -os_int_to_string_next_divide: - xor rdx, rdx ; RAX extended to (RDX,RAX) - div rbx ; divide by the number-base - push rdx ; save remainder on the stack - inc rcx ; and count this remainder - cmp rax, 0x0 ; was the quotient zero? - jne os_int_to_string_next_divide ; no, do another division -os_int_to_string_next_digit: - pop rdx ; else pop recent remainder - add dl, '0' ; and convert to a numeral - mov [rdi], dl ; store to memory-buffer - inc rdi - loop os_int_to_string_next_digit ; again for other remainders - mov al, 0x00 - stosb ; Store the null terminator at the end of the string - - pop rax - pop rbx - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_int_to_hex_string -- Convert an integer to a hex string -; IN: RAX = Integer value -; RDI = location to store string -; OUT: Nothing. All registers preserved -os_int_to_hex_string: - push rdi - push rdx - push rcx - push rbx - push rax - - mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes -os_int_to_hex_string_next_nibble: - rol rax, 4 ; next nibble into AL - mov bl, al ; copy nibble into BL - and rbx, 0x0F ; and convert to word - mov dl, [hextable + rbx] ; lookup ascii numeral - push rax - mov al, dl - stosb - pop rax - loop os_int_to_hex_string_next_nibble ; again for next nibble - xor rax, rax ; clear RAX to 0 - stosb ; Store AL to terminate string - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_serial_write -- Send a byte over the primary serial port -; IN: AL = Byte to send over serial port -; OUT: Nothing, all registers preserved -os_serial_send: - push rdx - push rax ; Save RAX since the serial line status check clobbers AL - - mov dx, 0x03FD ; Serial Line Status register -os_serial_send_wait: - in al, dx - bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag - jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte - - pop rax ; Get the byte back from the stack - mov dx, 0x03F8 ; Serial data register - out dx, al ; Send the byte - - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; create_gate -; rax = address of handler -; rdi = gate # to configure -create_gate: - push rdi - push rax - - shl rdi, 4 ; quickly multiply rdi by 16 - stosw ; store the low word (15..0) - shr rax, 16 - add rdi, 4 ; skip the gate marker - stosw ; store the high word (31..16) - shr rax, 16 - stosd ; store the high dword (63..32) - - pop rax - pop rdi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; System Calls +; ================================================================= + + +; ----------------------------------------------------------------------------- +; os_move_cursor -- Moves the virtual cursor in text mode +; IN: AH, AL = row, column +; OUT: Nothing. All registers preserved +os_move_cursor: + push rcx + push rbx + push rax + + mov [screen_cursor_x], ah + mov [screen_cursor_y], al + + and rax, 0x000000000000FFFF ; only keep the low 16 bits + ;calculate the new offset + mov cl, 80 + mul cl ; AX = AL * CL + xor rbx, rbx + mov bl, [screen_cursor_x] + add ax, bx + shl ax, 1 ; multiply by 2 + + add rax, 0x00000000000B8000 + mov [screen_cursor_offset], rax + + pop rax + pop rbx + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_newline -- Reset cursor to start of next line and scroll if needed +; IN: Nothing +; OUT: Nothing, all registers perserved +os_print_newline: + push rax + + mov ah, 0 ; Set the cursor x value to 0 + mov al, [screen_cursor_y] ; Grab the cursor y value + cmp al, 24 ; Compare to see if we are on the last line + je os_print_newline_scroll ; If so then we need to scroll the sreen + + inc al ; If not then we can go ahead an increment the y value + jmp os_print_newline_done + +os_print_newline_scroll: + mov ax, 0x0000 ; If we have reached the end then wrap back to the front + +os_print_newline_done: + call os_move_cursor ; update the cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_string -- Displays text +; IN: RSI = message location (zero-terminated string) +; OUT: Nothing, all registers perserved +os_print_string: + push rsi + push rax + + cld ; Clear the direction flag.. we want to increment through the string + +os_print_string_nextchar: + lodsb ; Get char from string and store in AL + cmp al, 0 ; Strings are Zero terminated. + je os_print_string_done ; If char is Zero then it is the end of the string + + cmp al, 13 ; Check if there was a newline character in the string + je os_print_string_newline ; If so then we print a new line + + call os_print_char + + jmp os_print_string_nextchar + +os_print_string_newline: + call os_print_newline + jmp os_print_string_nextchar + +os_print_string_done: + pop rax + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char -- Displays a char +; IN: AL = char to display +; OUT: Nothing. All registers preserved +os_print_char: + push rdi + + mov rdi, [screen_cursor_offset] + stosb + add qword [screen_cursor_offset], 2 ; Add 2 (1 byte for char and 1 byte for attribute) + + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_hex -- Displays a char in hex mode +; IN: AL = char to display +; OUT: Nothing. All registers preserved +os_print_char_hex: + push rbx + push rax + + mov rbx, hextable + + push rax ; save rax for the next part + shr al, 4 ; we want to work on the high part so shift right by 4 bits + xlatb + call os_print_char + + pop rax + and al, 0x0f ; we want to work on the low part so clear the high part + xlatb + call os_print_char + + pop rax + pop rbx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_copy -- Copy the contents of one string into another +; IN: RSI = source +; RDI = destination +; OUT: Nothing. All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_copy: + push rsi + push rdi + push rax + +os_string_copy_more: + lodsb ; Load a character from the source string + stosb + cmp al, 0 ; If source string is empty, quit out + jne os_string_copy_more + + pop rax + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_compare -- See if two strings match +; IN: RSI = string one +; RDI = string two +; OUT: Carry flag set if same +os_string_compare: + push rsi + push rdi + push rbx + push rax + +os_string_compare_more: + mov al, [rsi] ; Store string contents + mov bl, [rdi] + + cmp al, 0 ; End of first string? + je os_string_compare_terminated + + cmp al, bl + jne os_string_compare_not_same + + inc rsi + inc rdi + jmp os_string_compare_more + +os_string_compare_not_same: + pop rax + pop rbx + pop rdi + pop rsi + clc + ret + +os_string_compare_terminated: + cmp bl, 0 ; End of second string? + jne os_string_compare_not_same + + pop rax + pop rbx + pop rdi + pop rsi + stc + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_uppercase -- Convert zero-terminated string to uppercase +; IN: RSI = string location +; OUT: Nothing. All registers preserved +os_string_uppercase: + push rsi + +os_string_uppercase_more: + cmp byte [rsi], 0x00 ; Zero-termination of string? + je os_string_uppercase_done ; If so, quit + + cmp byte [rsi], 97 ; In the uppercase A to Z range? + jl os_string_uppercase_noatoz + cmp byte [rsi], 122 + jg os_string_uppercase_noatoz + + sub byte [rsi], 0x20 ; If so, convert input char to uppercase + + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_noatoz: + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_done: + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_dump_regs -- Dump the values on the registers to the screen (For debug purposes) +; IN/OUT: Nothing +; FIX: Clean this up.. it could be shorter with loops. +os_dump_regs: + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rsp + push rbp + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + + mov byte [os_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting + +os_dump_regs_again: + mov rsi, os_dump_reg_string00 + xor rax, rax + xor rbx, rbx + mov al, [os_dump_reg_stage] + mov bl, 5 ; each string is 5 bytes + mul bl ; ax = bl x al + add rsi, rax + call os_print_string ; Print the register name + + mov rdi, os_dump_reg_tstring + pop rax + call os_int_to_hex_string ; Convert the register value to a hex string + mov rsi, os_dump_reg_tstring + call os_print_string ; Print the hex string + + inc byte [os_dump_reg_stage] + cmp byte [os_dump_reg_stage], 0x10 + jne os_dump_regs_again + +; call os_print_newline + +ret + +os_dump_reg_string00: db ' A:', 0 +os_dump_reg_string01: db ' B:', 0 +os_dump_reg_string02: db ' C:', 0 +os_dump_reg_string03: db ' D:', 0 +os_dump_reg_string04: db ' SI:', 0 +os_dump_reg_string05: db ' DI:', 0 +os_dump_reg_string06: db ' BP:', 0 +os_dump_reg_string07: db ' SP:', 0 +os_dump_reg_string08: db ' 8:', 0 +os_dump_reg_string09: db ' 9:', 0 +os_dump_reg_string0A: db ' 10:', 0 +os_dump_reg_string0B: db ' 11:', 0 +os_dump_reg_string0C: db ' 12:', 0 +os_dump_reg_string0D: db ' 13:', 0 +os_dump_reg_string0E: db ' 14:', 0 +os_dump_reg_string0F: db ' 15:', 0 + +os_dump_reg_tstring: times 17 db 0 +os_dump_reg_stage: db 0x00 +; ----------------------------------------------------------------------------- + + + +; ----------------------------------------------------------------------------- +; os_dump_mem -- Dump some memory content to the screen (For debug purposes) +; IN: RSI = memory to dump (512bytes) +;OUT: +os_dump_mem: + push rdx + push rcx + push rbx + push rax + + push rsi + + mov rcx, 512 +dumpit: + lodsb + call os_print_char_hex + dec rcx + cmp rcx, 0 + jne dumpit + + pop rsi + +; call os_print_newline + + pop rax + pop rbx + pop rcx + pop rdx +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_int_to_string -- Convert a binary interger into an string string +; IN: RAX = binary integer +; RDI = location to store string +; OUT: RDI = pointer to end of string +; All other registers preserved +; Min return value is 0 and max return value is 18446744073709551615 so your +; string needs to be able to store at least 21 characters (20 for the number +; and 1 for the string terminator). +; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s +os_int_to_string: + push rdx + push rcx + push rbx + push rax + + mov rbx, 10 ; base of the decimal system + xor rcx, rcx ; number of digits generated +os_int_to_string_next_divide: + xor rdx, rdx ; RAX extended to (RDX,RAX) + div rbx ; divide by the number-base + push rdx ; save remainder on the stack + inc rcx ; and count this remainder + cmp rax, 0x0 ; was the quotient zero? + jne os_int_to_string_next_divide ; no, do another division +os_int_to_string_next_digit: + pop rdx ; else pop recent remainder + add dl, '0' ; and convert to a numeral + mov [rdi], dl ; store to memory-buffer + inc rdi + loop os_int_to_string_next_digit ; again for other remainders + mov al, 0x00 + stosb ; Store the null terminator at the end of the string + + pop rax + pop rbx + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_int_to_hex_string -- Convert an integer to a hex string +; IN: RAX = Integer value +; RDI = location to store string +; OUT: Nothing. All registers preserved +os_int_to_hex_string: + push rdi + push rdx + push rcx + push rbx + push rax + + mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes +os_int_to_hex_string_next_nibble: + rol rax, 4 ; next nibble into AL + mov bl, al ; copy nibble into BL + and rbx, 0x0F ; and convert to word + mov dl, [hextable + rbx] ; lookup ascii numeral + push rax + mov al, dl + stosb + pop rax + loop os_int_to_hex_string_next_nibble ; again for next nibble + xor rax, rax ; clear RAX to 0 + stosb ; Store AL to terminate string + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_serial_write -- Send a byte over the primary serial port +; IN: AL = Byte to send over serial port +; OUT: Nothing, all registers preserved +os_serial_send: + push rdx + push rax ; Save RAX since the serial line status check clobbers AL + + mov dx, 0x03FD ; Serial Line Status register +os_serial_send_wait: + in al, dx + bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag + jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte + + pop rax ; Get the byte back from the stack + mov dx, 0x03F8 ; Serial data register + out dx, al ; Send the byte + + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; create_gate +; rax = address of handler +; rdi = gate # to configure +create_gate: + push rdi + push rax + + shl rdi, 4 ; quickly multiply rdi by 16 + stosw ; store the low word (15..0) + shr rax, 16 + add rdi, 4 ; skip the gate marker + stosw ; store the high word (31..16) + shr rax, 16 + stosd ; store the high dword (63..32) + + pop rax + pop rdi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/sysvar.asm b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/sysvar.asm index 9d906271..25562328 100644 --- a/amd64/bareMetalOS-0.5.2/pure64.boot0/src/sysvar.asm +++ b/amd64/bareMetalOS-0.5.2/pure64.boot0/src/sysvar.asm @@ -1,160 +1,160 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; System Variables -; ============================================================================= - - -;CONFIG -cfg_smpinit: db 1 ; By default SMP is enabled. Set to 0 to disable. -cfg_vesa: db 0 ; By default VESA is disabled. Set to 1 to enable. -cfg_default: db 0 ; By default we don't need a config file so set to 0. If a config file is found set to 1. -cfg_e820: db 1 ; By default E820 should be present. Pure64 will set this to 0 if not found/usable. -cfg_mbr: db 0 ; Did we boot off of a disk with a proper MBR - -; Memory locations -E820Map: equ 0x0000000000004000 -InfoMap: equ 0x0000000000005000 -SystemVariables: equ 0x0000000000005A00 -VBEModeInfoBlock equ 0x0000000000005C00 -hdbuffer: equ 0x0000000000070000 ; 32768 bytes = 0x6000 -> 0xDFFF VERIFY THIS!!! -hdbuffer1: equ 0x000000000007E000 ; 512 bytes = 0xE000 -> 0xE1FF VERIFY THIS!!! - -; DQ - Starting at offset 0, increments by 0x8 -os_LocalAPICAddress: equ SystemVariables + 0x00 -os_IOAPICAddress: equ SystemVariables + 0x08 -os_ACPITableAddress: equ SystemVariables + 0x10 -screen_cursor_offset: equ SystemVariables + 0x18 -hd1_maxlba: equ SystemVariables + 0x20 -os_Counter: equ SystemVariables + 0x28 - -; DD - Starting at offset 128, increments by 4 -hd1_size: equ SystemVariables + 128 -fat16_FatStart: equ SystemVariables + 132 -fat16_TotalSectors: equ SystemVariables + 136 -fat16_DataStart: equ SystemVariables + 140 -fat16_RootStart: equ SystemVariables + 144 -fat16_PartitionOffset: equ SystemVariables + 148 - -; DW - Starting at offset 256, increments by 2 -cpu_speed: equ SystemVariables + 256 -cpu_activated: equ SystemVariables + 258 -cpu_detected: equ SystemVariables + 260 -mem_amount: equ SystemVariables + 262 -fat16_BytesPerSector: equ SystemVariables + 264 -fat16_ReservedSectors: equ SystemVariables + 266 -fat16_SectorsPerFat: equ SystemVariables + 268 -fat16_RootDirEnts: equ SystemVariables + 270 - -; DB - Starting at offset 384, increments by 1 -hd1_enable: equ SystemVariables + 384 -hd1_lba48: equ SystemVariables + 385 -screen_cursor_x: equ SystemVariables + 386 -screen_cursor_y: equ SystemVariables + 387 -fat16_SectorsPerCluster: equ SystemVariables + 388 -fat16_Fats: equ SystemVariables + 389 -memtempstring: equ SystemVariables + 390 -speedtempstring: equ SystemVariables + 400 -cpu_amount_string: equ SystemVariables + 410 -hdtempstring: equ SystemVariables + 420 - -;MISC -screen_cols: db 80 -screen_rows: db 25 -hextable: db '0123456789ABCDEF' - -;STRINGS -kernelerror: db 'FATAL ERROR: Software not found.', 0 -kernelname: db 'KERNEL64SYS', 0 -configname: db 'PURE64 CFG', 0 -msg_done: db ' Done', 0 -msg_CPU: db '[CPU: ', 0 -msg_MEM: db '] [MEM: ', 0 -msg_HDD: db ' [HDD: ', 0 -msg_mb: db ' MiB]', 0 -msg_mhz: db 'MHz x', 0 -msg_loadingkernel: db 'Loading software...', 0 -msg_startingkernel: db 'Starting software.', 0 -msg_noconfig: db '(default config)', 0 -no64msg: db 'FATAL ERROR: CPU does not support 64-bit mode. Please run on supported hardware.', 0 -initStartupMsg: db 'Pure64 v0.4.9 - http://www.returninfinity.com', 13, 10, 13, 10, 'Initializing system...', 0 -msg_date: db '2011/04/05', 0 - - -; Mandatory information for all VBE revisions -VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes -VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes -VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes -VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB -VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB -VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment -VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment -VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function -VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line -; Mandatory information for VBE 1.2 and above -VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters -VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters -VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels -VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels -VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes -VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel -VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks -VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type -VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB -VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages -VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) -; Direct Color fields (required for direct/6 and YUV/7 memory models) -VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits -VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask -VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits -VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask -VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits -VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask -VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits -VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask -VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes -; Mandatory information for VBE 2.0 and above -VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer -VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 -VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 -; Mandatory information for VBE 3.0 and above -;VBEModeInfoBlock.LinBytesPerScanLine dw 0 ; bytes per scan line for linear modes -;VBEModeInfoBlock.BnkNumberOfImagePages db 0 ; number of images for banked modes -;VBEModeInfoBlock.LinNumberOfImagePages db 0 ; number of images for linear modes -;VBEModeInfoBlock.LinRedMaskSize db 0 ; size of direct color red mask (linear modes) -;VBEModeInfoBlock.LinRedFieldPosition db 0 ; bit position of lsb of red mask (linear modes) -;VBEModeInfoBlock.LinGreenMaskSize db 0 ; size of direct color green mask (linear modes) -;VBEModeInfoBlock.LinGreenFieldPosition db 0 ; bit position of lsb of green mask (linear modes) -;VBEModeInfoBlock.LinBlueMaskSize db 0 ; size of direct color blue mask (linear modes) -;VBEModeInfoBlock.LinBlueFieldPosition db 0 ; bit position of lsb of blue mask (linear modes) -;VBEModeInfoBlock.LinRsvdMaskSize db 0 ; size of direct color reserved mask (linear modes) -;VBEModeInfoBlock.LinRsvdFieldPosition db 0 ; bit position of lsb of reserved mask (linear modes) -;VBEModeInfoBlock.MaxPixelClock dd 0 ; maximum pixel clock (in Hz) for graphics mode - - -; ----------------------------------------------------------------------------- -align 16 -GDTR64: ; Global Descriptors Table Register - dw gdt64_end - gdt64 - 1 ; limit of GDT (size minus one) - dq 0x0000000000001000 ; linear address of GDT - -align 16 -gdt64: ; This structure is copied to 0x0000000000001000 -SYS64_NULL_SEL equ $-gdt64 ; Null Segment - dq 0x0000000000000000 -SYS64_CODE_SEL equ $-gdt64 ; Code segment, read/execute, nonconforming - dq 0x0020980000000000 ; 0x00209A0000000000 -SYS64_DATA_SEL equ $-gdt64 ; Data segment, read/write, expand down - dq 0x0000900000000000 ; 0x0020920000000000 -gdt64_end: - -align 16 -IDTR64: ; Interrupt Descriptor Table Register - dw 256*16-1 ; limit of IDT (size minus one) (4096 bytes - 1) - dq 0x0000000000000000 ; linear address of IDT -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; System Variables +; ============================================================================= + + +;CONFIG +cfg_smpinit: db 1 ; By default SMP is enabled. Set to 0 to disable. +cfg_vesa: db 0 ; By default VESA is disabled. Set to 1 to enable. +cfg_default: db 0 ; By default we don't need a config file so set to 0. If a config file is found set to 1. +cfg_e820: db 1 ; By default E820 should be present. Pure64 will set this to 0 if not found/usable. +cfg_mbr: db 0 ; Did we boot off of a disk with a proper MBR + +; Memory locations +E820Map: equ 0x0000000000004000 +InfoMap: equ 0x0000000000005000 +SystemVariables: equ 0x0000000000005A00 +VBEModeInfoBlock equ 0x0000000000005C00 +hdbuffer: equ 0x0000000000070000 ; 32768 bytes = 0x6000 -> 0xDFFF VERIFY THIS!!! +hdbuffer1: equ 0x000000000007E000 ; 512 bytes = 0xE000 -> 0xE1FF VERIFY THIS!!! + +; DQ - Starting at offset 0, increments by 0x8 +os_LocalAPICAddress: equ SystemVariables + 0x00 +os_IOAPICAddress: equ SystemVariables + 0x08 +os_ACPITableAddress: equ SystemVariables + 0x10 +screen_cursor_offset: equ SystemVariables + 0x18 +hd1_maxlba: equ SystemVariables + 0x20 +os_Counter: equ SystemVariables + 0x28 + +; DD - Starting at offset 128, increments by 4 +hd1_size: equ SystemVariables + 128 +fat16_FatStart: equ SystemVariables + 132 +fat16_TotalSectors: equ SystemVariables + 136 +fat16_DataStart: equ SystemVariables + 140 +fat16_RootStart: equ SystemVariables + 144 +fat16_PartitionOffset: equ SystemVariables + 148 + +; DW - Starting at offset 256, increments by 2 +cpu_speed: equ SystemVariables + 256 +cpu_activated: equ SystemVariables + 258 +cpu_detected: equ SystemVariables + 260 +mem_amount: equ SystemVariables + 262 +fat16_BytesPerSector: equ SystemVariables + 264 +fat16_ReservedSectors: equ SystemVariables + 266 +fat16_SectorsPerFat: equ SystemVariables + 268 +fat16_RootDirEnts: equ SystemVariables + 270 + +; DB - Starting at offset 384, increments by 1 +hd1_enable: equ SystemVariables + 384 +hd1_lba48: equ SystemVariables + 385 +screen_cursor_x: equ SystemVariables + 386 +screen_cursor_y: equ SystemVariables + 387 +fat16_SectorsPerCluster: equ SystemVariables + 388 +fat16_Fats: equ SystemVariables + 389 +memtempstring: equ SystemVariables + 390 +speedtempstring: equ SystemVariables + 400 +cpu_amount_string: equ SystemVariables + 410 +hdtempstring: equ SystemVariables + 420 + +;MISC +screen_cols: db 80 +screen_rows: db 25 +hextable: db '0123456789ABCDEF' + +;STRINGS +kernelerror: db 'FATAL ERROR: Software not found.', 0 +kernelname: db 'KERNEL64SYS', 0 +configname: db 'PURE64 CFG', 0 +msg_done: db ' Done', 0 +msg_CPU: db '[CPU: ', 0 +msg_MEM: db '] [MEM: ', 0 +msg_HDD: db ' [HDD: ', 0 +msg_mb: db ' MiB]', 0 +msg_mhz: db 'MHz x', 0 +msg_loadingkernel: db 'Loading software...', 0 +msg_startingkernel: db 'Starting software.', 0 +msg_noconfig: db '(default config)', 0 +no64msg: db 'FATAL ERROR: CPU does not support 64-bit mode. Please run on supported hardware.', 0 +initStartupMsg: db 'Pure64 v0.4.9 - http://www.returninfinity.com', 13, 10, 13, 10, 'Initializing system...', 0 +msg_date: db '2011/04/05', 0 + + +; Mandatory information for all VBE revisions +VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes +VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes +VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes +VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB +VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB +VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment +VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment +VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function +VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line +; Mandatory information for VBE 1.2 and above +VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters +VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters +VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels +VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels +VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes +VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel +VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks +VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type +VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB +VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages +VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) +; Direct Color fields (required for direct/6 and YUV/7 memory models) +VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits +VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask +VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits +VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask +VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits +VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask +VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits +VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask +VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes +; Mandatory information for VBE 2.0 and above +VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer +VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 +VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 +; Mandatory information for VBE 3.0 and above +;VBEModeInfoBlock.LinBytesPerScanLine dw 0 ; bytes per scan line for linear modes +;VBEModeInfoBlock.BnkNumberOfImagePages db 0 ; number of images for banked modes +;VBEModeInfoBlock.LinNumberOfImagePages db 0 ; number of images for linear modes +;VBEModeInfoBlock.LinRedMaskSize db 0 ; size of direct color red mask (linear modes) +;VBEModeInfoBlock.LinRedFieldPosition db 0 ; bit position of lsb of red mask (linear modes) +;VBEModeInfoBlock.LinGreenMaskSize db 0 ; size of direct color green mask (linear modes) +;VBEModeInfoBlock.LinGreenFieldPosition db 0 ; bit position of lsb of green mask (linear modes) +;VBEModeInfoBlock.LinBlueMaskSize db 0 ; size of direct color blue mask (linear modes) +;VBEModeInfoBlock.LinBlueFieldPosition db 0 ; bit position of lsb of blue mask (linear modes) +;VBEModeInfoBlock.LinRsvdMaskSize db 0 ; size of direct color reserved mask (linear modes) +;VBEModeInfoBlock.LinRsvdFieldPosition db 0 ; bit position of lsb of reserved mask (linear modes) +;VBEModeInfoBlock.MaxPixelClock dd 0 ; maximum pixel clock (in Hz) for graphics mode + + +; ----------------------------------------------------------------------------- +align 16 +GDTR64: ; Global Descriptors Table Register + dw gdt64_end - gdt64 - 1 ; limit of GDT (size minus one) + dq 0x0000000000001000 ; linear address of GDT + +align 16 +gdt64: ; This structure is copied to 0x0000000000001000 +SYS64_NULL_SEL equ $-gdt64 ; Null Segment + dq 0x0000000000000000 +SYS64_CODE_SEL equ $-gdt64 ; Code segment, read/execute, nonconforming + dq 0x0020980000000000 ; 0x00209A0000000000 +SYS64_DATA_SEL equ $-gdt64 ; Data segment, read/write, expand down + dq 0x0000900000000000 ; 0x0020920000000000 +gdt64_end: + +align 16 +IDTR64: ; Interrupt Descriptor Table Register + dw 256*16-1 ; limit of IDT (size minus one) (4096 bytes - 1) + dq 0x0000000000000000 ; linear address of IDT +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/docs/CREDITS.TXT b/amd64/bareMetalOS-0.5.3/docs/CREDITS.TXT index f87968fd..e812001b 100644 --- a/amd64/bareMetalOS-0.5.3/docs/CREDITS.TXT +++ b/amd64/bareMetalOS-0.5.3/docs/CREDITS.TXT @@ -1,18 +1,18 @@ -=============================================================================== -BareMetal OS -- a 64-bit OS written in Assembly for x86-64 systems -Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -=============================================================================== - - -PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) - - * Ian Seyler -- ian.seyler@returninfinity.com - - -DEVELOPMENT AND TESTING - - * Mike Saunders (and the MikeOS team) - * Members of OSDev.org - - -=============================================================================== +=============================================================================== +BareMetal OS -- a 64-bit OS written in Assembly for x86-64 systems +Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +=============================================================================== + + +PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) + + * Ian Seyler -- ian.seyler@returninfinity.com + + +DEVELOPMENT AND TESTING + + * Mike Saunders (and the MikeOS team) + * Members of OSDev.org + + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.3/docs/LICENSE.TXT b/amd64/bareMetalOS-0.5.3/docs/LICENSE.TXT index 53cbf524..552674bd 100644 --- a/amd64/bareMetalOS-0.5.3/docs/LICENSE.TXT +++ b/amd64/bareMetalOS-0.5.3/docs/LICENSE.TXT @@ -1,35 +1,35 @@ -=============================================================================== -BareMetal OS -- License -=============================================================================== - -Copyright (C) 2008-2012 Return Infinity -- http://www.returninfinity.com - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name BareMetal nor the names of any BareMetal contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -=============================================================================== +=============================================================================== +BareMetal OS -- License +=============================================================================== + +Copyright (C) 2008-2012 Return Infinity -- http://www.returninfinity.com + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name BareMetal nor the names of any BareMetal contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +=============================================================================== diff --git a/amd64/bareMetalOS-0.5.3/newlib/baremetal/crt0.s b/amd64/bareMetalOS-0.5.3/newlib/baremetal/crt0.s index 875cded6..2eb82cc6 100644 --- a/amd64/bareMetalOS-0.5.3/newlib/baremetal/crt0.s +++ b/amd64/bareMetalOS-0.5.3/newlib/baremetal/crt0.s @@ -1,12 +1,12 @@ -.global _start -.extern main -_start: - -## here you might want to get the argc/argv pairs somehow and then push -## them onto the stack... - -# call the user's function -call main - -# return to the OS +.global _start +.extern main +_start: + +## here you might want to get the argc/argv pairs somehow and then push +## them onto the stack... + +# call the user's function +call main + +# return to the OS ret \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.3/os/cli.asm b/amd64/bareMetalOS-0.5.3/os/cli.asm index a6136921..7cd4cf63 100644 --- a/amd64/bareMetalOS-0.5.3/os/cli.asm +++ b/amd64/bareMetalOS-0.5.3/os/cli.asm @@ -1,502 +1,502 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; COMMAND LINE INTERFACE -; ============================================================================= - -align 16 -db 'DEBUG: CLI ' -align 16 - - -os_command_line: - mov rsi, prompt ; Prompt for input - mov bl, 0x09 ; Black background, Light Red text - call os_print_string_with_color - - mov rdi, cli_temp_string - mov rcx, 250 ; Limit the input to 250 characters - call os_input_string - call os_print_newline ; The user hit enter so print a new line - jrcxz os_command_line ; os_input_string stores the number of charaters received in RCX - - mov rsi, rdi - call os_string_parse ; Remove extra spaces - jrcxz os_command_line ; os_string_parse stores the number of words in RCX - mov byte [cli_args], cl ; Store the number of words in the string - -; Copy the first word in the string to a new string. This is the command/application to run - xor rcx, rcx - mov rsi, cli_temp_string - mov rdi, cli_command_string - push rdi ; Push the command string -nextbyte: - add rcx, 1 - lodsb - cmp al, ' ' ; End of the word - je endofcommand - cmp al, 0x00 ; End of the string - je endofcommand - cmp rcx, 13 ; More than 12 bytes - je endofcommand - stosb - jmp nextbyte -endofcommand: - mov al, 0x00 - stosb ; Terminate the string - -; At this point cli_command_string holds at least "a" and at most "abcdefgh.ijk" - - ; Break the contents of cli_temp_string into individual strings - mov rsi, cli_temp_string - mov al, 0x20 - mov bl, 0x00 - call os_string_change_char - - pop rsi ; Pop the command string - call os_string_uppercase ; Convert to uppercase for comparison - - mov rdi, cls_string ; 'CLS' entered? - call os_string_compare - jc near clear_screen - - mov rdi, dir_string ; 'DIR' entered? - call os_string_compare - jc near dir - - mov rdi, ver_string ; 'VER' entered? - call os_string_compare - jc near print_ver - - mov rdi, date_string ; 'DATE' entered? - call os_string_compare - jc near date - - mov rdi, exit_string ; 'EXIT' entered? - call os_string_compare - jc near exit - - mov rdi, help_string ; 'HELP' entered? - call os_string_compare - jc near print_help - - mov rdi, node_string ; 'NODE' entered? - call os_string_compare - jc near node - - mov rdi, time_string ; 'TIME' entered? - call os_string_compare - jc near time - - mov rdi, debug_string ; 'DEBUG' entered? - call os_string_compare - jc near debug - - mov rdi, reboot_string ; 'REBOOT' entered? - call os_string_compare - jc near reboot - - mov rdi, testzone_string ; 'TESTZONE' entered? - call os_string_compare - jc near testzone - - mov rdi, ipconfig_string ; 'IP' entered? - call os_string_compare - jc near ipconfig - -; At this point it is not one of the built-in CLI functions. Prepare to check the filesystem. - mov al, '.' - call os_string_find_char ; Check for a '.' in the string - cmp rax, 0 - jne full_name ; If there was a '.' then a suffix is present - -; No suffix was present so we add the default application suffix of ".APP" -add_suffix: - call os_string_length - cmp rcx, 8 - jg fail ; If the string is longer than 8 chars we can't add a suffix - - mov rdi, cli_command_string - mov rsi, appextension ; '.APP' - call os_string_append ; Append the extension to the command string - -; cli_command_string now contains a full filename -full_name: - mov rsi, cli_command_string - mov rdi, programlocation ; We load the program to this location in memory (currently 0x00100000 : at the 2MB mark) - call os_file_read ; Read the file into memory - jc fail ; If carry is set then the file was not found - - mov rax, programlocation ; 0x00100000 : at the 2MB mark - xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) - call os_smp_enqueue ; Queue the application to run on the next available core - jmp exit ; The CLI can quit now. IRQ 8 will restart it when the program is finished - -fail: ; We didn't get a valid command or program name - mov rsi, not_found_msg - call os_print_string - jmp os_command_line - -print_help: - mov rsi, help_text - call os_print_string - jmp os_command_line - -clear_screen: - call os_screen_clear - mov ax, 0x0018 - call os_move_cursor - jmp os_command_line - -print_ver: - mov rsi, version_msg - call os_print_string - jmp os_command_line - -dir: - mov rdi, cli_temp_string - mov rsi, rdi - call os_file_get_list - call os_print_string - jmp os_command_line - -date: - mov rdi, cli_temp_string - mov rsi, rdi - call os_get_date_string - call os_print_string - call os_print_newline - jmp os_command_line - -time: - mov rdi, cli_temp_string - mov rsi, rdi - call os_get_time_string - call os_print_string - call os_print_newline - jmp os_command_line - -node: - jmp os_command_line ; Nothing here yet... - -align 16 -testzone: - xchg bx, bx ; Bochs Magic Breakpoint - -; call os_ethernet_avail -; call os_debug_dump_rax - -; mov rdi, cli_temp_string -; mov rsi, rdi -; mov rcx, 12 -; call os_input_string -; call os_file_get_size -; mov rax, rcx -; call os_print_newline -; call os_debug_dump_rax - -; cli -; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected -; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue -; rdtsc -; mov r15d, eax - ; Benchmark code start - -; sub rsp, 0x28 -; mov [rsp + 0x20], rax -; mov [rsp + 0x18], rax -; mov [rsp + 0x10], rax -; mov [rsp + 0x8], rax -; mov [rsp], rax -; mov rax, [rsp] -; mov rax, [rsp + 0x8] -; mov rax, [rsp + 0x10] -; mov rax, [rsp + 0x18] -; mov rax, [rsp + 0x20] -; add rsp, 0x28 - -; push rax -; push rax -; push rax -; push rax -; push rax -; pop rax -; pop rax -; pop rax -; pop rax -; pop rax - - ; Benchmark code finish -; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected -; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue -; rdtsc -; sti -; sub eax, r15d -; call os_debug_dump_eax -; call os_print_newline - - - call os_mem_get_free - mov rax, rcx - call os_debug_dump_rax - call os_print_newline - - mov rcx, 16 - call os_mem_allocate - push rax - call os_mem_get_free - mov rax, rcx - call os_debug_dump_rax - call os_print_newline - - pop rax - mov rcx, 16 - call os_mem_release - call os_mem_get_free - mov rax, rcx - call os_debug_dump_rax -; mov al, ' ' -; call os_print_char -; mov rax, rcx -; call os_debug_dump_rax - -; call os_mem_get_free -; mov rax, rcx -; call os_debug_dump_rax -; mov al, ' ' -; call os_print_char -; xor eax, eax -; mov ax, word [os_MemAmount] -; shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) -; call os_debug_dump_rax -; call os_print_newline -; mov rcx, 2 ; 2 pages = 4 MiB -; call os_mem_allocate -; call os_debug_dump_rax -; call os_print_newline - -; mov rax, 0x400000 -; call os_get_time_data - - -; ud2 - -; xor rax, rax -; xor rbx, rcx -; xor rcx, rcx -; xor rdx, rdx -; div rax - - jmp os_command_line - -ipconfig: - call os_get_argc - cmp al, 1 - je ipconfig_display - cmp al, 3 - jl ipconfig_help - cmp al, 4 - jg ipconfig_help - - ; Filter the IP '.'s and the potential subnet '/' - xchg bx, bx - mov rsi, cli_temp_string - add rsi, 9 ; skip past 'ipconfig '. Will need updating if command name changes - mov al, '/' - mov bl, 0x00 - call os_string_change_char - mov al, '.' - mov bl, 0x00 - call os_string_change_char ; At this point the input is '192 168 0 2 24 192.168.0.1' - - ; Parse the Host IP - xor ebx, ebx - call os_string_to_int - mov bl, al - shl ebx, 8 - call os_string_parse_next_word - call os_string_to_int - mov bl, al - shl ebx, 8 - call os_string_parse_next_word - call os_string_to_int - mov bl, al - shl ebx, 8 - call os_string_parse_next_word - call os_string_to_int - mov bl, al - call os_string_parse_next_word - bswap ebx - mov [ip], ebx - - ; Parse the Subnet - call os_string_to_int - mov ecx, 32 - sub ecx, eax - mov ebx, 0xFFFFFFFF - shl ebx, cl - bswap ebx - mov [sn], ebx - call os_string_parse_next_word - - ; Parse the Gateway IP - mov al, '.' - mov bl, 0x00 - call os_string_change_char ; Filter the Gateway IP '.'s - xor ebx, ebx - call os_string_to_int - mov bl, al - shl ebx, 8 - call os_string_parse_next_word - call os_string_to_int - mov bl, al - shl ebx, 8 - call os_string_parse_next_word - call os_string_to_int - mov bl, al - shl ebx, 8 - call os_string_parse_next_word - call os_string_to_int - mov bl, al - call os_string_parse_next_word - bswap ebx - mov [gw], ebx - - jmp os_command_line - -os_string_parse_next_word: - lodsb - cmp al, 0 - jne os_string_parse_next_word - - ret - -ipconfig_display: - mov rsi, ip_ip - call os_print_string - mov rdi, cli_temp_string - mov eax, [ip] - call ipv4addr_to_string - mov rsi, cli_temp_string - call os_print_string - - mov rsi, ip_sn - call os_print_string - mov rdi, cli_temp_string - mov eax, [sn] - call ipv4addr_to_string - mov rsi, cli_temp_string - call os_print_string - - mov rsi, ip_gw - call os_print_string - mov rdi, cli_temp_string - mov eax, [gw] - call ipv4addr_to_string - mov rsi, cli_temp_string - call os_print_string - - mov rsi, ip_mc - call os_print_string - call os_debug_dump_MAC - call os_print_newline - jmp os_command_line - -ipconfig_help: - mov rsi, ipconfig_help_msg - call os_print_string - jmp os_command_line - -reboot: - in al, 0x64 - test al, 00000010b ; Wait for an empty Input Buffer - jne reboot - mov al, 0xFE - out 0x64, al ; Send the reboot call to the keyboard controller - jmp reboot - -debug: - call os_get_argc ; Check the argument number - cmp al, 1 - je debug_dump_reg ; If it is only one then do a register dump - mov rcx, 16 - cmp al, 3 ; Did we get at least 3? - jl noamount ; If not no amount was specified - mov al, 2 - call os_get_argv ; Get the amount of bytes to display - call os_string_to_int ; Convert to an integer - mov rcx, rax -noamount: - mov al, 1 - call os_get_argv ; Get the starting memory address - call os_hex_string_to_int - mov rsi, rax -debug_default: - call os_debug_dump_mem - call os_print_newline - - jmp os_command_line - -debug_dump_reg: - call os_debug_dump_reg - jmp os_command_line - -exit: - ret - -; Strings - help_text db 'Built-in commands: CLS, DATE, DEBUG, DIR, HELP, IPCONFIG, REBOOT, TIME, VER', 13, 0 - not_found_msg db 'Command or program not found', 13, 0 - version_msg db 'BareMetal OS ', BAREMETALOS_VER, 13, 0 - - cls_string db 'CLS', 0 - dir_string db 'DIR', 0 - ver_string db 'VER', 0 - date_string db 'DATE', 0 - exit_string db 'EXIT', 0 - help_string db 'HELP', 0 - node_string db 'NODE', 0 - time_string db 'TIME', 0 - debug_string db 'DEBUG', 0 - reboot_string db 'REBOOT', 0 - testzone_string db 'TESTZONE', 0 - ipconfig_string db 'IPCONFIG', 0 - ip_ip db 'IP: ', 0 - ip_sn db 13, 'Subnet: ', 0 - ip_gw db 13, 'Gateway: ', 0 - ip_mc db 13, 'Physical: 0x', 0 - ipconfig_help_msg db 'Invalid parameters.', 13, 'Usage is ipconfig IPAddress SubnetMask Gateway', 13, 'Example: ipconfig 192.168.0.2 24 192.168.0.1', 13, 0 - - -ipv4addr_to_string: - push rbx - - mov ebx, eax - xor eax, eax - mov al, bl - call os_int_to_string - mov al, '.' - sub rdi, 1 - stosb - shr ebx, 8 - mov al, bl - call os_int_to_string - mov al, '.' - sub rdi, 1 - stosb - shr ebx, 8 - mov al, bl - call os_int_to_string - mov al, '.' - sub rdi, 1 - stosb - shr ebx, 8 - mov al, bl - call os_int_to_string - - pop rbx -ret - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; COMMAND LINE INTERFACE +; ============================================================================= + +align 16 +db 'DEBUG: CLI ' +align 16 + + +os_command_line: + mov rsi, prompt ; Prompt for input + mov bl, 0x09 ; Black background, Light Red text + call os_print_string_with_color + + mov rdi, cli_temp_string + mov rcx, 250 ; Limit the input to 250 characters + call os_input_string + call os_print_newline ; The user hit enter so print a new line + jrcxz os_command_line ; os_input_string stores the number of charaters received in RCX + + mov rsi, rdi + call os_string_parse ; Remove extra spaces + jrcxz os_command_line ; os_string_parse stores the number of words in RCX + mov byte [cli_args], cl ; Store the number of words in the string + +; Copy the first word in the string to a new string. This is the command/application to run + xor rcx, rcx + mov rsi, cli_temp_string + mov rdi, cli_command_string + push rdi ; Push the command string +nextbyte: + add rcx, 1 + lodsb + cmp al, ' ' ; End of the word + je endofcommand + cmp al, 0x00 ; End of the string + je endofcommand + cmp rcx, 13 ; More than 12 bytes + je endofcommand + stosb + jmp nextbyte +endofcommand: + mov al, 0x00 + stosb ; Terminate the string + +; At this point cli_command_string holds at least "a" and at most "abcdefgh.ijk" + + ; Break the contents of cli_temp_string into individual strings + mov rsi, cli_temp_string + mov al, 0x20 + mov bl, 0x00 + call os_string_change_char + + pop rsi ; Pop the command string + call os_string_uppercase ; Convert to uppercase for comparison + + mov rdi, cls_string ; 'CLS' entered? + call os_string_compare + jc near clear_screen + + mov rdi, dir_string ; 'DIR' entered? + call os_string_compare + jc near dir + + mov rdi, ver_string ; 'VER' entered? + call os_string_compare + jc near print_ver + + mov rdi, date_string ; 'DATE' entered? + call os_string_compare + jc near date + + mov rdi, exit_string ; 'EXIT' entered? + call os_string_compare + jc near exit + + mov rdi, help_string ; 'HELP' entered? + call os_string_compare + jc near print_help + + mov rdi, node_string ; 'NODE' entered? + call os_string_compare + jc near node + + mov rdi, time_string ; 'TIME' entered? + call os_string_compare + jc near time + + mov rdi, debug_string ; 'DEBUG' entered? + call os_string_compare + jc near debug + + mov rdi, reboot_string ; 'REBOOT' entered? + call os_string_compare + jc near reboot + + mov rdi, testzone_string ; 'TESTZONE' entered? + call os_string_compare + jc near testzone + + mov rdi, ipconfig_string ; 'IP' entered? + call os_string_compare + jc near ipconfig + +; At this point it is not one of the built-in CLI functions. Prepare to check the filesystem. + mov al, '.' + call os_string_find_char ; Check for a '.' in the string + cmp rax, 0 + jne full_name ; If there was a '.' then a suffix is present + +; No suffix was present so we add the default application suffix of ".APP" +add_suffix: + call os_string_length + cmp rcx, 8 + jg fail ; If the string is longer than 8 chars we can't add a suffix + + mov rdi, cli_command_string + mov rsi, appextension ; '.APP' + call os_string_append ; Append the extension to the command string + +; cli_command_string now contains a full filename +full_name: + mov rsi, cli_command_string + mov rdi, programlocation ; We load the program to this location in memory (currently 0x00100000 : at the 2MB mark) + call os_file_read ; Read the file into memory + jc fail ; If carry is set then the file was not found + + mov rax, programlocation ; 0x00100000 : at the 2MB mark + xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) + call os_smp_enqueue ; Queue the application to run on the next available core + jmp exit ; The CLI can quit now. IRQ 8 will restart it when the program is finished + +fail: ; We didn't get a valid command or program name + mov rsi, not_found_msg + call os_print_string + jmp os_command_line + +print_help: + mov rsi, help_text + call os_print_string + jmp os_command_line + +clear_screen: + call os_screen_clear + mov ax, 0x0018 + call os_move_cursor + jmp os_command_line + +print_ver: + mov rsi, version_msg + call os_print_string + jmp os_command_line + +dir: + mov rdi, cli_temp_string + mov rsi, rdi + call os_file_get_list + call os_print_string + jmp os_command_line + +date: + mov rdi, cli_temp_string + mov rsi, rdi + call os_get_date_string + call os_print_string + call os_print_newline + jmp os_command_line + +time: + mov rdi, cli_temp_string + mov rsi, rdi + call os_get_time_string + call os_print_string + call os_print_newline + jmp os_command_line + +node: + jmp os_command_line ; Nothing here yet... + +align 16 +testzone: + xchg bx, bx ; Bochs Magic Breakpoint + +; call os_ethernet_avail +; call os_debug_dump_rax + +; mov rdi, cli_temp_string +; mov rsi, rdi +; mov rcx, 12 +; call os_input_string +; call os_file_get_size +; mov rax, rcx +; call os_print_newline +; call os_debug_dump_rax + +; cli +; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected +; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue +; rdtsc +; mov r15d, eax + ; Benchmark code start + +; sub rsp, 0x28 +; mov [rsp + 0x20], rax +; mov [rsp + 0x18], rax +; mov [rsp + 0x10], rax +; mov [rsp + 0x8], rax +; mov [rsp], rax +; mov rax, [rsp] +; mov rax, [rsp + 0x8] +; mov rax, [rsp + 0x10] +; mov rax, [rsp + 0x18] +; mov rax, [rsp + 0x20] +; add rsp, 0x28 + +; push rax +; push rax +; push rax +; push rax +; push rax +; pop rax +; pop rax +; pop rax +; pop rax +; pop rax + + ; Benchmark code finish +; xor eax, eax ; Out-of-order execution can cause RDTSC to be executed later than expected +; cpuid ; Execute a serializing instruction to force every preceding instruction to complete before allowing the program to continue +; rdtsc +; sti +; sub eax, r15d +; call os_debug_dump_eax +; call os_print_newline + + + call os_mem_get_free + mov rax, rcx + call os_debug_dump_rax + call os_print_newline + + mov rcx, 16 + call os_mem_allocate + push rax + call os_mem_get_free + mov rax, rcx + call os_debug_dump_rax + call os_print_newline + + pop rax + mov rcx, 16 + call os_mem_release + call os_mem_get_free + mov rax, rcx + call os_debug_dump_rax +; mov al, ' ' +; call os_print_char +; mov rax, rcx +; call os_debug_dump_rax + +; call os_mem_get_free +; mov rax, rcx +; call os_debug_dump_rax +; mov al, ' ' +; call os_print_char +; xor eax, eax +; mov ax, word [os_MemAmount] +; shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) +; call os_debug_dump_rax +; call os_print_newline +; mov rcx, 2 ; 2 pages = 4 MiB +; call os_mem_allocate +; call os_debug_dump_rax +; call os_print_newline + +; mov rax, 0x400000 +; call os_get_time_data + + +; ud2 + +; xor rax, rax +; xor rbx, rcx +; xor rcx, rcx +; xor rdx, rdx +; div rax + + jmp os_command_line + +ipconfig: + call os_get_argc + cmp al, 1 + je ipconfig_display + cmp al, 3 + jl ipconfig_help + cmp al, 4 + jg ipconfig_help + + ; Filter the IP '.'s and the potential subnet '/' + xchg bx, bx + mov rsi, cli_temp_string + add rsi, 9 ; skip past 'ipconfig '. Will need updating if command name changes + mov al, '/' + mov bl, 0x00 + call os_string_change_char + mov al, '.' + mov bl, 0x00 + call os_string_change_char ; At this point the input is '192 168 0 2 24 192.168.0.1' + + ; Parse the Host IP + xor ebx, ebx + call os_string_to_int + mov bl, al + shl ebx, 8 + call os_string_parse_next_word + call os_string_to_int + mov bl, al + shl ebx, 8 + call os_string_parse_next_word + call os_string_to_int + mov bl, al + shl ebx, 8 + call os_string_parse_next_word + call os_string_to_int + mov bl, al + call os_string_parse_next_word + bswap ebx + mov [ip], ebx + + ; Parse the Subnet + call os_string_to_int + mov ecx, 32 + sub ecx, eax + mov ebx, 0xFFFFFFFF + shl ebx, cl + bswap ebx + mov [sn], ebx + call os_string_parse_next_word + + ; Parse the Gateway IP + mov al, '.' + mov bl, 0x00 + call os_string_change_char ; Filter the Gateway IP '.'s + xor ebx, ebx + call os_string_to_int + mov bl, al + shl ebx, 8 + call os_string_parse_next_word + call os_string_to_int + mov bl, al + shl ebx, 8 + call os_string_parse_next_word + call os_string_to_int + mov bl, al + shl ebx, 8 + call os_string_parse_next_word + call os_string_to_int + mov bl, al + call os_string_parse_next_word + bswap ebx + mov [gw], ebx + + jmp os_command_line + +os_string_parse_next_word: + lodsb + cmp al, 0 + jne os_string_parse_next_word + + ret + +ipconfig_display: + mov rsi, ip_ip + call os_print_string + mov rdi, cli_temp_string + mov eax, [ip] + call ipv4addr_to_string + mov rsi, cli_temp_string + call os_print_string + + mov rsi, ip_sn + call os_print_string + mov rdi, cli_temp_string + mov eax, [sn] + call ipv4addr_to_string + mov rsi, cli_temp_string + call os_print_string + + mov rsi, ip_gw + call os_print_string + mov rdi, cli_temp_string + mov eax, [gw] + call ipv4addr_to_string + mov rsi, cli_temp_string + call os_print_string + + mov rsi, ip_mc + call os_print_string + call os_debug_dump_MAC + call os_print_newline + jmp os_command_line + +ipconfig_help: + mov rsi, ipconfig_help_msg + call os_print_string + jmp os_command_line + +reboot: + in al, 0x64 + test al, 00000010b ; Wait for an empty Input Buffer + jne reboot + mov al, 0xFE + out 0x64, al ; Send the reboot call to the keyboard controller + jmp reboot + +debug: + call os_get_argc ; Check the argument number + cmp al, 1 + je debug_dump_reg ; If it is only one then do a register dump + mov rcx, 16 + cmp al, 3 ; Did we get at least 3? + jl noamount ; If not no amount was specified + mov al, 2 + call os_get_argv ; Get the amount of bytes to display + call os_string_to_int ; Convert to an integer + mov rcx, rax +noamount: + mov al, 1 + call os_get_argv ; Get the starting memory address + call os_hex_string_to_int + mov rsi, rax +debug_default: + call os_debug_dump_mem + call os_print_newline + + jmp os_command_line + +debug_dump_reg: + call os_debug_dump_reg + jmp os_command_line + +exit: + ret + +; Strings + help_text db 'Built-in commands: CLS, DATE, DEBUG, DIR, HELP, IPCONFIG, REBOOT, TIME, VER', 13, 0 + not_found_msg db 'Command or program not found', 13, 0 + version_msg db 'BareMetal OS ', BAREMETALOS_VER, 13, 0 + + cls_string db 'CLS', 0 + dir_string db 'DIR', 0 + ver_string db 'VER', 0 + date_string db 'DATE', 0 + exit_string db 'EXIT', 0 + help_string db 'HELP', 0 + node_string db 'NODE', 0 + time_string db 'TIME', 0 + debug_string db 'DEBUG', 0 + reboot_string db 'REBOOT', 0 + testzone_string db 'TESTZONE', 0 + ipconfig_string db 'IPCONFIG', 0 + ip_ip db 'IP: ', 0 + ip_sn db 13, 'Subnet: ', 0 + ip_gw db 13, 'Gateway: ', 0 + ip_mc db 13, 'Physical: 0x', 0 + ipconfig_help_msg db 'Invalid parameters.', 13, 'Usage is ipconfig IPAddress SubnetMask Gateway', 13, 'Example: ipconfig 192.168.0.2 24 192.168.0.1', 13, 0 + + +ipv4addr_to_string: + push rbx + + mov ebx, eax + xor eax, eax + mov al, bl + call os_int_to_string + mov al, '.' + sub rdi, 1 + stosb + shr ebx, 8 + mov al, bl + call os_int_to_string + mov al, '.' + sub rdi, 1 + stosb + shr ebx, 8 + mov al, bl + call os_int_to_string + mov al, '.' + sub rdi, 1 + stosb + shr ebx, 8 + mov al, bl + call os_int_to_string + + pop rbx +ret + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers.asm b/amd64/bareMetalOS-0.5.3/os/drivers.asm index ca32b3ce..244dc949 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers.asm @@ -1,95 +1,95 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Driver Includes -; ============================================================================= - -align 16 -db 'DEBUG: DRIVERS ' -align 16 - - -%include "drivers/hdd.asm" -%include "drivers/fat16.asm" -%include "drivers/pci.asm" -%include "drivers/achi.asm" -%include "drivers/net/rtl8169.asm" -%include "drivers/net/i8254x.asm" -;%include "drivers/net/bcm57xx.asm" - - -NIC_DeviceVendor_ID: ; The supported list of NICs -; The ID's are Device/Vendor - -; Realtek 816x/811x Gigabit Ethernet -dd 0x8169FFFF -dd 0x816710EC ; 8110SC/8169SC -dd 0x816810EC ; 8111/8168B -dd 0x816910EC ; 8169 - -; Intel 8254x Gigabit Ethernet -dd 0x8254FFFF -dd 0x10008086 ; 82542 (Fiber) -dd 0x10018086 ; 82543GC (Fiber) -dd 0x10048086 ; 82543GC (Copper) -dd 0x10088086 ; 82544EI (Copper) -dd 0x10098086 ; 82544EI (Fiber) -dd 0x100A8086 ; 82540EM -dd 0x100C8086 ; 82544GC (Copper) -dd 0x100D8086 ; 82544GC (LOM) -dd 0x100E8086 ; 82540EM -dd 0x100F8086 ; 82545EM (Copper) -dd 0x10108086 ; 82546EB (Copper) -dd 0x10118086 ; 82545EM (Fiber) -dd 0x10128086 ; 82546EB (Fiber) -dd 0x10138086 ; 82541EI -dd 0x10148086 ; 82541ER -dd 0x10158086 ; 82540EM (LOM) -dd 0x10168086 ; 82540EP (Mobile) -dd 0x10178086 ; 82540EP -dd 0x10188086 ; 82541EI -dd 0x10198086 ; 82547EI -dd 0x101a8086 ; 82547EI (Mobile) -dd 0x101d8086 ; 82546EB -dd 0x101e8086 ; 82540EP (Mobile) -dd 0x10268086 ; 82545GM -dd 0x10278086 ; 82545GM -dd 0x10288086 ; 82545GM -dd 0x105b8086 ; 82546GB (Copper) -dd 0x10758086 ; 82547GI -dd 0x10768086 ; 82541GI -dd 0x10778086 ; 82541GI -dd 0x10788086 ; 82541ER -dd 0x10798086 ; 82546GB -dd 0x107a8086 ; 82546GB -dd 0x107b8086 ; 82546GB -dd 0x107c8086 ; 82541PI -dd 0x10b58086 ; 82546GB (Copper) -dd 0x11078086 ; 82544EI -dd 0x11128086 ; 82544GC - -; Broadcom BCM57xx Gigabit Ethernet -dd 0x5700FFFF -dd 0x000312AE ; 5700, Broadcom -dd 0x164514E4 ; 5701 -dd 0x16A614E4 ; 5702 -dd 0x16A714E4 ; 5703C, 5703S -dd 0x164814E4 ; 5704C -dd 0x164914E4 ; 5704S -dd 0x165D14E4 ; 5705M -dd 0x165314E4 ; 5705 -dd 0x03ED173B ; 5788 -dd 0x167714E4 ; 5721, 5751 -dd 0x167D14E4 ; 5751M -dd 0x160014E4 ; 5752 -dd 0x160114E4 ; 5752M -dd 0x166814E4 ; 5714C -dd 0x166914E4 ; 5714S -dd 0x167814E4 ; 5715C -dd 0x167914E4 ; 5715S - -dq 0x0000000000000000 ; End of list - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Driver Includes +; ============================================================================= + +align 16 +db 'DEBUG: DRIVERS ' +align 16 + + +%include "drivers/hdd.asm" +%include "drivers/fat16.asm" +%include "drivers/pci.asm" +%include "drivers/achi.asm" +%include "drivers/net/rtl8169.asm" +%include "drivers/net/i8254x.asm" +;%include "drivers/net/bcm57xx.asm" + + +NIC_DeviceVendor_ID: ; The supported list of NICs +; The ID's are Device/Vendor + +; Realtek 816x/811x Gigabit Ethernet +dd 0x8169FFFF +dd 0x816710EC ; 8110SC/8169SC +dd 0x816810EC ; 8111/8168B +dd 0x816910EC ; 8169 + +; Intel 8254x Gigabit Ethernet +dd 0x8254FFFF +dd 0x10008086 ; 82542 (Fiber) +dd 0x10018086 ; 82543GC (Fiber) +dd 0x10048086 ; 82543GC (Copper) +dd 0x10088086 ; 82544EI (Copper) +dd 0x10098086 ; 82544EI (Fiber) +dd 0x100A8086 ; 82540EM +dd 0x100C8086 ; 82544GC (Copper) +dd 0x100D8086 ; 82544GC (LOM) +dd 0x100E8086 ; 82540EM +dd 0x100F8086 ; 82545EM (Copper) +dd 0x10108086 ; 82546EB (Copper) +dd 0x10118086 ; 82545EM (Fiber) +dd 0x10128086 ; 82546EB (Fiber) +dd 0x10138086 ; 82541EI +dd 0x10148086 ; 82541ER +dd 0x10158086 ; 82540EM (LOM) +dd 0x10168086 ; 82540EP (Mobile) +dd 0x10178086 ; 82540EP +dd 0x10188086 ; 82541EI +dd 0x10198086 ; 82547EI +dd 0x101a8086 ; 82547EI (Mobile) +dd 0x101d8086 ; 82546EB +dd 0x101e8086 ; 82540EP (Mobile) +dd 0x10268086 ; 82545GM +dd 0x10278086 ; 82545GM +dd 0x10288086 ; 82545GM +dd 0x105b8086 ; 82546GB (Copper) +dd 0x10758086 ; 82547GI +dd 0x10768086 ; 82541GI +dd 0x10778086 ; 82541GI +dd 0x10788086 ; 82541ER +dd 0x10798086 ; 82546GB +dd 0x107a8086 ; 82546GB +dd 0x107b8086 ; 82546GB +dd 0x107c8086 ; 82541PI +dd 0x10b58086 ; 82546GB (Copper) +dd 0x11078086 ; 82544EI +dd 0x11128086 ; 82544GC + +; Broadcom BCM57xx Gigabit Ethernet +dd 0x5700FFFF +dd 0x000312AE ; 5700, Broadcom +dd 0x164514E4 ; 5701 +dd 0x16A614E4 ; 5702 +dd 0x16A714E4 ; 5703C, 5703S +dd 0x164814E4 ; 5704C +dd 0x164914E4 ; 5704S +dd 0x165D14E4 ; 5705M +dd 0x165314E4 ; 5705 +dd 0x03ED173B ; 5788 +dd 0x167714E4 ; 5721, 5751 +dd 0x167D14E4 ; 5751M +dd 0x160014E4 ; 5752 +dd 0x160114E4 ; 5752M +dd 0x166814E4 ; 5714C +dd 0x166914E4 ; 5714S +dd 0x167814E4 ; 5715C +dd 0x167914E4 ; 5715S + +dq 0x0000000000000000 ; End of list + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/achi.asm b/amd64/bareMetalOS-0.5.3/os/drivers/achi.asm index aabe2244..5019f81a 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/achi.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/achi.asm @@ -1,46 +1,46 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; ACHI Driver -; ============================================================================= - -align 16 -db 'DEBUG: ACHI ' -align 16 - - -; ----------------------------------------------------------------------------- -; achiread -- Read data from a SATA hard drive -; IN: RAX = starting sector # to read -; RCX = number of sectors to read -; RDX = disk # -; RDI = memory location to store sectors -; OUT: RAX = RAX + number of sectors that were read -; RCX = number of sectors that were read (0 on error) -; RDI = RDI + (number of sectors read * 512) -; All other registers preserved -achiread: - -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; achiwrite -- Write data tp a SATA hard drive -; IN: RAX = starting block # to write -; RCX = number of sectors to write -; RDX = disk # -; RSI = memory location of sectors -; OUT: RAX = RAX + number of sectors that were written -; RCX = number of sectors that were written (0 on error) -; RSI = RSI + (number of sectors written * 512) -; All other registers preserved -achiwrite: - -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; ACHI Driver +; ============================================================================= + +align 16 +db 'DEBUG: ACHI ' +align 16 + + +; ----------------------------------------------------------------------------- +; achiread -- Read data from a SATA hard drive +; IN: RAX = starting sector # to read +; RCX = number of sectors to read +; RDX = disk # +; RDI = memory location to store sectors +; OUT: RAX = RAX + number of sectors that were read +; RCX = number of sectors that were read (0 on error) +; RDI = RDI + (number of sectors read * 512) +; All other registers preserved +achiread: + +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; achiwrite -- Write data tp a SATA hard drive +; IN: RAX = starting block # to write +; RCX = number of sectors to write +; RDX = disk # +; RSI = memory location of sectors +; OUT: RAX = RAX + number of sectors that were written +; RCX = number of sectors that were written (0 on error) +; RSI = RSI + (number of sectors written * 512) +; All other registers preserved +achiwrite: + +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/fat16.asm b/amd64/bareMetalOS-0.5.3/os/drivers/fat16.asm index d18cc841..368e4706 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/fat16.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/fat16.asm @@ -1,799 +1,799 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; FAT16 Functions -; ============================================================================= - -align 16 -db 'DEBUG: FAT16 ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_fat16_read_cluster -- Read a cluster from the FAT16 partition -; IN: AX = Cluster # to read -; RDI = Memory location to store at least 32KB -; OUT: AX = Next cluster in chain (0xFFFF if this was the last) -; RDI = Points one byte after the last byte read -os_fat16_read_cluster: - push rsi - push rdx - push rcx - push rbx - - and rax, 0x000000000000FFFF ; Clear the top 48 bits - mov rbx, rax ; Save the cluster number to be used later - - cmp ax, 2 ; If less than 2 then bail out... - jl near os_fat16_read_cluster_bailout ; as clusters start at 2 - -; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start - xor rcx, rcx - mov cl, byte [fat16_SectorsPerCluster] - push rcx ; Save the number of sectors per cluster - sub ax, 2 - imul cx ; EAX now holds starting sector - add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - - pop rcx ; Restore the number of sectors per cluster - call readsectors ; Read one cluster of sectors - -; Calculate the next cluster -; Psuedo-code -; tint1 = Cluster / 256 <- Dump the remainder -; sector_to_read = tint1 + ReservedSectors -; tint2 = (Cluster - (tint1 * 256)) * 2 - push rdi - mov rdi, secbuffer1 ; Read to this temporary buffer - mov rsi, rdi ; Copy buffer address to RSI - push rbx ; Save the original cluster value - shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - add rax, rbx ; Add the sector offset - mov rcx, 1 - call readsectors - pop rax ; Get our original cluster value back - shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) - sub rax, rbx ; RAX is now pointed to the offset within the sector - shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) - add rsi, rax - lodsw ; AX now holds the next cluster - pop rdi - - jmp os_fat16_read_cluster_end - -os_fat16_read_cluster_bailout: - xor ax, ax - -os_fat16_read_cluster_end: - pop rbx - pop rcx - pop rdx - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_write_cluster -- Write a cluster to the FAT16 partition -; IN: AX = Cluster # to write to -; RSI = Memory location of data to write -; OUT: AX = Next cluster in the chain (set to 0xFFFF if this was the last cluster of the chain) -; RSI = Points one byte after the last byte written -os_fat16_write_cluster: - push rdi - push rdx - push rcx - push rbx - - and rax, 0x000000000000FFFF ; Clear the top 48 bits - mov rbx, rax ; Save the cluster number to be used later - - cmp ax, 2 ; If less than 2 then bail out... - jl near os_fat16_write_cluster_bailout ; as clusters start at 2 - -; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start - xor rcx, rcx - mov cl, byte [fat16_SectorsPerCluster] - push rcx ; Save the number of sectors per cluster - sub ax, 2 - imul cx ; EAX now holds starting sector - add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - - pop rcx ; Restore the number of sectors per cluster - call writesectors - -; Calculate the next cluster - push rsi - mov rdi, secbuffer1 ; Read to this temporary buffer - mov rsi, rdi ; Copy buffer address to RSI - push rbx ; Save the original cluster value - shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - add rax, rbx ; Add the sector offset - mov rcx, 1 - call readsectors - pop rax ; Get our original cluster value back - shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) - sub rax, rbx ; RAX is now pointed to the offset within the sector - shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) - add rsi, rax - lodsw ; AX now holds the next cluster - pop rsi - - jmp os_fat16_write_cluster_done - -os_fat16_write_cluster_bailout: - xor ax, ax - -os_fat16_write_cluster_done: - pop rbx - pop rcx - pop rdx - pop rdi -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_find_file -- Search for a file name and return the starting cluster -; IN: RSI = Pointer to file name, must be in 'FILENAMEEXT' format -; OUT: AX = Staring cluster -; ECX = File size -; Carry set if not found. If carry is set then ignore value in AX -os_fat16_find_file: - push rsi - push rdi - push rdx - push rbx - - clc ; Clear carry - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - -os_fat16_find_file_read_sector: - mov rdi, hdbuffer1 - push rdi - mov rcx, 1 - call readsectors - pop rdi - mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 - -os_fat16_find_file_next_entry: - cmp byte [rdi], 0x00 ; end of records - je os_fat16_find_file_notfound - - mov rcx, 11 - push rsi - repe cmpsb - pop rsi - mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at - mov ecx, [rdi+17] ; ECX now holds the size of the file in bytes - jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 - - add rdi, byte 0x20 - and rdi, byte -0x20 - dec rbx - cmp rbx, 0 - jne os_fat16_find_file_next_entry - -; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. - - add rdx, 1 - mov rax, rdx - jmp os_fat16_find_file_read_sector - -os_fat16_find_file_notfound: - stc ; Set carry - xor rax, rax - -os_fat16_find_file_done: - cmp ax, 0x0000 ; BUG HERE - jne wut ; Carry is not being set properly in this function - stc -wut: - pop rbx - pop rdx - pop rdi - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_get_file_list -- Generate a list of files on disk -; IN: RDI = location to store list -; OUT: RDI = pointer to end of list -os_fat16_get_file_list: - push rsi - push rdi - push rcx - push rbx - push rax - - push rsi - mov rsi, dir_title_string - call os_string_length - call os_string_copy ; Copy the header - add rdi, rcx - pop rsi - - xor rbx, rbx - mov ebx, [fat16_RootStart] ; ebx points to the first sector of the root - add ebx, [fat16_PartitionOffset] ; Add the offset to the partition - - jmp os_fat16_get_file_list_read_sector - -os_fat16_get_file_list_next_sector: - add rbx, 1 - -os_fat16_get_file_list_read_sector: - push rdi - mov rdi, hdbuffer1 - mov rsi, rdi - mov rcx, 1 - mov rax, rbx - call readsectors - pop rdi - - ; RDI = location of string - ; RSI = buffer that contains the cluster - - ; start reading -os_fat16_get_file_list_read: - cmp rsi, hdbuffer1+512 - je os_fat16_get_file_list_next_sector - cmp byte [rsi], 0x00 ; end of records - je os_fat16_get_file_list_done - cmp byte [rsi], 0xE5 ; unused record - je os_fat16_get_file_list_skip - - mov al, [rsi + 8] ; Grab the attribute byte - bt ax, 5 ; check if bit 3 is set (volume label) - jc os_fat16_get_file_list_skip ; if so skip the entry - mov al, [rsi + 11] ; Grab the attribute byte - cmp al, 0x0F ; Check if it is a LFN entry - je os_fat16_get_file_list_skip ; if so skip the entry - - ; copy the string - xor rcx, rcx - xor rax, rax -os_fat16_get_file_list_copy: - mov al, [rsi+rcx] - stosb ; Store to RDI - inc rcx - cmp rcx, 8 - jne os_fat16_get_file_list_copy - - mov al, ' ' ; Store a space as the separtator - stosb - - mov al, [rsi+8] - stosb - mov al, [rsi+9] - stosb - mov al, [rsi+10] - stosb - - mov al, ' ' ; Store a space as the separtator - stosb - - mov eax, [rsi+0x1C] - call os_int_to_string - dec rdi - mov al, 13 - stosb - -os_fat16_get_file_list_skip: - add rsi, 32 - jmp os_fat16_get_file_list_read - -os_fat16_get_file_list_done: - mov al, 0x00 - stosb - - pop rax - pop rbx - pop rcx - pop rdi - pop rsi -ret - -dir_title_string: db "Name Ext Size", 13, "====================", 13, 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_read -- Read a file from disk into memory -; IN: RSI = Address of filename string -; RDI = Memory location where file will be loaded to -; OUT: Carry clear on success, set if file was not found or error occured -os_fat16_file_read: - push rsi - push rdi - push rcx ; Used by os_fat16_find_file - push rax - -; Convert the file name to FAT format - push rdi ; Save the memory address - mov rdi, os_fat16_file_read_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - xchg rsi, rdi - pop rdi ; Grab the memory address - jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted - -; Check to see if the file exists - call os_fat16_find_file ; Fuction will return the starting cluster value in AX or carry set if not found - jc os_fat16_file_read_done ; If Carry is clear then the file exists. AX is set to the starting cluster - -os_fat16_file_read_read: - call os_fat16_read_cluster ; Store cluster in memory. AX is set to the next cluster - cmp ax, 0xFFFF ; 0xFFFF is the FAT end of file marker - jne os_fat16_file_read_read ; Are there more clusters? If so then read again.. if not fall through - clc ; Clear Carry - -os_fat16_file_read_done: - pop rax - pop rcx - pop rdi - pop rsi -ret - - os_fat16_file_read_string times 13 db 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_write -- Write a file to the hard disk -; IN: RSI = Address of data in memory -; RDI = File name to write -; RCX = number of bytes to write -; OUT: Carry clear on success, set on failure -os_fat16_file_write: - push rsi - push rdi - push rcx - push rax - - mov [memory_address], rsi ; Save the memory address - -; Convert the file name to FAT format - mov rsi, rdi ; Move the file name address into RSI - mov rdi, os_fat16_file_write_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - jc os_fat16_file_write_done ; Fail (Invalid file name) - -; Check to see if a file already exists with the same name - mov rsi, os_fat16_file_write_string - push rcx - call os_fat16_find_file ; Returns the starting cluster in AX or carry set if it doesn't exist - pop rcx - jc os_fat16_file_write_create ; Jump if the file doesn't exist (No need to delete it) - jmp os_fat16_file_write_done ; call os_fat16_file_delete - -; At this point the file doesn't exist so create it. -os_fat16_file_write_create: -xchg bx, bx - call os_fat16_file_create - jc os_fat16_file_write_done ; Fail (Couldn't create the file) - call os_fat16_find_file ; Call this to get the starting cluster - jc os_fat16_file_write_done ; Fail (File was supposed to be created but wasn't) - -; We are ready to start writing. First cluster is in AX - mov rsi, [memory_address] -os_fat16_file_write_write: - call os_fat16_write_cluster - cmp ax, 0xFFFF - jne os_fat16_file_write_write - clc - -os_fat16_file_write_done: - pop rax - pop rcx - pop rdi - pop rsi -ret - - os_fat16_file_write_string times 13 db 0 - memory_address dq 0x0000000000000000 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_create -- Create a file on the hard disk -; IN: RSI = Pointer to file name, must be in FAT 'FILENAMEEXT' format -; RCX = File size -; OUT: Carry clear on success, set on failure -; Note: This function pre-allocates all clusters required for the size of the file -os_fat16_file_create: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - clc ; Clear the carry flag. It will be set if there is an error - - mov [filesize], ecx ; Save file size for later - mov [filename], rsi - -; Check to see if a file already exists with the same name -; call os_fat16_find_file -; jc os_fat16_file_create_fail ; Fail (File already exists) - -; How many clusters will we need? - mov rax, rcx - xor rdx, rdx - xor rbx, rbx - mov bl, byte [fat16_SectorsPerCluster] - shl rbx, 9 ; Multiply by 512 to get bytes per cluster - div rbx - cmp rdx, 0 - jg add_a_bit ; If there's a remainder, we need another cluster - jmp carry_on -add_a_bit: - add rax, 1 -carry_on: - mov rcx, rax ; RCX holds number of clusters that are needed - -; Allocate all of the clusters required for the amount of bytes we are writting. - xor rax, rax - mov ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdi, hdbuffer0 - mov rsi, rdi - push rcx - mov rcx, 64 - call readsectors - pop rcx - xor rdx, rdx ; cluster we are currently at - xor rbx, rbx ; cluster marker -findfirstfreeclust: - mov rdi, rsi - lodsw - inc dx ; counter - cmp ax, 0x0000 - jne findfirstfreeclust ; Continue until we find a free cluster - dec dx - mov [startcluster], dx ; Save the starting cluster ID - inc dx - mov bx, dx - cmp rcx, 0 - je clusterdone - cmp rcx, 1 - je clusterdone - -findnextfreecluster: - lodsw - inc dx - cmp ax, 0x0000 - jne findnextfreecluster - mov ax, bx - mov bx, dx - stosw - mov rdi, rsi - sub rdi, 2 - dec rcx - cmp rcx, 1 - jne findnextfreecluster - -clusterdone: - mov ax, 0xFFFF - stosw -; push dx ; save the free cluster number -; inc rbx -; cmp rbx, rcx ; Have we found enough free clusters? -; jne nextclust ; If not keep going, if yes fall through -; At this point we have free cluster ID's on the stack - -; mov ax, 0xFFFF - - - -; At this point we have a sector of FAT in hdbuffer0. A cluster has been marked in use but the sector is not written back to disk yet! -; Save the sector # as we will write this to disk later - -; Load the first sector of the file info table - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdi, hdbuffer1 - push rdi - mov rcx, 1 - call readsectors - pop rdi - mov rcx, 16 ; records / sector - mov rsi, rdi -nextrecord: - sub rcx, 1 - cmp byte [rsi], 0x00 ; Empty record - je foundfree - cmp byte [rsi], 0xE5 ; Unused record - je foundfree - add rsi, 32 ; Each record is 32 bytes - cmp rcx, 0 - je os_fat16_file_create_fail - jmp nextrecord - -foundfree: - ; At this point RSI points to the start of the record - mov rdi, rsi - mov rsi, [filename] - mov rcx, 11 -nextchar: - lodsb - stosb - sub rcx, 1 - cmp rcx, 0 - jne nextchar - xor rax, rax - stosb ; LFN Attrib - stosb ; NT Reserved - stosw ; Create time - stosb ; Create time - stosw ; Create date - stosw ; Access date - stosw ; Access time - stosw ; Modified time - stosw ; Modified date - mov ax, [startcluster] - stosw - mov eax, [filesize] - stosd ; File size - -; At this point the updated file record is in memory at hdbuffer1 - - xor rax, rax - - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rsi, hdbuffer0 - mov rcx, 64 - call writesectors - - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rsi, hdbuffer1 - mov rcx, 1 - call writesectors - - jmp os_fat16_file_create_done - -os_fat16_file_create_fail: - stc - call os_speaker_beep - -os_fat16_file_create_done: - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret - -; newfile_string times 13 db 0 - startcluster dw 0x0000 - filesize dd 0x00000000 - filename dq 0x0000000000000000 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_file_delete -- Delete a file from the hard disk -; IN: RSI = File name to delete -; OUT: Carry clear on success, set on failure -os_fat16_file_delete: - push rsi - push rdi - push rdx - push rcx - push rbx - - clc ; Clear carry - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - -; Convert the file name to FAT format - mov rdi, os_fat16_file_delete_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - jc os_fat16_file_delete_error ; Fail (Invalid file name) - mov rsi, rdi - -; Read through the root cluster (if file not found bail out) -os_fat16_file_delete_read_sector: - mov rdi, hdbuffer0 - push rdi - mov rcx, 1 - call readsectors - pop rdi - mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 - -os_fat16_file_delete_next_entry: - cmp byte [rdi], 0x00 ; end of records - je os_fat16_file_delete_error - - mov rcx, 11 - push rsi - repe cmpsb - pop rsi - mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at - jz os_fat16_file_delete_found ; The file was found. Note that rdi now is at dirent+11 - - add rdi, byte 0x20 ; Great little trick here. Add 32 ... - and rdi, byte -0x20 ; ... and then round backwards to a 32-byte barrier. Sets RDI to the start of the next record - dec rbx - cmp rbx, 0 - jne os_fat16_file_delete_next_entry - -; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. - add rdx, 1 ; We are about to read the next sector so increment the counter - mov rax, rdx - jmp os_fat16_file_delete_read_sector - -; Mark the file as deleted (set first byte of file name to 0xE5) and write the sector back to the drive -os_fat16_file_delete_found: - xor rbx, rbx - mov bx, ax ; Save the starting cluster value - and rdi, byte -0x20 ; Round backward to get to the start of the record - mov al, 0xE5 ; Set the first character of the filename to this - stosb - mov rsi, hdbuffer0 - mov rax, rdx ; Retrieve the sector number - mov rcx, 1 - call writesectors - -; Follow cluster chain and set any cluster in the chain to 0x0000 (mark as free) - xor rax, rax - mov ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - mov rdi, hdbuffer1 - mov rsi, rdi - mov rcx, 1 - call readsectors - xor rax, rax -os_fat16_file_delete_next_cluster: - shl rbx, 1 - mov ax, word [rsi+rbx] - mov [rsi+rbx], word 0x0000 - mov bx, ax - cmp ax, 0xFFFF - jne os_fat16_file_delete_next_cluster - mov rax, rdx ; Get the sector back. RSI already points to what we need - mov rcx, 1 - call writesectors - jmp os_fat16_file_delete_done - -os_fat16_file_delete_error: - xor rax, rax - stc ; Set carry - -os_fat16_file_delete_done: - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret - - os_fat16_file_delete_string times 13 db 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_get_file_size -- Read a file from disk into memory -; IN: RSI = Address of filename string -; OUT: RCX = Size of file in bytes -; Carry clear on success, set if file was not found or error occured -os_fat16_get_file_size: - push rsi - push rdi - push rax - xor ecx, ecx - -; Convert the file name to FAT format - mov rdi, os_fat16_get_file_size_string - call os_fat16_filename_convert ; Convert the filename to the proper FAT format - mov rsi, rdi - jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted - -; Check to see if the file exists - call os_fat16_find_file ; Fuction will return the starting cluster value in AX and size in ECX or carry set if not found - -os_fat16_get_file_size_done: - pop rax - pop rdi - pop rsi -ret - - os_fat16_get_file_size_string times 13 db 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_fat16_filename_convert -- Change 'test.er' into 'TEST ER ' as per FAT16 -; IN: RSI = filename string -; RDI = location to store converted string (carry set if invalid) -; OUT: All registers preserved -; NOTE: Must have room for 12 bytes. 11 for the name and 1 for the NULL -; Need fix for short extensions! -os_fat16_filename_convert: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - mov rbx, rdi ; Save the string destination address - call os_string_length - cmp rcx, 12 ; Bigger than name + dot + extension? - jg os_fat16_filename_convert_failure ; Fail if so - cmp rcx, 0 - je os_fat16_filename_convert_failure ; Similarly, fail if zero-char string - - mov rdx, rcx ; Store string length for now - xor rcx, rcx -os_fat16_filename_convert_copy_loop: - lodsb - cmp al, '.' - je os_fat16_filename_convert_extension_found - stosb - inc rcx - cmp rcx, rdx - jg os_fat16_filename_convert_failure ; No extension found = wrong - jmp os_fat16_filename_convert_copy_loop - -os_fat16_filename_convert_failure: - stc ; Set carry for failure - jmp os_fat16_filename_convert_done - -os_fat16_filename_convert_extension_found: - cmp rcx, 0 - je os_fat16_filename_convert_failure ; Fail if extension dot is first char - cmp rcx, 8 - je os_fat16_filename_convert_do_extension ; Skip spaces if first bit is 8 chars - - mov al, ' ' -os_fat16_filename_convert_add_spaces: - stosb - inc rcx - cmp rcx, 8 - jl os_fat16_filename_convert_add_spaces - -os_fat16_filename_convert_do_extension: ; FIX THIS for cases where ext is less than 3 chars - lodsb - stosb - lodsb - stosb - lodsb - stosb - mov byte [rdi], 0 ; Zero-terminate filename - clc ; Clear carry for success - mov rsi, rbx ; Get the start address of the desitination string - call os_string_uppercase ; Set it all to uppercase - -os_fat16_filename_convert_done: - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; FAT16 Functions +; ============================================================================= + +align 16 +db 'DEBUG: FAT16 ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_fat16_read_cluster -- Read a cluster from the FAT16 partition +; IN: AX = Cluster # to read +; RDI = Memory location to store at least 32KB +; OUT: AX = Next cluster in chain (0xFFFF if this was the last) +; RDI = Points one byte after the last byte read +os_fat16_read_cluster: + push rsi + push rdx + push rcx + push rbx + + and rax, 0x000000000000FFFF ; Clear the top 48 bits + mov rbx, rax ; Save the cluster number to be used later + + cmp ax, 2 ; If less than 2 then bail out... + jl near os_fat16_read_cluster_bailout ; as clusters start at 2 + +; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start + xor rcx, rcx + mov cl, byte [fat16_SectorsPerCluster] + push rcx ; Save the number of sectors per cluster + sub ax, 2 + imul cx ; EAX now holds starting sector + add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + + pop rcx ; Restore the number of sectors per cluster + call readsectors ; Read one cluster of sectors + +; Calculate the next cluster +; Psuedo-code +; tint1 = Cluster / 256 <- Dump the remainder +; sector_to_read = tint1 + ReservedSectors +; tint2 = (Cluster - (tint1 * 256)) * 2 + push rdi + mov rdi, secbuffer1 ; Read to this temporary buffer + mov rsi, rdi ; Copy buffer address to RSI + push rbx ; Save the original cluster value + shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + add rax, rbx ; Add the sector offset + mov rcx, 1 + call readsectors + pop rax ; Get our original cluster value back + shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) + sub rax, rbx ; RAX is now pointed to the offset within the sector + shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) + add rsi, rax + lodsw ; AX now holds the next cluster + pop rdi + + jmp os_fat16_read_cluster_end + +os_fat16_read_cluster_bailout: + xor ax, ax + +os_fat16_read_cluster_end: + pop rbx + pop rcx + pop rdx + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_write_cluster -- Write a cluster to the FAT16 partition +; IN: AX = Cluster # to write to +; RSI = Memory location of data to write +; OUT: AX = Next cluster in the chain (set to 0xFFFF if this was the last cluster of the chain) +; RSI = Points one byte after the last byte written +os_fat16_write_cluster: + push rdi + push rdx + push rcx + push rbx + + and rax, 0x000000000000FFFF ; Clear the top 48 bits + mov rbx, rax ; Save the cluster number to be used later + + cmp ax, 2 ; If less than 2 then bail out... + jl near os_fat16_write_cluster_bailout ; as clusters start at 2 + +; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start + xor rcx, rcx + mov cl, byte [fat16_SectorsPerCluster] + push rcx ; Save the number of sectors per cluster + sub ax, 2 + imul cx ; EAX now holds starting sector + add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + + pop rcx ; Restore the number of sectors per cluster + call writesectors + +; Calculate the next cluster + push rsi + mov rdi, secbuffer1 ; Read to this temporary buffer + mov rsi, rdi ; Copy buffer address to RSI + push rbx ; Save the original cluster value + shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + add rax, rbx ; Add the sector offset + mov rcx, 1 + call readsectors + pop rax ; Get our original cluster value back + shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) + sub rax, rbx ; RAX is now pointed to the offset within the sector + shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) + add rsi, rax + lodsw ; AX now holds the next cluster + pop rsi + + jmp os_fat16_write_cluster_done + +os_fat16_write_cluster_bailout: + xor ax, ax + +os_fat16_write_cluster_done: + pop rbx + pop rcx + pop rdx + pop rdi +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_find_file -- Search for a file name and return the starting cluster +; IN: RSI = Pointer to file name, must be in 'FILENAMEEXT' format +; OUT: AX = Staring cluster +; ECX = File size +; Carry set if not found. If carry is set then ignore value in AX +os_fat16_find_file: + push rsi + push rdi + push rdx + push rbx + + clc ; Clear carry + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + +os_fat16_find_file_read_sector: + mov rdi, hdbuffer1 + push rdi + mov rcx, 1 + call readsectors + pop rdi + mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 + +os_fat16_find_file_next_entry: + cmp byte [rdi], 0x00 ; end of records + je os_fat16_find_file_notfound + + mov rcx, 11 + push rsi + repe cmpsb + pop rsi + mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at + mov ecx, [rdi+17] ; ECX now holds the size of the file in bytes + jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 + + add rdi, byte 0x20 + and rdi, byte -0x20 + dec rbx + cmp rbx, 0 + jne os_fat16_find_file_next_entry + +; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. + + add rdx, 1 + mov rax, rdx + jmp os_fat16_find_file_read_sector + +os_fat16_find_file_notfound: + stc ; Set carry + xor rax, rax + +os_fat16_find_file_done: + cmp ax, 0x0000 ; BUG HERE + jne wut ; Carry is not being set properly in this function + stc +wut: + pop rbx + pop rdx + pop rdi + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_get_file_list -- Generate a list of files on disk +; IN: RDI = location to store list +; OUT: RDI = pointer to end of list +os_fat16_get_file_list: + push rsi + push rdi + push rcx + push rbx + push rax + + push rsi + mov rsi, dir_title_string + call os_string_length + call os_string_copy ; Copy the header + add rdi, rcx + pop rsi + + xor rbx, rbx + mov ebx, [fat16_RootStart] ; ebx points to the first sector of the root + add ebx, [fat16_PartitionOffset] ; Add the offset to the partition + + jmp os_fat16_get_file_list_read_sector + +os_fat16_get_file_list_next_sector: + add rbx, 1 + +os_fat16_get_file_list_read_sector: + push rdi + mov rdi, hdbuffer1 + mov rsi, rdi + mov rcx, 1 + mov rax, rbx + call readsectors + pop rdi + + ; RDI = location of string + ; RSI = buffer that contains the cluster + + ; start reading +os_fat16_get_file_list_read: + cmp rsi, hdbuffer1+512 + je os_fat16_get_file_list_next_sector + cmp byte [rsi], 0x00 ; end of records + je os_fat16_get_file_list_done + cmp byte [rsi], 0xE5 ; unused record + je os_fat16_get_file_list_skip + + mov al, [rsi + 8] ; Grab the attribute byte + bt ax, 5 ; check if bit 3 is set (volume label) + jc os_fat16_get_file_list_skip ; if so skip the entry + mov al, [rsi + 11] ; Grab the attribute byte + cmp al, 0x0F ; Check if it is a LFN entry + je os_fat16_get_file_list_skip ; if so skip the entry + + ; copy the string + xor rcx, rcx + xor rax, rax +os_fat16_get_file_list_copy: + mov al, [rsi+rcx] + stosb ; Store to RDI + inc rcx + cmp rcx, 8 + jne os_fat16_get_file_list_copy + + mov al, ' ' ; Store a space as the separtator + stosb + + mov al, [rsi+8] + stosb + mov al, [rsi+9] + stosb + mov al, [rsi+10] + stosb + + mov al, ' ' ; Store a space as the separtator + stosb + + mov eax, [rsi+0x1C] + call os_int_to_string + dec rdi + mov al, 13 + stosb + +os_fat16_get_file_list_skip: + add rsi, 32 + jmp os_fat16_get_file_list_read + +os_fat16_get_file_list_done: + mov al, 0x00 + stosb + + pop rax + pop rbx + pop rcx + pop rdi + pop rsi +ret + +dir_title_string: db "Name Ext Size", 13, "====================", 13, 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_read -- Read a file from disk into memory +; IN: RSI = Address of filename string +; RDI = Memory location where file will be loaded to +; OUT: Carry clear on success, set if file was not found or error occured +os_fat16_file_read: + push rsi + push rdi + push rcx ; Used by os_fat16_find_file + push rax + +; Convert the file name to FAT format + push rdi ; Save the memory address + mov rdi, os_fat16_file_read_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + xchg rsi, rdi + pop rdi ; Grab the memory address + jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted + +; Check to see if the file exists + call os_fat16_find_file ; Fuction will return the starting cluster value in AX or carry set if not found + jc os_fat16_file_read_done ; If Carry is clear then the file exists. AX is set to the starting cluster + +os_fat16_file_read_read: + call os_fat16_read_cluster ; Store cluster in memory. AX is set to the next cluster + cmp ax, 0xFFFF ; 0xFFFF is the FAT end of file marker + jne os_fat16_file_read_read ; Are there more clusters? If so then read again.. if not fall through + clc ; Clear Carry + +os_fat16_file_read_done: + pop rax + pop rcx + pop rdi + pop rsi +ret + + os_fat16_file_read_string times 13 db 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_write -- Write a file to the hard disk +; IN: RSI = Address of data in memory +; RDI = File name to write +; RCX = number of bytes to write +; OUT: Carry clear on success, set on failure +os_fat16_file_write: + push rsi + push rdi + push rcx + push rax + + mov [memory_address], rsi ; Save the memory address + +; Convert the file name to FAT format + mov rsi, rdi ; Move the file name address into RSI + mov rdi, os_fat16_file_write_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + jc os_fat16_file_write_done ; Fail (Invalid file name) + +; Check to see if a file already exists with the same name + mov rsi, os_fat16_file_write_string + push rcx + call os_fat16_find_file ; Returns the starting cluster in AX or carry set if it doesn't exist + pop rcx + jc os_fat16_file_write_create ; Jump if the file doesn't exist (No need to delete it) + jmp os_fat16_file_write_done ; call os_fat16_file_delete + +; At this point the file doesn't exist so create it. +os_fat16_file_write_create: +xchg bx, bx + call os_fat16_file_create + jc os_fat16_file_write_done ; Fail (Couldn't create the file) + call os_fat16_find_file ; Call this to get the starting cluster + jc os_fat16_file_write_done ; Fail (File was supposed to be created but wasn't) + +; We are ready to start writing. First cluster is in AX + mov rsi, [memory_address] +os_fat16_file_write_write: + call os_fat16_write_cluster + cmp ax, 0xFFFF + jne os_fat16_file_write_write + clc + +os_fat16_file_write_done: + pop rax + pop rcx + pop rdi + pop rsi +ret + + os_fat16_file_write_string times 13 db 0 + memory_address dq 0x0000000000000000 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_create -- Create a file on the hard disk +; IN: RSI = Pointer to file name, must be in FAT 'FILENAMEEXT' format +; RCX = File size +; OUT: Carry clear on success, set on failure +; Note: This function pre-allocates all clusters required for the size of the file +os_fat16_file_create: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + clc ; Clear the carry flag. It will be set if there is an error + + mov [filesize], ecx ; Save file size for later + mov [filename], rsi + +; Check to see if a file already exists with the same name +; call os_fat16_find_file +; jc os_fat16_file_create_fail ; Fail (File already exists) + +; How many clusters will we need? + mov rax, rcx + xor rdx, rdx + xor rbx, rbx + mov bl, byte [fat16_SectorsPerCluster] + shl rbx, 9 ; Multiply by 512 to get bytes per cluster + div rbx + cmp rdx, 0 + jg add_a_bit ; If there's a remainder, we need another cluster + jmp carry_on +add_a_bit: + add rax, 1 +carry_on: + mov rcx, rax ; RCX holds number of clusters that are needed + +; Allocate all of the clusters required for the amount of bytes we are writting. + xor rax, rax + mov ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdi, hdbuffer0 + mov rsi, rdi + push rcx + mov rcx, 64 + call readsectors + pop rcx + xor rdx, rdx ; cluster we are currently at + xor rbx, rbx ; cluster marker +findfirstfreeclust: + mov rdi, rsi + lodsw + inc dx ; counter + cmp ax, 0x0000 + jne findfirstfreeclust ; Continue until we find a free cluster + dec dx + mov [startcluster], dx ; Save the starting cluster ID + inc dx + mov bx, dx + cmp rcx, 0 + je clusterdone + cmp rcx, 1 + je clusterdone + +findnextfreecluster: + lodsw + inc dx + cmp ax, 0x0000 + jne findnextfreecluster + mov ax, bx + mov bx, dx + stosw + mov rdi, rsi + sub rdi, 2 + dec rcx + cmp rcx, 1 + jne findnextfreecluster + +clusterdone: + mov ax, 0xFFFF + stosw +; push dx ; save the free cluster number +; inc rbx +; cmp rbx, rcx ; Have we found enough free clusters? +; jne nextclust ; If not keep going, if yes fall through +; At this point we have free cluster ID's on the stack + +; mov ax, 0xFFFF + + + +; At this point we have a sector of FAT in hdbuffer0. A cluster has been marked in use but the sector is not written back to disk yet! +; Save the sector # as we will write this to disk later + +; Load the first sector of the file info table + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdi, hdbuffer1 + push rdi + mov rcx, 1 + call readsectors + pop rdi + mov rcx, 16 ; records / sector + mov rsi, rdi +nextrecord: + sub rcx, 1 + cmp byte [rsi], 0x00 ; Empty record + je foundfree + cmp byte [rsi], 0xE5 ; Unused record + je foundfree + add rsi, 32 ; Each record is 32 bytes + cmp rcx, 0 + je os_fat16_file_create_fail + jmp nextrecord + +foundfree: + ; At this point RSI points to the start of the record + mov rdi, rsi + mov rsi, [filename] + mov rcx, 11 +nextchar: + lodsb + stosb + sub rcx, 1 + cmp rcx, 0 + jne nextchar + xor rax, rax + stosb ; LFN Attrib + stosb ; NT Reserved + stosw ; Create time + stosb ; Create time + stosw ; Create date + stosw ; Access date + stosw ; Access time + stosw ; Modified time + stosw ; Modified date + mov ax, [startcluster] + stosw + mov eax, [filesize] + stosd ; File size + +; At this point the updated file record is in memory at hdbuffer1 + + xor rax, rax + + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rsi, hdbuffer0 + mov rcx, 64 + call writesectors + + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rsi, hdbuffer1 + mov rcx, 1 + call writesectors + + jmp os_fat16_file_create_done + +os_fat16_file_create_fail: + stc + call os_speaker_beep + +os_fat16_file_create_done: + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret + +; newfile_string times 13 db 0 + startcluster dw 0x0000 + filesize dd 0x00000000 + filename dq 0x0000000000000000 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_file_delete -- Delete a file from the hard disk +; IN: RSI = File name to delete +; OUT: Carry clear on success, set on failure +os_fat16_file_delete: + push rsi + push rdi + push rdx + push rcx + push rbx + + clc ; Clear carry + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + +; Convert the file name to FAT format + mov rdi, os_fat16_file_delete_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + jc os_fat16_file_delete_error ; Fail (Invalid file name) + mov rsi, rdi + +; Read through the root cluster (if file not found bail out) +os_fat16_file_delete_read_sector: + mov rdi, hdbuffer0 + push rdi + mov rcx, 1 + call readsectors + pop rdi + mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 + +os_fat16_file_delete_next_entry: + cmp byte [rdi], 0x00 ; end of records + je os_fat16_file_delete_error + + mov rcx, 11 + push rsi + repe cmpsb + pop rsi + mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at + jz os_fat16_file_delete_found ; The file was found. Note that rdi now is at dirent+11 + + add rdi, byte 0x20 ; Great little trick here. Add 32 ... + and rdi, byte -0x20 ; ... and then round backwards to a 32-byte barrier. Sets RDI to the start of the next record + dec rbx + cmp rbx, 0 + jne os_fat16_file_delete_next_entry + +; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. + add rdx, 1 ; We are about to read the next sector so increment the counter + mov rax, rdx + jmp os_fat16_file_delete_read_sector + +; Mark the file as deleted (set first byte of file name to 0xE5) and write the sector back to the drive +os_fat16_file_delete_found: + xor rbx, rbx + mov bx, ax ; Save the starting cluster value + and rdi, byte -0x20 ; Round backward to get to the start of the record + mov al, 0xE5 ; Set the first character of the filename to this + stosb + mov rsi, hdbuffer0 + mov rax, rdx ; Retrieve the sector number + mov rcx, 1 + call writesectors + +; Follow cluster chain and set any cluster in the chain to 0x0000 (mark as free) + xor rax, rax + mov ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + mov rdi, hdbuffer1 + mov rsi, rdi + mov rcx, 1 + call readsectors + xor rax, rax +os_fat16_file_delete_next_cluster: + shl rbx, 1 + mov ax, word [rsi+rbx] + mov [rsi+rbx], word 0x0000 + mov bx, ax + cmp ax, 0xFFFF + jne os_fat16_file_delete_next_cluster + mov rax, rdx ; Get the sector back. RSI already points to what we need + mov rcx, 1 + call writesectors + jmp os_fat16_file_delete_done + +os_fat16_file_delete_error: + xor rax, rax + stc ; Set carry + +os_fat16_file_delete_done: + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret + + os_fat16_file_delete_string times 13 db 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_get_file_size -- Read a file from disk into memory +; IN: RSI = Address of filename string +; OUT: RCX = Size of file in bytes +; Carry clear on success, set if file was not found or error occured +os_fat16_get_file_size: + push rsi + push rdi + push rax + xor ecx, ecx + +; Convert the file name to FAT format + mov rdi, os_fat16_get_file_size_string + call os_fat16_filename_convert ; Convert the filename to the proper FAT format + mov rsi, rdi + jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted + +; Check to see if the file exists + call os_fat16_find_file ; Fuction will return the starting cluster value in AX and size in ECX or carry set if not found + +os_fat16_get_file_size_done: + pop rax + pop rdi + pop rsi +ret + + os_fat16_get_file_size_string times 13 db 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_fat16_filename_convert -- Change 'test.er' into 'TEST ER ' as per FAT16 +; IN: RSI = filename string +; RDI = location to store converted string (carry set if invalid) +; OUT: All registers preserved +; NOTE: Must have room for 12 bytes. 11 for the name and 1 for the NULL +; Need fix for short extensions! +os_fat16_filename_convert: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + mov rbx, rdi ; Save the string destination address + call os_string_length + cmp rcx, 12 ; Bigger than name + dot + extension? + jg os_fat16_filename_convert_failure ; Fail if so + cmp rcx, 0 + je os_fat16_filename_convert_failure ; Similarly, fail if zero-char string + + mov rdx, rcx ; Store string length for now + xor rcx, rcx +os_fat16_filename_convert_copy_loop: + lodsb + cmp al, '.' + je os_fat16_filename_convert_extension_found + stosb + inc rcx + cmp rcx, rdx + jg os_fat16_filename_convert_failure ; No extension found = wrong + jmp os_fat16_filename_convert_copy_loop + +os_fat16_filename_convert_failure: + stc ; Set carry for failure + jmp os_fat16_filename_convert_done + +os_fat16_filename_convert_extension_found: + cmp rcx, 0 + je os_fat16_filename_convert_failure ; Fail if extension dot is first char + cmp rcx, 8 + je os_fat16_filename_convert_do_extension ; Skip spaces if first bit is 8 chars + + mov al, ' ' +os_fat16_filename_convert_add_spaces: + stosb + inc rcx + cmp rcx, 8 + jl os_fat16_filename_convert_add_spaces + +os_fat16_filename_convert_do_extension: ; FIX THIS for cases where ext is less than 3 chars + lodsb + stosb + lodsb + stosb + lodsb + stosb + mov byte [rdi], 0 ; Zero-terminate filename + clc ; Clear carry for success + mov rsi, rbx ; Get the start address of the desitination string + call os_string_uppercase ; Set it all to uppercase + +os_fat16_filename_convert_done: + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/hdd.asm b/amd64/bareMetalOS-0.5.3/os/drivers/hdd.asm index 499c434f..aee20957 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/hdd.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/hdd.asm @@ -1,215 +1,215 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Hard Drive Functions -; ============================================================================= - -align 16 -db 'DEBUG: HDD ' -align 16 - - -; NOTE: These functions use LBA28. Maximum visible drive size is 128GiB -; LBA48 would be needed to access sectors over 128GiB (up to 128PiB) -; These functions are hard coded to access the Primary Master HDD - - -; ----------------------------------------------------------------------------- -; readsectors -- Read sectors on the hard drive -; IN: RAX = starting sector to read -; RCX = number of sectors to read (1 - 256) -; RDI = memory location to store sectors -; OUT: RAX = RAX + number of sectors that were read -; RCX = number of sectors that were read (0 on error) -; RDI = RDI + (number of sectors * 512) -; All other registers preserved -readsectors: - push rdx - push rcx - push rbx - push rax - - push rcx ; Save RCX for use in the read loop - mov rbx, rcx ; Store number of sectors to read - cmp rcx, 256 - jg readsectors_fail ; Over 256? Fail! - jne readsectors_skip ; Not 256? No need to modify CL - xor rcx, rcx ; 0 translates to 256 -readsectors_skip: - - push rax ; Save RAX since we are about to overwrite it - mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 - mov al, cl ; Read CL sectors - out dx, al - pop rax ; Restore RAX which is our sector number - inc dx ; 0x01F3 - LBA Low Port 7:0 - out dx, al - inc dx ; 0x01F4 - LBA Mid Port 15:8 - shr rax, 8 - out dx, al - inc dx ; 0x01F5 - LBA High Port 23:16 - shr rax, 8 - out dx, al - inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) - shr rax, 8 - and al, 00001111b ; Clear bits 4-7 just to be safe - or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) - out dx, al - inc dx ; 0x01F7 - Command Port - mov al, 0x20 ; Read sector(s). 0x24 if LBA48 - out dx, al - - mov rcx, 4 -readsectors_wait: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_retry - test al, 0x08 ; DRQ set? - jne readsectors_dataready -readsectors_retry: - dec rcx - jg readsectors_wait -readsectors_nextsector: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_nextsector - test al, 0x21 ; ERR or DF set? - jne readsectors_fail - -readsectors_dataready: - sub dx, 7 ; Data port (0x1F0) - mov rcx, 256 ; Read - rep insw ; Copy a 512 byte sector to RDI - add dx, 7 ; Set DX back to status register (0x01F7) - in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ - in al, dx - in al, dx - in al, dx - - dec rbx ; RBX is the "sectors to read" counter - cmp rbx, 0 - jne readsectors_nextsector - - pop rcx - pop rax - pop rbx - add rax, rcx - pop rcx - pop rdx -ret - -readsectors_fail: - pop rcx - pop rax - pop rbx - pop rcx - pop rdx - xor rcx, rcx ; Set RCX to 0 since nothing was read -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; writesectors -- Write sectors on the hard drive -; IN: RAX = starting sector to write -; RCX = number of sectors to write (1 - 256) -; RSI = memory location of sectors -; OUT: RAX = RAX + number of sectors that were written -; RCX = number of sectors that were written (0 on error) -; RSI = RSI + (number of sectors * 512) -; All other registers preserved -writesectors: - push rdx - push rcx - push rbx - push rax - - push rcx ; Save RCX for use in the write loop - mov rbx, rcx ; Store number of sectors to write - cmp rcx, 256 - jg writesectors_fail ; Over 256? Fail! - jne writesectors_skip ; Not 256? No need to modify CL - xor rcx, rcx ; 0 translates to 256 -writesectors_skip: - - push rax ; Save RAX since we are about to overwrite it - mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 - mov al, cl ; Write CL sectors - out dx, al - pop rax ; Restore RAX which is our sector number - inc dx ; 0x01F3 - LBA Low Port 7:0 - out dx, al - inc dx ; 0x01F4 - LBA Mid Port 15:8 - shr rax, 8 - out dx, al - inc dx ; 0x01F5 - LBA High Port 23:16 - shr rax, 8 - out dx, al - inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) - shr rax, 8 ; Bits 7 and 5 are obsolete in LBA mode so set to 0 - and al, 00001111b ; Clear bits 4-7 just to be safe - or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) - out dx, al - inc dx ; 0x01F7 - Command Port - mov al, 0x30 ; Write sector(s). 0x34 if LBA48 - out dx, al - - mov rcx, 4 -writesectors_wait: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne writesectors_retry - test al, 0x08 ; DRQ set? - jne writesectors_dataready -writesectors_retry: - dec rcx - jg writesectors_wait -writesectors_nextsector: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne writesectors_nextsector - test al, 0x21 ; ERR or DF set? - jne writesectors_fail - -writesectors_dataready: - sub dx, 7 ; Data port (0x01F0) - mov rcx, 256 ; Write 256 words (512 bytes) -writesectors_nextword: - outsw ; Cannot use rep as a small delay is needed between each out - sub rcx, 1 - cmp rcx, 0 - jne writesectors_nextword - add dx, 7 ; Set DX back to Command / Status Register (0x01F7) - mov al, 0xE7 ; Cache Flush command - out dx, al - in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ - in al, dx - in al, dx - in al, dx - - dec rbx ; RBX is the "sectors to write" counter - cmp rbx, 0 - jne writesectors_nextsector - - pop rcx - pop rax - pop rbx - add rax, rcx - pop rcx - pop rdx -ret - -writesectors_fail: - pop rcx - pop rax - pop rbx - pop rcx - pop rdx - xor rcx, rcx ; Set RCX to 0 since nothing was written -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Hard Drive Functions +; ============================================================================= + +align 16 +db 'DEBUG: HDD ' +align 16 + + +; NOTE: These functions use LBA28. Maximum visible drive size is 128GiB +; LBA48 would be needed to access sectors over 128GiB (up to 128PiB) +; These functions are hard coded to access the Primary Master HDD + + +; ----------------------------------------------------------------------------- +; readsectors -- Read sectors on the hard drive +; IN: RAX = starting sector to read +; RCX = number of sectors to read (1 - 256) +; RDI = memory location to store sectors +; OUT: RAX = RAX + number of sectors that were read +; RCX = number of sectors that were read (0 on error) +; RDI = RDI + (number of sectors * 512) +; All other registers preserved +readsectors: + push rdx + push rcx + push rbx + push rax + + push rcx ; Save RCX for use in the read loop + mov rbx, rcx ; Store number of sectors to read + cmp rcx, 256 + jg readsectors_fail ; Over 256? Fail! + jne readsectors_skip ; Not 256? No need to modify CL + xor rcx, rcx ; 0 translates to 256 +readsectors_skip: + + push rax ; Save RAX since we are about to overwrite it + mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 + mov al, cl ; Read CL sectors + out dx, al + pop rax ; Restore RAX which is our sector number + inc dx ; 0x01F3 - LBA Low Port 7:0 + out dx, al + inc dx ; 0x01F4 - LBA Mid Port 15:8 + shr rax, 8 + out dx, al + inc dx ; 0x01F5 - LBA High Port 23:16 + shr rax, 8 + out dx, al + inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) + shr rax, 8 + and al, 00001111b ; Clear bits 4-7 just to be safe + or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) + out dx, al + inc dx ; 0x01F7 - Command Port + mov al, 0x20 ; Read sector(s). 0x24 if LBA48 + out dx, al + + mov rcx, 4 +readsectors_wait: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_retry + test al, 0x08 ; DRQ set? + jne readsectors_dataready +readsectors_retry: + dec rcx + jg readsectors_wait +readsectors_nextsector: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_nextsector + test al, 0x21 ; ERR or DF set? + jne readsectors_fail + +readsectors_dataready: + sub dx, 7 ; Data port (0x1F0) + mov rcx, 256 ; Read + rep insw ; Copy a 512 byte sector to RDI + add dx, 7 ; Set DX back to status register (0x01F7) + in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ + in al, dx + in al, dx + in al, dx + + dec rbx ; RBX is the "sectors to read" counter + cmp rbx, 0 + jne readsectors_nextsector + + pop rcx + pop rax + pop rbx + add rax, rcx + pop rcx + pop rdx +ret + +readsectors_fail: + pop rcx + pop rax + pop rbx + pop rcx + pop rdx + xor rcx, rcx ; Set RCX to 0 since nothing was read +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; writesectors -- Write sectors on the hard drive +; IN: RAX = starting sector to write +; RCX = number of sectors to write (1 - 256) +; RSI = memory location of sectors +; OUT: RAX = RAX + number of sectors that were written +; RCX = number of sectors that were written (0 on error) +; RSI = RSI + (number of sectors * 512) +; All other registers preserved +writesectors: + push rdx + push rcx + push rbx + push rax + + push rcx ; Save RCX for use in the write loop + mov rbx, rcx ; Store number of sectors to write + cmp rcx, 256 + jg writesectors_fail ; Over 256? Fail! + jne writesectors_skip ; Not 256? No need to modify CL + xor rcx, rcx ; 0 translates to 256 +writesectors_skip: + + push rax ; Save RAX since we are about to overwrite it + mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 + mov al, cl ; Write CL sectors + out dx, al + pop rax ; Restore RAX which is our sector number + inc dx ; 0x01F3 - LBA Low Port 7:0 + out dx, al + inc dx ; 0x01F4 - LBA Mid Port 15:8 + shr rax, 8 + out dx, al + inc dx ; 0x01F5 - LBA High Port 23:16 + shr rax, 8 + out dx, al + inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) + shr rax, 8 ; Bits 7 and 5 are obsolete in LBA mode so set to 0 + and al, 00001111b ; Clear bits 4-7 just to be safe + or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) + out dx, al + inc dx ; 0x01F7 - Command Port + mov al, 0x30 ; Write sector(s). 0x34 if LBA48 + out dx, al + + mov rcx, 4 +writesectors_wait: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne writesectors_retry + test al, 0x08 ; DRQ set? + jne writesectors_dataready +writesectors_retry: + dec rcx + jg writesectors_wait +writesectors_nextsector: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne writesectors_nextsector + test al, 0x21 ; ERR or DF set? + jne writesectors_fail + +writesectors_dataready: + sub dx, 7 ; Data port (0x01F0) + mov rcx, 256 ; Write 256 words (512 bytes) +writesectors_nextword: + outsw ; Cannot use rep as a small delay is needed between each out + sub rcx, 1 + cmp rcx, 0 + jne writesectors_nextword + add dx, 7 ; Set DX back to Command / Status Register (0x01F7) + mov al, 0xE7 ; Cache Flush command + out dx, al + in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ + in al, dx + in al, dx + in al, dx + + dec rbx ; RBX is the "sectors to write" counter + cmp rbx, 0 + jne writesectors_nextsector + + pop rcx + pop rax + pop rbx + add rax, rcx + pop rcx + pop rdx +ret + +writesectors_fail: + pop rcx + pop rax + pop rbx + pop rcx + pop rdx + xor rcx, rcx ; Set RCX to 0 since nothing was written +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/net/bcm57xx.asm b/amd64/bareMetalOS-0.5.3/os/drivers/net/bcm57xx.asm index 8d94bc27..644964a8 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/net/bcm57xx.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/net/bcm57xx.asm @@ -1,122 +1,122 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Broadcom 57XX NIC. -; ============================================================================= - -align 16 -db 'DEBUG: BCM57xx ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_init - Initialize a Broadcom 57XX NIC -; IN: AL = Bus number of the Realtek device -; BL = Device/Slot number of the Realtek device -os_net_bcm57xx_init: - push rsi - push rdx - push rcx - push rax - - ; Grab the Base I/O Address of the device - push ax - mov cl, 0x04 ; BAR0 - Lower 32 bits of memory address - call os_pci_read_reg -; mov dword [os_NetIOAddress], eax - pop ax - - ; Grab the IRQ of the device - mov cl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) - call os_pci_read_reg - mov [os_NetIRQ], al ; AL holds the IRQ - - ; Grab the MAC address - mov rsi, [os_NetIOBaseMem] - mov eax, [rsi+0x410] ; Mac_Address_0 Part 1 - ror eax, 8 - mov [os_NetMAC], al - rol eax, 8 - mov [os_NetMAC+1], al - mov eax, [rsi+0x414] ; Mac_Address_0 Part 2 - rol eax, 8 - mov [os_NetMAC+2], al - rol eax, 8 - mov [os_NetMAC+3], al - rol eax, 8 - mov [os_NetMAC+4], al - rol eax, 8 - mov [os_NetMAC+5], al - - ; Enable the Network IRQ in the PIC - ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 - in al, 0x21 ; low byte target 0x21 - mov bl, al - mov al, [os_NetIRQ] - mov dx, 0x21 ; Use the low byte pic - cmp al, 8 - jl os_net_bcm57xx_init_low - sub al, 8 ; IRQ 8-16 - push ax - in al, 0xA1 ; High byte target 0xA1 - mov bl, al - pop ax - mov dx, 0xA1 ; Use the high byte pic -os_net_bcm57xx_init_low: - mov cl, al - mov al, 1 - shl al, cl - not al - and al, bl - out dx, al - - ; Reset the device - call os_net_bcm57xx_reset - - pop rax - pop rcx - pop rdx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_reset - Reset a Broadcom 57XX NIC -; IN: Nothing -; OUT: Nothing, all registers preserved -os_net_bcm57xx_reset: - - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_transmit - Transmit a packet via a Broadcom 57XX NIC -; IN: RSI = Location of packet -; RCX = Length of packet -; OUT: Nothing -; Uses RAX, RCX, RDX, RSI, RDI -; ToDo: Check for proper timeout instead of calling os_delay -os_net_bcm57xx_transmit: - - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_bcm57xx_poll - Polls the Broadcom 57XX NIC for a received packet -; IN: RDI = Location to store packet -; OUT: RCX = Length of packet -; Uses RAX, RCX, RDX, RSI, RDI -os_net_bcm57xx_poll: - -os_net_bcm57xx_ack_int: - - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Broadcom 57XX NIC. +; ============================================================================= + +align 16 +db 'DEBUG: BCM57xx ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_init - Initialize a Broadcom 57XX NIC +; IN: AL = Bus number of the Realtek device +; BL = Device/Slot number of the Realtek device +os_net_bcm57xx_init: + push rsi + push rdx + push rcx + push rax + + ; Grab the Base I/O Address of the device + push ax + mov cl, 0x04 ; BAR0 - Lower 32 bits of memory address + call os_pci_read_reg +; mov dword [os_NetIOAddress], eax + pop ax + + ; Grab the IRQ of the device + mov cl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) + call os_pci_read_reg + mov [os_NetIRQ], al ; AL holds the IRQ + + ; Grab the MAC address + mov rsi, [os_NetIOBaseMem] + mov eax, [rsi+0x410] ; Mac_Address_0 Part 1 + ror eax, 8 + mov [os_NetMAC], al + rol eax, 8 + mov [os_NetMAC+1], al + mov eax, [rsi+0x414] ; Mac_Address_0 Part 2 + rol eax, 8 + mov [os_NetMAC+2], al + rol eax, 8 + mov [os_NetMAC+3], al + rol eax, 8 + mov [os_NetMAC+4], al + rol eax, 8 + mov [os_NetMAC+5], al + + ; Enable the Network IRQ in the PIC + ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 + in al, 0x21 ; low byte target 0x21 + mov bl, al + mov al, [os_NetIRQ] + mov dx, 0x21 ; Use the low byte pic + cmp al, 8 + jl os_net_bcm57xx_init_low + sub al, 8 ; IRQ 8-16 + push ax + in al, 0xA1 ; High byte target 0xA1 + mov bl, al + pop ax + mov dx, 0xA1 ; Use the high byte pic +os_net_bcm57xx_init_low: + mov cl, al + mov al, 1 + shl al, cl + not al + and al, bl + out dx, al + + ; Reset the device + call os_net_bcm57xx_reset + + pop rax + pop rcx + pop rdx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_reset - Reset a Broadcom 57XX NIC +; IN: Nothing +; OUT: Nothing, all registers preserved +os_net_bcm57xx_reset: + + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_transmit - Transmit a packet via a Broadcom 57XX NIC +; IN: RSI = Location of packet +; RCX = Length of packet +; OUT: Nothing +; Uses RAX, RCX, RDX, RSI, RDI +; ToDo: Check for proper timeout instead of calling os_delay +os_net_bcm57xx_transmit: + + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_bcm57xx_poll - Polls the Broadcom 57XX NIC for a received packet +; IN: RDI = Location to store packet +; OUT: RCX = Length of packet +; Uses RAX, RCX, RDX, RSI, RDI +os_net_bcm57xx_poll: + +os_net_bcm57xx_ack_int: + + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/net/i8254x.asm b/amd64/bareMetalOS-0.5.3/os/drivers/net/i8254x.asm index 161b7f7d..1a0406e6 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/net/i8254x.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/net/i8254x.asm @@ -1,461 +1,461 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Intel i8254x NIC. -; ============================================================================= - -align 16 -db 'DEBUG: I8254X ' -align 16 - - -; ----------------------------------------------------------------------------- -; Initialize an Intel 8254x NIC -; IN: BL = Bus number of the Intel device -; CL = Device/Slot number of the Intel device -os_net_i8254x_init: - push rsi - push rdx - push rcx - push rax - - ; Read BAR4, If BAR4 is all 0'z then we are using 32-bit addresses - - ; Grab the Base I/O Address of the device - mov dl, 0x04 ; BAR0 - call os_pci_read_reg -; bt eax, 0 -; jc os_net_i8254x_init_pio -; bt eax, 2 -; jc os_net_i8253x_init_64_bit - and eax, 0xFFFFFFF0 ; EAX now holds the Base Memory IO Address (clear the low 4 bits) - - mov dword [os_NetIOBaseMem], eax - - ; Grab the IRQ of the device - mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) - call os_pci_read_reg - mov [os_NetIRQ], al ; AL holds the IRQ - - ; Grab the MAC address - mov rsi, [os_NetIOBaseMem] - mov eax, [rsi+0x5400] ; RAL - cmp eax, 0x00000000 - je os_net_i8254x_init_get_MAC_via_EPROM - mov [os_NetMAC], al - shr eax, 8 - mov [os_NetMAC+1], al - shr eax, 8 - mov [os_NetMAC+2], al - shr eax, 8 - mov [os_NetMAC+3], al - mov eax, [rsi+0x5404] ; RAH - mov [os_NetMAC+4], al - shr eax, 8 - mov [os_NetMAC+5], al - jmp os_net_i8254x_init_done_MAC - -os_net_i8254x_init_get_MAC_via_EPROM: - mov rsi, [os_NetIOBaseMem] - mov eax, 0x00000001 - mov [rsi+0x14], eax - mov eax, [rsi+0x14] - shr eax, 16 - mov [os_NetMAC], al - shr eax, 8 - mov [os_NetMAC+1], al - mov eax, 0x00000101 - mov [rsi+0x14], eax - mov eax, [rsi+0x14] - shr eax, 16 - mov [os_NetMAC+2], al - shr eax, 8 - mov [os_NetMAC+3], al - mov eax, 0x00000201 - mov [rsi+0x14], eax - mov eax, [rsi+0x14] - shr eax, 16 - mov [os_NetMAC+4], al - shr eax, 8 - mov [os_NetMAC+5], al -os_net_i8254x_init_done_MAC: - - ; Enable the Network IRQ in the PIC -; mov al, [os_NetIRQ] -; call interrupt_enable - - ; Reset the device - call os_net_i8254x_reset - - pop rax - pop rcx - pop rdx - pop rsi - ret - -;os_net_i8254x_init_pio: -; jmp $ -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_reset - Reset an Intel 8254x NIC -; IN: Nothing -; OUT: Nothing, all registers preserved -os_net_i8254x_reset: - mov rsi, [os_NetIOBaseMem] - mov rdi, rsi - - mov eax, 0xFFFFFFFF - mov [rsi+I8254X_REG_IMC], eax ; Disable all interrupt causes - mov eax, [rsi+I8254X_REG_ICR] ; Clear any pending interrupts - xor eax, eax - mov [rsi+I8254X_REG_ITR], eax ; Disable interrupt throttling logic - - mov eax, 0x00000030 - mov [rsi+I8254X_REG_PBA], eax ; PBA: set the RX buffer size to 48KB (TX buffer is calculated as 64-RX buffer) - - mov eax, 0x08008060 - mov [rsi+I8254X_REG_TXCW], eax ; TXCW: set ANE, TxConfigWord (Half/Full duplex, Next Page Request) - - mov eax, [rsi+I8254X_REG_CTRL] - btr eax, 3 - bts eax, 6 - bts eax, 5 - btr eax, 31 - btr eax, 30 - btr eax, 7 - mov [rsi+I8254X_REG_CTRL], eax ; CTRL: clear LRST, set SLU and ASDE, clear RSTPHY, VME, and ILOS - - push rdi - add rdi, 0x5200 ; MTA: reset - mov eax, 0xFFFFFFFF - stosd - stosd - stosd - stosd - pop rdi - - mov rax, os_eth_rx_buffer - mov [rsi+I8254X_REG_RDBAL], eax ; Receive Descriptor Base Address Low - shr rax, 32 - mov [rsi+I8254X_REG_RDBAH], eax ; Receive Descriptor Base Address High - mov eax, (32 * 16) - mov [rsi+I8254X_REG_RDLEN], eax ; Receive Descriptor Length - xor eax, eax - mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head - mov eax, 1 - mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail - mov eax, 0x04008006 ; Receiver Enable, Store Bad Packets, Broadcast Accept Mode, Strip Ethernet CRC from incoming packet - mov [rsi+I8254X_REG_RCTL], eax ; Receive Control Register - - push rdi - mov rdi, os_eth_rx_buffer - mov rax, 0x1c9000 - stosd - pop rdi - - mov rax, os_eth_tx_buffer - mov [rsi+I8254X_REG_TDBAL], eax ; Transmit Descriptor Base Address Low - shr rax, 32 - mov [rsi+I8254X_REG_TDBAH], eax ; Transmit Descriptor Base Address High - mov eax, (32 * 16) - mov [rsi+I8254X_REG_TDLEN], eax ; Transmit Descriptor Length - xor eax, eax - mov [rsi+I8254X_REG_TDH], eax ; Transmit Descriptor Head - mov [rsi+I8254X_REG_TDT], eax ; Transmit Descriptor Tail - mov eax, 0x010400FA ; Enabled, Pad Short Packets, 15 retrys, 64-byte COLD, Re-transmit on Late Collision - mov [rsi+I8254X_REG_TCTL], eax ; Transmit Control Register - mov eax, 0x0060200A ; IPGT 10, IPGR1 8, IPGR2 6 - mov [rsi+I8254X_REG_TIPG], eax ; Transmit IPG Register - - xor eax, eax - mov [rsi+I8254X_REG_RDTR], eax ; Clear the Receive Delay Timer Register - mov [rsi+I8254X_REG_RADV], eax ; Clear the Receive Interrupt Absolute Delay Timer - mov [rsi+I8254X_REG_RSRPD], eax ; Clear the Receive Small Packet Detect Interrupt - bts eax, 0 ; TXDW - bts eax, 7 ; RXT0 - mov eax, 0x1FFFF ; Temp enable all interrupt types - mov [rsi+I8254X_REG_IMS], eax ; Enable interrupt types - - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_transmit - Transmit a packet via an Intel 8254x NIC -; IN: RSI = Location of packet -; RCX = Length of packet -; OUT: Nothing -; Uses RAX, RCX, RSI, RDI -os_net_i8254x_transmit: - mov rdi, os_eth_tx_buffer ; Transmit Descriptor Base Address - mov rax, rsi - stosq ; Store the data location - mov rax, rcx ; The packet size is in CL - bts rax, 24 ; EOP - bts rax, 25 ; IFCS - bts rax, 27 ; RS - stosq - mov rdi, [os_NetIOBaseMem] - xor eax, eax - mov [rdi+I8254X_REG_TDH], eax ; TDH - Transmit Descriptor Head - add eax, 1 - mov [rdi+I8254X_REG_TDT], eax ; TDL - Transmit Descriptor Tail - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_poll - Polls the Intel 8254x NIC for a received packet -; IN: RDI = Location to store packet -; OUT: RCX = Length of packet -; Uses RAX, RCX, RDX, RSI, RDI -os_net_i8254x_poll: - xor ecx, ecx - - mov cx, [os_eth_rx_buffer+8] ; Get the packet length - mov rsi, 0x1c9000 - push rcx - rep movsb - pop rcx - mov rsi, [os_NetIOBaseMem] - xor eax, eax - mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head - mov eax, 1 - mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail - - push rdi - mov rdi, os_eth_rx_buffer - mov rax, 0x1c9000 - stosd - pop rdi - - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_i8254x_ack_int - Acknowledge an internal interrupt of the Intel 8254x NIC -os_net_i8254x_ack_int: - xor eax, eax - mov rdi, [os_NetIOBaseMem] - mov eax, [rdi+I8254X_REG_ICR] - ret -; ----------------------------------------------------------------------------- - - -; Maximum packet size -I8254X_MAX_PKT_SIZE equ 16384 - -; Register list -I8254X_REG_CTRL equ 0x0000 ; Control Register -I8254X_REG_STATUS equ 0x0008 ; Device Status Register -I8254X_REG_CTRLEXT equ 0x0018 ; Extended Control Register -I8254X_REG_MDIC equ 0x0020 ; MDI Control Register -I8254X_REG_FCAL equ 0x0028 ; Flow Control Address Low -I8254X_REG_FCAH equ 0x002C ; Flow Control Address High -I8254X_REG_FCT equ 0x0030 ; Flow Control Type -I8254X_REG_VET equ 0x0038 ; VLAN Ether Type -I8254X_REG_ICR equ 0x00C0 ; Interrupt Cause Read -I8254X_REG_ITR equ 0x00C4 ; Interrupt Throttling Register -I8254X_REG_ICS equ 0x00C8 ; Interrupt Cause Set Register -I8254X_REG_IMS equ 0x00D0 ; Interrupt Mask Set/Read Register -I8254X_REG_IMC equ 0x00D8 ; Interrupt Mask Clear Register -I8254X_REG_RCTL equ 0x0100 ; Receive Control Register -I8254X_REG_FCTTV equ 0x0170 ; Flow Control Transmit Timer Value -I8254X_REG_TXCW equ 0x0178 ; Transmit Configuration Word -I8254X_REG_RXCW equ 0x0180 ; Receive Configuration Word -I8254X_REG_TCTL equ 0x0400 ; Transmit Control Register -I8254X_REG_TIPG equ 0x0410 ; Transmit Inter Packet Gap - -I8254X_REG_LEDCTL equ 0x0E00 ; LED Control -I8254X_REG_PBA equ 0x1000 ; Packet Buffer Allocation - -I8254X_REG_RDBAL equ 0x2800 ; RX Descriptor Base Address Low -I8254X_REG_RDBAH equ 0x2804 ; RX Descriptor Base Address High -I8254X_REG_RDLEN equ 0x2808 ; RX Descriptor Length -I8254X_REG_RDH equ 0x2810 ; RX Descriptor Head -I8254X_REG_RDT equ 0x2818 ; RX Descriptor Tail -I8254X_REG_RDTR equ 0x2820 ; RX Delay Timer Register -I8254X_REG_RXDCTL equ 0x3828 ; RX Descriptor Control -I8254X_REG_RADV equ 0x282C ; RX Int. Absolute Delay Timer -I8254X_REG_RSRPD equ 0x2C00 ; RX Small Packet Detect Interrupt - -I8254X_REG_TXDMAC equ 0x3000 ; TX DMA Control -I8254X_REG_TDBAL equ 0x3800 ; TX Descriptor Base Address Low -I8254X_REG_TDBAH equ 0x3804 ; TX Descriptor Base Address High -I8254X_REG_TDLEN equ 0x3808 ; TX Descriptor Length -I8254X_REG_TDH equ 0x3810 ; TX Descriptor Head -I8254X_REG_TDT equ 0x3818 ; TX Descriptor Tail -I8254X_REG_TIDV equ 0x3820 ; TX Interrupt Delay Value -I8254X_REG_TXDCTL equ 0x3828 ; TX Descriptor Control -I8254X_REG_TADV equ 0x382C ; TX Absolute Interrupt Delay Value -I8254X_REG_TSPMT equ 0x3830 ; TCP Segmentation Pad & Min Threshold - -I8254X_REG_RXCSUM equ 0x5000 ; RX Checksum Control - -; Register list for i8254x -I82542_REG_RDTR equ 0x0108 ; RX Delay Timer Register -I82542_REG_RDBAL equ 0x0110 ; RX Descriptor Base Address Low -I82542_REG_RDBAH equ 0x0114 ; RX Descriptor Base Address High -I82542_REG_RDLEN equ 0x0118 ; RX Descriptor Length -I82542_REG_RDH equ 0x0120 ; RDH for i82542 -I82542_REG_RDT equ 0x0128 ; RDT for i82542 -I82542_REG_TDBAL equ 0x0420 ; TX Descriptor Base Address Low -I82542_REG_TDBAH equ 0x0424 ; TX Descriptor Base Address Low -I82542_REG_TDLEN equ 0x0428 ; TX Descriptor Length -I82542_REG_TDH equ 0x0430 ; TDH for i82542 -I82542_REG_TDT equ 0x0438 ; TDT for i82542 - -; CTRL - Control Register (0x0000) -I8254X_CTRL_FD equ 0x00000001 ; Full Duplex -I8254X_CTRL_LRST equ 0x00000008 ; Link Reset -I8254X_CTRL_ASDE equ 0x00000020 ; Auto-speed detection -I8254X_CTRL_SLU equ 0x00000040 ; Set Link Up -I8254X_CTRL_ILOS equ 0x00000080 ; Invert Loss of Signal -I8254X_CTRL_SPEED_MASK equ 0x00000300 ; Speed selection -I8254X_CTRL_SPEED_SHIFT equ 8 -I8254X_CTRL_FRCSPD equ 0x00000800 ; Force Speed -I8254X_CTRL_FRCDPLX equ 0x00001000 ; Force Duplex -I8254X_CTRL_SDP0_DATA equ 0x00040000 ; SDP0 data -I8254X_CTRL_SDP1_DATA equ 0x00080000 ; SDP1 data -I8254X_CTRL_SDP0_IODIR equ 0x00400000 ; SDP0 direction -I8254X_CTRL_SDP1_IODIR equ 0x00800000 ; SDP1 direction -I8254X_CTRL_RST equ 0x04000000 ; Device Reset -I8254X_CTRL_RFCE equ 0x08000000 ; RX Flow Ctrl Enable -I8254X_CTRL_TFCE equ 0x10000000 ; TX Flow Ctrl Enable -I8254X_CTRL_VME equ 0x40000000 ; VLAN Mode Enable -I8254X_CTRL_PHY_RST equ 0x80000000 ; PHY reset - -; STATUS - Device Status Register (0x0008) -I8254X_STATUS_FD equ 0x00000001 ; Full Duplex -I8254X_STATUS_LU equ 0x00000002 ; Link Up -I8254X_STATUS_TXOFF equ 0x00000010 ; Transmit paused -I8254X_STATUS_TBIMODE equ 0x00000020 ; TBI Mode -I8254X_STATUS_SPEED_MASK equ 0x000000C0 ; Link Speed setting -I8254X_STATUS_SPEED_SHIFT equ 6 -I8254X_STATUS_ASDV_MASK equ 0x00000300 ; Auto Speed Detection -I8254X_STATUS_ASDV_SHIFT equ 8 -I8254X_STATUS_PCI66 equ 0x00000800 ; PCI bus speed -I8254X_STATUS_BUS64 equ 0x00001000 ; PCI bus width -I8254X_STATUS_PCIX_MODE equ 0x00002000 ; PCI-X mode -I8254X_STATUS_PCIXSPD_MASK equ 0x0000C000 ; PCI-X speed -I8254X_STATUS_PCIXSPD_SHIFT equ 14 - -; CTRL_EXT - Extended Device Control Register (0x0018) -I8254X_CTRLEXT_PHY_INT equ 0x00000020 ; PHY interrupt -I8254X_CTRLEXT_SDP6_DATA equ 0x00000040 ; SDP6 data -I8254X_CTRLEXT_SDP7_DATA equ 0x00000080 ; SDP7 data -I8254X_CTRLEXT_SDP6_IODIR equ 0x00000400 ; SDP6 direction -I8254X_CTRLEXT_SDP7_IODIR equ 0x00000800 ; SDP7 direction -I8254X_CTRLEXT_ASDCHK equ 0x00001000 ; Auto-Speed Detect Chk -I8254X_CTRLEXT_EE_RST equ 0x00002000 ; EEPROM reset -I8254X_CTRLEXT_SPD_BYPS equ 0x00008000 ; Speed Select Bypass -I8254X_CTRLEXT_RO_DIS equ 0x00020000 ; Relaxed Ordering Dis. -I8254X_CTRLEXT_LNKMOD_MASK equ 0x00C00000 ; Link Mode -I8254X_CTRLEXT_LNKMOD_SHIFT equ 22 - -; MDIC - MDI Control Register (0x0020) -I8254X_MDIC_DATA_MASK equ 0x0000FFFF ; Data -I8254X_MDIC_REG_MASK equ 0x001F0000 ; PHY Register -I8254X_MDIC_REG_SHIFT equ 16 -I8254X_MDIC_PHY_MASK equ 0x03E00000 ; PHY Address -I8254X_MDIC_PHY_SHIFT equ 21 -I8254X_MDIC_OP_MASK equ 0x0C000000 ; Opcode -I8254X_MDIC_OP_SHIFT equ 26 -I8254X_MDIC_R equ 0x10000000 ; Ready -I8254X_MDIC_I equ 0x20000000 ; Interrupt Enable -I8254X_MDIC_E equ 0x40000000 ; Error - -; ICR - Interrupt Cause Read (0x00c0) -I8254X_ICR_TXDW equ 0x00000001 ; TX Desc Written back -I8254X_ICR_TXQE equ 0x00000002 ; TX Queue Empty -I8254X_ICR_LSC equ 0x00000004 ; Link Status Change -I8254X_ICR_RXSEQ equ 0x00000008 ; RX Sequence Error -I8254X_ICR_RXDMT0 equ 0x00000010 ; RX Desc min threshold reached -I8254X_ICR_RXO equ 0x00000040 ; RX Overrun -I8254X_ICR_RXT0 equ 0x00000080 ; RX Timer Interrupt -I8254X_ICR_MDAC equ 0x00000200 ; MDIO Access Complete -I8254X_ICR_RXCFG equ 0x00000400 -I8254X_ICR_PHY_INT equ 0x00001000 ; PHY Interrupt -I8254X_ICR_GPI_SDP6 equ 0x00002000 ; GPI on SDP6 -I8254X_ICR_GPI_SDP7 equ 0x00004000 ; GPI on SDP7 -I8254X_ICR_TXD_LOW equ 0x00008000 ; TX Desc low threshold hit -I8254X_ICR_SRPD equ 0x00010000 ; Small RX packet detected - -; RCTL - Receive Control Register (0x0100) -I8254X_RCTL_EN equ 0x00000002 ; Receiver Enable -I8254X_RCTL_SBP equ 0x00000004 ; Store Bad Packets -I8254X_RCTL_UPE equ 0x00000008 ; Unicast Promiscuous Enabled -I8254X_RCTL_MPE equ 0x00000010 ; Xcast Promiscuous Enabled -I8254X_RCTL_LPE equ 0x00000020 ; Long Packet Reception Enable -I8254X_RCTL_LBM_MASK equ 0x000000C0 ; Loopback Mode -I8254X_RCTL_LBM_SHIFT equ 6 -I8254X_RCTL_RDMTS_MASK equ 0x00000300 ; RX Desc Min Threshold Size -I8254X_RCTL_RDMTS_SHIFT equ 8 -I8254X_RCTL_MO_MASK equ 0x00003000 ; Multicast Offset -I8254X_RCTL_MO_SHIFT equ 12 -I8254X_RCTL_BAM equ 0x00008000 ; Broadcast Accept Mode -I8254X_RCTL_BSIZE_MASK equ 0x00030000 ; RX Buffer Size -I8254X_RCTL_BSIZE_SHIFT equ 16 -I8254X_RCTL_VFE equ 0x00040000 ; VLAN Filter Enable -I8254X_RCTL_CFIEN equ 0x00080000 ; CFI Enable -I8254X_RCTL_CFI equ 0x00100000 ; Canonical Form Indicator Bit -I8254X_RCTL_DPF equ 0x00400000 ; Discard Pause Frames -I8254X_RCTL_PMCF equ 0x00800000 ; Pass MAC Control Frames -I8254X_RCTL_BSEX equ 0x02000000 ; Buffer Size Extension -I8254X_RCTL_SECRC equ 0x04000000 ; Strip Ethernet CRC - -; TCTL - Transmit Control Register (0x0400) -I8254X_TCTL_EN equ 0x00000002 ; Transmit Enable -I8254X_TCTL_PSP equ 0x00000008 ; Pad short packets -I8254X_TCTL_SWXOFF equ 0x00400000 ; Software XOFF Transmission - -; PBA - Packet Buffer Allocation (0x1000) -I8254X_PBA_RXA_MASK equ 0x0000FFFF ; RX Packet Buffer -I8254X_PBA_RXA_SHIFT equ 0 -I8254X_PBA_TXA_MASK equ 0xFFFF0000 ; TX Packet Buffer -I8254X_PBA_TXA_SHIFT equ 16 - -; Flow Control Type -I8254X_FCT_TYPE_DEFAULT equ 0x8808 - -; === TX Descriptor fields === - -; TX Packet Length (word 2) -I8254X_TXDESC_LEN_MASK equ 0x0000ffff - -; TX Descriptor CMD field (word 2) -I8254X_TXDESC_IDE equ 0x80000000 ; Interrupt Delay Enable -I8254X_TXDESC_VLE equ 0x40000000 ; VLAN Packet Enable -I8254X_TXDESC_DEXT equ 0x20000000 ; Extension -I8254X_TXDESC_RPS equ 0x10000000 ; Report Packet Sent -I8254X_TXDESC_RS equ 0x08000000 ; Report Status -I8254X_TXDESC_IC equ 0x04000000 ; Insert Checksum -I8254X_TXDESC_IFCS equ 0x02000000 ; Insert FCS -I8254X_TXDESC_EOP equ 0x01000000 ; End Of Packet - -; TX Descriptor STA field (word 3) -I8254X_TXDESC_TU equ 0x00000008 ; Transmit Underrun -I8254X_TXDESC_LC equ 0x00000004 ; Late Collision -I8254X_TXDESC_EC equ 0x00000002 ; Excess Collisions -I8254X_TXDESC_DD equ 0x00000001 ; Descriptor Done - -; === RX Descriptor fields === - -; RX Packet Length (word 2) -I8254X_RXDESC_LEN_MASK equ 0x0000ffff - -; RX Descriptor STA field (word 3) -I8254X_RXDESC_PIF equ 0x00000080 ; Passed In-exact Filter -I8254X_RXDESC_IPCS equ 0x00000040 ; IP cksum calculated -I8254X_RXDESC_TCPCS equ 0x00000020 ; TCP cksum calculated -I8254X_RXDESC_VP equ 0x00000008 ; Packet is 802.1Q -I8254X_RXDESC_IXSM equ 0x00000004 ; Ignore cksum indication -I8254X_RXDESC_EOP equ 0x00000002 ; End Of Packet -I8254X_RXDESC_DD equ 0x00000001 ; Descriptor Done - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Intel i8254x NIC. +; ============================================================================= + +align 16 +db 'DEBUG: I8254X ' +align 16 + + +; ----------------------------------------------------------------------------- +; Initialize an Intel 8254x NIC +; IN: BL = Bus number of the Intel device +; CL = Device/Slot number of the Intel device +os_net_i8254x_init: + push rsi + push rdx + push rcx + push rax + + ; Read BAR4, If BAR4 is all 0'z then we are using 32-bit addresses + + ; Grab the Base I/O Address of the device + mov dl, 0x04 ; BAR0 + call os_pci_read_reg +; bt eax, 0 +; jc os_net_i8254x_init_pio +; bt eax, 2 +; jc os_net_i8253x_init_64_bit + and eax, 0xFFFFFFF0 ; EAX now holds the Base Memory IO Address (clear the low 4 bits) + + mov dword [os_NetIOBaseMem], eax + + ; Grab the IRQ of the device + mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) + call os_pci_read_reg + mov [os_NetIRQ], al ; AL holds the IRQ + + ; Grab the MAC address + mov rsi, [os_NetIOBaseMem] + mov eax, [rsi+0x5400] ; RAL + cmp eax, 0x00000000 + je os_net_i8254x_init_get_MAC_via_EPROM + mov [os_NetMAC], al + shr eax, 8 + mov [os_NetMAC+1], al + shr eax, 8 + mov [os_NetMAC+2], al + shr eax, 8 + mov [os_NetMAC+3], al + mov eax, [rsi+0x5404] ; RAH + mov [os_NetMAC+4], al + shr eax, 8 + mov [os_NetMAC+5], al + jmp os_net_i8254x_init_done_MAC + +os_net_i8254x_init_get_MAC_via_EPROM: + mov rsi, [os_NetIOBaseMem] + mov eax, 0x00000001 + mov [rsi+0x14], eax + mov eax, [rsi+0x14] + shr eax, 16 + mov [os_NetMAC], al + shr eax, 8 + mov [os_NetMAC+1], al + mov eax, 0x00000101 + mov [rsi+0x14], eax + mov eax, [rsi+0x14] + shr eax, 16 + mov [os_NetMAC+2], al + shr eax, 8 + mov [os_NetMAC+3], al + mov eax, 0x00000201 + mov [rsi+0x14], eax + mov eax, [rsi+0x14] + shr eax, 16 + mov [os_NetMAC+4], al + shr eax, 8 + mov [os_NetMAC+5], al +os_net_i8254x_init_done_MAC: + + ; Enable the Network IRQ in the PIC +; mov al, [os_NetIRQ] +; call interrupt_enable + + ; Reset the device + call os_net_i8254x_reset + + pop rax + pop rcx + pop rdx + pop rsi + ret + +;os_net_i8254x_init_pio: +; jmp $ +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_reset - Reset an Intel 8254x NIC +; IN: Nothing +; OUT: Nothing, all registers preserved +os_net_i8254x_reset: + mov rsi, [os_NetIOBaseMem] + mov rdi, rsi + + mov eax, 0xFFFFFFFF + mov [rsi+I8254X_REG_IMC], eax ; Disable all interrupt causes + mov eax, [rsi+I8254X_REG_ICR] ; Clear any pending interrupts + xor eax, eax + mov [rsi+I8254X_REG_ITR], eax ; Disable interrupt throttling logic + + mov eax, 0x00000030 + mov [rsi+I8254X_REG_PBA], eax ; PBA: set the RX buffer size to 48KB (TX buffer is calculated as 64-RX buffer) + + mov eax, 0x08008060 + mov [rsi+I8254X_REG_TXCW], eax ; TXCW: set ANE, TxConfigWord (Half/Full duplex, Next Page Request) + + mov eax, [rsi+I8254X_REG_CTRL] + btr eax, 3 + bts eax, 6 + bts eax, 5 + btr eax, 31 + btr eax, 30 + btr eax, 7 + mov [rsi+I8254X_REG_CTRL], eax ; CTRL: clear LRST, set SLU and ASDE, clear RSTPHY, VME, and ILOS + + push rdi + add rdi, 0x5200 ; MTA: reset + mov eax, 0xFFFFFFFF + stosd + stosd + stosd + stosd + pop rdi + + mov rax, os_eth_rx_buffer + mov [rsi+I8254X_REG_RDBAL], eax ; Receive Descriptor Base Address Low + shr rax, 32 + mov [rsi+I8254X_REG_RDBAH], eax ; Receive Descriptor Base Address High + mov eax, (32 * 16) + mov [rsi+I8254X_REG_RDLEN], eax ; Receive Descriptor Length + xor eax, eax + mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head + mov eax, 1 + mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail + mov eax, 0x04008006 ; Receiver Enable, Store Bad Packets, Broadcast Accept Mode, Strip Ethernet CRC from incoming packet + mov [rsi+I8254X_REG_RCTL], eax ; Receive Control Register + + push rdi + mov rdi, os_eth_rx_buffer + mov rax, 0x1c9000 + stosd + pop rdi + + mov rax, os_eth_tx_buffer + mov [rsi+I8254X_REG_TDBAL], eax ; Transmit Descriptor Base Address Low + shr rax, 32 + mov [rsi+I8254X_REG_TDBAH], eax ; Transmit Descriptor Base Address High + mov eax, (32 * 16) + mov [rsi+I8254X_REG_TDLEN], eax ; Transmit Descriptor Length + xor eax, eax + mov [rsi+I8254X_REG_TDH], eax ; Transmit Descriptor Head + mov [rsi+I8254X_REG_TDT], eax ; Transmit Descriptor Tail + mov eax, 0x010400FA ; Enabled, Pad Short Packets, 15 retrys, 64-byte COLD, Re-transmit on Late Collision + mov [rsi+I8254X_REG_TCTL], eax ; Transmit Control Register + mov eax, 0x0060200A ; IPGT 10, IPGR1 8, IPGR2 6 + mov [rsi+I8254X_REG_TIPG], eax ; Transmit IPG Register + + xor eax, eax + mov [rsi+I8254X_REG_RDTR], eax ; Clear the Receive Delay Timer Register + mov [rsi+I8254X_REG_RADV], eax ; Clear the Receive Interrupt Absolute Delay Timer + mov [rsi+I8254X_REG_RSRPD], eax ; Clear the Receive Small Packet Detect Interrupt + bts eax, 0 ; TXDW + bts eax, 7 ; RXT0 + mov eax, 0x1FFFF ; Temp enable all interrupt types + mov [rsi+I8254X_REG_IMS], eax ; Enable interrupt types + + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_transmit - Transmit a packet via an Intel 8254x NIC +; IN: RSI = Location of packet +; RCX = Length of packet +; OUT: Nothing +; Uses RAX, RCX, RSI, RDI +os_net_i8254x_transmit: + mov rdi, os_eth_tx_buffer ; Transmit Descriptor Base Address + mov rax, rsi + stosq ; Store the data location + mov rax, rcx ; The packet size is in CL + bts rax, 24 ; EOP + bts rax, 25 ; IFCS + bts rax, 27 ; RS + stosq + mov rdi, [os_NetIOBaseMem] + xor eax, eax + mov [rdi+I8254X_REG_TDH], eax ; TDH - Transmit Descriptor Head + add eax, 1 + mov [rdi+I8254X_REG_TDT], eax ; TDL - Transmit Descriptor Tail + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_poll - Polls the Intel 8254x NIC for a received packet +; IN: RDI = Location to store packet +; OUT: RCX = Length of packet +; Uses RAX, RCX, RDX, RSI, RDI +os_net_i8254x_poll: + xor ecx, ecx + + mov cx, [os_eth_rx_buffer+8] ; Get the packet length + mov rsi, 0x1c9000 + push rcx + rep movsb + pop rcx + mov rsi, [os_NetIOBaseMem] + xor eax, eax + mov [rsi+I8254X_REG_RDH], eax ; Receive Descriptor Head + mov eax, 1 + mov [rsi+I8254X_REG_RDT], eax ; Receive Descriptor Tail + + push rdi + mov rdi, os_eth_rx_buffer + mov rax, 0x1c9000 + stosd + pop rdi + + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_i8254x_ack_int - Acknowledge an internal interrupt of the Intel 8254x NIC +os_net_i8254x_ack_int: + xor eax, eax + mov rdi, [os_NetIOBaseMem] + mov eax, [rdi+I8254X_REG_ICR] + ret +; ----------------------------------------------------------------------------- + + +; Maximum packet size +I8254X_MAX_PKT_SIZE equ 16384 + +; Register list +I8254X_REG_CTRL equ 0x0000 ; Control Register +I8254X_REG_STATUS equ 0x0008 ; Device Status Register +I8254X_REG_CTRLEXT equ 0x0018 ; Extended Control Register +I8254X_REG_MDIC equ 0x0020 ; MDI Control Register +I8254X_REG_FCAL equ 0x0028 ; Flow Control Address Low +I8254X_REG_FCAH equ 0x002C ; Flow Control Address High +I8254X_REG_FCT equ 0x0030 ; Flow Control Type +I8254X_REG_VET equ 0x0038 ; VLAN Ether Type +I8254X_REG_ICR equ 0x00C0 ; Interrupt Cause Read +I8254X_REG_ITR equ 0x00C4 ; Interrupt Throttling Register +I8254X_REG_ICS equ 0x00C8 ; Interrupt Cause Set Register +I8254X_REG_IMS equ 0x00D0 ; Interrupt Mask Set/Read Register +I8254X_REG_IMC equ 0x00D8 ; Interrupt Mask Clear Register +I8254X_REG_RCTL equ 0x0100 ; Receive Control Register +I8254X_REG_FCTTV equ 0x0170 ; Flow Control Transmit Timer Value +I8254X_REG_TXCW equ 0x0178 ; Transmit Configuration Word +I8254X_REG_RXCW equ 0x0180 ; Receive Configuration Word +I8254X_REG_TCTL equ 0x0400 ; Transmit Control Register +I8254X_REG_TIPG equ 0x0410 ; Transmit Inter Packet Gap + +I8254X_REG_LEDCTL equ 0x0E00 ; LED Control +I8254X_REG_PBA equ 0x1000 ; Packet Buffer Allocation + +I8254X_REG_RDBAL equ 0x2800 ; RX Descriptor Base Address Low +I8254X_REG_RDBAH equ 0x2804 ; RX Descriptor Base Address High +I8254X_REG_RDLEN equ 0x2808 ; RX Descriptor Length +I8254X_REG_RDH equ 0x2810 ; RX Descriptor Head +I8254X_REG_RDT equ 0x2818 ; RX Descriptor Tail +I8254X_REG_RDTR equ 0x2820 ; RX Delay Timer Register +I8254X_REG_RXDCTL equ 0x3828 ; RX Descriptor Control +I8254X_REG_RADV equ 0x282C ; RX Int. Absolute Delay Timer +I8254X_REG_RSRPD equ 0x2C00 ; RX Small Packet Detect Interrupt + +I8254X_REG_TXDMAC equ 0x3000 ; TX DMA Control +I8254X_REG_TDBAL equ 0x3800 ; TX Descriptor Base Address Low +I8254X_REG_TDBAH equ 0x3804 ; TX Descriptor Base Address High +I8254X_REG_TDLEN equ 0x3808 ; TX Descriptor Length +I8254X_REG_TDH equ 0x3810 ; TX Descriptor Head +I8254X_REG_TDT equ 0x3818 ; TX Descriptor Tail +I8254X_REG_TIDV equ 0x3820 ; TX Interrupt Delay Value +I8254X_REG_TXDCTL equ 0x3828 ; TX Descriptor Control +I8254X_REG_TADV equ 0x382C ; TX Absolute Interrupt Delay Value +I8254X_REG_TSPMT equ 0x3830 ; TCP Segmentation Pad & Min Threshold + +I8254X_REG_RXCSUM equ 0x5000 ; RX Checksum Control + +; Register list for i8254x +I82542_REG_RDTR equ 0x0108 ; RX Delay Timer Register +I82542_REG_RDBAL equ 0x0110 ; RX Descriptor Base Address Low +I82542_REG_RDBAH equ 0x0114 ; RX Descriptor Base Address High +I82542_REG_RDLEN equ 0x0118 ; RX Descriptor Length +I82542_REG_RDH equ 0x0120 ; RDH for i82542 +I82542_REG_RDT equ 0x0128 ; RDT for i82542 +I82542_REG_TDBAL equ 0x0420 ; TX Descriptor Base Address Low +I82542_REG_TDBAH equ 0x0424 ; TX Descriptor Base Address Low +I82542_REG_TDLEN equ 0x0428 ; TX Descriptor Length +I82542_REG_TDH equ 0x0430 ; TDH for i82542 +I82542_REG_TDT equ 0x0438 ; TDT for i82542 + +; CTRL - Control Register (0x0000) +I8254X_CTRL_FD equ 0x00000001 ; Full Duplex +I8254X_CTRL_LRST equ 0x00000008 ; Link Reset +I8254X_CTRL_ASDE equ 0x00000020 ; Auto-speed detection +I8254X_CTRL_SLU equ 0x00000040 ; Set Link Up +I8254X_CTRL_ILOS equ 0x00000080 ; Invert Loss of Signal +I8254X_CTRL_SPEED_MASK equ 0x00000300 ; Speed selection +I8254X_CTRL_SPEED_SHIFT equ 8 +I8254X_CTRL_FRCSPD equ 0x00000800 ; Force Speed +I8254X_CTRL_FRCDPLX equ 0x00001000 ; Force Duplex +I8254X_CTRL_SDP0_DATA equ 0x00040000 ; SDP0 data +I8254X_CTRL_SDP1_DATA equ 0x00080000 ; SDP1 data +I8254X_CTRL_SDP0_IODIR equ 0x00400000 ; SDP0 direction +I8254X_CTRL_SDP1_IODIR equ 0x00800000 ; SDP1 direction +I8254X_CTRL_RST equ 0x04000000 ; Device Reset +I8254X_CTRL_RFCE equ 0x08000000 ; RX Flow Ctrl Enable +I8254X_CTRL_TFCE equ 0x10000000 ; TX Flow Ctrl Enable +I8254X_CTRL_VME equ 0x40000000 ; VLAN Mode Enable +I8254X_CTRL_PHY_RST equ 0x80000000 ; PHY reset + +; STATUS - Device Status Register (0x0008) +I8254X_STATUS_FD equ 0x00000001 ; Full Duplex +I8254X_STATUS_LU equ 0x00000002 ; Link Up +I8254X_STATUS_TXOFF equ 0x00000010 ; Transmit paused +I8254X_STATUS_TBIMODE equ 0x00000020 ; TBI Mode +I8254X_STATUS_SPEED_MASK equ 0x000000C0 ; Link Speed setting +I8254X_STATUS_SPEED_SHIFT equ 6 +I8254X_STATUS_ASDV_MASK equ 0x00000300 ; Auto Speed Detection +I8254X_STATUS_ASDV_SHIFT equ 8 +I8254X_STATUS_PCI66 equ 0x00000800 ; PCI bus speed +I8254X_STATUS_BUS64 equ 0x00001000 ; PCI bus width +I8254X_STATUS_PCIX_MODE equ 0x00002000 ; PCI-X mode +I8254X_STATUS_PCIXSPD_MASK equ 0x0000C000 ; PCI-X speed +I8254X_STATUS_PCIXSPD_SHIFT equ 14 + +; CTRL_EXT - Extended Device Control Register (0x0018) +I8254X_CTRLEXT_PHY_INT equ 0x00000020 ; PHY interrupt +I8254X_CTRLEXT_SDP6_DATA equ 0x00000040 ; SDP6 data +I8254X_CTRLEXT_SDP7_DATA equ 0x00000080 ; SDP7 data +I8254X_CTRLEXT_SDP6_IODIR equ 0x00000400 ; SDP6 direction +I8254X_CTRLEXT_SDP7_IODIR equ 0x00000800 ; SDP7 direction +I8254X_CTRLEXT_ASDCHK equ 0x00001000 ; Auto-Speed Detect Chk +I8254X_CTRLEXT_EE_RST equ 0x00002000 ; EEPROM reset +I8254X_CTRLEXT_SPD_BYPS equ 0x00008000 ; Speed Select Bypass +I8254X_CTRLEXT_RO_DIS equ 0x00020000 ; Relaxed Ordering Dis. +I8254X_CTRLEXT_LNKMOD_MASK equ 0x00C00000 ; Link Mode +I8254X_CTRLEXT_LNKMOD_SHIFT equ 22 + +; MDIC - MDI Control Register (0x0020) +I8254X_MDIC_DATA_MASK equ 0x0000FFFF ; Data +I8254X_MDIC_REG_MASK equ 0x001F0000 ; PHY Register +I8254X_MDIC_REG_SHIFT equ 16 +I8254X_MDIC_PHY_MASK equ 0x03E00000 ; PHY Address +I8254X_MDIC_PHY_SHIFT equ 21 +I8254X_MDIC_OP_MASK equ 0x0C000000 ; Opcode +I8254X_MDIC_OP_SHIFT equ 26 +I8254X_MDIC_R equ 0x10000000 ; Ready +I8254X_MDIC_I equ 0x20000000 ; Interrupt Enable +I8254X_MDIC_E equ 0x40000000 ; Error + +; ICR - Interrupt Cause Read (0x00c0) +I8254X_ICR_TXDW equ 0x00000001 ; TX Desc Written back +I8254X_ICR_TXQE equ 0x00000002 ; TX Queue Empty +I8254X_ICR_LSC equ 0x00000004 ; Link Status Change +I8254X_ICR_RXSEQ equ 0x00000008 ; RX Sequence Error +I8254X_ICR_RXDMT0 equ 0x00000010 ; RX Desc min threshold reached +I8254X_ICR_RXO equ 0x00000040 ; RX Overrun +I8254X_ICR_RXT0 equ 0x00000080 ; RX Timer Interrupt +I8254X_ICR_MDAC equ 0x00000200 ; MDIO Access Complete +I8254X_ICR_RXCFG equ 0x00000400 +I8254X_ICR_PHY_INT equ 0x00001000 ; PHY Interrupt +I8254X_ICR_GPI_SDP6 equ 0x00002000 ; GPI on SDP6 +I8254X_ICR_GPI_SDP7 equ 0x00004000 ; GPI on SDP7 +I8254X_ICR_TXD_LOW equ 0x00008000 ; TX Desc low threshold hit +I8254X_ICR_SRPD equ 0x00010000 ; Small RX packet detected + +; RCTL - Receive Control Register (0x0100) +I8254X_RCTL_EN equ 0x00000002 ; Receiver Enable +I8254X_RCTL_SBP equ 0x00000004 ; Store Bad Packets +I8254X_RCTL_UPE equ 0x00000008 ; Unicast Promiscuous Enabled +I8254X_RCTL_MPE equ 0x00000010 ; Xcast Promiscuous Enabled +I8254X_RCTL_LPE equ 0x00000020 ; Long Packet Reception Enable +I8254X_RCTL_LBM_MASK equ 0x000000C0 ; Loopback Mode +I8254X_RCTL_LBM_SHIFT equ 6 +I8254X_RCTL_RDMTS_MASK equ 0x00000300 ; RX Desc Min Threshold Size +I8254X_RCTL_RDMTS_SHIFT equ 8 +I8254X_RCTL_MO_MASK equ 0x00003000 ; Multicast Offset +I8254X_RCTL_MO_SHIFT equ 12 +I8254X_RCTL_BAM equ 0x00008000 ; Broadcast Accept Mode +I8254X_RCTL_BSIZE_MASK equ 0x00030000 ; RX Buffer Size +I8254X_RCTL_BSIZE_SHIFT equ 16 +I8254X_RCTL_VFE equ 0x00040000 ; VLAN Filter Enable +I8254X_RCTL_CFIEN equ 0x00080000 ; CFI Enable +I8254X_RCTL_CFI equ 0x00100000 ; Canonical Form Indicator Bit +I8254X_RCTL_DPF equ 0x00400000 ; Discard Pause Frames +I8254X_RCTL_PMCF equ 0x00800000 ; Pass MAC Control Frames +I8254X_RCTL_BSEX equ 0x02000000 ; Buffer Size Extension +I8254X_RCTL_SECRC equ 0x04000000 ; Strip Ethernet CRC + +; TCTL - Transmit Control Register (0x0400) +I8254X_TCTL_EN equ 0x00000002 ; Transmit Enable +I8254X_TCTL_PSP equ 0x00000008 ; Pad short packets +I8254X_TCTL_SWXOFF equ 0x00400000 ; Software XOFF Transmission + +; PBA - Packet Buffer Allocation (0x1000) +I8254X_PBA_RXA_MASK equ 0x0000FFFF ; RX Packet Buffer +I8254X_PBA_RXA_SHIFT equ 0 +I8254X_PBA_TXA_MASK equ 0xFFFF0000 ; TX Packet Buffer +I8254X_PBA_TXA_SHIFT equ 16 + +; Flow Control Type +I8254X_FCT_TYPE_DEFAULT equ 0x8808 + +; === TX Descriptor fields === + +; TX Packet Length (word 2) +I8254X_TXDESC_LEN_MASK equ 0x0000ffff + +; TX Descriptor CMD field (word 2) +I8254X_TXDESC_IDE equ 0x80000000 ; Interrupt Delay Enable +I8254X_TXDESC_VLE equ 0x40000000 ; VLAN Packet Enable +I8254X_TXDESC_DEXT equ 0x20000000 ; Extension +I8254X_TXDESC_RPS equ 0x10000000 ; Report Packet Sent +I8254X_TXDESC_RS equ 0x08000000 ; Report Status +I8254X_TXDESC_IC equ 0x04000000 ; Insert Checksum +I8254X_TXDESC_IFCS equ 0x02000000 ; Insert FCS +I8254X_TXDESC_EOP equ 0x01000000 ; End Of Packet + +; TX Descriptor STA field (word 3) +I8254X_TXDESC_TU equ 0x00000008 ; Transmit Underrun +I8254X_TXDESC_LC equ 0x00000004 ; Late Collision +I8254X_TXDESC_EC equ 0x00000002 ; Excess Collisions +I8254X_TXDESC_DD equ 0x00000001 ; Descriptor Done + +; === RX Descriptor fields === + +; RX Packet Length (word 2) +I8254X_RXDESC_LEN_MASK equ 0x0000ffff + +; RX Descriptor STA field (word 3) +I8254X_RXDESC_PIF equ 0x00000080 ; Passed In-exact Filter +I8254X_RXDESC_IPCS equ 0x00000040 ; IP cksum calculated +I8254X_RXDESC_TCPCS equ 0x00000020 ; TCP cksum calculated +I8254X_RXDESC_VP equ 0x00000008 ; Packet is 802.1Q +I8254X_RXDESC_IXSM equ 0x00000004 ; Ignore cksum indication +I8254X_RXDESC_EOP equ 0x00000002 ; End Of Packet +I8254X_RXDESC_DD equ 0x00000001 ; Descriptor Done + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/net/rtl8169.asm b/amd64/bareMetalOS-0.5.3/os/drivers/net/rtl8169.asm index f763f768..c900fc3b 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/net/rtl8169.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/net/rtl8169.asm @@ -1,343 +1,343 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Realtek 8169 NIC. http://wiki.osdev.org/RTL8169 -; ============================================================================= - -align 16 -db 'DEBUG: RTL8169 ' -align 16 - - -; ----------------------------------------------------------------------------- -; Initialize a Realtek 8169 NIC -; IN: BL = Bus number of the Realtek device -; CL = Device/Slot number of the Realtek device -os_net_rtl8169_init: - push rsi - push rdx - push rcx - push rax - - ; Grab the Base I/O Address of the device - mov dl, 0x04 ; BAR0 - call os_pci_read_reg - and eax, 0xFFFFFFFC ; EAX now holds the Base IO Address (clear the low 2 bits) - mov word [os_NetIOAddress], ax - - ; Grab the IRQ of the device - mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) - call os_pci_read_reg - mov [os_NetIRQ], al ; AL holds the IRQ - - ; Grab the MAC address - mov dx, word [os_NetIOAddress] - in al, dx - mov [os_NetMAC], al - add dx, 1 - in al, dx - mov [os_NetMAC+1], al - add dx, 1 - in al, dx - mov [os_NetMAC+2], al - add dx, 1 - in al, dx - mov [os_NetMAC+3], al - add dx, 1 - in al, dx - mov [os_NetMAC+4], al - add dx, 1 - in al, dx - mov [os_NetMAC+5], al - - ; Enable the Network IRQ in the PIC - ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 -; in al, 0x21 ; low byte target 0x21 -; mov bl, al -; mov al, [os_NetIRQ] -; mov dx, 0x21 ; Use the low byte pic -; cmp al, 8 -; jl os_net_rtl8169_init_low -; sub al, 8 ; IRQ 8-16 -; push ax -; in al, 0xA1 ; High byte target 0xA1 -; mov bl, al -; pop ax -; mov dx, 0xA1 ; Use the high byte pic -;os_net_rtl8169_init_low: -; mov cl, al -; mov al, 1 -; shl al, cl -; not al -; and al, bl -; out dx, al - - ; Reset the device - call os_net_rtl8169_reset - - pop rax - pop rcx - pop rdx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8136_reset - Reset a Realtek 8169 NIC -; IN: Nothing -; OUT: Nothing, all registers preserved -os_net_rtl8169_reset: - push rdx - push rcx - push rax - - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_COMMAND - mov al, 0x10 ; Bit 4 set for Reset - out dx, al - mov cx, 1000 ; Wait no longer for the reset to complete -wait_for_8169_reset: - in al, dx - test al, 0x10 - jz reset_8169_completed ; RST remains 1 during reset, Reset complete when 0 - dec cx - jns wait_for_8169_reset -reset_8169_completed: - - ; Unlock config registers - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_9346CR - mov al, 0xC0 ; Unlock - out dx, al - - ; Set the C+ Command - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_CCR - in ax, dx - bts ax, 3 ; Enable PCI Multiple Read/Write - btc ax, 9 ; Little-endian mode - out dx, ax - - ; Power management? - - ; Recieve configuration - mov dx, word [os_NetIOAddress] - add edx, RTL8169_REG_RCR - mov eax, 0x0000E70A ; Set bits 1 (APM), 3 (AB), 8-10 (Unlimited), 13-15 (No limit) - out dx, eax - - ; Set up TCR - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_TCR - mov eax, 0x03000700 - out dx, eax - - ; Setup max RX size - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_MAXRX - mov ax, 0x3FFF ; 16384 - 1 - out dx, ax - - ; Setup max TX size - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_MAXTX - mov al, 0x3B - out dx, al - - ; Set the Transmit Normal Priority Descriptor Start Address - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_TNPDS - mov rax, os_eth_tx_buffer - out dx, eax ; Write the low bits - shr rax, 32 - add dx, 4 - out dx, eax ; Write the high bits - mov eax, 0x70000000 ; Set bit 30 (End of Descriptor Ring), 29 (FS), and 28 (LS) - mov [os_eth_tx_buffer], eax - - ; Set the Receive Descriptor Start Address - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_RDSAR - mov rax, os_eth_rx_buffer - out dx, eax ; Write the low bits - shr rax, 32 - add dx, 4 - out dx, eax ; Write the high bits - mov eax, 0x80001FF8 ; Set bits 31 (Ownership), also buffer size (Max 0x1FF8) - mov [os_eth_rx_buffer], eax - mov rax, os_ethernet_rx_buffer - mov [os_eth_rx_buffer+8], rax - mov eax, 0xC0001FF8 ; Set bits 31 (Ownership) and 30 (End of Descriptor Ring), also buffer size (Max 0x1FF8) - mov [os_eth_rx_buffer+16], eax - mov rax, os_ethernet_rx_buffer - mov [os_eth_rx_buffer+24], rax - - ; Initialize multicast registers (no filtering) - mov eax, 0xFFFFFFFF - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_MAR0 - out dx, eax - add dx, 4 ; MAR4 - out dx, eax - - ; Enable Rx/Tx in the Command register - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_COMMAND - mov al, (1 << RTL8169_BIT_RE) | (1 << RTL8169_BIT_TE) ;0x0C ; Set bits 2 (TE) and 3 (RE) - out dx, al - - ; Enable Receive and Transmit interrupts - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_IMR - mov ax, 0x0005 ; Set bits 0 (RX OK) and 2 (TX OK) - out dx, ax - - ; Lock config register - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_9346CR - mov al, 0x00 ; Lock - out dx, al - - pop rax - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8169_transmit - Transmit a packet via a Realtek 8169 NIC -; IN: RSI = Location of packet -; RCX = Length of packet -; OUT: Nothing -; Uses RAX, RCX, RDX, RSI, RDI -; ToDo: Check for proper timeout -os_net_rtl8169_transmit: - mov rdi, os_eth_tx_buffer - mov rax, rcx - stosw ; Store the frame length - add rdi, 6 ; Should the other data be cleared here? - mov rax, rsi - stosq ; Store the packet location - or dword [os_eth_tx_buffer], 0xF0000000 ; Set bit 31 (OWN), 30 (EOR), 29 (FS), and 28 (LS) - mov dx, word [os_NetIOAddress] - add dx, RTL8169_REG_TPPOLL - mov al, 0x40 - out dx, al ; Set up TX Polling -os_net_rtl8169_transmit_sendloop: - mov eax, [os_eth_tx_buffer] - and eax, 0x80000000 ; Check the ownership bit (BT command instead?) - cmp eax, 0x80000000 ; If the ownership bit is clear then the NIC sent the packet - je os_net_rtl8169_transmit_sendloop - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8169_poll - Polls the Realtek 8169 NIC for a received packet -; IN: RDI = Location to store packet -; OUT: RCX = Length of packet -; Uses RAX, RCX, RDX, RSI, RDI -os_net_rtl8169_poll: - xor ecx, ecx - mov cx, [os_eth_rx_buffer] - and cx, 0x3FFF ; Clear the two high bits as length is bits 13-0 - cmp cx, 0x1FF8 - jne os_net_rtl8169_poll_first_descriptor - mov cx, [os_eth_rx_buffer+16] - and cx, 0x3FFF ; Clear the two high bits as length is bits 13-0 -os_net_rtl8169_poll_first_descriptor: - mov rsi, os_ethernet_rx_buffer - push rcx - rep movsb ; Copy the packet to the lacation stored in RDI - pop rcx - mov eax, 0x80001FF8 ; Set bits 31 (Ownership), also buffer size (Max 0x1FF8) - mov [os_eth_rx_buffer], eax - mov rax, os_ethernet_rx_buffer - mov [os_eth_rx_buffer+8], rax - mov eax, 0xC0001FF8 ; Set bits 31 (Ownership) and 30 (End of Descriptor Ring), also buffer size (Max 0x1FF8) - mov [os_eth_rx_buffer+16], eax - mov rax, os_ethernet_rx_buffer - mov [os_eth_rx_buffer+24], rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_net_rtl8169_ack_int - Acknowledge an internal interrupt of the Realtek 8169 NIC -os_net_rtl8169_ack_int: - mov dx, word [os_NetIOAddress] ; Clear active interrupt sources - add dx, RTL8169_REG_ISR - in ax, dx -; call os_debug_dump_ax ; Display the interrupt type - out dx, ax - shr eax, 2 - ret -; ----------------------------------------------------------------------------- - - -; Register Descriptors - RTL8169_REG_IDR0 equ 0x00 ; ID Register 0 - RTL8169_REG_IDR1 equ 0x01 ; ID Register 1 - RTL8169_REG_IDR2 equ 0x02 ; ID Register 2 - RTL8169_REG_IDR3 equ 0x03 ; ID Register 3 - RTL8169_REG_IDR4 equ 0x04 ; ID Register 4 - RTL8169_REG_IDR5 equ 0x05 ; ID Register 5 - RTL8169_REG_MAR0 equ 0x08 ; Multicast Register 0 - RTL8169_REG_MAR1 equ 0x09 ; Multicast Register 1 - RTL8169_REG_MAR2 equ 0x0A ; Multicast Register 2 - RTL8169_REG_MAR3 equ 0x0B ; Multicast Register 3 - RTL8169_REG_MAR4 equ 0x0C ; Multicast Register 4 - RTL8169_REG_MAR5 equ 0x0D ; Multicast Register 5 - RTL8169_REG_MAR6 equ 0x0E ; Multicast Register 6 - RTL8169_REG_MAR7 equ 0x0F ; Multicast Register 7 - RTL8169_REG_TNPDS equ 0x20 ; Transmit Normal Priority Descriptors: Start address (64-bit). (256-byte alignment) - RTL8169_REG_COMMAND equ 0x37 ; Command Register - RTL8169_REG_TPPOLL equ 0x38 ; Transmit Priority Polling Register - RTL8169_REG_IMR equ 0x3C ; Interrupt Mask Register - RTL8169_REG_ISR equ 0x3E ; Interrupt Status Register - RTL8169_REG_TCR equ 0x40 ; Transmit (Tx) Configuration Register - RTL8169_REG_RCR equ 0x44 ; Receive (Rx) Configuration Register - RTL8169_REG_9346CR equ 0x50 ; 93C46 (93C56) Command Register - RTL8169_REG_CONFIG0 equ 0x51 ; Configuration Register 0 - RTL8169_REG_CONFIG1 equ 0x52 ; Configuration Register 1 - RTL8169_REG_CONFIG2 equ 0x53 ; Configuration Register 2 - RTL8169_REG_CONFIG3 equ 0x54 ; Configuration Register 3 - RTL8169_REG_CONFIG4 equ 0x55 ; Configuration Register 4 - RTL8169_REG_CONFIG5 equ 0x56 ; Configuration Register 5 - RTL8169_REG_PHYAR equ 0x60 ; PHY Access Register - RTL8169_REG_PHYStatus equ 0x6C ; PHY(GMII, MII, or TBI) Status Register - RTL8169_REG_MAXRX equ 0xDA ; Mac Receive Packet Size Register - RTL8169_REG_CCR equ 0xE0 ; C+ Command Register - RTL8169_REG_RDSAR equ 0xE4 ; Receive Descriptor Start Address Register (256-byte alignment) - RTL8169_REG_MAXTX equ 0xEC ; Max Transmit Packet Size Register - -; Command Register (Offset 0037h, R/W) - RTL8169_BIT_RST equ 4 ; Reset - RTL8169_BIT_RE equ 3 ; Receiver Enable - RTL8169_BIT_TE equ 2 ; Transmitter Enable - -; Receive Configuration (Offset 0044h-0047h, R/W) - RTL8169_BIT_AER equ 5 ; Accept Error - RTL8169_BIT_AR equ 4 ; Accept Runt - RTL8169_BIT_AB equ 3 ; Accept Broadcast Packets - RTL8169_BIT_AM equ 2 ; Accept Multicast Packets - RTL8169_BIT_APM equ 1 ; Accept Physical Match Packets - RTL8169_BIT_AAP equ 0 ; Accept All Packets with Destination Address - -; PHY Register Table -; BMCR (address 0x00) - RTL8169_BIT_ANE equ 12 ; Auto-Negotiation Enable - -PHYConfig: -dd 0x801f0001, 0x80151000, 0x801865c7, 0x80040000, 0x800300a1, 0x80020008, 0x80011020, 0x80001000 -dd 0x80040800, 0x80040000, 0x80047000, 0x8003ff41, 0x8002de60, 0x80010140, 0x80000077, 0x80047800 -dd 0x80047000, 0x8004a000, 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000fa00, 0x8004a800, 0x8004a000 -dd 0x8004b000, 0x8003ff41, 0x8002de20, 0x80010140, 0x800000bb, 0x8004b800, 0x8004b000, 0x8004f000 -dd 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000bf00, 0x8004f800, 0x8004f000, 0x80040000, 0x801f0000 -dd 0x800b0000 - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Realtek 8169 NIC. http://wiki.osdev.org/RTL8169 +; ============================================================================= + +align 16 +db 'DEBUG: RTL8169 ' +align 16 + + +; ----------------------------------------------------------------------------- +; Initialize a Realtek 8169 NIC +; IN: BL = Bus number of the Realtek device +; CL = Device/Slot number of the Realtek device +os_net_rtl8169_init: + push rsi + push rdx + push rcx + push rax + + ; Grab the Base I/O Address of the device + mov dl, 0x04 ; BAR0 + call os_pci_read_reg + and eax, 0xFFFFFFFC ; EAX now holds the Base IO Address (clear the low 2 bits) + mov word [os_NetIOAddress], ax + + ; Grab the IRQ of the device + mov dl, 0x0F ; Get device's IRQ number from PCI Register 15 (IRQ is bits 7-0) + call os_pci_read_reg + mov [os_NetIRQ], al ; AL holds the IRQ + + ; Grab the MAC address + mov dx, word [os_NetIOAddress] + in al, dx + mov [os_NetMAC], al + add dx, 1 + in al, dx + mov [os_NetMAC+1], al + add dx, 1 + in al, dx + mov [os_NetMAC+2], al + add dx, 1 + in al, dx + mov [os_NetMAC+3], al + add dx, 1 + in al, dx + mov [os_NetMAC+4], al + add dx, 1 + in al, dx + mov [os_NetMAC+5], al + + ; Enable the Network IRQ in the PIC + ; IRQ value 0-7 set to zero bit 0-7 in 0x21 and value 8-15 set to zero bit 0-7 in 0xa1 +; in al, 0x21 ; low byte target 0x21 +; mov bl, al +; mov al, [os_NetIRQ] +; mov dx, 0x21 ; Use the low byte pic +; cmp al, 8 +; jl os_net_rtl8169_init_low +; sub al, 8 ; IRQ 8-16 +; push ax +; in al, 0xA1 ; High byte target 0xA1 +; mov bl, al +; pop ax +; mov dx, 0xA1 ; Use the high byte pic +;os_net_rtl8169_init_low: +; mov cl, al +; mov al, 1 +; shl al, cl +; not al +; and al, bl +; out dx, al + + ; Reset the device + call os_net_rtl8169_reset + + pop rax + pop rcx + pop rdx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8136_reset - Reset a Realtek 8169 NIC +; IN: Nothing +; OUT: Nothing, all registers preserved +os_net_rtl8169_reset: + push rdx + push rcx + push rax + + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_COMMAND + mov al, 0x10 ; Bit 4 set for Reset + out dx, al + mov cx, 1000 ; Wait no longer for the reset to complete +wait_for_8169_reset: + in al, dx + test al, 0x10 + jz reset_8169_completed ; RST remains 1 during reset, Reset complete when 0 + dec cx + jns wait_for_8169_reset +reset_8169_completed: + + ; Unlock config registers + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_9346CR + mov al, 0xC0 ; Unlock + out dx, al + + ; Set the C+ Command + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_CCR + in ax, dx + bts ax, 3 ; Enable PCI Multiple Read/Write + btc ax, 9 ; Little-endian mode + out dx, ax + + ; Power management? + + ; Recieve configuration + mov dx, word [os_NetIOAddress] + add edx, RTL8169_REG_RCR + mov eax, 0x0000E70A ; Set bits 1 (APM), 3 (AB), 8-10 (Unlimited), 13-15 (No limit) + out dx, eax + + ; Set up TCR + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_TCR + mov eax, 0x03000700 + out dx, eax + + ; Setup max RX size + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_MAXRX + mov ax, 0x3FFF ; 16384 - 1 + out dx, ax + + ; Setup max TX size + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_MAXTX + mov al, 0x3B + out dx, al + + ; Set the Transmit Normal Priority Descriptor Start Address + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_TNPDS + mov rax, os_eth_tx_buffer + out dx, eax ; Write the low bits + shr rax, 32 + add dx, 4 + out dx, eax ; Write the high bits + mov eax, 0x70000000 ; Set bit 30 (End of Descriptor Ring), 29 (FS), and 28 (LS) + mov [os_eth_tx_buffer], eax + + ; Set the Receive Descriptor Start Address + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_RDSAR + mov rax, os_eth_rx_buffer + out dx, eax ; Write the low bits + shr rax, 32 + add dx, 4 + out dx, eax ; Write the high bits + mov eax, 0x80001FF8 ; Set bits 31 (Ownership), also buffer size (Max 0x1FF8) + mov [os_eth_rx_buffer], eax + mov rax, os_ethernet_rx_buffer + mov [os_eth_rx_buffer+8], rax + mov eax, 0xC0001FF8 ; Set bits 31 (Ownership) and 30 (End of Descriptor Ring), also buffer size (Max 0x1FF8) + mov [os_eth_rx_buffer+16], eax + mov rax, os_ethernet_rx_buffer + mov [os_eth_rx_buffer+24], rax + + ; Initialize multicast registers (no filtering) + mov eax, 0xFFFFFFFF + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_MAR0 + out dx, eax + add dx, 4 ; MAR4 + out dx, eax + + ; Enable Rx/Tx in the Command register + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_COMMAND + mov al, (1 << RTL8169_BIT_RE) | (1 << RTL8169_BIT_TE) ;0x0C ; Set bits 2 (TE) and 3 (RE) + out dx, al + + ; Enable Receive and Transmit interrupts + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_IMR + mov ax, 0x0005 ; Set bits 0 (RX OK) and 2 (TX OK) + out dx, ax + + ; Lock config register + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_9346CR + mov al, 0x00 ; Lock + out dx, al + + pop rax + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8169_transmit - Transmit a packet via a Realtek 8169 NIC +; IN: RSI = Location of packet +; RCX = Length of packet +; OUT: Nothing +; Uses RAX, RCX, RDX, RSI, RDI +; ToDo: Check for proper timeout +os_net_rtl8169_transmit: + mov rdi, os_eth_tx_buffer + mov rax, rcx + stosw ; Store the frame length + add rdi, 6 ; Should the other data be cleared here? + mov rax, rsi + stosq ; Store the packet location + or dword [os_eth_tx_buffer], 0xF0000000 ; Set bit 31 (OWN), 30 (EOR), 29 (FS), and 28 (LS) + mov dx, word [os_NetIOAddress] + add dx, RTL8169_REG_TPPOLL + mov al, 0x40 + out dx, al ; Set up TX Polling +os_net_rtl8169_transmit_sendloop: + mov eax, [os_eth_tx_buffer] + and eax, 0x80000000 ; Check the ownership bit (BT command instead?) + cmp eax, 0x80000000 ; If the ownership bit is clear then the NIC sent the packet + je os_net_rtl8169_transmit_sendloop + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8169_poll - Polls the Realtek 8169 NIC for a received packet +; IN: RDI = Location to store packet +; OUT: RCX = Length of packet +; Uses RAX, RCX, RDX, RSI, RDI +os_net_rtl8169_poll: + xor ecx, ecx + mov cx, [os_eth_rx_buffer] + and cx, 0x3FFF ; Clear the two high bits as length is bits 13-0 + cmp cx, 0x1FF8 + jne os_net_rtl8169_poll_first_descriptor + mov cx, [os_eth_rx_buffer+16] + and cx, 0x3FFF ; Clear the two high bits as length is bits 13-0 +os_net_rtl8169_poll_first_descriptor: + mov rsi, os_ethernet_rx_buffer + push rcx + rep movsb ; Copy the packet to the lacation stored in RDI + pop rcx + mov eax, 0x80001FF8 ; Set bits 31 (Ownership), also buffer size (Max 0x1FF8) + mov [os_eth_rx_buffer], eax + mov rax, os_ethernet_rx_buffer + mov [os_eth_rx_buffer+8], rax + mov eax, 0xC0001FF8 ; Set bits 31 (Ownership) and 30 (End of Descriptor Ring), also buffer size (Max 0x1FF8) + mov [os_eth_rx_buffer+16], eax + mov rax, os_ethernet_rx_buffer + mov [os_eth_rx_buffer+24], rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_net_rtl8169_ack_int - Acknowledge an internal interrupt of the Realtek 8169 NIC +os_net_rtl8169_ack_int: + mov dx, word [os_NetIOAddress] ; Clear active interrupt sources + add dx, RTL8169_REG_ISR + in ax, dx +; call os_debug_dump_ax ; Display the interrupt type + out dx, ax + shr eax, 2 + ret +; ----------------------------------------------------------------------------- + + +; Register Descriptors + RTL8169_REG_IDR0 equ 0x00 ; ID Register 0 + RTL8169_REG_IDR1 equ 0x01 ; ID Register 1 + RTL8169_REG_IDR2 equ 0x02 ; ID Register 2 + RTL8169_REG_IDR3 equ 0x03 ; ID Register 3 + RTL8169_REG_IDR4 equ 0x04 ; ID Register 4 + RTL8169_REG_IDR5 equ 0x05 ; ID Register 5 + RTL8169_REG_MAR0 equ 0x08 ; Multicast Register 0 + RTL8169_REG_MAR1 equ 0x09 ; Multicast Register 1 + RTL8169_REG_MAR2 equ 0x0A ; Multicast Register 2 + RTL8169_REG_MAR3 equ 0x0B ; Multicast Register 3 + RTL8169_REG_MAR4 equ 0x0C ; Multicast Register 4 + RTL8169_REG_MAR5 equ 0x0D ; Multicast Register 5 + RTL8169_REG_MAR6 equ 0x0E ; Multicast Register 6 + RTL8169_REG_MAR7 equ 0x0F ; Multicast Register 7 + RTL8169_REG_TNPDS equ 0x20 ; Transmit Normal Priority Descriptors: Start address (64-bit). (256-byte alignment) + RTL8169_REG_COMMAND equ 0x37 ; Command Register + RTL8169_REG_TPPOLL equ 0x38 ; Transmit Priority Polling Register + RTL8169_REG_IMR equ 0x3C ; Interrupt Mask Register + RTL8169_REG_ISR equ 0x3E ; Interrupt Status Register + RTL8169_REG_TCR equ 0x40 ; Transmit (Tx) Configuration Register + RTL8169_REG_RCR equ 0x44 ; Receive (Rx) Configuration Register + RTL8169_REG_9346CR equ 0x50 ; 93C46 (93C56) Command Register + RTL8169_REG_CONFIG0 equ 0x51 ; Configuration Register 0 + RTL8169_REG_CONFIG1 equ 0x52 ; Configuration Register 1 + RTL8169_REG_CONFIG2 equ 0x53 ; Configuration Register 2 + RTL8169_REG_CONFIG3 equ 0x54 ; Configuration Register 3 + RTL8169_REG_CONFIG4 equ 0x55 ; Configuration Register 4 + RTL8169_REG_CONFIG5 equ 0x56 ; Configuration Register 5 + RTL8169_REG_PHYAR equ 0x60 ; PHY Access Register + RTL8169_REG_PHYStatus equ 0x6C ; PHY(GMII, MII, or TBI) Status Register + RTL8169_REG_MAXRX equ 0xDA ; Mac Receive Packet Size Register + RTL8169_REG_CCR equ 0xE0 ; C+ Command Register + RTL8169_REG_RDSAR equ 0xE4 ; Receive Descriptor Start Address Register (256-byte alignment) + RTL8169_REG_MAXTX equ 0xEC ; Max Transmit Packet Size Register + +; Command Register (Offset 0037h, R/W) + RTL8169_BIT_RST equ 4 ; Reset + RTL8169_BIT_RE equ 3 ; Receiver Enable + RTL8169_BIT_TE equ 2 ; Transmitter Enable + +; Receive Configuration (Offset 0044h-0047h, R/W) + RTL8169_BIT_AER equ 5 ; Accept Error + RTL8169_BIT_AR equ 4 ; Accept Runt + RTL8169_BIT_AB equ 3 ; Accept Broadcast Packets + RTL8169_BIT_AM equ 2 ; Accept Multicast Packets + RTL8169_BIT_APM equ 1 ; Accept Physical Match Packets + RTL8169_BIT_AAP equ 0 ; Accept All Packets with Destination Address + +; PHY Register Table +; BMCR (address 0x00) + RTL8169_BIT_ANE equ 12 ; Auto-Negotiation Enable + +PHYConfig: +dd 0x801f0001, 0x80151000, 0x801865c7, 0x80040000, 0x800300a1, 0x80020008, 0x80011020, 0x80001000 +dd 0x80040800, 0x80040000, 0x80047000, 0x8003ff41, 0x8002de60, 0x80010140, 0x80000077, 0x80047800 +dd 0x80047000, 0x8004a000, 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000fa00, 0x8004a800, 0x8004a000 +dd 0x8004b000, 0x8003ff41, 0x8002de20, 0x80010140, 0x800000bb, 0x8004b800, 0x8004b000, 0x8004f000 +dd 0x8003df01, 0x8002df20, 0x8001ff95, 0x8000bf00, 0x8004f800, 0x8004f000, 0x80040000, 0x801f0000 +dd 0x800b0000 + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/pci.asm b/amd64/bareMetalOS-0.5.3/os/drivers/pci.asm index 91d3c954..0143eb60 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/pci.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/pci.asm @@ -1,157 +1,157 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; PCI Functions. http://wiki.osdev.org/PCI -; ============================================================================= - -align 16 -db 'DEBUG: PCI ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_pci_read_reg -- Read a register from a PCI device -; IN: BL = Bus number -; CL = Device/Slot number -; DL = Register number -; OUT: EAX = Register information -; All other registers preserved -os_pci_read_reg: - push rdx - push rcx - push rbx - - shl ebx, 16 ; Move Bus number to bits 23 - 16 - shl ecx, 11 ; Move Device number to bits 15 - 11 - mov bx, cx - shl edx, 2 - mov bl, dl - and ebx, 0x00ffffff ; Clear bits 31 - 24 - or ebx, 0x80000000 ; Set bit 31 - mov eax, ebx - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - mov dx, PCI_CONFIG_DATA - in eax, dx - - pop rbx - pop rcx - pop rdx -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_pci_find_device -- Finds a PCI device based on the Device and Vendor ID provided -; IN: EAX = Device and Vendor ID (ie: 0x70008086) -; OUT: BL = Bus number (8-bit value) -; CL = Device/Slot number (5-bit value) -; Carry set if no matching device was found -; All other registers preserved -os_pci_find_device: - push rdx - - mov rbx, rax ; Save device and vendor IDs to RBX - xor rcx, rcx - xor rax, rax - - mov ecx, 0x80000000 ; Bit 31 must be set - -os_pci_find_device_check_next: - mov eax, ecx - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - mov dx, PCI_CONFIG_DATA - in eax, dx ; EAX now holds the Device and Vendor ID - cmp eax, ebx - je os_pci_find_device_found - add ecx, 0x800 - cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) - jne os_pci_find_device_check_next - -os_pci_find_device_not_found: - stc ; Set carry (failure) - jmp os_pci_find_device_end - -os_pci_find_device_found: ; ECX bits 23 - 16 is the Bus # and bits 15 - 11 is the Device/Slot # - xor rax, rax - xor rbx, rbx - shr ecx, 11 ; Device/Slot number is now bits 4 - 0 - mov bl, cl ; BL contains Device/Slot number - and bl, 00011111b ; Clear the top 3 bits, BL contains the Device/Slot number - shr ecx, 5 ; Bus number is now bits 7 - 0 - mov al, cl ; AL contains the Bus number - xor ecx, ecx - mov cl, bl - mov bl, al - clc ; Clear carry (success) - -os_pci_find_device_end: - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_pci_dump_devices -- Dump all Device and Vendor ID's to the screen -; IN: Nothing -; OUT: Nothing, All registers preserved -; http://pci-ids.ucw.cz/read/PC/ - Online list of Device and Vendor ID's -os_pci_dump_devices: - push rdx - push rcx - push rbx - push rax - - xor rcx, rcx - xor rax, rax - - mov ecx, 0x80000000 ; Bit 31 must be set - -os_pci_dump_devices_check_next: - mov eax, ecx - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - mov dx, PCI_CONFIG_DATA - in eax, dx ; EAX now holds the Device and Vendor ID - cmp eax, 0xffffffff ; 0xFFFFFFFF means no device present on that Bus and Slot - je os_pci_dump_devices_nothing_there - call os_debug_dump_eax ; Print the Device and Vendor ID (DDDDVVVV) - call os_print_newline -os_pci_dump_devices_nothing_there: - add ecx, 0x800 - cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) - jne os_pci_dump_devices_check_next - -os_pci_dump_devices_end: - pop rax - pop rbx - pop rcx - pop rdx -ret -; ----------------------------------------------------------------------------- - - -;Configuration Mechanism One has two IO port rages associated with it. -;The address port (0xcf8-0xcfb) and the data port (0xcfc-0xcff). -;A configuration cycle consists of writing to the address port to specify which device and register you want to access and then reading or writing the data to the data port. - -PCI_CONFIG_ADDRESS EQU 0x0CF8 -PCI_CONFIG_DATA EQU 0x0CFC - -;ddress dd 10000000000000000000000000000000b -; /\ /\ /\ /\ /\ /\ -; E Res Bus Dev F Reg 0 -; Bits -; 31 Enable bit = set to 1 -; 30 - 24 Reserved = set to 0 -; 23 - 16 Bus number = 256 options -; 15 - 11 Device/Slot number = 32 options -; 10 - 8 Function number = will leave at 0 (8 options) -; 7 - 2 Register number = will leave at 0 (64 options) 64 x 4 bytes = 256 bytes worth of accessible registers -; 1 - 0 Set to 0 - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; PCI Functions. http://wiki.osdev.org/PCI +; ============================================================================= + +align 16 +db 'DEBUG: PCI ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_pci_read_reg -- Read a register from a PCI device +; IN: BL = Bus number +; CL = Device/Slot number +; DL = Register number +; OUT: EAX = Register information +; All other registers preserved +os_pci_read_reg: + push rdx + push rcx + push rbx + + shl ebx, 16 ; Move Bus number to bits 23 - 16 + shl ecx, 11 ; Move Device number to bits 15 - 11 + mov bx, cx + shl edx, 2 + mov bl, dl + and ebx, 0x00ffffff ; Clear bits 31 - 24 + or ebx, 0x80000000 ; Set bit 31 + mov eax, ebx + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + mov dx, PCI_CONFIG_DATA + in eax, dx + + pop rbx + pop rcx + pop rdx +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_pci_find_device -- Finds a PCI device based on the Device and Vendor ID provided +; IN: EAX = Device and Vendor ID (ie: 0x70008086) +; OUT: BL = Bus number (8-bit value) +; CL = Device/Slot number (5-bit value) +; Carry set if no matching device was found +; All other registers preserved +os_pci_find_device: + push rdx + + mov rbx, rax ; Save device and vendor IDs to RBX + xor rcx, rcx + xor rax, rax + + mov ecx, 0x80000000 ; Bit 31 must be set + +os_pci_find_device_check_next: + mov eax, ecx + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + mov dx, PCI_CONFIG_DATA + in eax, dx ; EAX now holds the Device and Vendor ID + cmp eax, ebx + je os_pci_find_device_found + add ecx, 0x800 + cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) + jne os_pci_find_device_check_next + +os_pci_find_device_not_found: + stc ; Set carry (failure) + jmp os_pci_find_device_end + +os_pci_find_device_found: ; ECX bits 23 - 16 is the Bus # and bits 15 - 11 is the Device/Slot # + xor rax, rax + xor rbx, rbx + shr ecx, 11 ; Device/Slot number is now bits 4 - 0 + mov bl, cl ; BL contains Device/Slot number + and bl, 00011111b ; Clear the top 3 bits, BL contains the Device/Slot number + shr ecx, 5 ; Bus number is now bits 7 - 0 + mov al, cl ; AL contains the Bus number + xor ecx, ecx + mov cl, bl + mov bl, al + clc ; Clear carry (success) + +os_pci_find_device_end: + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_pci_dump_devices -- Dump all Device and Vendor ID's to the screen +; IN: Nothing +; OUT: Nothing, All registers preserved +; http://pci-ids.ucw.cz/read/PC/ - Online list of Device and Vendor ID's +os_pci_dump_devices: + push rdx + push rcx + push rbx + push rax + + xor rcx, rcx + xor rax, rax + + mov ecx, 0x80000000 ; Bit 31 must be set + +os_pci_dump_devices_check_next: + mov eax, ecx + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + mov dx, PCI_CONFIG_DATA + in eax, dx ; EAX now holds the Device and Vendor ID + cmp eax, 0xffffffff ; 0xFFFFFFFF means no device present on that Bus and Slot + je os_pci_dump_devices_nothing_there + call os_debug_dump_eax ; Print the Device and Vendor ID (DDDDVVVV) + call os_print_newline +os_pci_dump_devices_nothing_there: + add ecx, 0x800 + cmp ecx, 0x81000000 ; The end has been reached (already looked at 8192 devices) + jne os_pci_dump_devices_check_next + +os_pci_dump_devices_end: + pop rax + pop rbx + pop rcx + pop rdx +ret +; ----------------------------------------------------------------------------- + + +;Configuration Mechanism One has two IO port rages associated with it. +;The address port (0xcf8-0xcfb) and the data port (0xcfc-0xcff). +;A configuration cycle consists of writing to the address port to specify which device and register you want to access and then reading or writing the data to the data port. + +PCI_CONFIG_ADDRESS EQU 0x0CF8 +PCI_CONFIG_DATA EQU 0x0CFC + +;ddress dd 10000000000000000000000000000000b +; /\ /\ /\ /\ /\ /\ +; E Res Bus Dev F Reg 0 +; Bits +; 31 Enable bit = set to 1 +; 30 - 24 Reserved = set to 0 +; 23 - 16 Bus number = 256 options +; 15 - 11 Device/Slot number = 32 options +; 10 - 8 Function number = will leave at 0 (8 options) +; 7 - 2 Register number = will leave at 0 (64 options) 64 x 4 bytes = 256 bytes worth of accessible registers +; 1 - 0 Set to 0 + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/drivers/storage.asm b/amd64/bareMetalOS-0.5.3/os/drivers/storage.asm index eab3316e..30bc03bf 100644 --- a/amd64/bareMetalOS-0.5.3/os/drivers/storage.asm +++ b/amd64/bareMetalOS-0.5.3/os/drivers/storage.asm @@ -1,46 +1,46 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Disk Storage Functions -; ============================================================================= - -align 16 -db 'DEBUG: STORAGE' -align 16 - - -; ----------------------------------------------------------------------------- -; readblocks -- Read blocks on the hard drive -; IN: RAX = starting block # to read -; RCX = number of blocks to read -; RDX = disk # -; RDI = memory location to store blocks (Ideally 2MiB alligned) -; OUT: RAX = RAX + number of blocks that were read -; RCX = number of blocks that were read (0 on error) -; RDI = RDI + (number of blocks read * 2097152) -; All other registers preserved -readblocks: - -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; writeblocks -- Write blocks on the hard drive -; IN: RAX = starting block # to write -; RCX = number of blocks to write -; RDX = disk # -; RSI = memory location of blocks (Ideally 2MiB alligned) -; OUT: RAX = RAX + number of blocks that were written -; RCX = number of blocks that were written (0 on error) -; RSI = RSI + (number of blocks written * 2097152) -; All other registers preserved -writeblocks: - -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Disk Storage Functions +; ============================================================================= + +align 16 +db 'DEBUG: STORAGE' +align 16 + + +; ----------------------------------------------------------------------------- +; readblocks -- Read blocks on the hard drive +; IN: RAX = starting block # to read +; RCX = number of blocks to read +; RDX = disk # +; RDI = memory location to store blocks (Ideally 2MiB alligned) +; OUT: RAX = RAX + number of blocks that were read +; RCX = number of blocks that were read (0 on error) +; RDI = RDI + (number of blocks read * 2097152) +; All other registers preserved +readblocks: + +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; writeblocks -- Write blocks on the hard drive +; IN: RAX = starting block # to write +; RCX = number of blocks to write +; RDX = disk # +; RSI = memory location of blocks (Ideally 2MiB alligned) +; OUT: RAX = RAX + number of blocks that were written +; RCX = number of blocks that were written (0 on error) +; RSI = RSI + (number of blocks written * 2097152) +; All other registers preserved +writeblocks: + +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/init_64.asm b/amd64/bareMetalOS-0.5.3/os/init_64.asm index 64ddcfd1..9b44948d 100644 --- a/amd64/bareMetalOS-0.5.3/os/init_64.asm +++ b/amd64/bareMetalOS-0.5.3/os/init_64.asm @@ -1,302 +1,302 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT_64 -; ============================================================================= - -align 16 -db 'DEBUG: INIT_64 ' -align 16 - - -init_64: - ; Make sure that memory range 0x110000 - 0x200000 is cleared - mov rdi, os_SystemVariables - xor rcx, rcx - xor rax, rax -clearmem: - stosq - add rcx, 1 - cmp rcx, 122880 ; Clear 960 KiB - jne clearmem - - mov ax, 0x000A ; Set the cursor to 0,10 (needs to happen before anything is printed to the screen) - call os_move_cursor - - xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) as defined by Pure64 - - ; Create exception gate stubs (Pure64 has already set the correct gate markers) - mov rcx, 32 - mov rax, exception_gate -make_exception_gate_stubs: - call create_gate - add rdi, 1 - sub rcx, 1 - jnz make_exception_gate_stubs - - ; Create interrupt gate stubs (Pure64 has already set the correct gate markers) - mov rcx, 256-32 - mov rax, interrupt_gate -make_interrupt_gate_stubs: - call create_gate - add rdi, 1 - sub rcx, 1 - jnz make_interrupt_gate_stubs - - ; Set up the exception gates for all of the CPU exceptions - mov rcx, 20 - xor rdi, rdi - mov rax, exception_gate_00 -make_exception_gates: - call create_gate - add rdi, 1 - add rax, 16 ; The exception gates are aligned at 16 bytes - sub rcx, 1 - jnz make_exception_gates - - ; Set up the IRQ handlers (Network IRQ handler is configured in init_net) - mov rdi, 0x21 - mov rax, keyboard - call create_gate - mov rdi, 0x28 - mov rax, rtc - call create_gate - mov rdi, 0x80 - mov rax, ap_wakeup - call create_gate - mov rdi, 0x81 - mov rax, ap_reset - call create_gate - - ; Set up RTC - ; Rate defines how often the RTC interrupt is triggered - ; Rate is a 4-bit value from 1 to 15. 1 = 32768Hz, 6 = 1024Hz, 15 = 2Hz - ; RTC value must stay at 32.768KHz or the computer will not keep the correct time - ; http://wiki.osdev.org/RTC -rtc_poll: - mov al, 0x0A ; Status Register A - out 0x70, al - in al, 0x71 - test al, 0x80 ; Is there an update in process? - jne rtc_poll ; If so then keep polling - mov al, 0x0A ; Status Register A - out 0x70, al - mov al, 00101101b ; RTC@32.768KHz (0010), Rate@8Hz (1101) - out 0x71, al - mov al, 0x0C ; Acknowledge the RTC - out 0x70, al - in al, 0x71 - - ; Disable blink - mov dx, 0x3DA - in al, dx - mov dx, 0x3C0 - mov al, 0x30 - out dx, al - add dx, 1 - in al, dx - and al, 0xF7 - sub dx, 1 - out dx, al - - ; Set color palette - xor eax, eax - mov dx, 0x03C8 ; DAC Address Write Mode Register - out dx, al - mov dx, 0x03C9 ; DAC Data Register - mov rbx, 16 ; 16 lines -nextline: - mov rcx, 16 ; 16 colors - mov rsi, palette -nexttritone: - lodsb - out dx, al - lodsb - out dx, al - lodsb - out dx, al - dec rcx - cmp rcx, 0 - jne nexttritone - dec rbx - cmp rbx, 0 - jne nextline ; Set the next 16 colors to the same - mov eax, 0x14 ; Fix for color 6 - mov dx, 0x03c8 ; DAC Address Write Mode Register - out dx, al - mov dx, 0x03c9 ; DAC Data Register - mov rsi, palette - add rsi, 18 - lodsb - out dx, al - lodsb - out dx, al - lodsb - out dx, al - - xor eax, eax - xor ebx, ebx - xor ecx, ecx - ; Grab data from Pure64's infomap - mov rsi, 0x5008 - lodsd ; Load the BSP ID - mov ebx, eax ; Save it to EBX - mov rsi, 0x5012 - lodsw ; Load the number of activated cores - mov cx, ax ; Save it to CX - mov rsi, 0x5060 - lodsq - mov [os_LocalAPICAddress], rax - lodsq - mov [os_IOAPICAddress], rax - - mov rsi, 0x5012 - lodsw - mov [os_NumCores], ax - - mov rsi, 0x5020 - lodsw - mov [os_MemAmount], ax ; In MiB's - - ; Build the OS memory table - call init_memory_map - - ; Initialize all AP's to run our reset code. Skip the BSP - xor rax, rax - mov rsi, 0x0000000000005100 ; Location in memory of the Pure64 CPU data -next_ap: - cmp cx, 0 - je no_more_aps - lodsb ; Load the CPU APIC ID - cmp al, bl - je skip_ap - call os_smp_reset ; Reset the CPU -skip_ap: - sub cx, 1 - jmp next_ap - -no_more_aps: - - ; Enable specific interrupts - mov rcx, 1 ; Enable Keyboard - mov rax, 0x21 - call ioapic_entry_write - mov rcx, 8 ; Enable RTC - mov rax, 0x0100000000000928 ; Lowest priority -; mov rax, 0x28 ; Handled by APIC ID 0 (BSP) - call ioapic_entry_write - - call os_seed_random ; Seed the RNG - -ret - -; create_gate -; rax = address of handler -; rdi = gate # to configure -create_gate: - push rdi - push rax - - shl rdi, 4 ; quickly multiply rdi by 16 - stosw ; store the low word (15..0) - shr rax, 16 - add rdi, 4 ; skip the gate marker - stosw ; store the high word (31..16) - shr rax, 16 - stosd ; store the high dword (63..32) - - pop rax - pop rdi -ret - - -init_memory_map: ; Build the OS memory table - push rax - push rcx - push rdi - - ; Build a fresh memory map for the system - mov rdi, os_MemoryMap - push rdi - xor rcx, rcx - mov cx, [os_MemAmount] - shr cx, 1 ; Divide actual memory by 2 - mov al, 1 - rep stosb - pop rdi - mov al, 2 - stosb ; Mark the first 2 MiB as in use (by Kernel and system buffers) - stosb ; As well as the second 2 MiB (by loaded application) - ; The CLI should take care of the Application memory - - ; Allocate memory for CPU stacks (2 MiB's for each core) - xor rcx, rcx - mov cx, [os_NumCores] ; Get the amount of cores in the system - call os_mem_allocate ; Allocate a page for each core - cmp rcx, 0 ; os_mem_allocate returns 0 on failure - je system_failure - add rax, 2097152 - mov [os_StackBase], rax ; Store the Stack base address - - pop rdi - pop rcx - pop rax -ret - - -system_failure: - mov ax, 0x0016 - call os_move_cursor - mov rsi, memory_message - mov bl, 0xF0 - call os_print_string_with_color -system_failure_hang: - hlt - jmp system_failure_hang -ret - -; ----------------------------------------------------------------------------- -; ioapic_reg_write -- Write to an I/O APIC register -; IN: EAX = Value to write -; ECX = Index of register -; OUT: Nothing. All registers preserved -ioapic_reg_write: - push rsi - mov rsi, [os_IOAPICAddress] - mov dword [rsi], ecx ; Write index to register selector - mov dword [rsi + 0x10], eax ; Write data to window register - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; ioapic_entry_write -- Write to an I/O APIC entry in the redirection table -; IN: RAX = Data to write to entry -; ECX = Index of the entry -; OUT: Nothing. All registers preserved -ioapic_entry_write: - push rax - push rcx - - ; Calculate index for lower DWORD - shl rcx, 1 ; Quick multiply by 2 - add rcx, 0x10 ; IO Redirection tables start at 0x10 - - ; Write lower DWORD - call ioapic_reg_write - - ; Write higher DWORD - shr rax, 32 - add rcx, 1 - call ioapic_reg_write - - pop rcx - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT_64 +; ============================================================================= + +align 16 +db 'DEBUG: INIT_64 ' +align 16 + + +init_64: + ; Make sure that memory range 0x110000 - 0x200000 is cleared + mov rdi, os_SystemVariables + xor rcx, rcx + xor rax, rax +clearmem: + stosq + add rcx, 1 + cmp rcx, 122880 ; Clear 960 KiB + jne clearmem + + mov ax, 0x000A ; Set the cursor to 0,10 (needs to happen before anything is printed to the screen) + call os_move_cursor + + xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) as defined by Pure64 + + ; Create exception gate stubs (Pure64 has already set the correct gate markers) + mov rcx, 32 + mov rax, exception_gate +make_exception_gate_stubs: + call create_gate + add rdi, 1 + sub rcx, 1 + jnz make_exception_gate_stubs + + ; Create interrupt gate stubs (Pure64 has already set the correct gate markers) + mov rcx, 256-32 + mov rax, interrupt_gate +make_interrupt_gate_stubs: + call create_gate + add rdi, 1 + sub rcx, 1 + jnz make_interrupt_gate_stubs + + ; Set up the exception gates for all of the CPU exceptions + mov rcx, 20 + xor rdi, rdi + mov rax, exception_gate_00 +make_exception_gates: + call create_gate + add rdi, 1 + add rax, 16 ; The exception gates are aligned at 16 bytes + sub rcx, 1 + jnz make_exception_gates + + ; Set up the IRQ handlers (Network IRQ handler is configured in init_net) + mov rdi, 0x21 + mov rax, keyboard + call create_gate + mov rdi, 0x28 + mov rax, rtc + call create_gate + mov rdi, 0x80 + mov rax, ap_wakeup + call create_gate + mov rdi, 0x81 + mov rax, ap_reset + call create_gate + + ; Set up RTC + ; Rate defines how often the RTC interrupt is triggered + ; Rate is a 4-bit value from 1 to 15. 1 = 32768Hz, 6 = 1024Hz, 15 = 2Hz + ; RTC value must stay at 32.768KHz or the computer will not keep the correct time + ; http://wiki.osdev.org/RTC +rtc_poll: + mov al, 0x0A ; Status Register A + out 0x70, al + in al, 0x71 + test al, 0x80 ; Is there an update in process? + jne rtc_poll ; If so then keep polling + mov al, 0x0A ; Status Register A + out 0x70, al + mov al, 00101101b ; RTC@32.768KHz (0010), Rate@8Hz (1101) + out 0x71, al + mov al, 0x0C ; Acknowledge the RTC + out 0x70, al + in al, 0x71 + + ; Disable blink + mov dx, 0x3DA + in al, dx + mov dx, 0x3C0 + mov al, 0x30 + out dx, al + add dx, 1 + in al, dx + and al, 0xF7 + sub dx, 1 + out dx, al + + ; Set color palette + xor eax, eax + mov dx, 0x03C8 ; DAC Address Write Mode Register + out dx, al + mov dx, 0x03C9 ; DAC Data Register + mov rbx, 16 ; 16 lines +nextline: + mov rcx, 16 ; 16 colors + mov rsi, palette +nexttritone: + lodsb + out dx, al + lodsb + out dx, al + lodsb + out dx, al + dec rcx + cmp rcx, 0 + jne nexttritone + dec rbx + cmp rbx, 0 + jne nextline ; Set the next 16 colors to the same + mov eax, 0x14 ; Fix for color 6 + mov dx, 0x03c8 ; DAC Address Write Mode Register + out dx, al + mov dx, 0x03c9 ; DAC Data Register + mov rsi, palette + add rsi, 18 + lodsb + out dx, al + lodsb + out dx, al + lodsb + out dx, al + + xor eax, eax + xor ebx, ebx + xor ecx, ecx + ; Grab data from Pure64's infomap + mov rsi, 0x5008 + lodsd ; Load the BSP ID + mov ebx, eax ; Save it to EBX + mov rsi, 0x5012 + lodsw ; Load the number of activated cores + mov cx, ax ; Save it to CX + mov rsi, 0x5060 + lodsq + mov [os_LocalAPICAddress], rax + lodsq + mov [os_IOAPICAddress], rax + + mov rsi, 0x5012 + lodsw + mov [os_NumCores], ax + + mov rsi, 0x5020 + lodsw + mov [os_MemAmount], ax ; In MiB's + + ; Build the OS memory table + call init_memory_map + + ; Initialize all AP's to run our reset code. Skip the BSP + xor rax, rax + mov rsi, 0x0000000000005100 ; Location in memory of the Pure64 CPU data +next_ap: + cmp cx, 0 + je no_more_aps + lodsb ; Load the CPU APIC ID + cmp al, bl + je skip_ap + call os_smp_reset ; Reset the CPU +skip_ap: + sub cx, 1 + jmp next_ap + +no_more_aps: + + ; Enable specific interrupts + mov rcx, 1 ; Enable Keyboard + mov rax, 0x21 + call ioapic_entry_write + mov rcx, 8 ; Enable RTC + mov rax, 0x0100000000000928 ; Lowest priority +; mov rax, 0x28 ; Handled by APIC ID 0 (BSP) + call ioapic_entry_write + + call os_seed_random ; Seed the RNG + +ret + +; create_gate +; rax = address of handler +; rdi = gate # to configure +create_gate: + push rdi + push rax + + shl rdi, 4 ; quickly multiply rdi by 16 + stosw ; store the low word (15..0) + shr rax, 16 + add rdi, 4 ; skip the gate marker + stosw ; store the high word (31..16) + shr rax, 16 + stosd ; store the high dword (63..32) + + pop rax + pop rdi +ret + + +init_memory_map: ; Build the OS memory table + push rax + push rcx + push rdi + + ; Build a fresh memory map for the system + mov rdi, os_MemoryMap + push rdi + xor rcx, rcx + mov cx, [os_MemAmount] + shr cx, 1 ; Divide actual memory by 2 + mov al, 1 + rep stosb + pop rdi + mov al, 2 + stosb ; Mark the first 2 MiB as in use (by Kernel and system buffers) + stosb ; As well as the second 2 MiB (by loaded application) + ; The CLI should take care of the Application memory + + ; Allocate memory for CPU stacks (2 MiB's for each core) + xor rcx, rcx + mov cx, [os_NumCores] ; Get the amount of cores in the system + call os_mem_allocate ; Allocate a page for each core + cmp rcx, 0 ; os_mem_allocate returns 0 on failure + je system_failure + add rax, 2097152 + mov [os_StackBase], rax ; Store the Stack base address + + pop rdi + pop rcx + pop rax +ret + + +system_failure: + mov ax, 0x0016 + call os_move_cursor + mov rsi, memory_message + mov bl, 0xF0 + call os_print_string_with_color +system_failure_hang: + hlt + jmp system_failure_hang +ret + +; ----------------------------------------------------------------------------- +; ioapic_reg_write -- Write to an I/O APIC register +; IN: EAX = Value to write +; ECX = Index of register +; OUT: Nothing. All registers preserved +ioapic_reg_write: + push rsi + mov rsi, [os_IOAPICAddress] + mov dword [rsi], ecx ; Write index to register selector + mov dword [rsi + 0x10], eax ; Write data to window register + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; ioapic_entry_write -- Write to an I/O APIC entry in the redirection table +; IN: RAX = Data to write to entry +; ECX = Index of the entry +; OUT: Nothing. All registers preserved +ioapic_entry_write: + push rax + push rcx + + ; Calculate index for lower DWORD + shl rcx, 1 ; Quick multiply by 2 + add rcx, 0x10 ; IO Redirection tables start at 0x10 + + ; Write lower DWORD + call ioapic_reg_write + + ; Write higher DWORD + shr rax, 32 + add rcx, 1 + call ioapic_reg_write + + pop rcx + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/init_hdd.asm b/amd64/bareMetalOS-0.5.3/os/init_hdd.asm index 064faef1..6a73e905 100644 --- a/amd64/bareMetalOS-0.5.3/os/init_hdd.asm +++ b/amd64/bareMetalOS-0.5.3/os/init_hdd.asm @@ -1,84 +1,84 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT HDD -; ============================================================================= - -align 16 -db 'DEBUG: INIT_HDD ' -align 16 - - -hdd_setup: -; Read first sector (MBR) into memory - xor rax, rax - mov rdi, secbuffer0 - push rdi - mov rcx, 1 - call readsectors - pop rdi - - cmp byte [0x0000000000005030], 0x01 ; Did we boot from a MBR drive - jne hdd_setup_no_mbr ; If not then we already have the correct sector - -; Grab the partition offset value for the first partition - mov eax, [rdi+0x01C6] - mov [fat16_PartitionOffset], eax - -; Read the first sector of the first partition - mov rdi, secbuffer0 - push rdi - mov rcx, 1 - call readsectors - pop rdi - -hdd_setup_no_mbr: -; Get the values we need to start using fat16 - mov ax, [rdi+0x0b] - mov [fat16_BytesPerSector], ax ; This will probably be 512 - mov al, [rdi+0x0d] - mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) - mov ax, [rdi+0x0e] - mov [fat16_ReservedSectors], ax - mov [fat16_FatStart], eax - mov al, [rdi+0x10] - mov [fat16_Fats], al ; This will probably be 2 - mov ax, [rdi+0x11] - mov [fat16_RootDirEnts], ax - mov ax, [rdi+0x16] - mov [fat16_SectorsPerFat], ax - -; Find out how many sectors are on the disk - xor eax, eax - mov ax, [rdi+0x13] - cmp ax, 0x0000 - jne lessthan65536sectors - mov eax, [rdi+0x20] -lessthan65536sectors: - mov [fat16_TotalSectors], eax - -; Calculate the size of the drive in MiB - xor rax, rax - mov eax, [fat16_TotalSectors] - mov [hd1_maxlba], rax - shr rax, 11 ; rax = rax * 512 / 1048576 - mov [hd1_size], eax ; in mebibytes - -; Calculate FAT16 info - xor rax, rax - xor rbx, rbx - mov ax, [fat16_SectorsPerFat] - shl ax, 1 ; quick multiply by two - add ax, [fat16_ReservedSectors] - mov [fat16_RootStart], eax - mov bx, [fat16_RootDirEnts] - shr ebx, 4 ; bx = (bx * 32) / 512 - add ebx, eax ; BX now holds the datastart sector number - mov [fat16_DataStart], ebx - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT HDD +; ============================================================================= + +align 16 +db 'DEBUG: INIT_HDD ' +align 16 + + +hdd_setup: +; Read first sector (MBR) into memory + xor rax, rax + mov rdi, secbuffer0 + push rdi + mov rcx, 1 + call readsectors + pop rdi + + cmp byte [0x0000000000005030], 0x01 ; Did we boot from a MBR drive + jne hdd_setup_no_mbr ; If not then we already have the correct sector + +; Grab the partition offset value for the first partition + mov eax, [rdi+0x01C6] + mov [fat16_PartitionOffset], eax + +; Read the first sector of the first partition + mov rdi, secbuffer0 + push rdi + mov rcx, 1 + call readsectors + pop rdi + +hdd_setup_no_mbr: +; Get the values we need to start using fat16 + mov ax, [rdi+0x0b] + mov [fat16_BytesPerSector], ax ; This will probably be 512 + mov al, [rdi+0x0d] + mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) + mov ax, [rdi+0x0e] + mov [fat16_ReservedSectors], ax + mov [fat16_FatStart], eax + mov al, [rdi+0x10] + mov [fat16_Fats], al ; This will probably be 2 + mov ax, [rdi+0x11] + mov [fat16_RootDirEnts], ax + mov ax, [rdi+0x16] + mov [fat16_SectorsPerFat], ax + +; Find out how many sectors are on the disk + xor eax, eax + mov ax, [rdi+0x13] + cmp ax, 0x0000 + jne lessthan65536sectors + mov eax, [rdi+0x20] +lessthan65536sectors: + mov [fat16_TotalSectors], eax + +; Calculate the size of the drive in MiB + xor rax, rax + mov eax, [fat16_TotalSectors] + mov [hd1_maxlba], rax + shr rax, 11 ; rax = rax * 512 / 1048576 + mov [hd1_size], eax ; in mebibytes + +; Calculate FAT16 info + xor rax, rax + xor rbx, rbx + mov ax, [fat16_SectorsPerFat] + shl ax, 1 ; quick multiply by two + add ax, [fat16_ReservedSectors] + mov [fat16_RootStart], eax + mov bx, [fat16_RootDirEnts] + shr ebx, 4 ; bx = (bx * 32) / 512 + add ebx, eax ; BX now holds the datastart sector number + mov [fat16_DataStart], ebx + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/init_net.asm b/amd64/bareMetalOS-0.5.3/os/init_net.asm index f54c6bb1..756e2187 100644 --- a/amd64/bareMetalOS-0.5.3/os/init_net.asm +++ b/amd64/bareMetalOS-0.5.3/os/init_net.asm @@ -1,84 +1,84 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT_NET -; ============================================================================= - -align 16 -db 'DEBUG: INIT_NET ' -align 16 - - -init_net: - ; Search for a supported NIC - mov rsi, NIC_DeviceVendor_ID - -init_net_probe_next: - lodsd ; Load a driver ID - Low half must be 0xFFFF -init_net_probe_next_driver: - mov rdx, rax ; Save the driver ID -init_net_probe_next_device: - lodsd ; Load a device and vendor ID from our list of supported NICs - cmp eax, 0x00000000 ; 0x00000000 means we have reached the end of the list - je init_net_probe_not_found ; No suported NIC found - cmp ax, 0xFFFF ; New driver ID? - je init_net_probe_next_driver ; We found the next driver type - call os_pci_find_device ; Returns BL = Bus number (8-bit value) and CL = Device/Slot number (5-bit value) if NIC was found - jnc init_net_probe_found ; If Carry is clear then we found a supported NIC - jmp init_net_probe_next_device ; Check the next device - -init_net_probe_found: - cmp edx, 0x8169FFFF - je init_net_probe_found_rtl8169 - cmp edx, 0x8254FFFF - je init_net_probe_found_i8254x - jmp init_net_probe_not_found - -init_net_probe_found_rtl8169: - call os_net_rtl8169_init - mov rdi, os_net_transmit - mov rax, os_net_rtl8169_transmit - stosq - mov rax, os_net_rtl8169_poll - stosq - mov rax, os_net_rtl8169_ack_int - stosq - jmp init_net_probe_found_finish - -init_net_probe_found_i8254x: - call os_net_i8254x_init - mov rdi, os_net_transmit - mov rax, os_net_i8254x_transmit - stosq - mov rax, os_net_i8254x_poll - stosq - mov rax, os_net_i8254x_ack_int - stosq - jmp init_net_probe_found_finish - -init_net_probe_found_finish: - xor eax, eax - mov al, [os_NetIRQ] - push rax ; Save the IRQ - add al, 0x20 - mov rdi, rax - mov rax, network - call create_gate - pop rax ; Restore the IRQ - mov rcx, rax - add rax, 0x20 - bts rax, 13 ; 1=Low active - bts rax, 15 ; 1=Level sensitive - call ioapic_entry_write - - mov byte [os_NetEnabled], 1 ; A supported NIC was found. Signal to the OS that networking is enabled - call os_ethernet_ack_int ; Call the driver function to acknowledge the interrupt internally - -init_net_probe_not_found: - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT_NET +; ============================================================================= + +align 16 +db 'DEBUG: INIT_NET ' +align 16 + + +init_net: + ; Search for a supported NIC + mov rsi, NIC_DeviceVendor_ID + +init_net_probe_next: + lodsd ; Load a driver ID - Low half must be 0xFFFF +init_net_probe_next_driver: + mov rdx, rax ; Save the driver ID +init_net_probe_next_device: + lodsd ; Load a device and vendor ID from our list of supported NICs + cmp eax, 0x00000000 ; 0x00000000 means we have reached the end of the list + je init_net_probe_not_found ; No suported NIC found + cmp ax, 0xFFFF ; New driver ID? + je init_net_probe_next_driver ; We found the next driver type + call os_pci_find_device ; Returns BL = Bus number (8-bit value) and CL = Device/Slot number (5-bit value) if NIC was found + jnc init_net_probe_found ; If Carry is clear then we found a supported NIC + jmp init_net_probe_next_device ; Check the next device + +init_net_probe_found: + cmp edx, 0x8169FFFF + je init_net_probe_found_rtl8169 + cmp edx, 0x8254FFFF + je init_net_probe_found_i8254x + jmp init_net_probe_not_found + +init_net_probe_found_rtl8169: + call os_net_rtl8169_init + mov rdi, os_net_transmit + mov rax, os_net_rtl8169_transmit + stosq + mov rax, os_net_rtl8169_poll + stosq + mov rax, os_net_rtl8169_ack_int + stosq + jmp init_net_probe_found_finish + +init_net_probe_found_i8254x: + call os_net_i8254x_init + mov rdi, os_net_transmit + mov rax, os_net_i8254x_transmit + stosq + mov rax, os_net_i8254x_poll + stosq + mov rax, os_net_i8254x_ack_int + stosq + jmp init_net_probe_found_finish + +init_net_probe_found_finish: + xor eax, eax + mov al, [os_NetIRQ] + push rax ; Save the IRQ + add al, 0x20 + mov rdi, rax + mov rax, network + call create_gate + pop rax ; Restore the IRQ + mov rcx, rax + add rax, 0x20 + bts rax, 13 ; 1=Low active + bts rax, 15 ; 1=Level sensitive + call ioapic_entry_write + + mov byte [os_NetEnabled], 1 ; A supported NIC was found. Signal to the OS that networking is enabled + call os_ethernet_ack_int ; Call the driver function to acknowledge the interrupt internally + +init_net_probe_not_found: + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/init_pci.asm b/amd64/bareMetalOS-0.5.3/os/init_pci.asm index b6fc30a5..ee5ebdf9 100644 --- a/amd64/bareMetalOS-0.5.3/os/init_pci.asm +++ b/amd64/bareMetalOS-0.5.3/os/init_pci.asm @@ -1,29 +1,29 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT_PCI -; ============================================================================= - -align 16 -db 'DEBUG: INIT_PCI ' -align 16 - - -init_pci: - ; - mov eax, 0x80000000 - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - in eax, dx - cmp eax, 0x80000000 - jne init_pci_not_found - mov byte [os_PCIEnabled], 1 - -init_pci_not_found: - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT_PCI +; ============================================================================= + +align 16 +db 'DEBUG: INIT_PCI ' +align 16 + + +init_pci: + ; + mov eax, 0x80000000 + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + in eax, dx + cmp eax, 0x80000000 + jne init_pci_not_found + mov byte [os_PCIEnabled], 1 + +init_pci_not_found: + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/interrupt.asm b/amd64/bareMetalOS-0.5.3/os/interrupt.asm index 1e89cd6f..a4d0f322 100644 --- a/amd64/bareMetalOS-0.5.3/os/interrupt.asm +++ b/amd64/bareMetalOS-0.5.3/os/interrupt.asm @@ -1,533 +1,533 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Interrupts -; ============================================================================= - -align 16 -db 'DEBUG: INTERRUPT' -align 16 - - -; ----------------------------------------------------------------------------- -; Default exception handler -exception_gate: - mov rsi, int_string00 - call os_print_string - mov rsi, exc_string - call os_print_string - jmp $ ; Hang -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Default interrupt handler -align 16 -interrupt_gate: ; handler for all other interrupts - iretq ; It was an undefined interrupt so return to caller -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Keyboard interrupt. IRQ 0x01, INT 0x21 -; This IRQ runs whenever there is input on the keyboard -align 16 -keyboard: - push rdi - push rbx - push rax - - xor eax, eax - - in al, 0x60 ; Get the scancode from the keyboard - cmp al, 0x01 - je keyboard_escape - cmp al, 0x2A ; Left Shift Make - je keyboard_shift - cmp al, 0x36 ; Right Shift Make - je keyboard_shift - cmp al, 0xAA ; Left Shift Break - je keyboard_noshift - cmp al, 0xB6 ; Right Shift Break - je keyboard_noshift - test al, 0x80 - jz keydown - jmp keyup - -keydown: - cmp byte [key_shift], 0x00 - jne keyboard_lowercase - jmp keyboard_uppercase - -keyboard_lowercase: - mov rbx, keylayoutupper - jmp keyboard_processkey - -keyboard_uppercase: - mov rbx, keylayoutlower - -keyboard_processkey: ; Convert the scancode - add rbx, rax - mov bl, [rbx] - mov [key], bl - mov al, [key] - jmp keyboard_done - -keyboard_escape: - jmp reboot - -keyup: - jmp keyboard_done - -keyboard_shift: - mov byte [key_shift], 0x01 - jmp keyboard_done - -keyboard_noshift: - mov byte [key_shift], 0x00 - jmp keyboard_done - -keyboard_done: - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC - add rdi, 0xB0 - xor eax, eax - stosd - call os_smp_wakeup_all ; A terrible hack - - pop rax - pop rbx - pop rdi - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Real-time clock interrupt. IRQ 0x08, INT 0x28 -; Currently this IRQ runs 8 times per second (As defined in init_64.asm) -; The supervisor lives here -align 16 -rtc: - push rsi - push rcx - push rax - - cld ; Clear direction flag - add qword [os_ClockCounter], 1 ; 64-bit counter started at bootup - - cmp byte [os_show_sysstatus], 0 - je rtc_no_sysstatus - call system_status ; Show System Status information on screen -rtc_no_sysstatus: - -; Check to make sure that at least one core is running something - cmp word [os_QueueLen], 0 ; Check the length of the Queue - jne rtc_end ; If it is greater than 0 then skip to the end - mov rcx, 256 - mov rsi, cpustatus -nextcpu: - lodsb - dec rcx - bt ax, 1 ; Is bit 1 set? If so then the CPU is running a job - jc rtc_end - cmp rcx, 0 - jne nextcpu - mov rax, os_command_line ; If nothing is running then restart the CLI - call os_smp_enqueue - -rtc_end: - mov al, 0x0C ; Select RTC register C - out 0x70, al ; Port 0x70 is the RTC index, and 0x71 is the RTC data - in al, 0x71 ; Read the value in register C - mov rsi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC - xor eax, eax - mov dword [rsi+0xB0], eax - - pop rax - pop rcx - pop rsi - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Network interrupt. -align 16 -network: - push rdi - push rsi - push rcx - push rax - pushfq - - cld ; Clear direction flag - call os_ethernet_ack_int ; Call the driver function to acknowledge the interrupt internally - - bt ax, 0 ; TX bit set (caused the IRQ?) - jc network_tx ; If so then jump past RX section - bt ax, 7 ; RX bit set - jnc network_end -network_rx_as_well: - mov byte [os_NetActivity_RX], 1 - - ; Max size of Ethernet packet: 1518 - ; + size: 2 = 1520 = 0x5F0 - ; Set each element size to 0x800 (2048). 262144 byte buffer / 2048 = room for 128 packets - ; Deal with the received packet - ; Get current offset in the ring buffer - mov rdi, os_EthernetBuffer - xor rax, rax - mov al, byte [os_EthernetBuffer_C2] - push rax ; Save the ring element value - shl rax, 11 ; Quickly multiply RAX by 2048 - add rdi, rax - push rdi - add rdi, 2 - call os_ethernet_rx_from_interrupt - pop rdi - mov rax, rcx - stosw ; Store the size of the packet - ; increment the offset in the ring buffer - pop rax ; Restore the ring element value - add al, 1 - cmp al, 128 ; Max element number is 127 - jne network_rx_buffer_nowrap - xor al, al -network_rx_buffer_nowrap: - mov byte [os_EthernetBuffer_C2], al - - ; Check the packet type - mov ax, [rdi+12] ; Grab the EtherType/Length - xchg al, ah ; Convert big endian to little endian - cmp ax, 0x0800 ; IPv4 - je network_IPv4_handler - cmp ax, 0x0806 ; ARP - je network_ARP_handler - cmp ax, 0x86DD ; IPv6 - je network_IPv6_handler - - jmp network_end - -network_tx: - mov byte [os_NetActivity_TX], 1 - bt ax, 7 - jc network_rx_as_well - -network_end: - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC - add rdi, 0xB0 - xor eax, eax - stosd - - popfq - pop rax - pop rcx - pop rsi - pop rdi - iretq - -network_ARP_handler: ; Copy the packet and call the handler - mov rsi, rdi ; Copy the packet location - mov rdi, os_eth_temp_buffer ; and copy it here - push rsi - push rcx - rep movsb - pop rcx - pop rsi - - ; Remove the ARP packet from the ring buffer -; mov al, byte [os_EthernetBuffer_C2] - - call os_arp_handler ; Handle the packet - jmp network_end - -network_IPv4_handler: - mov rsi, rdi ; Copy the packet location - mov rdi, os_eth_temp_buffer ; and copy it here - push rsi - push rcx - rep movsb - pop rcx - pop rsi - - mov al, [rsi+0x17] - cmp al, 0x01 ; ICMP - je network_IPv4_ICMP_handler - cmp al, 0x06 ; TCP - je network_IPv4_TCP_handler - cmp al, 0x11 ; UDP - je network_end - jmp network_end - -network_IPv4_ICMP_handler: - call os_icmp_handler - jmp network_end - -network_IPv4_TCP_handler: - call os_tcp_handler - jmp network_end - -network_IPv6_handler: - jmp network_end - -network_string01 db 'ARP!', 0 -network_string02 db 'ICMP!', 0 -network_string03 db 'TCP!', 0 -network_string04 db 'UDP!', 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; A simple interrupt that just acknowledges an IPI. Useful for getting an AP past a 'hlt' in the code. -align 16 -ap_wakeup: - push rdi - push rax - - cld ; Clear direction flag - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI - add rdi, 0xB0 - xor rax, rax - stosd - - pop rax - pop rdi - iretq ; Return from the IPI. -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Resets a CPU to execute ap_clear -align 16 -ap_reset: - cld ; Clear direction flag - mov rax, ap_clear ; Set RAX to the address of ap_clear - mov [rsp], rax ; Overwrite the return address on the CPU's stack - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI - add rdi, 0xB0 - xor rax, rax - stosd - iretq ; Return from the IPI. CPU will execute code at ap_clear -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; CPU Exception Gates -align 16 -exception_gate_00: - push rax - mov al, 0x00 - jmp exception_gate_main - -align 16 -exception_gate_01: - push rax - mov al, 0x01 - jmp exception_gate_main - -align 16 -exception_gate_02: - push rax - mov al, 0x02 - jmp exception_gate_main - -align 16 -exception_gate_03: - push rax - mov al, 0x03 - jmp exception_gate_main - -align 16 -exception_gate_04: - push rax - mov al, 0x04 - jmp exception_gate_main - -align 16 -exception_gate_05: - push rax - mov al, 0x05 - jmp exception_gate_main - -align 16 -exception_gate_06: - push rax - mov al, 0x06 - jmp exception_gate_main - -align 16 -exception_gate_07: - push rax - mov al, 0x07 - jmp exception_gate_main - -align 16 -exception_gate_08: - push rax - mov al, 0x08 - jmp exception_gate_main - -align 16 -exception_gate_09: - push rax - mov al, 0x09 - jmp exception_gate_main - -align 16 -exception_gate_10: - push rax - mov al, 0x0A - jmp exception_gate_main - -align 16 -exception_gate_11: - push rax - mov al, 0x0B - jmp exception_gate_main - -align 16 -exception_gate_12: - push rax - mov al, 0x0C - jmp exception_gate_main - -align 16 -exception_gate_13: - push rax - mov al, 0x0D - jmp exception_gate_main - -align 16 -exception_gate_14: - push rax - mov al, 0x0E - jmp exception_gate_main - -align 16 -exception_gate_15: - push rax - mov al, 0x0F - jmp exception_gate_main - -align 16 -exception_gate_16: - push rax - mov al, 0x10 - jmp exception_gate_main - -align 16 -exception_gate_17: - push rax - mov al, 0x11 - jmp exception_gate_main - -align 16 -exception_gate_18: - push rax - mov al, 0x12 - jmp exception_gate_main - -align 16 -exception_gate_19: - push rax - mov al, 0x13 - jmp exception_gate_main - -align 16 -exception_gate_main: - push rbx - push rdi - push rsi - push rax ; Save RAX since os_smp_get_id clobers it - call os_print_newline - mov bl, 0x0F - mov rsi, int_string00 - call os_print_string_with_color - call os_smp_get_id ; Get the local CPU ID and print it - mov rdi, os_temp_string - mov rsi, rdi - call os_int_to_string - call os_print_string_with_color - mov rsi, int_string01 - call os_print_string - mov rsi, exc_string00 - pop rax - and rax, 0x00000000000000FF ; Clear out everything in RAX except for AL - push rax - mov bl, 52 - mul bl ; AX = AL x BL - add rsi, rax ; Use the value in RAX as an offset to get to the right message - pop rax - mov bl, 0x0F - call os_print_string_with_color - call os_print_newline - pop rsi - pop rdi - pop rbx - pop rax - call os_print_newline - call os_debug_dump_reg - mov rsi, rip_string - call os_print_string - push rax - mov rax, [rsp+0x08] ; RIP of caller - call os_debug_dump_rax - pop rax - call os_print_newline - push rax - push rcx - push rsi - mov rsi, stack_string - call os_print_string - mov rsi, rsp - add rsi, 0x18 - mov rcx, 4 -next_stack: - lodsq - call os_debug_dump_rax - mov al, ' ' - call os_print_char -; call os_print_char -; call os_print_char -; call os_print_char - loop next_stack - call os_print_newline - pop rsi - pop rcx - pop rax -; jmp $ ; For debugging - call init_memory_map - jmp ap_clear ; jump to AP clear code - - -int_string00 db 'BareMetal OS - CPU ', 0 -int_string01 db ' - ', 0 -; Strings for the error messages -exc_string db 'Unknown Fatal Exception!', 0 -exc_string00 db 'Interrupt 00 - Divide Error Exception (#DE) ', 0 -exc_string01 db 'Interrupt 01 - Debug Exception (#DB) ', 0 -exc_string02 db 'Interrupt 02 - NMI Interrupt ', 0 -exc_string03 db 'Interrupt 03 - Breakpoint Exception (#BP) ', 0 -exc_string04 db 'Interrupt 04 - Overflow Exception (#OF) ', 0 -exc_string05 db 'Interrupt 05 - BOUND Range Exceeded Exception (#BR)', 0 -exc_string06 db 'Interrupt 06 - Invalid Opcode Exception (#UD) ', 0 -exc_string07 db 'Interrupt 07 - Device Not Available Exception (#NM)', 0 -exc_string08 db 'Interrupt 08 - Double Fault Exception (#DF) ', 0 -exc_string09 db 'Interrupt 09 - Coprocessor Segment Overrun ', 0 ; No longer generated on new CPU's -exc_string10 db 'Interrupt 10 - Invalid TSS Exception (#TS) ', 0 -exc_string11 db 'Interrupt 11 - Segment Not Present (#NP) ', 0 -exc_string12 db 'Interrupt 12 - Stack Fault Exception (#SS) ', 0 -exc_string13 db 'Interrupt 13 - General Protection Exception (#GP) ', 0 -exc_string14 db 'Interrupt 14 - Page-Fault Exception (#PF) ', 0 -exc_string15 db 'Interrupt 15 - Undefined ', 0 -exc_string16 db 'Interrupt 16 - x87 FPU Floating-Point Error (#MF) ', 0 -exc_string17 db 'Interrupt 17 - Alignment Check Exception (#AC) ', 0 -exc_string18 db 'Interrupt 18 - Machine-Check Exception (#MC) ', 0 -exc_string19 db 'Interrupt 19 - SIMD Floating-Point Exception (#XM) ', 0 -rip_string db ' IP:', 0 -stack_string db ' ST:', 0 - - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Interrupts +; ============================================================================= + +align 16 +db 'DEBUG: INTERRUPT' +align 16 + + +; ----------------------------------------------------------------------------- +; Default exception handler +exception_gate: + mov rsi, int_string00 + call os_print_string + mov rsi, exc_string + call os_print_string + jmp $ ; Hang +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Default interrupt handler +align 16 +interrupt_gate: ; handler for all other interrupts + iretq ; It was an undefined interrupt so return to caller +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Keyboard interrupt. IRQ 0x01, INT 0x21 +; This IRQ runs whenever there is input on the keyboard +align 16 +keyboard: + push rdi + push rbx + push rax + + xor eax, eax + + in al, 0x60 ; Get the scancode from the keyboard + cmp al, 0x01 + je keyboard_escape + cmp al, 0x2A ; Left Shift Make + je keyboard_shift + cmp al, 0x36 ; Right Shift Make + je keyboard_shift + cmp al, 0xAA ; Left Shift Break + je keyboard_noshift + cmp al, 0xB6 ; Right Shift Break + je keyboard_noshift + test al, 0x80 + jz keydown + jmp keyup + +keydown: + cmp byte [key_shift], 0x00 + jne keyboard_lowercase + jmp keyboard_uppercase + +keyboard_lowercase: + mov rbx, keylayoutupper + jmp keyboard_processkey + +keyboard_uppercase: + mov rbx, keylayoutlower + +keyboard_processkey: ; Convert the scancode + add rbx, rax + mov bl, [rbx] + mov [key], bl + mov al, [key] + jmp keyboard_done + +keyboard_escape: + jmp reboot + +keyup: + jmp keyboard_done + +keyboard_shift: + mov byte [key_shift], 0x01 + jmp keyboard_done + +keyboard_noshift: + mov byte [key_shift], 0x00 + jmp keyboard_done + +keyboard_done: + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC + add rdi, 0xB0 + xor eax, eax + stosd + call os_smp_wakeup_all ; A terrible hack + + pop rax + pop rbx + pop rdi + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Real-time clock interrupt. IRQ 0x08, INT 0x28 +; Currently this IRQ runs 8 times per second (As defined in init_64.asm) +; The supervisor lives here +align 16 +rtc: + push rsi + push rcx + push rax + + cld ; Clear direction flag + add qword [os_ClockCounter], 1 ; 64-bit counter started at bootup + + cmp byte [os_show_sysstatus], 0 + je rtc_no_sysstatus + call system_status ; Show System Status information on screen +rtc_no_sysstatus: + +; Check to make sure that at least one core is running something + cmp word [os_QueueLen], 0 ; Check the length of the Queue + jne rtc_end ; If it is greater than 0 then skip to the end + mov rcx, 256 + mov rsi, cpustatus +nextcpu: + lodsb + dec rcx + bt ax, 1 ; Is bit 1 set? If so then the CPU is running a job + jc rtc_end + cmp rcx, 0 + jne nextcpu + mov rax, os_command_line ; If nothing is running then restart the CLI + call os_smp_enqueue + +rtc_end: + mov al, 0x0C ; Select RTC register C + out 0x70, al ; Port 0x70 is the RTC index, and 0x71 is the RTC data + in al, 0x71 ; Read the value in register C + mov rsi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC + xor eax, eax + mov dword [rsi+0xB0], eax + + pop rax + pop rcx + pop rsi + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Network interrupt. +align 16 +network: + push rdi + push rsi + push rcx + push rax + pushfq + + cld ; Clear direction flag + call os_ethernet_ack_int ; Call the driver function to acknowledge the interrupt internally + + bt ax, 0 ; TX bit set (caused the IRQ?) + jc network_tx ; If so then jump past RX section + bt ax, 7 ; RX bit set + jnc network_end +network_rx_as_well: + mov byte [os_NetActivity_RX], 1 + + ; Max size of Ethernet packet: 1518 + ; + size: 2 = 1520 = 0x5F0 + ; Set each element size to 0x800 (2048). 262144 byte buffer / 2048 = room for 128 packets + ; Deal with the received packet + ; Get current offset in the ring buffer + mov rdi, os_EthernetBuffer + xor rax, rax + mov al, byte [os_EthernetBuffer_C2] + push rax ; Save the ring element value + shl rax, 11 ; Quickly multiply RAX by 2048 + add rdi, rax + push rdi + add rdi, 2 + call os_ethernet_rx_from_interrupt + pop rdi + mov rax, rcx + stosw ; Store the size of the packet + ; increment the offset in the ring buffer + pop rax ; Restore the ring element value + add al, 1 + cmp al, 128 ; Max element number is 127 + jne network_rx_buffer_nowrap + xor al, al +network_rx_buffer_nowrap: + mov byte [os_EthernetBuffer_C2], al + + ; Check the packet type + mov ax, [rdi+12] ; Grab the EtherType/Length + xchg al, ah ; Convert big endian to little endian + cmp ax, 0x0800 ; IPv4 + je network_IPv4_handler + cmp ax, 0x0806 ; ARP + je network_ARP_handler + cmp ax, 0x86DD ; IPv6 + je network_IPv6_handler + + jmp network_end + +network_tx: + mov byte [os_NetActivity_TX], 1 + bt ax, 7 + jc network_rx_as_well + +network_end: + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC + add rdi, 0xB0 + xor eax, eax + stosd + + popfq + pop rax + pop rcx + pop rsi + pop rdi + iretq + +network_ARP_handler: ; Copy the packet and call the handler + mov rsi, rdi ; Copy the packet location + mov rdi, os_eth_temp_buffer ; and copy it here + push rsi + push rcx + rep movsb + pop rcx + pop rsi + + ; Remove the ARP packet from the ring buffer +; mov al, byte [os_EthernetBuffer_C2] + + call os_arp_handler ; Handle the packet + jmp network_end + +network_IPv4_handler: + mov rsi, rdi ; Copy the packet location + mov rdi, os_eth_temp_buffer ; and copy it here + push rsi + push rcx + rep movsb + pop rcx + pop rsi + + mov al, [rsi+0x17] + cmp al, 0x01 ; ICMP + je network_IPv4_ICMP_handler + cmp al, 0x06 ; TCP + je network_IPv4_TCP_handler + cmp al, 0x11 ; UDP + je network_end + jmp network_end + +network_IPv4_ICMP_handler: + call os_icmp_handler + jmp network_end + +network_IPv4_TCP_handler: + call os_tcp_handler + jmp network_end + +network_IPv6_handler: + jmp network_end + +network_string01 db 'ARP!', 0 +network_string02 db 'ICMP!', 0 +network_string03 db 'TCP!', 0 +network_string04 db 'UDP!', 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; A simple interrupt that just acknowledges an IPI. Useful for getting an AP past a 'hlt' in the code. +align 16 +ap_wakeup: + push rdi + push rax + + cld ; Clear direction flag + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI + add rdi, 0xB0 + xor rax, rax + stosd + + pop rax + pop rdi + iretq ; Return from the IPI. +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Resets a CPU to execute ap_clear +align 16 +ap_reset: + cld ; Clear direction flag + mov rax, ap_clear ; Set RAX to the address of ap_clear + mov [rsp], rax ; Overwrite the return address on the CPU's stack + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI + add rdi, 0xB0 + xor rax, rax + stosd + iretq ; Return from the IPI. CPU will execute code at ap_clear +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; CPU Exception Gates +align 16 +exception_gate_00: + push rax + mov al, 0x00 + jmp exception_gate_main + +align 16 +exception_gate_01: + push rax + mov al, 0x01 + jmp exception_gate_main + +align 16 +exception_gate_02: + push rax + mov al, 0x02 + jmp exception_gate_main + +align 16 +exception_gate_03: + push rax + mov al, 0x03 + jmp exception_gate_main + +align 16 +exception_gate_04: + push rax + mov al, 0x04 + jmp exception_gate_main + +align 16 +exception_gate_05: + push rax + mov al, 0x05 + jmp exception_gate_main + +align 16 +exception_gate_06: + push rax + mov al, 0x06 + jmp exception_gate_main + +align 16 +exception_gate_07: + push rax + mov al, 0x07 + jmp exception_gate_main + +align 16 +exception_gate_08: + push rax + mov al, 0x08 + jmp exception_gate_main + +align 16 +exception_gate_09: + push rax + mov al, 0x09 + jmp exception_gate_main + +align 16 +exception_gate_10: + push rax + mov al, 0x0A + jmp exception_gate_main + +align 16 +exception_gate_11: + push rax + mov al, 0x0B + jmp exception_gate_main + +align 16 +exception_gate_12: + push rax + mov al, 0x0C + jmp exception_gate_main + +align 16 +exception_gate_13: + push rax + mov al, 0x0D + jmp exception_gate_main + +align 16 +exception_gate_14: + push rax + mov al, 0x0E + jmp exception_gate_main + +align 16 +exception_gate_15: + push rax + mov al, 0x0F + jmp exception_gate_main + +align 16 +exception_gate_16: + push rax + mov al, 0x10 + jmp exception_gate_main + +align 16 +exception_gate_17: + push rax + mov al, 0x11 + jmp exception_gate_main + +align 16 +exception_gate_18: + push rax + mov al, 0x12 + jmp exception_gate_main + +align 16 +exception_gate_19: + push rax + mov al, 0x13 + jmp exception_gate_main + +align 16 +exception_gate_main: + push rbx + push rdi + push rsi + push rax ; Save RAX since os_smp_get_id clobers it + call os_print_newline + mov bl, 0x0F + mov rsi, int_string00 + call os_print_string_with_color + call os_smp_get_id ; Get the local CPU ID and print it + mov rdi, os_temp_string + mov rsi, rdi + call os_int_to_string + call os_print_string_with_color + mov rsi, int_string01 + call os_print_string + mov rsi, exc_string00 + pop rax + and rax, 0x00000000000000FF ; Clear out everything in RAX except for AL + push rax + mov bl, 52 + mul bl ; AX = AL x BL + add rsi, rax ; Use the value in RAX as an offset to get to the right message + pop rax + mov bl, 0x0F + call os_print_string_with_color + call os_print_newline + pop rsi + pop rdi + pop rbx + pop rax + call os_print_newline + call os_debug_dump_reg + mov rsi, rip_string + call os_print_string + push rax + mov rax, [rsp+0x08] ; RIP of caller + call os_debug_dump_rax + pop rax + call os_print_newline + push rax + push rcx + push rsi + mov rsi, stack_string + call os_print_string + mov rsi, rsp + add rsi, 0x18 + mov rcx, 4 +next_stack: + lodsq + call os_debug_dump_rax + mov al, ' ' + call os_print_char +; call os_print_char +; call os_print_char +; call os_print_char + loop next_stack + call os_print_newline + pop rsi + pop rcx + pop rax +; jmp $ ; For debugging + call init_memory_map + jmp ap_clear ; jump to AP clear code + + +int_string00 db 'BareMetal OS - CPU ', 0 +int_string01 db ' - ', 0 +; Strings for the error messages +exc_string db 'Unknown Fatal Exception!', 0 +exc_string00 db 'Interrupt 00 - Divide Error Exception (#DE) ', 0 +exc_string01 db 'Interrupt 01 - Debug Exception (#DB) ', 0 +exc_string02 db 'Interrupt 02 - NMI Interrupt ', 0 +exc_string03 db 'Interrupt 03 - Breakpoint Exception (#BP) ', 0 +exc_string04 db 'Interrupt 04 - Overflow Exception (#OF) ', 0 +exc_string05 db 'Interrupt 05 - BOUND Range Exceeded Exception (#BR)', 0 +exc_string06 db 'Interrupt 06 - Invalid Opcode Exception (#UD) ', 0 +exc_string07 db 'Interrupt 07 - Device Not Available Exception (#NM)', 0 +exc_string08 db 'Interrupt 08 - Double Fault Exception (#DF) ', 0 +exc_string09 db 'Interrupt 09 - Coprocessor Segment Overrun ', 0 ; No longer generated on new CPU's +exc_string10 db 'Interrupt 10 - Invalid TSS Exception (#TS) ', 0 +exc_string11 db 'Interrupt 11 - Segment Not Present (#NP) ', 0 +exc_string12 db 'Interrupt 12 - Stack Fault Exception (#SS) ', 0 +exc_string13 db 'Interrupt 13 - General Protection Exception (#GP) ', 0 +exc_string14 db 'Interrupt 14 - Page-Fault Exception (#PF) ', 0 +exc_string15 db 'Interrupt 15 - Undefined ', 0 +exc_string16 db 'Interrupt 16 - x87 FPU Floating-Point Error (#MF) ', 0 +exc_string17 db 'Interrupt 17 - Alignment Check Exception (#AC) ', 0 +exc_string18 db 'Interrupt 18 - Machine-Check Exception (#MC) ', 0 +exc_string19 db 'Interrupt 19 - SIMD Floating-Point Exception (#XM) ', 0 +rip_string db ' IP:', 0 +stack_string db ' ST:', 0 + + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/ipv4.asm b/amd64/bareMetalOS-0.5.3/os/ipv4.asm index d60b0945..ebe05401 100644 --- a/amd64/bareMetalOS-0.5.3/os/ipv4.asm +++ b/amd64/bareMetalOS-0.5.3/os/ipv4.asm @@ -1,29 +1,29 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; IP (Internet Protocol) Version 4 -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 IP ' -align 16 - -; os_ipv4_open -- Open an IPv4 socket -; os_ipv4_close -- Close an IPv4 socket -; os_ipv4_connect -- Connect an IPv4 socket to a specified destination -; os_ipv4_disconnect -- Disconnect an IPv4 socket -; os_ipv4_bind -- Bind an IPv4 socket to a port -; os_ipv4_listen -- Listen on a socket -; os_ipv4_accept -- Accept a connection -; os_ipv4_select -- - - -%include "ipv4/arp.asm" -%include "ipv4/icmp.asm" -%include "ipv4/tcp.asm" -%include "ipv4/udp.asm" - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; IP (Internet Protocol) Version 4 +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 IP ' +align 16 + +; os_ipv4_open -- Open an IPv4 socket +; os_ipv4_close -- Close an IPv4 socket +; os_ipv4_connect -- Connect an IPv4 socket to a specified destination +; os_ipv4_disconnect -- Disconnect an IPv4 socket +; os_ipv4_bind -- Bind an IPv4 socket to a port +; os_ipv4_listen -- Listen on a socket +; os_ipv4_accept -- Accept a connection +; os_ipv4_select -- + + +%include "ipv4/arp.asm" +%include "ipv4/icmp.asm" +%include "ipv4/tcp.asm" +%include "ipv4/udp.asm" + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/ipv4/arp.asm b/amd64/bareMetalOS-0.5.3/os/ipv4/arp.asm index 96ca9eb8..920404cc 100644 --- a/amd64/bareMetalOS-0.5.3/os/ipv4/arp.asm +++ b/amd64/bareMetalOS-0.5.3/os/ipv4/arp.asm @@ -1,137 +1,137 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; ARP (Address Resolution Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: ARP ' -align 16 - - -; ARP Incoming Request layout: -; Ethernet header: -; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) -; 6-11, Source MAC -; 12-13, Type ARP (0x0806) -; ARP data: -; 14-15, Hardware type (0x0001 Ethernet) -; 16-17, Protocol type (0x0800 IP) -; 18, Hardware size (0x06) -; 19, Protocol size (0x04) -; 20-21, Opcode (0x0001 Request) -; 22-27, Sender MAC -; 28-31, Sender IP -; 32-37, Target MAC (0x000000000000) -; 38-41, Target IP - -; ARP Outgoing Request layout: -; Ethernet header: -; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) -; 6-11, Source MAC (This host) -; 12-13, Type ARP (0x0806) -; ARP data: -; 14-15, Hardware type (0x0001 Ethernet) -; 16-17, Protocol type (0x0800 IP) -; 18, Hardware size (0x06) -; 19, Protocol size (0x04) -; 20-21, Opcode (0x0001 Request) -; 22-27, Sender MAC (This host) -; 28-31, Sender IP (This host) -; 32-37, Target MAC (0x000000000000) -; 38-41, Target IP - -; ARP Outgoing Reply layout: -; Ethernet header: -; 0-5, Destination MAC (This host) -; 6-11, Source MAC -; 12-13, Type ARP (0x0806) -; ARP data: -; 14-15, Hardware type (0x0001 Ethernet) -; 16-17, Protocol type (0x0800 IP) -; 18, Hardware size (0x06) -; 19, Protocol size (0x04) -; 20-21, Opcode (0x0002 Reply) -; 22-27, Sender MAC -; 28-31, Sender IP -; 32-37, Target MAC -; 38-41, Target IP - - -; ----------------------------------------------------------------------------- -os_arp_request: - -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_arp_handler -- Handle an incoming ARP packet; Called by Network interrupt -; IN: RCX = packet length -; RSI = location of received ARP packet -os_arp_handler: - push rdi - push rsi - push rax - - mov ax, [rsi+0x14] ; Grab the Opcode - xchg al, ah ; Convert to proper endianess - cmp ax, 0x0001 ; Request - je os_arp_handler_request ; Respond if the ARP packet is for us - cmp ax, 0x0002 ; Reply - je os_arp_handler_reply ; Add to our local ARP table - jmp os_arp_handler_end ; Bail out - -os_arp_handler_request: - mov eax, [rsi+0x26] ; Grab the target IP address - cmp eax, [ip] ; Does it match our IP? - jne os_arp_handler_end ; If not then we don't need to respond - - push rsi ; Save the address of the packet - mov rdi, rsi - add rsi, 0x1C ; Skip to Sender IP - mov eax, [rsi] - push rax ; Save the Sender IP - sub rsi, 0x16 ; Skip back to Source MAC - movsd ; Copy destination MAC address - movsw - push rsi ; Copy source MAC address - mov rsi, os_NetMAC - movsd - movsw - pop rsi - add rdi, 9 - mov al, 0x02 ; Change the opcode to a reply - stosb - push rsi ; Copy source MAC address (again) - mov rsi, os_NetMAC - movsd - movsw - pop rsi - mov eax, [ip] ; Copy our IP - stosd - sub rsi, 12 ; Copy destination MAC - movsd - movsw - pop rax ; Restore the Sender IP - stosd - pop rsi ; Restore the packet address - mov cx, 60 - call os_ethernet_tx_raw ; Send the packet - jmp os_arp_handler_end - -os_arp_handler_reply: - ; If this was a reply to a request that this computer sent out then this should be added to the local ARP table - jmp os_arp_handler_end - -os_arp_handler_end: - pop rax - pop rsi - pop rdi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; ARP (Address Resolution Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: ARP ' +align 16 + + +; ARP Incoming Request layout: +; Ethernet header: +; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) +; 6-11, Source MAC +; 12-13, Type ARP (0x0806) +; ARP data: +; 14-15, Hardware type (0x0001 Ethernet) +; 16-17, Protocol type (0x0800 IP) +; 18, Hardware size (0x06) +; 19, Protocol size (0x04) +; 20-21, Opcode (0x0001 Request) +; 22-27, Sender MAC +; 28-31, Sender IP +; 32-37, Target MAC (0x000000000000) +; 38-41, Target IP + +; ARP Outgoing Request layout: +; Ethernet header: +; 0-5, Broadcast MAC (0xFFFFFFFFFFFF) +; 6-11, Source MAC (This host) +; 12-13, Type ARP (0x0806) +; ARP data: +; 14-15, Hardware type (0x0001 Ethernet) +; 16-17, Protocol type (0x0800 IP) +; 18, Hardware size (0x06) +; 19, Protocol size (0x04) +; 20-21, Opcode (0x0001 Request) +; 22-27, Sender MAC (This host) +; 28-31, Sender IP (This host) +; 32-37, Target MAC (0x000000000000) +; 38-41, Target IP + +; ARP Outgoing Reply layout: +; Ethernet header: +; 0-5, Destination MAC (This host) +; 6-11, Source MAC +; 12-13, Type ARP (0x0806) +; ARP data: +; 14-15, Hardware type (0x0001 Ethernet) +; 16-17, Protocol type (0x0800 IP) +; 18, Hardware size (0x06) +; 19, Protocol size (0x04) +; 20-21, Opcode (0x0002 Reply) +; 22-27, Sender MAC +; 28-31, Sender IP +; 32-37, Target MAC +; 38-41, Target IP + + +; ----------------------------------------------------------------------------- +os_arp_request: + +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_arp_handler -- Handle an incoming ARP packet; Called by Network interrupt +; IN: RCX = packet length +; RSI = location of received ARP packet +os_arp_handler: + push rdi + push rsi + push rax + + mov ax, [rsi+0x14] ; Grab the Opcode + xchg al, ah ; Convert to proper endianess + cmp ax, 0x0001 ; Request + je os_arp_handler_request ; Respond if the ARP packet is for us + cmp ax, 0x0002 ; Reply + je os_arp_handler_reply ; Add to our local ARP table + jmp os_arp_handler_end ; Bail out + +os_arp_handler_request: + mov eax, [rsi+0x26] ; Grab the target IP address + cmp eax, [ip] ; Does it match our IP? + jne os_arp_handler_end ; If not then we don't need to respond + + push rsi ; Save the address of the packet + mov rdi, rsi + add rsi, 0x1C ; Skip to Sender IP + mov eax, [rsi] + push rax ; Save the Sender IP + sub rsi, 0x16 ; Skip back to Source MAC + movsd ; Copy destination MAC address + movsw + push rsi ; Copy source MAC address + mov rsi, os_NetMAC + movsd + movsw + pop rsi + add rdi, 9 + mov al, 0x02 ; Change the opcode to a reply + stosb + push rsi ; Copy source MAC address (again) + mov rsi, os_NetMAC + movsd + movsw + pop rsi + mov eax, [ip] ; Copy our IP + stosd + sub rsi, 12 ; Copy destination MAC + movsd + movsw + pop rax ; Restore the Sender IP + stosd + pop rsi ; Restore the packet address + mov cx, 60 + call os_ethernet_tx_raw ; Send the packet + jmp os_arp_handler_end + +os_arp_handler_reply: + ; If this was a reply to a request that this computer sent out then this should be added to the local ARP table + jmp os_arp_handler_end + +os_arp_handler_end: + pop rax + pop rsi + pop rdi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/ipv4/icmp.asm b/amd64/bareMetalOS-0.5.3/os/ipv4/icmp.asm index d47c6e56..2cca75c0 100644 --- a/amd64/bareMetalOS-0.5.3/os/ipv4/icmp.asm +++ b/amd64/bareMetalOS-0.5.3/os/ipv4/icmp.asm @@ -1,59 +1,59 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; ICMP (Internet Control Message Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 ICMP' -align 16 - - -; ----------------------------------------------------------------------------- -; os_icmp_handler -- Handle an incoming ICMP packet; Called by Network interrupt -; IN: RCX = packet length -; RSI = location of received ICMP packet -os_icmp_handler: - push rsi - push rax - - ; Check if reply or request - - -os_icmp_handler_request: - ; Swap the MAC addresses - mov rax, [rsi] ; Grab the Destination MAC as 8 bytes even though the MAC is 6 bytes - mov ax, [rsi+0x0C] ; Store the EtherType in the low 16-bits of RAX - push rax ; Save the new Source MAC (with EtherType) to the stack - mov rax, [rsi+0x06] ; Grab the Source MAC as 8 bytes (the last two bytes will be overwritten) - mov [rsi], rax ; Store the new Destination MAC in the packet - pop rax ; Restore the new Source MAC + EtherType - mov [rsi+0x06], rax ; Write it to the packet - - ; Swap the IP addresses - mov eax, [rsi+0x1A] ; Grab the Source IP - push rax - mov eax, [rsi+0x1E] ; Grab the Destination IP - mov dword [rsi+0x1A], eax ; Overwrite the 'old' Source with the 'new' Source - pop rax - mov dword [rsi+0x1E], eax ; Overwrite the 'old' Destination with the 'new' Destination - - ; Set to Echo Reply - mov byte [rsi+0x22], 0x00 ; Set to 0 for Echo Reply (Was originally 8 for Echo Request) - - ; Adjust the checksum - mov ax, [rsi+0x24] - add ax, 8 ; Add 8 since we removed 8 (by clearing the Echo Request) - mov word [rsi+0x24], ax - - call os_ethernet_tx_raw ; Send the packet - - pop rax - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; ICMP (Internet Control Message Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 ICMP' +align 16 + + +; ----------------------------------------------------------------------------- +; os_icmp_handler -- Handle an incoming ICMP packet; Called by Network interrupt +; IN: RCX = packet length +; RSI = location of received ICMP packet +os_icmp_handler: + push rsi + push rax + + ; Check if reply or request + + +os_icmp_handler_request: + ; Swap the MAC addresses + mov rax, [rsi] ; Grab the Destination MAC as 8 bytes even though the MAC is 6 bytes + mov ax, [rsi+0x0C] ; Store the EtherType in the low 16-bits of RAX + push rax ; Save the new Source MAC (with EtherType) to the stack + mov rax, [rsi+0x06] ; Grab the Source MAC as 8 bytes (the last two bytes will be overwritten) + mov [rsi], rax ; Store the new Destination MAC in the packet + pop rax ; Restore the new Source MAC + EtherType + mov [rsi+0x06], rax ; Write it to the packet + + ; Swap the IP addresses + mov eax, [rsi+0x1A] ; Grab the Source IP + push rax + mov eax, [rsi+0x1E] ; Grab the Destination IP + mov dword [rsi+0x1A], eax ; Overwrite the 'old' Source with the 'new' Source + pop rax + mov dword [rsi+0x1E], eax ; Overwrite the 'old' Destination with the 'new' Destination + + ; Set to Echo Reply + mov byte [rsi+0x22], 0x00 ; Set to 0 for Echo Reply (Was originally 8 for Echo Request) + + ; Adjust the checksum + mov ax, [rsi+0x24] + add ax, 8 ; Add 8 since we removed 8 (by clearing the Echo Request) + mov word [rsi+0x24], ax + + call os_ethernet_tx_raw ; Send the packet + + pop rax + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/ipv4/tcp.asm b/amd64/bareMetalOS-0.5.3/os/ipv4/tcp.asm index 320f93e1..d25284be 100644 --- a/amd64/bareMetalOS-0.5.3/os/ipv4/tcp.asm +++ b/amd64/bareMetalOS-0.5.3/os/ipv4/tcp.asm @@ -1,34 +1,34 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; TCP (Transmission Control Protocol) over IPv4 -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 TCP ' -align 16 - - -; os_ipv4_tcp_send -- Send data over a TCP socket -; os_ipv4_tcp_recv -- Receive data from a TCP socket - - -; ----------------------------------------------------------------------------- -; os_tcp_handler -- Handle an incoming TCP packet; Called by Network interrupt -; IN: RCX = packet length -; RSI = location of received TCP packet -os_tcp_handler: - push rsi - push rax - - - - pop rax - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; TCP (Transmission Control Protocol) over IPv4 +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 TCP ' +align 16 + + +; os_ipv4_tcp_send -- Send data over a TCP socket +; os_ipv4_tcp_recv -- Receive data from a TCP socket + + +; ----------------------------------------------------------------------------- +; os_tcp_handler -- Handle an incoming TCP packet; Called by Network interrupt +; IN: RCX = packet length +; RSI = location of received TCP packet +os_tcp_handler: + push rsi + push rax + + + + pop rax + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/ipv4/udp.asm b/amd64/bareMetalOS-0.5.3/os/ipv4/udp.asm index 4fdf2ac1..770eed2c 100644 --- a/amd64/bareMetalOS-0.5.3/os/ipv4/udp.asm +++ b/amd64/bareMetalOS-0.5.3/os/ipv4/udp.asm @@ -1,34 +1,34 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; UDP (User Datagram Protocol) over IPv4 -; ============================================================================= - -align 16 -db 'DEBUG: IPv4 UDP ' -align 16 - - -; os_ipv4_udp_sendto -- Writes data the remote host via UDP -; os_ipv4_udp_recvfrom -- Reads data from the remote host via UDP - - -; ----------------------------------------------------------------------------- -; os_udp_handler -- Handle an incoming UDP packet; Called by Network interrupt -; IN: RCX = packet length -; RSI = location of received UDP packet -os_udp_handler: - push rsi - push rax - - - - pop rax - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; UDP (User Datagram Protocol) over IPv4 +; ============================================================================= + +align 16 +db 'DEBUG: IPv4 UDP ' +align 16 + + +; os_ipv4_udp_sendto -- Writes data the remote host via UDP +; os_ipv4_udp_recvfrom -- Reads data from the remote host via UDP + + +; ----------------------------------------------------------------------------- +; os_udp_handler -- Handle an incoming UDP packet; Called by Network interrupt +; IN: RCX = packet length +; RSI = location of received UDP packet +os_udp_handler: + push rsi + push rax + + + + pop rax + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/ipv6/ndp.asm b/amd64/bareMetalOS-0.5.3/os/ipv6/ndp.asm index 53d13540..0cf484c1 100644 --- a/amd64/bareMetalOS-0.5.3/os/ipv6/ndp.asm +++ b/amd64/bareMetalOS-0.5.3/os/ipv6/ndp.asm @@ -1,14 +1,14 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; NDP (Neighbor Discovery Protocol) -; ============================================================================= - -align 16 -db 'DEBUG: NDP ' -align 16 - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; NDP (Neighbor Discovery Protocol) +; ============================================================================= + +align 16 +db 'DEBUG: NDP ' +align 16 + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/kernel64.asm b/amd64/bareMetalOS-0.5.3/os/kernel64.asm index 940b8c66..175ca914 100644 --- a/amd64/bareMetalOS-0.5.3/os/kernel64.asm +++ b/amd64/bareMetalOS-0.5.3/os/kernel64.asm @@ -1,568 +1,568 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; The BareMetal OS kernel. Assemble with NASM -; ============================================================================= - - -USE64 -ORG 0x0000000000100000 - -%DEFINE BAREMETALOS_VER 'v0.5.2 (June 29, 2011)', 13, 'Copyright (C) 2008-2011 Return Infinity', 13, 0 -%DEFINE BAREMETALOS_API_VER 1 - -kernel_start: - jmp start ; Skip over the function call index - nop - db 'BAREMETAL' - - align 16 ; 0x0010 - jmp os_print_string ; Jump to function - align 8 - dq os_print_string ; Memory address of function - - align 8 ; 0x0020 - jmp os_print_char - align 8 - dq os_print_char - - align 8 ; 0x0030 - jmp os_print_char_hex - align 8 - dq os_print_char_hex - - align 8 ; 0x0040 - jmp os_print_newline - align 8 - dq os_print_newline - - align 8 ; 0x0050 - jmp os_input_key_check - align 8 - dq os_input_key_check - - align 8 ; 0x0060 - jmp os_input_key_wait - align 8 - dq os_input_key_wait - - align 8 ; 0x0070 - jmp os_input_string - align 8 - dq os_input_string - - align 8 ; 0x0080 - jmp os_delay - align 8 - dq os_delay - - align 8 ; 0x0090 - jmp os_speaker_tone - align 8 - dq os_speaker_tone - - align 8 ; 0x00A0 - jmp os_speaker_off - align 8 - dq os_speaker_off - - align 8 ; 0x00B0 - jmp os_speaker_beep - align 8 - dq os_speaker_beep - - align 8 ; 0x00C0 - jmp os_move_cursor - align 8 - dq os_move_cursor - - align 8 ; 0x00D0 - jmp os_string_length - align 8 - dq os_string_length - - align 8 ; 0x00E0 - jmp os_string_find_char - align 8 - dq os_string_find_char - - align 8 ; 0x00F0 - jmp os_string_copy - align 8 - dq os_string_copy - - align 8 ; 0x0100 - jmp os_string_truncate - align 8 - dq os_string_truncate - - align 8 ; 0x0110 - jmp os_string_join - align 8 - dq os_string_join - - align 8 ; 0x0120 - jmp os_string_chomp - align 8 - dq os_string_chomp - - align 8 ; 0x0130 - jmp os_string_strip - align 8 - dq os_string_strip - - align 8 ; 0x0140 - jmp os_string_compare - align 8 - dq os_string_compare - - align 8 ; 0x0150 - jmp os_string_uppercase - align 8 - dq os_string_uppercase - - align 8 ; 0x0160 - jmp os_string_lowercase - align 8 - dq os_string_lowercase - - align 8 ; 0x0170 - jmp os_int_to_string - align 8 - dq os_int_to_string - - align 8 ; 0x0180 - jmp os_string_to_int - align 8 - dq os_string_to_int - - align 8 ; 0x0190 - jmp os_debug_dump_reg - align 8 - dq os_debug_dump_reg - - align 8 ; 0x01A0 - jmp os_debug_dump_mem - align 8 - dq os_debug_dump_mem - - align 8 ; 0x01B0 - jmp os_debug_dump_rax - align 8 - dq os_debug_dump_rax - - align 8 ; 0x01C0 - jmp os_debug_dump_eax - align 8 - dq os_debug_dump_eax - - align 8 ; 0x01D0 - jmp os_debug_dump_ax - align 8 - dq os_debug_dump_ax - - align 8 ; 0x01E0 - jmp os_debug_dump_al - align 8 - dq os_debug_dump_al - - align 8 ; 0x01F0 - jmp os_smp_reset - align 8 - dq os_smp_reset - - align 8 ; 0x0200 - jmp os_smp_get_id - align 8 - dq os_smp_get_id - - align 8 ; 0x0210 - jmp os_smp_enqueue - align 8 - dq os_smp_enqueue - - align 8 ; 0x0220 - jmp os_smp_dequeue - align 8 - dq os_smp_dequeue - - align 8 ; 0x0230 - jmp os_serial_send - align 8 - dq os_serial_send - - align 8 ; 0x0240 - jmp os_serial_recv - align 8 - dq os_serial_recv - - align 8 ; 0x0250 - jmp os_string_parse - align 8 - dq os_string_parse - - align 8 ; 0x0260 - jmp os_get_argc - align 8 - dq os_get_argc - - align 8 ; 0x0270 - jmp os_get_argv - align 8 - dq os_get_argv - - align 8 ; 0x0280 - jmp os_smp_queuelen - align 8 - dq os_smp_queuelen - - align 8 ; 0x0290 - jmp os_smp_wait - align 8 - dq os_smp_wait - - align 8 ; 0x02A0 - jmp os_get_timecounter - align 8 - dq os_get_timecounter - - align 8 ; 0x02B0 - jmp os_string_append - align 8 - dq os_string_append - - align 8 ; 0x02C0 - jmp os_int_to_hex_string - align 8 - dq os_int_to_hex_string - - align 8 ; 0x02D0 - jmp os_hex_string_to_int - align 8 - dq os_hex_string_to_int - - align 8 ; 0x02E0 - jmp os_string_change_char - align 8 - dq os_string_change_char - - align 8 ; 0x02F0 - jmp os_is_digit - align 8 - dq os_is_digit - - align 8 ; 0x0300 - jmp os_is_alpha - align 8 - dq os_is_alpha - - align 8 ; 0x0310 - jmp os_file_read - align 8 - dq os_file_read - - align 8 ; 0x0320 - jmp os_file_write - align 8 - dq os_file_write - - align 8 ; 0x0330 - jmp os_file_delete - align 8 - dq os_file_delete - - align 8 ; 0x0340 - jmp os_file_get_list - align 8 - dq os_file_get_list - - align 8 ; 0x0350 - jmp os_smp_run - align 8 - dq os_smp_run - - align 8 ; 0x0360 - jmp os_smp_lock - align 8 - dq os_smp_lock - - align 8 ; 0x0370 - jmp os_smp_unlock - align 8 - dq os_smp_unlock - - align 8 ; 0x0380 - jmp os_print_string_with_color - align 8 - dq os_print_string_with_color - - align 8 ; 0x0390 - jmp os_print_char_with_color - align 8 - dq os_print_char_with_color - - align 8 ; 0x03A0 - jmp os_ethernet_tx - align 8 - dq os_ethernet_tx - - align 8 ; 0x03B0 - jmp os_ethernet_rx - align 8 - dq os_ethernet_rx - - align 8 ; 0x03C0 - jmp os_mem_allocate - align 8 - dq os_mem_allocate - - align 8 ; 0x03D0 - jmp os_mem_release - align 8 - dq os_mem_release - - align 8 ; 0x03E0 - jmp os_mem_get_free - align 8 - dq os_mem_get_free - - align 8 ; 0x03F0 - jmp os_smp_numcores - align 8 - dq os_smp_numcores - - align 8 ; 0x0400 - jmp os_file_get_size - align 8 - dq os_file_get_size - - align 8 ; 0x0410 - jmp os_ethernet_avail - align 8 - dq os_ethernet_avail - - align 8 ; 0x0420 - jmp os_print_char_hex_with_color - align 8 - dq os_print_char_hex_with_color - - align 8 ; 0x0430 - jmp os_ethernet_tx_raw - align 8 - dq os_ethernet_tx_raw - - align 8 ; 0x0440 - jmp os_screen_clear - align 8 - dq os_screen_clear - - align 8 ; 0x0450 - jmp os_show_cursor - align 8 - dq os_show_cursor - - align 8 ; 0x0460 - jmp os_hide_cursor - align 8 - dq os_hide_cursor - - align 8 ; 0x0470 - jmp os_show_statusbar - align 8 - dq os_show_statusbar - - align 8 ; 0x0480 - jmp os_hide_statusbar - align 8 - dq os_hide_statusbar - - align 8 ; 0x0490 - jmp os_screen_update - align 8 - dq os_screen_update - - align 8 ; 0x04A0 - jmp os_print_chars - align 8 - dq os_print_chars - - align 8 ; 0x04B0 - jmp os_print_chars_with_color - align 8 - dq os_print_chars_with_color - -align 16 - -start: - - call init_64 ; After this point we are in a working 64-bit enviroment - - call init_pci - - call init_net ; Initialize the network - - call hdd_setup ; Gather information about the harddrive and set it up - - call os_screen_clear ; Clear screen and display cursor - - cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) - jne start_no_network - mov ax, 0x0013 - call os_move_cursor - mov rsi, networkmsg - call os_print_string - call os_debug_dump_MAC -start_no_network: - - mov ax, 0x0016 ; Print the "ready" message - call os_move_cursor - mov rsi, readymsg - call os_print_string - - mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner - call os_move_cursor - call os_show_cursor - - mov rsi, startupapp ; Look for a file called startup.app - mov rdi, programlocation ; We load the program to this location in memory (currently 0x00200000 : at the 2MB mark) - call os_file_read ; Read the file into memory - jc ap_clear ; If carry is set then the file was not found - - xchg bx, bx - mov rax, programlocation ; 0x00200000 : at the 2MB mark - xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) - call os_smp_enqueue ; Queue the application to run on the next available core - - ; Fall through to ap_clear as align fills the space with No-Ops - ; At this point the BSP is just like one of the AP's - - -align 16 - -ap_clear: ; All cores start here on first startup and after an exception - - cli ; Disable interrupts on this core - - ; Get local ID of the core - mov rsi, [os_LocalAPICAddress] - xor eax, eax ; Clear Task Priority (bits 7:4) and Task Priority Sub-Class (bits 3:0) - mov dword [rsi+0x80], eax ; APIC Task Priority Register (TPR) - mov eax, dword [rsi+0x20] ; APIC ID - shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID - - ; Calculate offset into CPU status table - mov rdi, cpustatus - add rdi, rax ; RDI points to this cores status byte (we will clear it later) - - ; Set up the stack - shl rax, 21 ; Shift left 21 bits for a 2 MiB stack - add rax, [os_StackBase] ; The stack decrements when you "push", start at 2 MiB in - mov rsp, rax - - ; Set the CPU status to "Present" and "Ready" - mov al, 00000001b ; Bit 0 set for "Present", Bit 1 clear for "Ready" - stosb ; Set status to Ready for this CPU - - sti ; Re-enable interrupts on this core - - ; Clear registers. Gives us a clean slate to work with - xor rax, rax ; aka r0 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rbx, rbx ; aka r3 - xor rbp, rbp ; aka r5, We skip RSP (aka r4) as it was previously set - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - -ap_spin: ; Spin until there is a workload in the queue - cmp word [os_QueueLen], 0 ; Check the length of the queue - je ap_halt ; If the queue was empty then jump to the HLT - call os_smp_dequeue ; Try to pull a workload out of the queue - jnc ap_process ; Carry clear if successful, jump to ap_process - -ap_halt: ; Halt until a wakup call is received - hlt ; If carry was set we fall through to the HLT - jmp ap_spin ; Try again - -ap_process: ; Set the status byte to "Busy" and run the code - cli - push rsi - push rax - mov rsi, [os_LocalAPICAddress] - xor eax, eax - mov al, 0x10 - mov dword [rsi+0x80], eax ; APIC Task Priority Register (TPR) - pop rax - pop rsi - sti - - push rdi ; Push RDI since it is used temporarily - push rax ; Push RAX since os_smp_get_id uses it - mov rdi, cpustatus - call os_smp_get_id ; Set RAX to the APIC ID - add rdi, rax - mov al, 00000011b ; Bit 0 set for "Present", Bit 1 set for "Busy" - stosb - pop rax ; Pop RAX (holds the workload code address) - pop rdi ; Pop RDI (holds the variable/variable address) - - mov r15, rax - - call os_get_argc - mov rcx, rax - cmp al, 1 - je noargs - - mov rdi, os_args - sub rcx, 1 - shl rcx, 3 - add rdi, rcx - shr rcx, 3 - add rcx, 1 -nextargv: - sub al, 1 - call os_get_argv - mov [rdi], rsi - sub rdi, 8 - cmp al, 1 - jne nextargv - -noargs: - mov al, 0 - call os_get_argv - mov [os_args], rsi - mov rsi, os_args ; ARGV[0] - - mov rdi, rcx ; ARGC - mov rax, r15 - - call rax ; Run the code - - jmp ap_clear ; Reset the stack, clear the registers, and wait for something else to work on - - -; Includes -%include "init_64.asm" -%include "init_pci.asm" -%include "init_net.asm" -%include "init_hdd.asm" -%include "syscalls.asm" -%include "drivers.asm" -%include "interrupt.asm" -%include "cli.asm" -%include "ipv4.asm" -%include "sysvar.asm" ; Include this last to keep the read/write variables away from the code - -;times 16384-($-$$) db 0 ; Set the compiled kernel binary to at least this size in bytes - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; The BareMetal OS kernel. Assemble with NASM +; ============================================================================= + + +USE64 +ORG 0x0000000000100000 + +%DEFINE BAREMETALOS_VER 'v0.5.2 (June 29, 2011)', 13, 'Copyright (C) 2008-2011 Return Infinity', 13, 0 +%DEFINE BAREMETALOS_API_VER 1 + +kernel_start: + jmp start ; Skip over the function call index + nop + db 'BAREMETAL' + + align 16 ; 0x0010 + jmp os_print_string ; Jump to function + align 8 + dq os_print_string ; Memory address of function + + align 8 ; 0x0020 + jmp os_print_char + align 8 + dq os_print_char + + align 8 ; 0x0030 + jmp os_print_char_hex + align 8 + dq os_print_char_hex + + align 8 ; 0x0040 + jmp os_print_newline + align 8 + dq os_print_newline + + align 8 ; 0x0050 + jmp os_input_key_check + align 8 + dq os_input_key_check + + align 8 ; 0x0060 + jmp os_input_key_wait + align 8 + dq os_input_key_wait + + align 8 ; 0x0070 + jmp os_input_string + align 8 + dq os_input_string + + align 8 ; 0x0080 + jmp os_delay + align 8 + dq os_delay + + align 8 ; 0x0090 + jmp os_speaker_tone + align 8 + dq os_speaker_tone + + align 8 ; 0x00A0 + jmp os_speaker_off + align 8 + dq os_speaker_off + + align 8 ; 0x00B0 + jmp os_speaker_beep + align 8 + dq os_speaker_beep + + align 8 ; 0x00C0 + jmp os_move_cursor + align 8 + dq os_move_cursor + + align 8 ; 0x00D0 + jmp os_string_length + align 8 + dq os_string_length + + align 8 ; 0x00E0 + jmp os_string_find_char + align 8 + dq os_string_find_char + + align 8 ; 0x00F0 + jmp os_string_copy + align 8 + dq os_string_copy + + align 8 ; 0x0100 + jmp os_string_truncate + align 8 + dq os_string_truncate + + align 8 ; 0x0110 + jmp os_string_join + align 8 + dq os_string_join + + align 8 ; 0x0120 + jmp os_string_chomp + align 8 + dq os_string_chomp + + align 8 ; 0x0130 + jmp os_string_strip + align 8 + dq os_string_strip + + align 8 ; 0x0140 + jmp os_string_compare + align 8 + dq os_string_compare + + align 8 ; 0x0150 + jmp os_string_uppercase + align 8 + dq os_string_uppercase + + align 8 ; 0x0160 + jmp os_string_lowercase + align 8 + dq os_string_lowercase + + align 8 ; 0x0170 + jmp os_int_to_string + align 8 + dq os_int_to_string + + align 8 ; 0x0180 + jmp os_string_to_int + align 8 + dq os_string_to_int + + align 8 ; 0x0190 + jmp os_debug_dump_reg + align 8 + dq os_debug_dump_reg + + align 8 ; 0x01A0 + jmp os_debug_dump_mem + align 8 + dq os_debug_dump_mem + + align 8 ; 0x01B0 + jmp os_debug_dump_rax + align 8 + dq os_debug_dump_rax + + align 8 ; 0x01C0 + jmp os_debug_dump_eax + align 8 + dq os_debug_dump_eax + + align 8 ; 0x01D0 + jmp os_debug_dump_ax + align 8 + dq os_debug_dump_ax + + align 8 ; 0x01E0 + jmp os_debug_dump_al + align 8 + dq os_debug_dump_al + + align 8 ; 0x01F0 + jmp os_smp_reset + align 8 + dq os_smp_reset + + align 8 ; 0x0200 + jmp os_smp_get_id + align 8 + dq os_smp_get_id + + align 8 ; 0x0210 + jmp os_smp_enqueue + align 8 + dq os_smp_enqueue + + align 8 ; 0x0220 + jmp os_smp_dequeue + align 8 + dq os_smp_dequeue + + align 8 ; 0x0230 + jmp os_serial_send + align 8 + dq os_serial_send + + align 8 ; 0x0240 + jmp os_serial_recv + align 8 + dq os_serial_recv + + align 8 ; 0x0250 + jmp os_string_parse + align 8 + dq os_string_parse + + align 8 ; 0x0260 + jmp os_get_argc + align 8 + dq os_get_argc + + align 8 ; 0x0270 + jmp os_get_argv + align 8 + dq os_get_argv + + align 8 ; 0x0280 + jmp os_smp_queuelen + align 8 + dq os_smp_queuelen + + align 8 ; 0x0290 + jmp os_smp_wait + align 8 + dq os_smp_wait + + align 8 ; 0x02A0 + jmp os_get_timecounter + align 8 + dq os_get_timecounter + + align 8 ; 0x02B0 + jmp os_string_append + align 8 + dq os_string_append + + align 8 ; 0x02C0 + jmp os_int_to_hex_string + align 8 + dq os_int_to_hex_string + + align 8 ; 0x02D0 + jmp os_hex_string_to_int + align 8 + dq os_hex_string_to_int + + align 8 ; 0x02E0 + jmp os_string_change_char + align 8 + dq os_string_change_char + + align 8 ; 0x02F0 + jmp os_is_digit + align 8 + dq os_is_digit + + align 8 ; 0x0300 + jmp os_is_alpha + align 8 + dq os_is_alpha + + align 8 ; 0x0310 + jmp os_file_read + align 8 + dq os_file_read + + align 8 ; 0x0320 + jmp os_file_write + align 8 + dq os_file_write + + align 8 ; 0x0330 + jmp os_file_delete + align 8 + dq os_file_delete + + align 8 ; 0x0340 + jmp os_file_get_list + align 8 + dq os_file_get_list + + align 8 ; 0x0350 + jmp os_smp_run + align 8 + dq os_smp_run + + align 8 ; 0x0360 + jmp os_smp_lock + align 8 + dq os_smp_lock + + align 8 ; 0x0370 + jmp os_smp_unlock + align 8 + dq os_smp_unlock + + align 8 ; 0x0380 + jmp os_print_string_with_color + align 8 + dq os_print_string_with_color + + align 8 ; 0x0390 + jmp os_print_char_with_color + align 8 + dq os_print_char_with_color + + align 8 ; 0x03A0 + jmp os_ethernet_tx + align 8 + dq os_ethernet_tx + + align 8 ; 0x03B0 + jmp os_ethernet_rx + align 8 + dq os_ethernet_rx + + align 8 ; 0x03C0 + jmp os_mem_allocate + align 8 + dq os_mem_allocate + + align 8 ; 0x03D0 + jmp os_mem_release + align 8 + dq os_mem_release + + align 8 ; 0x03E0 + jmp os_mem_get_free + align 8 + dq os_mem_get_free + + align 8 ; 0x03F0 + jmp os_smp_numcores + align 8 + dq os_smp_numcores + + align 8 ; 0x0400 + jmp os_file_get_size + align 8 + dq os_file_get_size + + align 8 ; 0x0410 + jmp os_ethernet_avail + align 8 + dq os_ethernet_avail + + align 8 ; 0x0420 + jmp os_print_char_hex_with_color + align 8 + dq os_print_char_hex_with_color + + align 8 ; 0x0430 + jmp os_ethernet_tx_raw + align 8 + dq os_ethernet_tx_raw + + align 8 ; 0x0440 + jmp os_screen_clear + align 8 + dq os_screen_clear + + align 8 ; 0x0450 + jmp os_show_cursor + align 8 + dq os_show_cursor + + align 8 ; 0x0460 + jmp os_hide_cursor + align 8 + dq os_hide_cursor + + align 8 ; 0x0470 + jmp os_show_statusbar + align 8 + dq os_show_statusbar + + align 8 ; 0x0480 + jmp os_hide_statusbar + align 8 + dq os_hide_statusbar + + align 8 ; 0x0490 + jmp os_screen_update + align 8 + dq os_screen_update + + align 8 ; 0x04A0 + jmp os_print_chars + align 8 + dq os_print_chars + + align 8 ; 0x04B0 + jmp os_print_chars_with_color + align 8 + dq os_print_chars_with_color + +align 16 + +start: + + call init_64 ; After this point we are in a working 64-bit enviroment + + call init_pci + + call init_net ; Initialize the network + + call hdd_setup ; Gather information about the harddrive and set it up + + call os_screen_clear ; Clear screen and display cursor + + cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) + jne start_no_network + mov ax, 0x0013 + call os_move_cursor + mov rsi, networkmsg + call os_print_string + call os_debug_dump_MAC +start_no_network: + + mov ax, 0x0016 ; Print the "ready" message + call os_move_cursor + mov rsi, readymsg + call os_print_string + + mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner + call os_move_cursor + call os_show_cursor + + mov rsi, startupapp ; Look for a file called startup.app + mov rdi, programlocation ; We load the program to this location in memory (currently 0x00200000 : at the 2MB mark) + call os_file_read ; Read the file into memory + jc ap_clear ; If carry is set then the file was not found + + xchg bx, bx + mov rax, programlocation ; 0x00200000 : at the 2MB mark + xor rbx, rbx ; No arguements required (The app can get them with os_get_argc and os_get_argv) + call os_smp_enqueue ; Queue the application to run on the next available core + + ; Fall through to ap_clear as align fills the space with No-Ops + ; At this point the BSP is just like one of the AP's + + +align 16 + +ap_clear: ; All cores start here on first startup and after an exception + + cli ; Disable interrupts on this core + + ; Get local ID of the core + mov rsi, [os_LocalAPICAddress] + xor eax, eax ; Clear Task Priority (bits 7:4) and Task Priority Sub-Class (bits 3:0) + mov dword [rsi+0x80], eax ; APIC Task Priority Register (TPR) + mov eax, dword [rsi+0x20] ; APIC ID + shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID + + ; Calculate offset into CPU status table + mov rdi, cpustatus + add rdi, rax ; RDI points to this cores status byte (we will clear it later) + + ; Set up the stack + shl rax, 21 ; Shift left 21 bits for a 2 MiB stack + add rax, [os_StackBase] ; The stack decrements when you "push", start at 2 MiB in + mov rsp, rax + + ; Set the CPU status to "Present" and "Ready" + mov al, 00000001b ; Bit 0 set for "Present", Bit 1 clear for "Ready" + stosb ; Set status to Ready for this CPU + + sti ; Re-enable interrupts on this core + + ; Clear registers. Gives us a clean slate to work with + xor rax, rax ; aka r0 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rbx, rbx ; aka r3 + xor rbp, rbp ; aka r5, We skip RSP (aka r4) as it was previously set + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + +ap_spin: ; Spin until there is a workload in the queue + cmp word [os_QueueLen], 0 ; Check the length of the queue + je ap_halt ; If the queue was empty then jump to the HLT + call os_smp_dequeue ; Try to pull a workload out of the queue + jnc ap_process ; Carry clear if successful, jump to ap_process + +ap_halt: ; Halt until a wakup call is received + hlt ; If carry was set we fall through to the HLT + jmp ap_spin ; Try again + +ap_process: ; Set the status byte to "Busy" and run the code + cli + push rsi + push rax + mov rsi, [os_LocalAPICAddress] + xor eax, eax + mov al, 0x10 + mov dword [rsi+0x80], eax ; APIC Task Priority Register (TPR) + pop rax + pop rsi + sti + + push rdi ; Push RDI since it is used temporarily + push rax ; Push RAX since os_smp_get_id uses it + mov rdi, cpustatus + call os_smp_get_id ; Set RAX to the APIC ID + add rdi, rax + mov al, 00000011b ; Bit 0 set for "Present", Bit 1 set for "Busy" + stosb + pop rax ; Pop RAX (holds the workload code address) + pop rdi ; Pop RDI (holds the variable/variable address) + + mov r15, rax + + call os_get_argc + mov rcx, rax + cmp al, 1 + je noargs + + mov rdi, os_args + sub rcx, 1 + shl rcx, 3 + add rdi, rcx + shr rcx, 3 + add rcx, 1 +nextargv: + sub al, 1 + call os_get_argv + mov [rdi], rsi + sub rdi, 8 + cmp al, 1 + jne nextargv + +noargs: + mov al, 0 + call os_get_argv + mov [os_args], rsi + mov rsi, os_args ; ARGV[0] + + mov rdi, rcx ; ARGC + mov rax, r15 + + call rax ; Run the code + + jmp ap_clear ; Reset the stack, clear the registers, and wait for something else to work on + + +; Includes +%include "init_64.asm" +%include "init_pci.asm" +%include "init_net.asm" +%include "init_hdd.asm" +%include "syscalls.asm" +%include "drivers.asm" +%include "interrupt.asm" +%include "cli.asm" +%include "ipv4.asm" +%include "sysvar.asm" ; Include this last to keep the read/write variables away from the code + +;times 16384-($-$$) db 0 ; Set the compiled kernel binary to at least this size in bytes + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls.asm b/amd64/bareMetalOS-0.5.3/os/syscalls.asm index 2e327f68..4f82d609 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls.asm @@ -1,27 +1,27 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; System Call Section -- Accessible to user programs -; ============================================================================= - -align 16 -db 'DEBUG: SYSCALLS ' -align 16 - - -%include "syscalls/string.asm" -%include "syscalls/screen.asm" -%include "syscalls/input.asm" -%include "syscalls/sound.asm" -%include "syscalls/debug.asm" -%include "syscalls/misc.asm" -%include "syscalls/smp.asm" -%include "syscalls/serial.asm" -%include "syscalls/file.asm" -%include "syscalls/ethernet.asm" -%include "syscalls/memory.asm" - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; System Call Section -- Accessible to user programs +; ============================================================================= + +align 16 +db 'DEBUG: SYSCALLS ' +align 16 + + +%include "syscalls/string.asm" +%include "syscalls/screen.asm" +%include "syscalls/input.asm" +%include "syscalls/sound.asm" +%include "syscalls/debug.asm" +%include "syscalls/misc.asm" +%include "syscalls/smp.asm" +%include "syscalls/serial.asm" +%include "syscalls/file.asm" +%include "syscalls/ethernet.asm" +%include "syscalls/memory.asm" + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/debug.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/debug.asm index 81de8ed3..4d5db4e9 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/debug.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/debug.asm @@ -1,266 +1,266 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Debug functions -; ============================================================================= - -align 16 -db 'DEBUG: DEBUG ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_debug_dump_reg -- Dump the values on the registers to the screen (For debug purposes) -; IN: Nothing -; OUT: Nothing, all registers preserved -os_debug_dump_reg: - pushfq ; Push the registers used by this function - push rsi - push rbx - push rax - - pushfq ; Push the flags to the stack - push r15 ; Push all of the registers to the stack - push r14 - push r13 - push r12 - push r11 - push r10 - push r9 - push r8 - push rsp - push rbp - push rdi - push rsi - push rdx - push rcx - push rbx - push rax - - mov byte [os_debug_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting -os_debug_dump_reg_next: - mov rsi, os_debug_dump_reg_string00 - xor rax, rax - xor rbx, rbx - mov al, [os_debug_dump_reg_stage] - mov bl, 5 ; Each string is 5 bytes - mul bl ; AX = BL x AL - add rsi, rax ; Add the offset to get to the correct string - call os_print_string ; Print the register name - pop rax ; Pop the register from the stack - call os_debug_dump_rax ; Print the hex string value of RAX - inc byte [os_debug_dump_reg_stage] - cmp byte [os_debug_dump_reg_stage], 0x11 ; Check to see if all 16 registers as well as the flags are displayed - jne os_debug_dump_reg_next - - mov rbx, rax ; Store the flags in RBX - - mov rsi, os_debug_dump_flag_string0 ; Print the Carry flag - call os_print_string - bt rbx, 0 - jc carry_1 -carry_0: - mov al, '0' - jmp print_carry -carry_1: - mov al, '1' -print_carry: - call os_print_char - - mov rsi, os_debug_dump_flag_string1 ; Print the Zero flag - call os_print_string - bt rbx, 6 - jc zero_1 -zero_0: - mov al, '0' - jmp print_zero -zero_1: - mov al, '1' -print_zero: - call os_print_char - - mov rsi, os_debug_dump_flag_string2 ; Print the Sign flag - call os_print_string - bt rbx, 7 - jc sign_1 -sign_0: - mov al, '0' - jmp print_sign -sign_1: - mov al, '1' -print_sign: - call os_print_char - - mov rsi, os_debug_dump_flag_string3 ; Print the Direction flag - call os_print_string - bt rbx, 10 - jc dir_1 -dir_0: - mov al, '0' - jmp print_dir -dir_1: - mov al, '1' -print_dir: - call os_print_char - - mov rsi, os_debug_dump_flag_string4 ; Print the Overflow flag - call os_print_string - bt rbx, 11 - jc over_1 -over_0: - mov al, '0' - jmp print_over -over_1: - mov al, '1' -print_over: - call os_print_char - - -os_debug_dump_reg_done: - call os_print_newline - pop rax - pop rbx - pop rsi - popfq - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_dump_mem -- Dump some memory content to the screen -; IN: RSI = Start of memory address to dump -; RCX = number of bytes to dump -; OUT: Nothing, all registers preserved -os_debug_dump_mem: - push rsi - push rcx ; counter - push rdx ; total number of bytes to display - push rbx ; color attribute - push rax - mov bl, 0x07 ; Default of light grey on black - - cmp rcx, 0 - je os_debug_dump_mem_done - mov rdx, rcx ; Save the total number of bytes to display - add rdx, 15 - and rdx, 0xFFFFFFF0 - and rsi, 0xFFFFFFF0 - -os_debug_dump_mem_print_address: - mov rax, rsi - call os_debug_dump_rax - push rsi - mov rsi, divider - call os_print_string - pop rsi - xor rcx, rcx ; Clear the counter - -os_debug_dump_mem_next_byte_hex: - lodsb - call os_print_char_hex_with_color - xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey - add rcx, 1 - cmp rcx, 16 - jne os_debug_dump_mem_next_byte_hex - - push rsi - mov rsi, divider - call os_print_string - pop rsi - sub rsi, 0x10 - xor rcx, rcx ; Clear the counter - -os_debug_dump_mem_next_byte_ascii: - lodsb - call os_print_char_with_color - xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey - add rcx, 1 - cmp rcx, 16 - jne os_debug_dump_mem_next_byte_ascii - - sub rdx, 16 - cmp rdx, 0 - je os_debug_dump_mem_done - call os_print_newline - jmp os_debug_dump_mem_print_address - -os_debug_dump_mem_done: - pop rax - pop rbx - pop rcx - pop rdx - pop rsi - ret - -divider: db ' | ', 0 -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_dump_(rax|eax|ax|al) -- Dump content of RAX, EAX, AX, or AL to the screen in hex format -; IN: RAX = content to dump -; OUT: Nothing, all registers preserved -os_debug_dump_rax: - ror rax, 56 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 32 -os_debug_dump_eax: - ror rax, 24 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 16 -os_debug_dump_ax: - ror rax, 8 - call os_print_char_hex - rol rax, 8 -os_debug_dump_al: - call os_print_char_hex - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_get_ip -- Dump content of RIP into RAX -; IN: Nothing -; OUT: RAX = RIP -os_debug_get_ip: - mov rax, qword [rsp] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_dump_MAC -- Dump MAC address to screen -; IN: Nothing -; OUT: Nothing, all registers preserved -os_debug_dump_MAC: - push rsi - push rcx - push rax - - mov ecx, 6 - mov rsi, os_NetMAC -os_debug_dump_MAC_display: - lodsb - call os_debug_dump_al - sub ecx, 1 - test ecx, ecx - jnz os_debug_dump_MAC_display - - pop rax - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Debug functions +; ============================================================================= + +align 16 +db 'DEBUG: DEBUG ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_debug_dump_reg -- Dump the values on the registers to the screen (For debug purposes) +; IN: Nothing +; OUT: Nothing, all registers preserved +os_debug_dump_reg: + pushfq ; Push the registers used by this function + push rsi + push rbx + push rax + + pushfq ; Push the flags to the stack + push r15 ; Push all of the registers to the stack + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rsp + push rbp + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + + mov byte [os_debug_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting +os_debug_dump_reg_next: + mov rsi, os_debug_dump_reg_string00 + xor rax, rax + xor rbx, rbx + mov al, [os_debug_dump_reg_stage] + mov bl, 5 ; Each string is 5 bytes + mul bl ; AX = BL x AL + add rsi, rax ; Add the offset to get to the correct string + call os_print_string ; Print the register name + pop rax ; Pop the register from the stack + call os_debug_dump_rax ; Print the hex string value of RAX + inc byte [os_debug_dump_reg_stage] + cmp byte [os_debug_dump_reg_stage], 0x11 ; Check to see if all 16 registers as well as the flags are displayed + jne os_debug_dump_reg_next + + mov rbx, rax ; Store the flags in RBX + + mov rsi, os_debug_dump_flag_string0 ; Print the Carry flag + call os_print_string + bt rbx, 0 + jc carry_1 +carry_0: + mov al, '0' + jmp print_carry +carry_1: + mov al, '1' +print_carry: + call os_print_char + + mov rsi, os_debug_dump_flag_string1 ; Print the Zero flag + call os_print_string + bt rbx, 6 + jc zero_1 +zero_0: + mov al, '0' + jmp print_zero +zero_1: + mov al, '1' +print_zero: + call os_print_char + + mov rsi, os_debug_dump_flag_string2 ; Print the Sign flag + call os_print_string + bt rbx, 7 + jc sign_1 +sign_0: + mov al, '0' + jmp print_sign +sign_1: + mov al, '1' +print_sign: + call os_print_char + + mov rsi, os_debug_dump_flag_string3 ; Print the Direction flag + call os_print_string + bt rbx, 10 + jc dir_1 +dir_0: + mov al, '0' + jmp print_dir +dir_1: + mov al, '1' +print_dir: + call os_print_char + + mov rsi, os_debug_dump_flag_string4 ; Print the Overflow flag + call os_print_string + bt rbx, 11 + jc over_1 +over_0: + mov al, '0' + jmp print_over +over_1: + mov al, '1' +print_over: + call os_print_char + + +os_debug_dump_reg_done: + call os_print_newline + pop rax + pop rbx + pop rsi + popfq + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_dump_mem -- Dump some memory content to the screen +; IN: RSI = Start of memory address to dump +; RCX = number of bytes to dump +; OUT: Nothing, all registers preserved +os_debug_dump_mem: + push rsi + push rcx ; counter + push rdx ; total number of bytes to display + push rbx ; color attribute + push rax + mov bl, 0x07 ; Default of light grey on black + + cmp rcx, 0 + je os_debug_dump_mem_done + mov rdx, rcx ; Save the total number of bytes to display + add rdx, 15 + and rdx, 0xFFFFFFF0 + and rsi, 0xFFFFFFF0 + +os_debug_dump_mem_print_address: + mov rax, rsi + call os_debug_dump_rax + push rsi + mov rsi, divider + call os_print_string + pop rsi + xor rcx, rcx ; Clear the counter + +os_debug_dump_mem_next_byte_hex: + lodsb + call os_print_char_hex_with_color + xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey + add rcx, 1 + cmp rcx, 16 + jne os_debug_dump_mem_next_byte_hex + + push rsi + mov rsi, divider + call os_print_string + pop rsi + sub rsi, 0x10 + xor rcx, rcx ; Clear the counter + +os_debug_dump_mem_next_byte_ascii: + lodsb + call os_print_char_with_color + xor bl, 10000000b ; Toggle between light grey on black and light grey on dark grey + add rcx, 1 + cmp rcx, 16 + jne os_debug_dump_mem_next_byte_ascii + + sub rdx, 16 + cmp rdx, 0 + je os_debug_dump_mem_done + call os_print_newline + jmp os_debug_dump_mem_print_address + +os_debug_dump_mem_done: + pop rax + pop rbx + pop rcx + pop rdx + pop rsi + ret + +divider: db ' | ', 0 +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_dump_(rax|eax|ax|al) -- Dump content of RAX, EAX, AX, or AL to the screen in hex format +; IN: RAX = content to dump +; OUT: Nothing, all registers preserved +os_debug_dump_rax: + ror rax, 56 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 32 +os_debug_dump_eax: + ror rax, 24 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 16 +os_debug_dump_ax: + ror rax, 8 + call os_print_char_hex + rol rax, 8 +os_debug_dump_al: + call os_print_char_hex + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_get_ip -- Dump content of RIP into RAX +; IN: Nothing +; OUT: RAX = RIP +os_debug_get_ip: + mov rax, qword [rsp] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_dump_MAC -- Dump MAC address to screen +; IN: Nothing +; OUT: Nothing, all registers preserved +os_debug_dump_MAC: + push rsi + push rcx + push rax + + mov ecx, 6 + mov rsi, os_NetMAC +os_debug_dump_MAC_display: + lodsb + call os_debug_dump_al + sub ecx, 1 + test ecx, ecx + jnz os_debug_dump_MAC_display + + pop rax + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/ethernet.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/ethernet.asm index 96474bb3..310a749a 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/ethernet.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/ethernet.asm @@ -1,294 +1,294 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Ethernet Functions -; ============================================================================= - -align 16 -db 'DEBUG: ETHERNET ' -align 16 - - -; Ethernet Type II Frame (64 - 1518 bytes) -; MAC Header (14 bytes) -; Destination MAC Address (6 bytes) -; Source MAC Address (6 bytes) -; EtherType/Length (2 bytes) -; Payload (46 - 1500 bytes) -; CRC (4 bytes) -; Network card handles the Preamble (7 bytes), Start-of-Frame-Delimiter (1 byte), and Interframe Gap (12 bytes) - - -; ----------------------------------------------------------------------------- -; os_ethernet_avail -- Check if Ethernet is available -; IN: Nothing -; OUT: RAX = MAC Address if Ethernet is enabled, otherwise 0 -os_ethernet_avail: - push rsi - push rcx - - cld - xor eax, eax - cmp byte [os_NetEnabled], 0 - je os_ethernet_avail_end - - mov ecx, 6 - mov rsi, os_NetMAC -os_ethernet_avail_loadMAC: - shl rax, 8 - lodsb - sub ecx, 1 - test ecx, ecx - jnz os_ethernet_avail_loadMAC - -os_ethernet_avail_end: - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_tx -- Transmit a packet via Ethernet -; IN: RSI = Memory location where data is stored -; RDI = Pointer to 48 bit destination address -; BX = Type of packet (If set to 0 then the EtherType will be set to the length of data) -; CX = Length of data -; OUT: Nothing. All registers preserved -os_ethernet_tx: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - cmp byte [os_NetEnabled], 1 - jne os_ethernet_tx_fail - cmp cx, 1500 ; Fail if more then 1500 bytes - jg os_ethernet_tx_fail - - mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time - call os_smp_lock - - push rsi - mov rsi, rdi - mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location - ; TODO: Ask the driver where in memory the packet should be assembled. - - ; Copy destination MAC address - movsd - movsw - - ; Copy source MAC address - mov rsi, os_NetMAC - movsd - movsw - - ; Set the EtherType/Length - cmp bx, 0 - jne os_ethernet_tx_typeset ; If EtherType is not set then use the Data Length instead - mov bx, cx ; Length of data (Does not include header) -os_ethernet_tx_typeset: - xchg bl, bh ; x86 is Little-endian but packets use Big-endian - mov [rdi], bx - add rdi, 2 - - ; Copy the packet data - pop rsi - mov rax, 0x000000000000FFFF - and rcx, rax ; Clear the top 48 bits - push rcx - rep movsb - pop rcx - - ; Add padding to the packet data if needed - cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) - jge os_ethernet_tx_nopadding - mov ax, 46 - sub ax, cx ; Padding needed = 46 - CX - mov cx, ax - xor ax, ax - rep stosb ; Store 0x00 CX times - mov cx, 46 -os_ethernet_tx_nopadding: - - xor eax, eax - stosd ; Store a blank CRC value - -; Call the send function of the ethernet card driver - add cx, 14 ; Add 14 for the header bytes - mov rsi, os_ethernet_tx_buffer - call qword [os_net_transmit] - - mov rax, os_EthernetBusyLock - call os_smp_unlock - -os_ethernet_tx_fail: - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_tx_raw -- Transmit a raw frame via Ethernet -; IN: RSI = Memory location where raw frame is stored -; CX = Length of frame -; OUT: Nothing. All registers preserved -os_ethernet_tx_raw: - push rsi - push rdi - push rdx - push rcx - push rbx - push rax - - cmp byte [os_NetEnabled], 1 - jne os_ethernet_tx_raw_fail - cmp cx, 1500 ; Fail if more then 1500 bytes - jg os_ethernet_tx_raw_fail - - mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time - call os_smp_lock - - ; Copy the packet data - mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location - mov rax, 0x000000000000FFFF - and rcx, rax ; Clear the top 48 bits - push rcx - rep movsb - pop rcx - - ; Add padding to the packet data if needed - cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) - jge os_ethernet_tx_raw_nopadding - mov ax, 46 - sub ax, cx ; Padding needed = 46 - CX - mov cx, ax - xor ax, ax - rep stosb ; Store 0x00 CX times - mov cx, 46 -os_ethernet_tx_raw_nopadding: - - xor eax, eax - stosd ; Store a blank CRC value - -; Call the send function of the ethernet card driver - mov rsi, os_ethernet_tx_buffer - call qword [os_net_transmit] - - mov rax, os_EthernetBusyLock - call os_smp_unlock - -os_ethernet_tx_raw_fail: - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_rx -- Polls the Ethernet card for received data -; IN: RDI = Memory location where packet will be stored -; OUT: RCX = Length of packet -; All other registers preserved -os_ethernet_rx: - push rdi - push rsi - push rdx - push rax - - xor ecx, ecx - - cmp byte [os_NetEnabled], 1 - jne os_ethernet_rx_fail - -; Is there anything in the ring buffer? - mov al, byte [os_EthernetBuffer_C1] - mov dl, byte [os_EthernetBuffer_C2] - cmp al, dl ; If both counters are equal then the buffer is empty - je os_ethernet_rx_fail - -; Read the packet from the ring buffer to RDI - mov rsi, os_EthernetBuffer - xor rax, rax - mov al, byte [os_EthernetBuffer_C1] - push rax ; Save the ring element value - shl rax, 11 ; Quickly multiply RAX by 2048 - add rsi, rax ; RSI points to the packet in the ring buffer - lodsw ; Load the packet length - mov cx, ax ; Copy the packet length to RCX - push rcx - rep movsb ; Copy the packet to RDI - pop rcx - pop rax ; Restore the ring element value - add al, 1 - cmp al, 128 ; Max element number is 127 - jne os_ethernet_rx_buffer_nowrap - xor al, al -os_ethernet_rx_buffer_nowrap: - mov byte [os_EthernetBuffer_C1], al - -os_ethernet_rx_fail: - - pop rax - pop rdx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_ack_int -- Acknowledge an interrupt within the NIC -; IN: Nothing -; OUT: RAX = Type of interrupt trigger -; All other registers preserved -os_ethernet_ack_int: - push rdx - - call qword [os_net_ack_int] - - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_ethernet_rx_from_interrupt -- Polls the Ethernet card for received data -; IN: RDI = Memory location where packet will be stored -; OUT: RCX = Length of packet -; All other registers preserved -os_ethernet_rx_from_interrupt: - push rdi - push rsi - push rdx - push rax - - xor ecx, ecx - -; Call the poll function of the ethernet card driver - call qword [os_net_poll] - - pop rax - pop rdx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Ethernet Functions +; ============================================================================= + +align 16 +db 'DEBUG: ETHERNET ' +align 16 + + +; Ethernet Type II Frame (64 - 1518 bytes) +; MAC Header (14 bytes) +; Destination MAC Address (6 bytes) +; Source MAC Address (6 bytes) +; EtherType/Length (2 bytes) +; Payload (46 - 1500 bytes) +; CRC (4 bytes) +; Network card handles the Preamble (7 bytes), Start-of-Frame-Delimiter (1 byte), and Interframe Gap (12 bytes) + + +; ----------------------------------------------------------------------------- +; os_ethernet_avail -- Check if Ethernet is available +; IN: Nothing +; OUT: RAX = MAC Address if Ethernet is enabled, otherwise 0 +os_ethernet_avail: + push rsi + push rcx + + cld + xor eax, eax + cmp byte [os_NetEnabled], 0 + je os_ethernet_avail_end + + mov ecx, 6 + mov rsi, os_NetMAC +os_ethernet_avail_loadMAC: + shl rax, 8 + lodsb + sub ecx, 1 + test ecx, ecx + jnz os_ethernet_avail_loadMAC + +os_ethernet_avail_end: + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_tx -- Transmit a packet via Ethernet +; IN: RSI = Memory location where data is stored +; RDI = Pointer to 48 bit destination address +; BX = Type of packet (If set to 0 then the EtherType will be set to the length of data) +; CX = Length of data +; OUT: Nothing. All registers preserved +os_ethernet_tx: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + cmp byte [os_NetEnabled], 1 + jne os_ethernet_tx_fail + cmp cx, 1500 ; Fail if more then 1500 bytes + jg os_ethernet_tx_fail + + mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time + call os_smp_lock + + push rsi + mov rsi, rdi + mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location + ; TODO: Ask the driver where in memory the packet should be assembled. + + ; Copy destination MAC address + movsd + movsw + + ; Copy source MAC address + mov rsi, os_NetMAC + movsd + movsw + + ; Set the EtherType/Length + cmp bx, 0 + jne os_ethernet_tx_typeset ; If EtherType is not set then use the Data Length instead + mov bx, cx ; Length of data (Does not include header) +os_ethernet_tx_typeset: + xchg bl, bh ; x86 is Little-endian but packets use Big-endian + mov [rdi], bx + add rdi, 2 + + ; Copy the packet data + pop rsi + mov rax, 0x000000000000FFFF + and rcx, rax ; Clear the top 48 bits + push rcx + rep movsb + pop rcx + + ; Add padding to the packet data if needed + cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) + jge os_ethernet_tx_nopadding + mov ax, 46 + sub ax, cx ; Padding needed = 46 - CX + mov cx, ax + xor ax, ax + rep stosb ; Store 0x00 CX times + mov cx, 46 +os_ethernet_tx_nopadding: + + xor eax, eax + stosd ; Store a blank CRC value + +; Call the send function of the ethernet card driver + add cx, 14 ; Add 14 for the header bytes + mov rsi, os_ethernet_tx_buffer + call qword [os_net_transmit] + + mov rax, os_EthernetBusyLock + call os_smp_unlock + +os_ethernet_tx_fail: + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_tx_raw -- Transmit a raw frame via Ethernet +; IN: RSI = Memory location where raw frame is stored +; CX = Length of frame +; OUT: Nothing. All registers preserved +os_ethernet_tx_raw: + push rsi + push rdi + push rdx + push rcx + push rbx + push rax + + cmp byte [os_NetEnabled], 1 + jne os_ethernet_tx_raw_fail + cmp cx, 1500 ; Fail if more then 1500 bytes + jg os_ethernet_tx_raw_fail + + mov rax, os_EthernetBusyLock ; Lock the Ethernet so only one send can happen at a time + call os_smp_lock + + ; Copy the packet data + mov rdi, os_ethernet_tx_buffer ; Build the packet to transfer at this location + mov rax, 0x000000000000FFFF + and rcx, rax ; Clear the top 48 bits + push rcx + rep movsb + pop rcx + + ; Add padding to the packet data if needed + cmp cx, 46 ; Data needs to be at least 46 bytes (if not it needs to be padded) + jge os_ethernet_tx_raw_nopadding + mov ax, 46 + sub ax, cx ; Padding needed = 46 - CX + mov cx, ax + xor ax, ax + rep stosb ; Store 0x00 CX times + mov cx, 46 +os_ethernet_tx_raw_nopadding: + + xor eax, eax + stosd ; Store a blank CRC value + +; Call the send function of the ethernet card driver + mov rsi, os_ethernet_tx_buffer + call qword [os_net_transmit] + + mov rax, os_EthernetBusyLock + call os_smp_unlock + +os_ethernet_tx_raw_fail: + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_rx -- Polls the Ethernet card for received data +; IN: RDI = Memory location where packet will be stored +; OUT: RCX = Length of packet +; All other registers preserved +os_ethernet_rx: + push rdi + push rsi + push rdx + push rax + + xor ecx, ecx + + cmp byte [os_NetEnabled], 1 + jne os_ethernet_rx_fail + +; Is there anything in the ring buffer? + mov al, byte [os_EthernetBuffer_C1] + mov dl, byte [os_EthernetBuffer_C2] + cmp al, dl ; If both counters are equal then the buffer is empty + je os_ethernet_rx_fail + +; Read the packet from the ring buffer to RDI + mov rsi, os_EthernetBuffer + xor rax, rax + mov al, byte [os_EthernetBuffer_C1] + push rax ; Save the ring element value + shl rax, 11 ; Quickly multiply RAX by 2048 + add rsi, rax ; RSI points to the packet in the ring buffer + lodsw ; Load the packet length + mov cx, ax ; Copy the packet length to RCX + push rcx + rep movsb ; Copy the packet to RDI + pop rcx + pop rax ; Restore the ring element value + add al, 1 + cmp al, 128 ; Max element number is 127 + jne os_ethernet_rx_buffer_nowrap + xor al, al +os_ethernet_rx_buffer_nowrap: + mov byte [os_EthernetBuffer_C1], al + +os_ethernet_rx_fail: + + pop rax + pop rdx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_ack_int -- Acknowledge an interrupt within the NIC +; IN: Nothing +; OUT: RAX = Type of interrupt trigger +; All other registers preserved +os_ethernet_ack_int: + push rdx + + call qword [os_net_ack_int] + + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_ethernet_rx_from_interrupt -- Polls the Ethernet card for received data +; IN: RDI = Memory location where packet will be stored +; OUT: RCX = Length of packet +; All other registers preserved +os_ethernet_rx_from_interrupt: + push rdi + push rsi + push rdx + push rax + + xor ecx, ecx + +; Call the poll function of the ethernet card driver + call qword [os_net_poll] + + pop rax + pop rdx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/file.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/file.asm index dfaccd75..94a2afb0 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/file.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/file.asm @@ -1,86 +1,86 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; File System Functions -; ============================================================================= - -align 16 -db 'DEBUG: FILESYS ' -align 16 - - -; This source acts as an abstraction layer between the OS and an actual File -; System driver. A check can go here to detect the actual FS used and call the -; appropriate FS driver. -; -; Example: -; os_file_read: -; cmp [os_FS], 1 ; FAT16 -; je os_fat16_file_read -; cmp [os_FS], 2 ; FAT32 -; je os_fat32_file_read -; etc... - - -; ----------------------------------------------------------------------------- -; os_file_read -- Read a file from disk into memory -; IN: RSI = Address of filename string -; RDI = Memory location where file will be loaded to -; OUT: Carry is set if the file was not found or an error occured -os_file_read: - jmp os_fat16_file_read -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_write -- Write a file from memory to disk -; IN: RSI = Memory location of data to be written -; RDI = Address of filename string -; RCX = Number of bytes to write -; OUT: Carry is set if an error occured -os_file_write: - jmp os_fat16_file_write -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_rename -- Rename a file on disk -; IN: RSI = Memory location of file name to change -; RDI = Memory location of new file name -; OUT: Carry is set if the file was not found or an error occured -os_file_rename: - jmp $ -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_delete -- Delete a file from disk -; IN: RSI = Memory location of file name to delete -; OUT: Carry is set if the file was not found or an error occured -os_file_delete: - jmp os_fat16_file_delete -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_get_list -- Generate a list of files on disk -; IN: RDI = location to store list -; OUT: RDI = pointer to end of list -os_file_get_list: - jmp os_fat16_get_file_list -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_file_size -- Return the size of a file on disk -; IN: RSI = Address of filename string -; OUT: RCX = Size in bytes -; Carry is set if the file was not found or an error occured -os_file_get_size: - jmp os_fat16_get_file_size -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; File System Functions +; ============================================================================= + +align 16 +db 'DEBUG: FILESYS ' +align 16 + + +; This source acts as an abstraction layer between the OS and an actual File +; System driver. A check can go here to detect the actual FS used and call the +; appropriate FS driver. +; +; Example: +; os_file_read: +; cmp [os_FS], 1 ; FAT16 +; je os_fat16_file_read +; cmp [os_FS], 2 ; FAT32 +; je os_fat32_file_read +; etc... + + +; ----------------------------------------------------------------------------- +; os_file_read -- Read a file from disk into memory +; IN: RSI = Address of filename string +; RDI = Memory location where file will be loaded to +; OUT: Carry is set if the file was not found or an error occured +os_file_read: + jmp os_fat16_file_read +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_write -- Write a file from memory to disk +; IN: RSI = Memory location of data to be written +; RDI = Address of filename string +; RCX = Number of bytes to write +; OUT: Carry is set if an error occured +os_file_write: + jmp os_fat16_file_write +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_rename -- Rename a file on disk +; IN: RSI = Memory location of file name to change +; RDI = Memory location of new file name +; OUT: Carry is set if the file was not found or an error occured +os_file_rename: + jmp $ +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_delete -- Delete a file from disk +; IN: RSI = Memory location of file name to delete +; OUT: Carry is set if the file was not found or an error occured +os_file_delete: + jmp os_fat16_file_delete +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_get_list -- Generate a list of files on disk +; IN: RDI = location to store list +; OUT: RDI = pointer to end of list +os_file_get_list: + jmp os_fat16_get_file_list +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_file_size -- Return the size of a file on disk +; IN: RSI = Address of filename string +; OUT: RCX = Size in bytes +; Carry is set if the file was not found or an error occured +os_file_get_size: + jmp os_fat16_get_file_size +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/input.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/input.asm index d2d59f5a..7fe0c191 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/input.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/input.asm @@ -1,107 +1,107 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Input Functions -; ============================================================================= - -align 16 -db 'DEBUG: INPUT ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_input_key_check -- Scans keyboard for input, but doesn't wait -; IN: Nothing -; OUT: AL = 0 if no key pressed, otherwise ASCII code, other regs preserved -; Carry flag is set if there was a keystoke, clear if there was not -; All other registers preserved -os_input_key_check: - mov al, [key] - cmp al, 0 - je os_input_key_check_no_key - mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now - stc ; set the carry flag - ret - -os_input_key_check_no_key: - xor al, al ; mov al, 0x00 - clc ; clear the carry flag - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_input_key_wait -- Waits for keypress and returns key -; IN: Nothing -; OUT: AL = key pressed -; All other registers preserved -os_input_key_wait: - mov al, [key] - cmp al, 0 - je os_input_key_wait - mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_input_string -- Take string from keyboard entry -; IN: RDI = location where string will be stored -; RCX = number of characters to accept -; OUT: RCX = length of string that was inputed (NULL not counted) -; All other registers preserved -os_input_string: - push rdi - push rdx ; Counter to keep track of max accepted characters - push rax - - mov rdx, rcx - xor rcx, rcx -os_input_string_more: - call os_input_key_check - jnc os_input_string_halt ; No key entered... halt until an interrupt is received - cmp al, 0x1C ; If Enter key pressed, finish - je os_input_string_done - cmp al, 0x0E ; Backspace - je os_input_string_backspace - cmp al, 32 ; In ASCII range (32 - 126)? - jl os_input_string_more - cmp al, 126 - jg os_input_string_more - cmp rcx, rdx ; Check if we have reached the max number of chars - je os_input_string_more ; Jump if we have (should beep as well) - stosb ; Store AL at RDI and increment RDI by 1 - inc rcx ; Increment the couter - call os_print_char ; Display char - jmp os_input_string_more - -os_input_string_backspace: - cmp rcx, 0 ; backspace at the beginning? get a new char - je os_input_string_more - call os_dec_cursor ; Decrement the cursor - mov al, 0x20 ; 0x20 is the character for a space - call os_print_char ; Write over the last typed character with the space - call os_dec_cursor ; Decremnt the cursor again - dec rdi ; go back one in the string - mov byte [rdi], 0x00 ; NULL out the char - dec rcx ; decrement the counter by one - jmp os_input_string_more - -os_input_string_halt: - hlt ; Halt until another keystroke is received - jmp os_input_string_more - -os_input_string_done: - mov al, 0x00 - stosb ; We NULL terminate the string - - pop rax - pop rdx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Input Functions +; ============================================================================= + +align 16 +db 'DEBUG: INPUT ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_input_key_check -- Scans keyboard for input, but doesn't wait +; IN: Nothing +; OUT: AL = 0 if no key pressed, otherwise ASCII code, other regs preserved +; Carry flag is set if there was a keystoke, clear if there was not +; All other registers preserved +os_input_key_check: + mov al, [key] + cmp al, 0 + je os_input_key_check_no_key + mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now + stc ; set the carry flag + ret + +os_input_key_check_no_key: + xor al, al ; mov al, 0x00 + clc ; clear the carry flag + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_input_key_wait -- Waits for keypress and returns key +; IN: Nothing +; OUT: AL = key pressed +; All other registers preserved +os_input_key_wait: + mov al, [key] + cmp al, 0 + je os_input_key_wait + mov byte [key], 0x00 ; clear the variable as the keystroke is in AL now + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_input_string -- Take string from keyboard entry +; IN: RDI = location where string will be stored +; RCX = number of characters to accept +; OUT: RCX = length of string that was inputed (NULL not counted) +; All other registers preserved +os_input_string: + push rdi + push rdx ; Counter to keep track of max accepted characters + push rax + + mov rdx, rcx + xor rcx, rcx +os_input_string_more: + call os_input_key_check + jnc os_input_string_halt ; No key entered... halt until an interrupt is received + cmp al, 0x1C ; If Enter key pressed, finish + je os_input_string_done + cmp al, 0x0E ; Backspace + je os_input_string_backspace + cmp al, 32 ; In ASCII range (32 - 126)? + jl os_input_string_more + cmp al, 126 + jg os_input_string_more + cmp rcx, rdx ; Check if we have reached the max number of chars + je os_input_string_more ; Jump if we have (should beep as well) + stosb ; Store AL at RDI and increment RDI by 1 + inc rcx ; Increment the couter + call os_print_char ; Display char + jmp os_input_string_more + +os_input_string_backspace: + cmp rcx, 0 ; backspace at the beginning? get a new char + je os_input_string_more + call os_dec_cursor ; Decrement the cursor + mov al, 0x20 ; 0x20 is the character for a space + call os_print_char ; Write over the last typed character with the space + call os_dec_cursor ; Decremnt the cursor again + dec rdi ; go back one in the string + mov byte [rdi], 0x00 ; NULL out the char + dec rcx ; decrement the counter by one + jmp os_input_string_more + +os_input_string_halt: + hlt ; Halt until another keystroke is received + jmp os_input_string_more + +os_input_string_done: + mov al, 0x00 + stosb ; We NULL terminate the string + + pop rax + pop rdx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/math.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/math.asm index b63f50f6..906d7258 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/math.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/math.asm @@ -1,26 +1,26 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Math Functions -; ============================================================================= - -align 16 -db 'DEBUG: MATH ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_oword_add -- Add two 128-bit integer together -; IN: RDX,RAX = Integer 1, RCX,RBX = Integer 2 -; OUT: RDX,RAX = Result -; Note: Carry set if overflow -os_oword_add: - add rax, rbx - adc rdx, rcx - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Math Functions +; ============================================================================= + +align 16 +db 'DEBUG: MATH ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_oword_add -- Add two 128-bit integer together +; IN: RDX,RAX = Integer 1, RCX,RBX = Integer 2 +; OUT: RDX,RAX = Result +; Note: Carry set if overflow +os_oword_add: + add rax, rbx + adc rdx, rcx + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/memory.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/memory.asm index 0605d55a..a3b57903 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/memory.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/memory.asm @@ -1,142 +1,142 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Memory functions -; ============================================================================= - -align 16 -db 'DEBUG: MEMORY ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_mem_allocate -- Allocates the requested number of 2 MiB pages -; IN: RCX = Number of pages to allocate -; OUT: RAX = Starting address -; RCX = Number of pages allocated (Set to the value asked for or 0 on failure) -; This function will only allocate continous pages -os_mem_allocate: - push rdi - push rsi - push rdx - push rbx - - cmp rcx, 0 - je os_mem_allocate_fail ; At least 1 page must be allocated - xor rax, rax - mov rsi, os_MemoryMap - mov ax, word [os_MemAmount] - shr ax, 1 ; Divide actual memory by 2 - add rsi, rax ; RSI now points to the last page - sub rsi, 1 - std ; Set direction flag to backward - -os_mem_allocate_start: ; Find a free page of memory - lodsb - cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no free pages - je os_mem_allocate_fail - cmp al, 1 ; If the byte is one then we found a free memory page - jne os_mem_allocate_start - mov rbx, rcx ; RBX is our temporary counter - sub rbx, 1 ; One free page was already found - cmp rbx, 0 ; Was only one page requested? - je os_mem_allocate_mark - -os_mem_allocate_nextpage: - lodsb - cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no more free pages - je os_mem_allocate_fail - cmp al, 1 - jne os_mem_allocate_start - sub rbx, 1 - cmp rbx, 0 - jne os_mem_allocate_nextpage - -os_mem_allocate_mark: - ; We have a suitable free series of pages. Allocate them. - cld ; Set direction flag to forward - mov rdi, rsi - add rdi, 1 - mov rdx, rdi ; RDX points to the starting page - mov al, 2 - push rcx - rep stosb - pop rcx - sub rdx, os_MemoryMap ; RDX now contains the memory page number - shl rdx, 21 ; Quick multiply by 2097152 (2 MiB) to get the starting memory address - mov rax, rdx ; Return the starting address in RAX - jmp os_mem_allocate_end - -os_mem_allocate_fail: - cld ; Set direction flag to forward - xor rcx, rcx ; Failure so set RCX to 0 (No pages allocated) - xor rax, rax - -os_mem_allocate_end: - pop rbx - pop rdx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_mem_release -- Frees the requested number of 2 MiB pages -; IN: RAX = Starting address -; RCX = Number of pages to free -; OUT: RCX = Number of pages freed -os_mem_release: - push rdi - push rcx - push rax - - shr rax, 21 ; Quick divide by 2097152 (2 MiB) to get the starting page number - add rax, os_MemoryMap - mov rdi, rax - mov al, 1 - rep stosb - - pop rax - pop rcx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_mem_get_free -- Returns the number of 2 MiB pages that are available -; IN: Nothing -; OUT: RCX = Number of free 2 MiB pages -os_mem_get_free: - push rsi - push rbx - push rax - - mov rsi, os_MemoryMap - xor rcx, rcx - xor rbx, rbx - -os_mem_get_free_next: - lodsb - add rcx, 1 - cmp rcx, 65536 - je os_mem_get_free_end - cmp al, 1 - jne os_mem_get_free_next - add rbx, 1 - jmp os_mem_get_free_next - -os_mem_get_free_end: - mov rcx, rbx - - pop rax - pop rbx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Memory functions +; ============================================================================= + +align 16 +db 'DEBUG: MEMORY ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_mem_allocate -- Allocates the requested number of 2 MiB pages +; IN: RCX = Number of pages to allocate +; OUT: RAX = Starting address +; RCX = Number of pages allocated (Set to the value asked for or 0 on failure) +; This function will only allocate continous pages +os_mem_allocate: + push rdi + push rsi + push rdx + push rbx + + cmp rcx, 0 + je os_mem_allocate_fail ; At least 1 page must be allocated + xor rax, rax + mov rsi, os_MemoryMap + mov ax, word [os_MemAmount] + shr ax, 1 ; Divide actual memory by 2 + add rsi, rax ; RSI now points to the last page + sub rsi, 1 + std ; Set direction flag to backward + +os_mem_allocate_start: ; Find a free page of memory + lodsb + cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no free pages + je os_mem_allocate_fail + cmp al, 1 ; If the byte is one then we found a free memory page + jne os_mem_allocate_start + mov rbx, rcx ; RBX is our temporary counter + sub rbx, 1 ; One free page was already found + cmp rbx, 0 ; Was only one page requested? + je os_mem_allocate_mark + +os_mem_allocate_nextpage: + lodsb + cmp rsi, os_MemoryMap ; We have hit the start of the memory map, no more free pages + je os_mem_allocate_fail + cmp al, 1 + jne os_mem_allocate_start + sub rbx, 1 + cmp rbx, 0 + jne os_mem_allocate_nextpage + +os_mem_allocate_mark: + ; We have a suitable free series of pages. Allocate them. + cld ; Set direction flag to forward + mov rdi, rsi + add rdi, 1 + mov rdx, rdi ; RDX points to the starting page + mov al, 2 + push rcx + rep stosb + pop rcx + sub rdx, os_MemoryMap ; RDX now contains the memory page number + shl rdx, 21 ; Quick multiply by 2097152 (2 MiB) to get the starting memory address + mov rax, rdx ; Return the starting address in RAX + jmp os_mem_allocate_end + +os_mem_allocate_fail: + cld ; Set direction flag to forward + xor rcx, rcx ; Failure so set RCX to 0 (No pages allocated) + xor rax, rax + +os_mem_allocate_end: + pop rbx + pop rdx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_mem_release -- Frees the requested number of 2 MiB pages +; IN: RAX = Starting address +; RCX = Number of pages to free +; OUT: RCX = Number of pages freed +os_mem_release: + push rdi + push rcx + push rax + + shr rax, 21 ; Quick divide by 2097152 (2 MiB) to get the starting page number + add rax, os_MemoryMap + mov rdi, rax + mov al, 1 + rep stosb + + pop rax + pop rcx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_mem_get_free -- Returns the number of 2 MiB pages that are available +; IN: Nothing +; OUT: RCX = Number of free 2 MiB pages +os_mem_get_free: + push rsi + push rbx + push rax + + mov rsi, os_MemoryMap + xor rcx, rcx + xor rbx, rbx + +os_mem_get_free_next: + lodsb + add rcx, 1 + cmp rcx, 65536 + je os_mem_get_free_end + cmp al, 1 + jne os_mem_get_free_next + add rbx, 1 + jmp os_mem_get_free_next + +os_mem_get_free_end: + mov rcx, rbx + + pop rax + pop rbx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/misc.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/misc.asm index 5a4721ed..2909b6d9 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/misc.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/misc.asm @@ -1,429 +1,429 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Misc Functions -; ============================================================================= - -align 16 -db 'DEBUG: MISC ' -align 16 - - -; ----------------------------------------------------------------------------- -; Display Core activity with flashing blocks on screen -; Blocks flash every quarter of a second -system_status: - push rsi - push rdi - push rdx - push rcx - push rax - - ; Display the dark grey bar - mov ax, 0x8720 ; 0x87 for dark grey background/white foreground, 0x20 for space (blank) character - mov rdi, os_screen ;0x00000000000B8000 - mov rcx, 80 - rep stosw - - ; Display CPU status - mov rdi, os_screen ; 0x00000000000B8000 - mov al, '[' - stosb - add rdi, 1 ; Skip the attribute byte - mov ax, 0x8F63 ; 'c' - stosw - mov ax, 0x8F70 ; 'p' - stosw - mov ax, 0x8F75 ; 'u' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 ; Skip to the next char - - xor ecx, ecx - mov rsi, cpustatus -system_status_cpu_next: - cmp cx, 256 - je system_status_cpu_done - add rcx, 1 - lodsb - bt ax, 0 ; Check to see if the Core is Present - jnc system_status_cpu_next ; If not then check the next - ror ax, 8 ; Exchange AL and AH - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - rol ax, 8 ; Exchange AL and AH - bt ax, 1 ; Check to see if the Core is Ready or Busy - jc system_status_cpu_busy ; Jump if it is Busy.. otherwise fall through for Idle - mov al, 0x80 ; Black on Dark Gray (Idle Core) - jmp system_status_cpu_color - -system_status_cpu_busy: - mov rax, [os_ClockCounter] - bt rax, 0 ; Check bit 0. Store bit 0 in CF - jc system_status_cpu_flash_hi - mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) - jmp system_status_cpu_color -system_status_cpu_flash_hi: - mov al, 0x8F ; White on Dark Gray (Active Core High) -system_status_cpu_color: - stosb ; Store the color (attribute) byte - jmp system_status_cpu_next ; Check the next Core - -system_status_cpu_done: - mov al, ']' - stosb - add rdi, 1 - - ; Display memory status - add rdi, 4 - mov al, '[' - stosb - add rdi, 1 ; Skip the attribute byte - mov ax, 0x8F6D ; 'm' - stosw - mov ax, 0x8F65 ; 'e' - stosw - mov ax, 0x8F6D ; 'm' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 ; Skip to the next char - - call os_mem_get_free ; Store number of free 2 MiB pages in RCX - xor rax, rax - mov ax, word [os_MemAmount] - shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) - push rax - sub rax, rcx ; RAX holds inuse pages (ex 6) - pop rcx ; RCX holds total pages (ex 512) - shr rcx, 3 ; Quickly divide RCX by 8, RCX now holds pages/block (ex 64) - xor rdx, rdx - div rcx ; Divide inuse pages by pages/block - mov rcx, rax - mov ax, 8 - cmp cx, 0 - jne notzero - add cx, 1 -notzero: - sub ax, cx - push rax - -system_status_mem_used: - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x8F ; Light Gray on Blue - stosb ; Put the block character on the screen - sub rcx, 1 - jrcxz system_status_mem_used_finish - jmp system_status_mem_used - -system_status_mem_used_finish: - - pop rcx -system_status_mem_free: - jrcxz system_status_mem_finish - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x80 ; Light Gray on Blue - stosb ; Put the block character on the screen - sub rcx, 1 - jrcxz system_status_mem_finish - jmp system_status_mem_free - -system_status_mem_finish: - mov al, ']' - stosb - add rdi, 1 - - ; Display network status - cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) - jne system_status_no_network - add rdi, 4 - mov al, '[' - stosb - add rdi, 1 - mov ax, 0x8F6E ; 'n' - stosw - mov ax, 0x8F65 ; 'e' - stosw - mov ax, 0x8F74 ; 't' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 - mov al, 'T' - stosb - add rdi, 1 - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x80 ; Black on Dark Gray (No Activity) - cmp byte [os_NetActivity_TX], 1 - jne tx_idle - mov al, 0x8F - mov byte [os_NetActivity_TX], 0 -tx_idle: - stosb - mov al, 'R' - stosb - add rdi, 1 - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov al, 0x80 ; Black on Dark Gray (No Activity) - cmp byte [os_NetActivity_RX], 1 - jne rx_idle - mov al, 0x8F - mov byte [os_NetActivity_RX], 0 -rx_idle: - stosb - mov al, ']' - stosb - add rdi, 1 -system_status_no_network: - - ; Display the RTC pulse - add rdi, 4 - mov al, '[' - stosb - add rdi, 1 - mov ax, 0x8F72 ; 'r' - stosw - mov ax, 0x8F74 ; 't' - stosw - mov ax, 0x8F63 ; 'c' - stosw - mov ax, 0x8F3A ; ':' - stosw - add rdi, 2 - mov al, 0xFE ; Ascii block character - stosb ; Put the block character on the screen - mov rax, [os_ClockCounter] - bt rax, 0 ; Check bit 0. Store bit 0 in CF - jc system_status_rtc_flash_hi - mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) - jmp system_status_rtc_flash_lo -system_status_rtc_flash_hi: - mov al, 0x8F ; White on Dark Gray (Active Core High) -system_status_rtc_flash_lo: - stosb ; Store the color (attribute) byte - mov al, ']' - stosb - add rdi, 1 - - ; Display header text - mov rdi, os_screen ;0x00000000000B8080 - add rdi, 0x80 - mov rsi, system_status_header - mov rcx, 16 -headernext: - lodsb - stosb - inc rdi - dec rcx - cmp rcx, 0 - jne headernext - - ; Copy the system status to the screen - mov rsi, os_screen - mov rdi, 0xB8000 - mov rcx, 80 - rep movsw - - pop rax - pop rcx - pop rdx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_delay -- Delay by X eights of a second -; IN: RAX = Time in eights of a second -; OUT: All registers preserved -; A value of 8 in RAX will delay 1 second and a value of 1 will delay 1/8 of a second -; This function depends on the RTC (IRQ 8) so interrupts must be enabled. -os_delay: - push rcx - push rax - - mov rcx, [os_ClockCounter] ; Grab the initial timer counter. It increments 8 times a second - add rax, rcx ; Add RCX so we get the end time we want -os_delay_loop: - cmp qword [os_ClockCounter], rax ; Compare it against our end time - jle os_delay_loop ; Loop if RAX is still lower - - pop rax - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_seed_random -- Seed the RNG based on the current date and time -; IN: Nothing -; OUT: All registers preserved -os_seed_random: - push rdx - push rbx - push rax - - xor rbx, rbx - mov al, 0x09 ; year - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x08 ; month - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x07 ; day - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x04 ; hour - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x02 ; minute - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 8 - mov al, 0x00 ; second - out 0x70, al - in al, 0x71 - mov bl, al - shl rbx, 16 - rdtsc ; Read the Time Stamp Counter in EDX:EAX - mov bx, ax ; Only use the last 2 bytes - - mov [os_RandomSeed], rbx ; Seed will be something like 0x091229164435F30A - - pop rax - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_random -- Return a random integer -; IN: Nothing -; OUT: RAX = Random number -; All other registers preserved -os_get_random: - push rdx - push rbx - - mov rax, [os_RandomSeed] - mov rdx, 0x23D8AD1401DE7383 ; The magic number (random.org) - mul rdx ; RDX:RAX = RAX * RDX - mov [os_RandomSeed], rax - - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_random_integer -- Return a random integer between Low and High (incl) -; IN: RAX = Low integer -; RBX = High integer -; OUT: RCX = Random integer -os_get_random_integer: - push rdx - push rbx - push rax - - sub rbx, rax ; We want to look for a number between 0 and (High-Low) - call os_get_random - mov rdx, rbx - add rdx, 1 - mul rdx - mov rcx, rdx - - pop rax - pop rbx - pop rdx - add rcx, rax ; Add the low offset back - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_argc -- Return the number arguments passed to the program -; IN: Nothing -; OUT: AL = Number of arguments -os_get_argc: - xor eax, eax - mov al, [cli_args] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_argv -- Get the value of an argument that was passed to the program -; IN: AL = Argument number -; OUT: RSI = Start of numbered argument string -os_get_argv: - push rcx - push rax - mov rsi, cli_temp_string - cmp al, 0x00 - je os_get_argv_end - mov cl, al - -os_get_argv_nextchar: - lodsb - cmp al, 0x00 - jne os_get_argv_nextchar - dec cl - cmp cl, 0 - jne os_get_argv_nextchar - -os_get_argv_end: - pop rax - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_timecounter -- Get the current RTC clock couter value -; IN: Nothing -; OUT: RAX = Time in eights of a second since clock started -; This function depends on the RTC (IRQ 8) so interrupts must be enabled. -os_get_timecounter: - mov rax, [os_ClockCounter] ; Grab the timer counter value. It increments 8 times a second - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_hide_statusbar -- Hide the system status bar -; IN: -os_hide_statusbar: - mov byte [os_show_sysstatus], 0 - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_show_statusbar -- Show the system status bar -; IN: -os_show_statusbar: - mov byte [os_show_sysstatus], 1 - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Misc Functions +; ============================================================================= + +align 16 +db 'DEBUG: MISC ' +align 16 + + +; ----------------------------------------------------------------------------- +; Display Core activity with flashing blocks on screen +; Blocks flash every quarter of a second +system_status: + push rsi + push rdi + push rdx + push rcx + push rax + + ; Display the dark grey bar + mov ax, 0x8720 ; 0x87 for dark grey background/white foreground, 0x20 for space (blank) character + mov rdi, os_screen ;0x00000000000B8000 + mov rcx, 80 + rep stosw + + ; Display CPU status + mov rdi, os_screen ; 0x00000000000B8000 + mov al, '[' + stosb + add rdi, 1 ; Skip the attribute byte + mov ax, 0x8F63 ; 'c' + stosw + mov ax, 0x8F70 ; 'p' + stosw + mov ax, 0x8F75 ; 'u' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 ; Skip to the next char + + xor ecx, ecx + mov rsi, cpustatus +system_status_cpu_next: + cmp cx, 256 + je system_status_cpu_done + add rcx, 1 + lodsb + bt ax, 0 ; Check to see if the Core is Present + jnc system_status_cpu_next ; If not then check the next + ror ax, 8 ; Exchange AL and AH + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + rol ax, 8 ; Exchange AL and AH + bt ax, 1 ; Check to see if the Core is Ready or Busy + jc system_status_cpu_busy ; Jump if it is Busy.. otherwise fall through for Idle + mov al, 0x80 ; Black on Dark Gray (Idle Core) + jmp system_status_cpu_color + +system_status_cpu_busy: + mov rax, [os_ClockCounter] + bt rax, 0 ; Check bit 0. Store bit 0 in CF + jc system_status_cpu_flash_hi + mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) + jmp system_status_cpu_color +system_status_cpu_flash_hi: + mov al, 0x8F ; White on Dark Gray (Active Core High) +system_status_cpu_color: + stosb ; Store the color (attribute) byte + jmp system_status_cpu_next ; Check the next Core + +system_status_cpu_done: + mov al, ']' + stosb + add rdi, 1 + + ; Display memory status + add rdi, 4 + mov al, '[' + stosb + add rdi, 1 ; Skip the attribute byte + mov ax, 0x8F6D ; 'm' + stosw + mov ax, 0x8F65 ; 'e' + stosw + mov ax, 0x8F6D ; 'm' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 ; Skip to the next char + + call os_mem_get_free ; Store number of free 2 MiB pages in RCX + xor rax, rax + mov ax, word [os_MemAmount] + shr ax, 1 ; Divide actual memory by 2 (RAX now holds total pages) + push rax + sub rax, rcx ; RAX holds inuse pages (ex 6) + pop rcx ; RCX holds total pages (ex 512) + shr rcx, 3 ; Quickly divide RCX by 8, RCX now holds pages/block (ex 64) + xor rdx, rdx + div rcx ; Divide inuse pages by pages/block + mov rcx, rax + mov ax, 8 + cmp cx, 0 + jne notzero + add cx, 1 +notzero: + sub ax, cx + push rax + +system_status_mem_used: + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x8F ; Light Gray on Blue + stosb ; Put the block character on the screen + sub rcx, 1 + jrcxz system_status_mem_used_finish + jmp system_status_mem_used + +system_status_mem_used_finish: + + pop rcx +system_status_mem_free: + jrcxz system_status_mem_finish + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x80 ; Light Gray on Blue + stosb ; Put the block character on the screen + sub rcx, 1 + jrcxz system_status_mem_finish + jmp system_status_mem_free + +system_status_mem_finish: + mov al, ']' + stosb + add rdi, 1 + + ; Display network status + cmp byte [os_NetEnabled], 1 ; Print network details (if a supported NIC was initialized) + jne system_status_no_network + add rdi, 4 + mov al, '[' + stosb + add rdi, 1 + mov ax, 0x8F6E ; 'n' + stosw + mov ax, 0x8F65 ; 'e' + stosw + mov ax, 0x8F74 ; 't' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 + mov al, 'T' + stosb + add rdi, 1 + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x80 ; Black on Dark Gray (No Activity) + cmp byte [os_NetActivity_TX], 1 + jne tx_idle + mov al, 0x8F + mov byte [os_NetActivity_TX], 0 +tx_idle: + stosb + mov al, 'R' + stosb + add rdi, 1 + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov al, 0x80 ; Black on Dark Gray (No Activity) + cmp byte [os_NetActivity_RX], 1 + jne rx_idle + mov al, 0x8F + mov byte [os_NetActivity_RX], 0 +rx_idle: + stosb + mov al, ']' + stosb + add rdi, 1 +system_status_no_network: + + ; Display the RTC pulse + add rdi, 4 + mov al, '[' + stosb + add rdi, 1 + mov ax, 0x8F72 ; 'r' + stosw + mov ax, 0x8F74 ; 't' + stosw + mov ax, 0x8F63 ; 'c' + stosw + mov ax, 0x8F3A ; ':' + stosw + add rdi, 2 + mov al, 0xFE ; Ascii block character + stosb ; Put the block character on the screen + mov rax, [os_ClockCounter] + bt rax, 0 ; Check bit 0. Store bit 0 in CF + jc system_status_rtc_flash_hi + mov al, 0x87 ; Light Gray on Dark Gray (Active Core Low) + jmp system_status_rtc_flash_lo +system_status_rtc_flash_hi: + mov al, 0x8F ; White on Dark Gray (Active Core High) +system_status_rtc_flash_lo: + stosb ; Store the color (attribute) byte + mov al, ']' + stosb + add rdi, 1 + + ; Display header text + mov rdi, os_screen ;0x00000000000B8080 + add rdi, 0x80 + mov rsi, system_status_header + mov rcx, 16 +headernext: + lodsb + stosb + inc rdi + dec rcx + cmp rcx, 0 + jne headernext + + ; Copy the system status to the screen + mov rsi, os_screen + mov rdi, 0xB8000 + mov rcx, 80 + rep movsw + + pop rax + pop rcx + pop rdx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_delay -- Delay by X eights of a second +; IN: RAX = Time in eights of a second +; OUT: All registers preserved +; A value of 8 in RAX will delay 1 second and a value of 1 will delay 1/8 of a second +; This function depends on the RTC (IRQ 8) so interrupts must be enabled. +os_delay: + push rcx + push rax + + mov rcx, [os_ClockCounter] ; Grab the initial timer counter. It increments 8 times a second + add rax, rcx ; Add RCX so we get the end time we want +os_delay_loop: + cmp qword [os_ClockCounter], rax ; Compare it against our end time + jle os_delay_loop ; Loop if RAX is still lower + + pop rax + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_seed_random -- Seed the RNG based on the current date and time +; IN: Nothing +; OUT: All registers preserved +os_seed_random: + push rdx + push rbx + push rax + + xor rbx, rbx + mov al, 0x09 ; year + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x08 ; month + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x07 ; day + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x04 ; hour + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x02 ; minute + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 8 + mov al, 0x00 ; second + out 0x70, al + in al, 0x71 + mov bl, al + shl rbx, 16 + rdtsc ; Read the Time Stamp Counter in EDX:EAX + mov bx, ax ; Only use the last 2 bytes + + mov [os_RandomSeed], rbx ; Seed will be something like 0x091229164435F30A + + pop rax + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_random -- Return a random integer +; IN: Nothing +; OUT: RAX = Random number +; All other registers preserved +os_get_random: + push rdx + push rbx + + mov rax, [os_RandomSeed] + mov rdx, 0x23D8AD1401DE7383 ; The magic number (random.org) + mul rdx ; RDX:RAX = RAX * RDX + mov [os_RandomSeed], rax + + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_random_integer -- Return a random integer between Low and High (incl) +; IN: RAX = Low integer +; RBX = High integer +; OUT: RCX = Random integer +os_get_random_integer: + push rdx + push rbx + push rax + + sub rbx, rax ; We want to look for a number between 0 and (High-Low) + call os_get_random + mov rdx, rbx + add rdx, 1 + mul rdx + mov rcx, rdx + + pop rax + pop rbx + pop rdx + add rcx, rax ; Add the low offset back + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_argc -- Return the number arguments passed to the program +; IN: Nothing +; OUT: AL = Number of arguments +os_get_argc: + xor eax, eax + mov al, [cli_args] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_argv -- Get the value of an argument that was passed to the program +; IN: AL = Argument number +; OUT: RSI = Start of numbered argument string +os_get_argv: + push rcx + push rax + mov rsi, cli_temp_string + cmp al, 0x00 + je os_get_argv_end + mov cl, al + +os_get_argv_nextchar: + lodsb + cmp al, 0x00 + jne os_get_argv_nextchar + dec cl + cmp cl, 0 + jne os_get_argv_nextchar + +os_get_argv_end: + pop rax + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_timecounter -- Get the current RTC clock couter value +; IN: Nothing +; OUT: RAX = Time in eights of a second since clock started +; This function depends on the RTC (IRQ 8) so interrupts must be enabled. +os_get_timecounter: + mov rax, [os_ClockCounter] ; Grab the timer counter value. It increments 8 times a second + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_hide_statusbar -- Hide the system status bar +; IN: +os_hide_statusbar: + mov byte [os_show_sysstatus], 0 + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_show_statusbar -- Show the system status bar +; IN: +os_show_statusbar: + mov byte [os_show_sysstatus], 1 + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/screen.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/screen.asm index d620ea1c..e31c84ef 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/screen.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/screen.asm @@ -1,539 +1,539 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Screen Output Functions -; ============================================================================= - -align 16 -db 'DEBUG: SCREEN ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_move_cursor -- Moves cursor in text mode -; IN: AH = row -; AL = column -; OUT: All registers preserved -os_move_cursor: - push rdx - push rcx - push rbx - push rax - - mov [screen_cursor_x], ah - mov [screen_cursor_y], al - push rax - and rax, 0x000000000000FFFF ; only keep the low 16 bits - ;calculate the new offset - mov cl, 80 - mul cl ; AX = AL * CL - xor rbx, rbx - mov bl, [screen_cursor_x] - add ax, bx - shl ax, 1 ; multiply by 2 - add rax, os_screen ;0x00000000000B8000 - mov [screen_cursor_offset], rax - pop rax ; Move the hardware cursor - mov bh, ah - mov bl, al - xor ax, ax - mov al, 0x50 - mul bl ; bl * al = ax - movzx bx, bh - add bx, ax - mov al, 0x0E - mov ah, bh - mov dx, 0x03D4 - out dx, ax - inc ax - mov ah, bl - out dx, ax - - pop rax - pop rbx - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_inc_cursor -- Increment the hardware cursor by one -; IN: Nothing -; OUT: All registers preserved -os_inc_cursor: - push rax - - mov ah, [screen_cursor_x] ; grab the current cursor location values - mov al, [screen_cursor_y] - inc ah - cmp ah, [screen_cols] ; 80 - jne os_inc_cursor_done - xor ah, ah - inc al - cmp al, [screen_rows] ; 25 - jne os_inc_cursor_done - call os_screen_scroll ; we are on the last column of the last row (bottom right) so we need to scroll the screen up by one line - mov ah, 0x00 ; now reset the cursor to be in the first colum of the last row (bottom left) - mov al, [screen_rows] - dec al - -os_inc_cursor_done: - call os_move_cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_dec_cursor -- Decrement the hardware cursor by one -; IN: Nothing -; OUT: All registers preserved -os_dec_cursor: - push rax - - mov ah, [screen_cursor_x] ; Get the current cursor location values - mov al, [screen_cursor_y] - cmp ah, 0 ; Check if the cursor in located on the first column? - jne os_dec_cursor_done - dec al ; Wrap the cursor back to the above line - mov ah, [screen_cols] - -os_dec_cursor_done: - dec ah - call os_move_cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_newline -- Reset cursor to start of next line and scroll if needed -; IN: Nothing -; OUT: All registers perserved -os_print_newline: - push rax - - mov ah, 0 ; Set the cursor x value to 0 - mov al, [screen_cursor_y] ; Grab the cursor y value - cmp al, 24 ; Compare to see if we are on the last line - je os_print_newline_scroll ; If so then we need to scroll the sreen - inc al ; If not then we can go ahead an increment the y value - jmp os_print_newline_done - -os_print_newline_scroll: - call os_screen_scroll - -os_print_newline_done: - call os_move_cursor ; Update the cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_string -- Displays text -; IN: RSI = message location (zero-terminated string) -; OUT: All registers perserved -os_print_string: - push rdi - push rsi - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on - -os_print_string_nextchar: - lodsb ; Get char from string and store in AL - cmp al, 0 ; Strings are Zero terminated. - je os_print_string_done ; If char is Zero then it is the end of the string - cmp al, 10 ; Check if there was a newline character in the string - je os_print_string_newline ; If so then we print a new line - cmp al, 13 ; Check if there was a newline character in the string - je os_print_string_newline ; If so then we print a new line - mov rdi, [screen_cursor_offset] - stosw ; Write the character and attribute with one call - call os_inc_cursor - jmp os_print_string_nextchar - -os_print_string_newline: - call os_print_newline - jmp os_print_string_nextchar - -os_print_string_done: - call os_screen_update - - pop rax - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_string_with_color -- Displays text with color -; IN: RSI = message location (zero-terminated string) -; BL = color -; OUT: All registers perserved -; This function uses the the os_print_string function to do the actual printing -os_print_string_with_color: - push rdi - push rsi - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, bl ; Copy the attribute into AH so STOSW can be used later on - - jmp os_print_string_nextchar ; Use the logic from os_print_string -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char -- Displays a char -; IN: AL = char to display -; OUT: All registers perserved -os_print_char: - push rdi - push rsi - push rax - - mov rdi, [screen_cursor_offset] - mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on - stosw ; Write the character and attribute with one call - - call os_inc_cursor - sub rdi, 2 - mov rsi, rdi - sub rdi, os_screen - add rdi, 0xB8000 ; Offset to video text memory - movsw - - pop rax - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_with_color -- Displays a char with color -; IN: AL = char to display -; BL = color -; OUT: All registers perserved -os_print_char_with_color: - push rdi - push rsi - - mov rdi, [screen_cursor_offset] - stosb ; Store the character to video memory - xchg al, bl ; Swap AL and BL as stosb uses AL - stosb ; Store the color attribute to video memory - xchg al, bl ; Swap AL and BL back again - call os_inc_cursor - sub rdi, 2 - mov rsi, rdi - sub rdi, os_screen - add rdi, 0xB8000 ; Offset to video text memory - movsw - - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_chars -- Displays text -; IN: RSI = message location (A string, not zero-terminated) -; RCX = number of chars to print -; OUT: All registers perserved -os_print_chars: - push rdi - push rsi - push rcx - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on - -os_print_chars_nextchar: - jrcxz os_print_chars_done - sub rcx, 1 - lodsb ; Get char from string and store in AL - cmp al, 13 ; Check if there was a newline character in the string - je os_print_chars_newline ; If so then we print a new line - cmp al, 10 ; Check if there was a newline character in the string - je os_print_chars_newline ; If so then we print a new line - mov rdi, [screen_cursor_offset] - stosw ; Write the character and attribute with one call - call os_inc_cursor - jmp os_print_chars_nextchar - -os_print_chars_newline: - mov al, [rsi] - cmp al, 10 - je os_print_chars_newline_skip_LF - call os_print_newline - jmp os_print_chars_nextchar - -os_print_chars_newline_skip_LF: - cmp rcx, 0 - je os_print_chars_newline_skip_LF_nosub - sub rcx, 1 -os_print_chars_newline_skip_LF_nosub: - add rsi, 1 - call os_print_newline - jmp os_print_chars_nextchar - -os_print_chars_done: - call os_screen_update - - pop rax - pop rcx - pop rsi - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_chars_with_color -- Displays text with color -; IN: RSI = message location (A string, not zero-terminated) -; BL = color -; RCX = number of chars to print -; OUT: All registers perserved -; This function uses the the os_print_chars function to do the actual printing -os_print_chars_with_color: - push rdi - push rsi - push rcx - push rax - - cld ; Clear the direction flag.. we want to increment through the string - mov ah, bl ; Store the attribute into AH so STOSW can be used later on - - jmp os_print_chars_nextchar ; Use the logic from os_print_chars -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_hex -- Displays a char in hex mode -; IN: AL = char to display -; OUT: All registers perserved -os_print_char_hex: - push rbx - push rax - - mov rbx, hextable - - push rax ; save rax for the next part - shr al, 4 ; we want to work on the high part so shift right by 4 bits - xlatb - call os_print_char - - pop rax - and al, 0x0f ; we want to work on the low part so clear the high part - xlatb - call os_print_char - - pop rax - pop rbx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_hex_with_color -- Displays a char in hex mode -; IN: AL = char to display -; BL = color -; OUT: All registers perserved -os_print_char_hex_with_color: - push rcx - push rbx - push rax - - mov cl, bl - mov rbx, hextable - - push rax ; save rax for the next part - shr al, 4 ; we want to work on the high part so shift right by 4 bits - xlatb - push rbx - mov bl, cl - call os_print_char_with_color - pop rbx - - pop rax - and al, 0x0f ; we want to work on the low part so clear the high part - xlatb - push rbx - mov bl, cl - call os_print_char_with_color - pop rbx - - pop rax - pop rbx - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_scroll_screen -- Scrolls the screen up by one line -; IN: Nothing -; OUT: All registers perserved -os_screen_scroll: - push rsi - push rdi - push rcx - push rax - - cld ; Clear the direction flag as we want to increment through memory - - cmp byte [os_show_sysstatus], 0 - je os_screen_scroll_no_sysstatus - - mov rsi, os_screen ; Start of video text memory for row 3 - add rsi, 0x140 - mov rdi, os_screen ; Start of video text memory for row 2 - add rdi, 0xa0 - mov rcx, 1840 ; 80 x 23 - rep movsw ; Copy the Character and Attribute - jmp os_screen_scroll_lastline - -os_screen_scroll_no_sysstatus: - mov rsi, os_screen ; Start of video text memory for row 2 - add rsi, 0xa0 - mov rdi, os_screen ; Start of video text memory for row 1 - mov rcx, 1920 ; 80 x 24 - rep movsw ; Copy the Character and Attribute - -os_screen_scroll_lastline: ; Clear the last line in video memory - mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character - mov rdi, os_screen - add rdi, 0xf00 - mov rcx, 80 - rep stosw ; Store word in AX to RDI, RCX times - - call os_screen_update - - pop rax - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_screen_clear -- Clear the screen -; IN: Nothing -; OUT: All registers perserved -os_screen_clear: - push rdi - push rcx - push rax - - mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character - mov rdi, os_screen ; Address for start of color video memory - mov rcx, 2000 - rep stosw ; Clear the screen. Store word in AX to RDI, RCX times - - call os_screen_update ; Copy the video buffer to video memory - - pop rax - pop rcx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_hide_cursor -- Turns off cursor in text mode -; IN: Nothing -; OUT: All registers perserved -os_hide_cursor: - push rdx - push rbx - push rax - - mov dx, 0x03d4 - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - xor ax, ax - in al, dx - mov bl, al - or bl, 00100000b ; Bit 5 set to 1 to disable cursor - dec dx - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - mov al, bl - out dx, al - - pop rax - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_show_cursor -- Turns on cursor in text mode -; IN: Nothing -; OUT: All registers perserved -os_show_cursor: - push rdx - push rbx - push rax - - mov dx, 0x03d4 - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - xor ax, ax - in al, dx - mov bl, al - and bl, 11011111b ; Bit 5 set to 0 to enable cursor - dec dx - mov ax, 0x000a ; Cursor Start Register - out dx, ax - inc dx - mov al, bl - out dx, al - - pop rax - pop rbx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_show_cursor -- Manually refresh the screen from the frame buffer -; IN: Nothing -; OUT: All registers perserved -os_screen_update: - push rsi - push rdi - push rcx - - mov rsi, os_screen - mov rdi, 0xb8000 - mov rcx, 2000 - rep movsw - - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Screen Output Functions +; ============================================================================= + +align 16 +db 'DEBUG: SCREEN ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_move_cursor -- Moves cursor in text mode +; IN: AH = row +; AL = column +; OUT: All registers preserved +os_move_cursor: + push rdx + push rcx + push rbx + push rax + + mov [screen_cursor_x], ah + mov [screen_cursor_y], al + push rax + and rax, 0x000000000000FFFF ; only keep the low 16 bits + ;calculate the new offset + mov cl, 80 + mul cl ; AX = AL * CL + xor rbx, rbx + mov bl, [screen_cursor_x] + add ax, bx + shl ax, 1 ; multiply by 2 + add rax, os_screen ;0x00000000000B8000 + mov [screen_cursor_offset], rax + pop rax ; Move the hardware cursor + mov bh, ah + mov bl, al + xor ax, ax + mov al, 0x50 + mul bl ; bl * al = ax + movzx bx, bh + add bx, ax + mov al, 0x0E + mov ah, bh + mov dx, 0x03D4 + out dx, ax + inc ax + mov ah, bl + out dx, ax + + pop rax + pop rbx + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_inc_cursor -- Increment the hardware cursor by one +; IN: Nothing +; OUT: All registers preserved +os_inc_cursor: + push rax + + mov ah, [screen_cursor_x] ; grab the current cursor location values + mov al, [screen_cursor_y] + inc ah + cmp ah, [screen_cols] ; 80 + jne os_inc_cursor_done + xor ah, ah + inc al + cmp al, [screen_rows] ; 25 + jne os_inc_cursor_done + call os_screen_scroll ; we are on the last column of the last row (bottom right) so we need to scroll the screen up by one line + mov ah, 0x00 ; now reset the cursor to be in the first colum of the last row (bottom left) + mov al, [screen_rows] + dec al + +os_inc_cursor_done: + call os_move_cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_dec_cursor -- Decrement the hardware cursor by one +; IN: Nothing +; OUT: All registers preserved +os_dec_cursor: + push rax + + mov ah, [screen_cursor_x] ; Get the current cursor location values + mov al, [screen_cursor_y] + cmp ah, 0 ; Check if the cursor in located on the first column? + jne os_dec_cursor_done + dec al ; Wrap the cursor back to the above line + mov ah, [screen_cols] + +os_dec_cursor_done: + dec ah + call os_move_cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_newline -- Reset cursor to start of next line and scroll if needed +; IN: Nothing +; OUT: All registers perserved +os_print_newline: + push rax + + mov ah, 0 ; Set the cursor x value to 0 + mov al, [screen_cursor_y] ; Grab the cursor y value + cmp al, 24 ; Compare to see if we are on the last line + je os_print_newline_scroll ; If so then we need to scroll the sreen + inc al ; If not then we can go ahead an increment the y value + jmp os_print_newline_done + +os_print_newline_scroll: + call os_screen_scroll + +os_print_newline_done: + call os_move_cursor ; Update the cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_string -- Displays text +; IN: RSI = message location (zero-terminated string) +; OUT: All registers perserved +os_print_string: + push rdi + push rsi + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on + +os_print_string_nextchar: + lodsb ; Get char from string and store in AL + cmp al, 0 ; Strings are Zero terminated. + je os_print_string_done ; If char is Zero then it is the end of the string + cmp al, 10 ; Check if there was a newline character in the string + je os_print_string_newline ; If so then we print a new line + cmp al, 13 ; Check if there was a newline character in the string + je os_print_string_newline ; If so then we print a new line + mov rdi, [screen_cursor_offset] + stosw ; Write the character and attribute with one call + call os_inc_cursor + jmp os_print_string_nextchar + +os_print_string_newline: + call os_print_newline + jmp os_print_string_nextchar + +os_print_string_done: + call os_screen_update + + pop rax + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_string_with_color -- Displays text with color +; IN: RSI = message location (zero-terminated string) +; BL = color +; OUT: All registers perserved +; This function uses the the os_print_string function to do the actual printing +os_print_string_with_color: + push rdi + push rsi + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, bl ; Copy the attribute into AH so STOSW can be used later on + + jmp os_print_string_nextchar ; Use the logic from os_print_string +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char -- Displays a char +; IN: AL = char to display +; OUT: All registers perserved +os_print_char: + push rdi + push rsi + push rax + + mov rdi, [screen_cursor_offset] + mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on + stosw ; Write the character and attribute with one call + + call os_inc_cursor + sub rdi, 2 + mov rsi, rdi + sub rdi, os_screen + add rdi, 0xB8000 ; Offset to video text memory + movsw + + pop rax + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_with_color -- Displays a char with color +; IN: AL = char to display +; BL = color +; OUT: All registers perserved +os_print_char_with_color: + push rdi + push rsi + + mov rdi, [screen_cursor_offset] + stosb ; Store the character to video memory + xchg al, bl ; Swap AL and BL as stosb uses AL + stosb ; Store the color attribute to video memory + xchg al, bl ; Swap AL and BL back again + call os_inc_cursor + sub rdi, 2 + mov rsi, rdi + sub rdi, os_screen + add rdi, 0xB8000 ; Offset to video text memory + movsw + + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_chars -- Displays text +; IN: RSI = message location (A string, not zero-terminated) +; RCX = number of chars to print +; OUT: All registers perserved +os_print_chars: + push rdi + push rsi + push rcx + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on + +os_print_chars_nextchar: + jrcxz os_print_chars_done + sub rcx, 1 + lodsb ; Get char from string and store in AL + cmp al, 13 ; Check if there was a newline character in the string + je os_print_chars_newline ; If so then we print a new line + cmp al, 10 ; Check if there was a newline character in the string + je os_print_chars_newline ; If so then we print a new line + mov rdi, [screen_cursor_offset] + stosw ; Write the character and attribute with one call + call os_inc_cursor + jmp os_print_chars_nextchar + +os_print_chars_newline: + mov al, [rsi] + cmp al, 10 + je os_print_chars_newline_skip_LF + call os_print_newline + jmp os_print_chars_nextchar + +os_print_chars_newline_skip_LF: + cmp rcx, 0 + je os_print_chars_newline_skip_LF_nosub + sub rcx, 1 +os_print_chars_newline_skip_LF_nosub: + add rsi, 1 + call os_print_newline + jmp os_print_chars_nextchar + +os_print_chars_done: + call os_screen_update + + pop rax + pop rcx + pop rsi + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_chars_with_color -- Displays text with color +; IN: RSI = message location (A string, not zero-terminated) +; BL = color +; RCX = number of chars to print +; OUT: All registers perserved +; This function uses the the os_print_chars function to do the actual printing +os_print_chars_with_color: + push rdi + push rsi + push rcx + push rax + + cld ; Clear the direction flag.. we want to increment through the string + mov ah, bl ; Store the attribute into AH so STOSW can be used later on + + jmp os_print_chars_nextchar ; Use the logic from os_print_chars +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_hex -- Displays a char in hex mode +; IN: AL = char to display +; OUT: All registers perserved +os_print_char_hex: + push rbx + push rax + + mov rbx, hextable + + push rax ; save rax for the next part + shr al, 4 ; we want to work on the high part so shift right by 4 bits + xlatb + call os_print_char + + pop rax + and al, 0x0f ; we want to work on the low part so clear the high part + xlatb + call os_print_char + + pop rax + pop rbx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_hex_with_color -- Displays a char in hex mode +; IN: AL = char to display +; BL = color +; OUT: All registers perserved +os_print_char_hex_with_color: + push rcx + push rbx + push rax + + mov cl, bl + mov rbx, hextable + + push rax ; save rax for the next part + shr al, 4 ; we want to work on the high part so shift right by 4 bits + xlatb + push rbx + mov bl, cl + call os_print_char_with_color + pop rbx + + pop rax + and al, 0x0f ; we want to work on the low part so clear the high part + xlatb + push rbx + mov bl, cl + call os_print_char_with_color + pop rbx + + pop rax + pop rbx + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_scroll_screen -- Scrolls the screen up by one line +; IN: Nothing +; OUT: All registers perserved +os_screen_scroll: + push rsi + push rdi + push rcx + push rax + + cld ; Clear the direction flag as we want to increment through memory + + cmp byte [os_show_sysstatus], 0 + je os_screen_scroll_no_sysstatus + + mov rsi, os_screen ; Start of video text memory for row 3 + add rsi, 0x140 + mov rdi, os_screen ; Start of video text memory for row 2 + add rdi, 0xa0 + mov rcx, 1840 ; 80 x 23 + rep movsw ; Copy the Character and Attribute + jmp os_screen_scroll_lastline + +os_screen_scroll_no_sysstatus: + mov rsi, os_screen ; Start of video text memory for row 2 + add rsi, 0xa0 + mov rdi, os_screen ; Start of video text memory for row 1 + mov rcx, 1920 ; 80 x 24 + rep movsw ; Copy the Character and Attribute + +os_screen_scroll_lastline: ; Clear the last line in video memory + mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character + mov rdi, os_screen + add rdi, 0xf00 + mov rcx, 80 + rep stosw ; Store word in AX to RDI, RCX times + + call os_screen_update + + pop rax + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_screen_clear -- Clear the screen +; IN: Nothing +; OUT: All registers perserved +os_screen_clear: + push rdi + push rcx + push rax + + mov ax, 0x0720 ; 0x07 for black background/white foreground, 0x20 for space (black) character + mov rdi, os_screen ; Address for start of color video memory + mov rcx, 2000 + rep stosw ; Clear the screen. Store word in AX to RDI, RCX times + + call os_screen_update ; Copy the video buffer to video memory + + pop rax + pop rcx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_hide_cursor -- Turns off cursor in text mode +; IN: Nothing +; OUT: All registers perserved +os_hide_cursor: + push rdx + push rbx + push rax + + mov dx, 0x03d4 + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + xor ax, ax + in al, dx + mov bl, al + or bl, 00100000b ; Bit 5 set to 1 to disable cursor + dec dx + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + mov al, bl + out dx, al + + pop rax + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_show_cursor -- Turns on cursor in text mode +; IN: Nothing +; OUT: All registers perserved +os_show_cursor: + push rdx + push rbx + push rax + + mov dx, 0x03d4 + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + xor ax, ax + in al, dx + mov bl, al + and bl, 11011111b ; Bit 5 set to 0 to enable cursor + dec dx + mov ax, 0x000a ; Cursor Start Register + out dx, ax + inc dx + mov al, bl + out dx, al + + pop rax + pop rbx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_show_cursor -- Manually refresh the screen from the frame buffer +; IN: Nothing +; OUT: All registers perserved +os_screen_update: + push rsi + push rdi + push rcx + + mov rsi, os_screen + mov rdi, 0xb8000 + mov rcx, 2000 + rep movsw + + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/serial.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/serial.asm index 37cc8366..900715b9 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/serial.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/serial.asm @@ -1,58 +1,58 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Serial Port Functions -; ============================================================================= - -align 16 -db 'DEBUG: SERIAL ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_serial_send -- Send a byte over the primary serial port -; IN: AL = Byte to send over serial port -; OUT: All registers preserved -os_serial_send: - push rdx - - push rax ; Save RAX since the serial line status check clobbers AL - mov dx, 0x03FD ; Serial Line Status register -os_serial_send_wait: - in al, dx - bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag - jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte - pop rax ; Get the byte back from the stack - mov dx, 0x03F8 ; Serial data register - out dx, al ; Send the byte - - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_serial_recv -- Receive a byte from the primary serial port -; IN: Nothing -; OUT: AL = Byte recevied -; Carry flag is set if a byte was received, otherwise AL is trashed -; All other registers preserved -os_serial_recv: - push rdx - - mov dx, 0x03FD ; Serial Line Status register - in al, dx - bt ax, 0 ; Copy bit 0 (Data available) to the Carry Flag - jnc os_serial_recv_no_data - mov dx, 0x03F8 ; Serial data register - in al, dx ; Grab the byte - -os_serial_recv_no_data: - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Serial Port Functions +; ============================================================================= + +align 16 +db 'DEBUG: SERIAL ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_serial_send -- Send a byte over the primary serial port +; IN: AL = Byte to send over serial port +; OUT: All registers preserved +os_serial_send: + push rdx + + push rax ; Save RAX since the serial line status check clobbers AL + mov dx, 0x03FD ; Serial Line Status register +os_serial_send_wait: + in al, dx + bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag + jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte + pop rax ; Get the byte back from the stack + mov dx, 0x03F8 ; Serial data register + out dx, al ; Send the byte + + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_serial_recv -- Receive a byte from the primary serial port +; IN: Nothing +; OUT: AL = Byte recevied +; Carry flag is set if a byte was received, otherwise AL is trashed +; All other registers preserved +os_serial_recv: + push rdx + + mov dx, 0x03FD ; Serial Line Status register + in al, dx + bt ax, 0 ; Copy bit 0 (Data available) to the Carry Flag + jnc os_serial_recv_no_data + mov dx, 0x03F8 ; Serial data register + in al, dx ; Grab the byte + +os_serial_recv_no_data: + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/smp.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/smp.asm index d1be8710..fb442a76 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/smp.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/smp.asm @@ -1,308 +1,308 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; SMP Functions -; ============================================================================= - -align 16 -db 'DEBUG: SMP ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_smp_reset -- Resets a CPU Core -; IN: AL = CPU # -; OUT: Nothing. All registers preserved. -; Note: This code resets an AP -; For setup use only. -os_smp_reset: - push rdi - push rax - - mov rdi, [os_LocalAPICAddress] - shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved - mov [rdi+0x0310], eax ; Write to the high bits first - xor eax, eax ; Clear EAX, namely bits 31:24 - mov al, 0x81 ; Execute interrupt 0x81 - mov [rdi+0x0300], eax ; Then write to the low bits - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_wakeup -- Wake up a CPU Core -; IN: AL = CPU # -; OUT: Nothing. All registers preserved. -os_smp_wakeup: - push rdi - push rax - - mov rdi, [os_LocalAPICAddress] - shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved - mov [rdi+0x0310], eax ; Write to the high bits first - xor eax, eax ; Clear EAX, namely bits 31:24 - mov al, 0x80 ; Execute interrupt 0x80 - mov [rdi+0x0300], eax ; Then write to the low bits - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_wakeup_all -- Wake up all CPU Cores -; IN: Nothing. -; OUT: Nothing. All registers preserved. -os_smp_wakeup_all: - push rdi - push rax - - mov rdi, [os_LocalAPICAddress] - xor eax, eax - mov [rdi+0x0310], eax ; Write to the high bits first - mov eax, 0x000C0080 ; Execute interrupt 0x80 - mov [rdi+0x0300], eax ; Then write to the low bits - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_get_id -- Returns the APIC ID of the CPU that ran this function -; IN: Nothing -; OUT: RAX = CPU's APIC ID number, All other registers perserved. -os_smp_get_id: - push rsi - - xor eax, eax - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) - - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_enqueue -- Add a workload to the processing queue -; IN: RAX = Address of code to execute -; RSI = Variable -; OUT: Nothing -os_smp_enqueue: - push rdi - push rsi - push rcx - push rax - -os_smp_enqueue_spin: - bt word [os_QueueLock], 0 ; Check if the mutex is free - jc os_smp_enqueue_spin ; If not check it again - lock ; The mutex was free, lock the bus - bts word [os_QueueLock], 0 ; Try to grab the mutex - jc os_smp_enqueue_spin ; Jump if we were unsuccessful - - cmp word [os_QueueLen], 256 ; aka cpuqueuemax - je os_smp_enqueue_fail - - xor ecx, ecx - mov rdi, cpuqueue - mov cx, [cpuqueuefinish] - shl rcx, 4 ; Quickly multiply RCX by 16 - add rdi, rcx - - stosq ; Store the code address from RAX - mov rax, rsi - stosq ; Store the variable - - add word [os_QueueLen], 1 - shr rcx, 4 ; Quickly divide RCX by 16 - add cx, 1 - cmp cx, [cpuqueuemax] - jne os_smp_enqueue_end - xor cx, cx ; We wrap around - -os_smp_enqueue_end: - mov [cpuqueuefinish], cx - pop rax - pop rcx - pop rsi - pop rdi - btr word [os_QueueLock], 0 ; Release the lock - call os_smp_wakeup_all - clc ; Carry clear for success - ret - -os_smp_enqueue_fail: - pop rax - pop rcx - pop rsi - pop rdi - btr word [os_QueueLock], 0 ; Release the lock - stc ; Carry set for failure (Queue full) - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_dequeue -- Dequeue a workload from the processing queue -; IN: Nothing -; OUT: RAX = Address of code to execute (Set to 0 if queue is empty) -; RDI = Variable -os_smp_dequeue: - push rsi - push rcx - -os_smp_dequeue_spin: - bt word [os_QueueLock], 0 ; Check if the mutex is free - jc os_smp_dequeue_spin ; If not check it again - lock ; The mutex was free, lock the bus - bts word [os_QueueLock], 0 ; Try to grab the mutex - jc os_smp_dequeue_spin ; Jump if we were unsuccessful - - cmp word [os_QueueLen], 0 - je os_smp_dequeue_fail - - xor ecx, ecx - mov rsi, cpuqueue - mov cx, [cpuqueuestart] - shl rcx, 4 ; Quickly multiply RCX by 16 - add rsi, rcx - - lodsq ; Load the code address into RAX - push rax - lodsq ; Load the variable - mov rdi, rax - pop rax - - sub word [os_QueueLen], 1 - shr rcx, 4 ; Quickly divide RCX by 16 - add cx, 1 - cmp cx, [cpuqueuemax] - jne os_smp_dequeue_end - xor cx, cx ; We wrap around - -os_smp_dequeue_end: - mov word [cpuqueuestart], cx - pop rcx - pop rsi - btr word [os_QueueLock], 0 ; Release the lock - clc ; If we got here then ok - ret - -os_smp_dequeue_fail: - xor rax, rax - pop rcx - pop rsi - btr word [os_QueueLock], 0 ; Release the lock - stc - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_run -- Call the code address stored in RAX -; IN: RAX = Address of code to execute -; OUT: Nothing -os_smp_run: - call rax ; Run the code - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_queuelen -- Returns the number of items in the processing queue -; IN: Nothing -; OUT: RAX = number of items in processing queue -os_smp_queuelen: - xor eax, eax - mov ax, [os_QueueLen] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_numcores -- Returns the number of cores in this computer -; IN: Nothing -; OUT: RAX = number of cores in this computer -os_smp_numcores: - xor eax, eax - mov ax, [os_NumCores] - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_wait -- Wait until all other CPU Cores are finished processing -; IN: Nothing -; OUT: Nothing. All registers preserved. -os_smp_wait: - push rsi - push rcx - push rbx - push rax - - call os_smp_get_id - mov rbx, rax - - xor eax, eax - xor ecx, ecx - mov rsi, cpustatus - -checkit: - lodsb - cmp rbx, rcx ; Check to see if it is looking at itself - je skipit ; If so then skip as it shouild be marked as busy - bt ax, 0 ; Check the Present bit - jnc skipit ; If carry is not set then the CPU does not exist - bt ax, 1 ; Check the Ready/Busy bit - jnc skipit ; If carry is not set then the CPU is Ready - sub rsi, 1 - jmp checkit ; Core is marked as Busy, check it again -skipit: - add rcx, 1 - cmp rcx, 256 - jne checkit - - pop rax - pop rbx - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_lock -- Attempt to lock a mutex -; IN: RAX = Address of lock variable -; OUT: Nothing. All registers preserved. -os_smp_lock: - bt word [rax], 0 ; Check if the mutex is free (Bit 0 cleared to 0) - jc os_smp_lock ; If not check it again - lock ; The mutex was free, lock the bus - bts word [rax], 0 ; Try to grab the mutex (Bit 0 set to 1) - jc os_smp_lock ; Jump if we were unsuccessful - ret ; Lock acquired. Return to the caller -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_smp_unlock -- Unlock a mutex -; IN: RAX = Address of lock variable -; OUT: Nothing. All registers preserved. -os_smp_unlock: - btr word [rax], 0 ; Release the lock (Bit 0 cleared to 0) - ret ; Lock released. Return to the caller -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; SMP Functions +; ============================================================================= + +align 16 +db 'DEBUG: SMP ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_smp_reset -- Resets a CPU Core +; IN: AL = CPU # +; OUT: Nothing. All registers preserved. +; Note: This code resets an AP +; For setup use only. +os_smp_reset: + push rdi + push rax + + mov rdi, [os_LocalAPICAddress] + shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved + mov [rdi+0x0310], eax ; Write to the high bits first + xor eax, eax ; Clear EAX, namely bits 31:24 + mov al, 0x81 ; Execute interrupt 0x81 + mov [rdi+0x0300], eax ; Then write to the low bits + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_wakeup -- Wake up a CPU Core +; IN: AL = CPU # +; OUT: Nothing. All registers preserved. +os_smp_wakeup: + push rdi + push rax + + mov rdi, [os_LocalAPICAddress] + shl eax, 24 ; AL holds the CPU #, shift left 24 bits to get it into 31:24, 23:0 are reserved + mov [rdi+0x0310], eax ; Write to the high bits first + xor eax, eax ; Clear EAX, namely bits 31:24 + mov al, 0x80 ; Execute interrupt 0x80 + mov [rdi+0x0300], eax ; Then write to the low bits + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_wakeup_all -- Wake up all CPU Cores +; IN: Nothing. +; OUT: Nothing. All registers preserved. +os_smp_wakeup_all: + push rdi + push rax + + mov rdi, [os_LocalAPICAddress] + xor eax, eax + mov [rdi+0x0310], eax ; Write to the high bits first + mov eax, 0x000C0080 ; Execute interrupt 0x80 + mov [rdi+0x0300], eax ; Then write to the low bits + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_get_id -- Returns the APIC ID of the CPU that ran this function +; IN: Nothing +; OUT: RAX = CPU's APIC ID number, All other registers perserved. +os_smp_get_id: + push rsi + + xor eax, eax + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) + + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_enqueue -- Add a workload to the processing queue +; IN: RAX = Address of code to execute +; RSI = Variable +; OUT: Nothing +os_smp_enqueue: + push rdi + push rsi + push rcx + push rax + +os_smp_enqueue_spin: + bt word [os_QueueLock], 0 ; Check if the mutex is free + jc os_smp_enqueue_spin ; If not check it again + lock ; The mutex was free, lock the bus + bts word [os_QueueLock], 0 ; Try to grab the mutex + jc os_smp_enqueue_spin ; Jump if we were unsuccessful + + cmp word [os_QueueLen], 256 ; aka cpuqueuemax + je os_smp_enqueue_fail + + xor ecx, ecx + mov rdi, cpuqueue + mov cx, [cpuqueuefinish] + shl rcx, 4 ; Quickly multiply RCX by 16 + add rdi, rcx + + stosq ; Store the code address from RAX + mov rax, rsi + stosq ; Store the variable + + add word [os_QueueLen], 1 + shr rcx, 4 ; Quickly divide RCX by 16 + add cx, 1 + cmp cx, [cpuqueuemax] + jne os_smp_enqueue_end + xor cx, cx ; We wrap around + +os_smp_enqueue_end: + mov [cpuqueuefinish], cx + pop rax + pop rcx + pop rsi + pop rdi + btr word [os_QueueLock], 0 ; Release the lock + call os_smp_wakeup_all + clc ; Carry clear for success + ret + +os_smp_enqueue_fail: + pop rax + pop rcx + pop rsi + pop rdi + btr word [os_QueueLock], 0 ; Release the lock + stc ; Carry set for failure (Queue full) + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_dequeue -- Dequeue a workload from the processing queue +; IN: Nothing +; OUT: RAX = Address of code to execute (Set to 0 if queue is empty) +; RDI = Variable +os_smp_dequeue: + push rsi + push rcx + +os_smp_dequeue_spin: + bt word [os_QueueLock], 0 ; Check if the mutex is free + jc os_smp_dequeue_spin ; If not check it again + lock ; The mutex was free, lock the bus + bts word [os_QueueLock], 0 ; Try to grab the mutex + jc os_smp_dequeue_spin ; Jump if we were unsuccessful + + cmp word [os_QueueLen], 0 + je os_smp_dequeue_fail + + xor ecx, ecx + mov rsi, cpuqueue + mov cx, [cpuqueuestart] + shl rcx, 4 ; Quickly multiply RCX by 16 + add rsi, rcx + + lodsq ; Load the code address into RAX + push rax + lodsq ; Load the variable + mov rdi, rax + pop rax + + sub word [os_QueueLen], 1 + shr rcx, 4 ; Quickly divide RCX by 16 + add cx, 1 + cmp cx, [cpuqueuemax] + jne os_smp_dequeue_end + xor cx, cx ; We wrap around + +os_smp_dequeue_end: + mov word [cpuqueuestart], cx + pop rcx + pop rsi + btr word [os_QueueLock], 0 ; Release the lock + clc ; If we got here then ok + ret + +os_smp_dequeue_fail: + xor rax, rax + pop rcx + pop rsi + btr word [os_QueueLock], 0 ; Release the lock + stc + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_run -- Call the code address stored in RAX +; IN: RAX = Address of code to execute +; OUT: Nothing +os_smp_run: + call rax ; Run the code + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_queuelen -- Returns the number of items in the processing queue +; IN: Nothing +; OUT: RAX = number of items in processing queue +os_smp_queuelen: + xor eax, eax + mov ax, [os_QueueLen] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_numcores -- Returns the number of cores in this computer +; IN: Nothing +; OUT: RAX = number of cores in this computer +os_smp_numcores: + xor eax, eax + mov ax, [os_NumCores] + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_wait -- Wait until all other CPU Cores are finished processing +; IN: Nothing +; OUT: Nothing. All registers preserved. +os_smp_wait: + push rsi + push rcx + push rbx + push rax + + call os_smp_get_id + mov rbx, rax + + xor eax, eax + xor ecx, ecx + mov rsi, cpustatus + +checkit: + lodsb + cmp rbx, rcx ; Check to see if it is looking at itself + je skipit ; If so then skip as it shouild be marked as busy + bt ax, 0 ; Check the Present bit + jnc skipit ; If carry is not set then the CPU does not exist + bt ax, 1 ; Check the Ready/Busy bit + jnc skipit ; If carry is not set then the CPU is Ready + sub rsi, 1 + jmp checkit ; Core is marked as Busy, check it again +skipit: + add rcx, 1 + cmp rcx, 256 + jne checkit + + pop rax + pop rbx + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_lock -- Attempt to lock a mutex +; IN: RAX = Address of lock variable +; OUT: Nothing. All registers preserved. +os_smp_lock: + bt word [rax], 0 ; Check if the mutex is free (Bit 0 cleared to 0) + jc os_smp_lock ; If not check it again + lock ; The mutex was free, lock the bus + bts word [rax], 0 ; Try to grab the mutex (Bit 0 set to 1) + jc os_smp_lock ; Jump if we were unsuccessful + ret ; Lock acquired. Return to the caller +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_smp_unlock -- Unlock a mutex +; IN: RAX = Address of lock variable +; OUT: Nothing. All registers preserved. +os_smp_unlock: + btr word [rax], 0 ; Release the lock (Bit 0 cleared to 0) + ret ; Lock released. Return to the caller +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/sound.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/sound.asm index 8b51c424..e4d7bb46 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/sound.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/sound.asm @@ -1,77 +1,77 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; PC Speaker Sound Functions -; ============================================================================= - -align 16 -db 'DEBUG: SOUND ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_speaker_tone -- Generate a tone on the PC speaker -; IN: RAX = note frequency -; OUT: All registers preserved -; Note: Call os_speaker_off to stop the tone -os_speaker_tone: - push rax - push rcx - - mov cx, ax ; Store note value for now - mov al, 182 - out 0x43, al ; System timers.. - mov ax, cx ; Set up frequency - out 0x42, al - mov al, ah ; 64-bit mode.... AH allowed???? - out 0x42, al - in al, 0x61 ; Switch PC speaker on - or al, 0x03 - out 0x61, al - - pop rcx - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_speaker_off -- Turn off PC speaker -; IN: Nothing -; OUT: All registers preserved -os_speaker_off: - push rax - - in al, 0x61 ; Switch PC speaker off - and al, 0xFC - out 0x61, al - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_speaker_beep -- Create a standard OS beep -; IN: Nothing -; OUT: All registers preserved -os_speaker_beep: - push rax - push rcx - - xor eax, eax - mov ax, 0x0C80 - call os_speaker_tone - mov ax, 2 ; A quarter of a second - call os_delay - call os_speaker_off - - pop rcx - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; PC Speaker Sound Functions +; ============================================================================= + +align 16 +db 'DEBUG: SOUND ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_speaker_tone -- Generate a tone on the PC speaker +; IN: RAX = note frequency +; OUT: All registers preserved +; Note: Call os_speaker_off to stop the tone +os_speaker_tone: + push rax + push rcx + + mov cx, ax ; Store note value for now + mov al, 182 + out 0x43, al ; System timers.. + mov ax, cx ; Set up frequency + out 0x42, al + mov al, ah ; 64-bit mode.... AH allowed???? + out 0x42, al + in al, 0x61 ; Switch PC speaker on + or al, 0x03 + out 0x61, al + + pop rcx + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_speaker_off -- Turn off PC speaker +; IN: Nothing +; OUT: All registers preserved +os_speaker_off: + push rax + + in al, 0x61 ; Switch PC speaker off + and al, 0xFC + out 0x61, al + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_speaker_beep -- Create a standard OS beep +; IN: Nothing +; OUT: All registers preserved +os_speaker_beep: + push rax + push rcx + + xor eax, eax + mov ax, 0x0C80 + call os_speaker_tone + mov ax, 2 ; A quarter of a second + call os_delay + call os_speaker_off + + pop rcx + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/syscalls/string.asm b/amd64/bareMetalOS-0.5.3/os/syscalls/string.asm index 54a0b42a..1193a7a3 100644 --- a/amd64/bareMetalOS-0.5.3/os/syscalls/string.asm +++ b/amd64/bareMetalOS-0.5.3/os/syscalls/string.asm @@ -1,745 +1,745 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; String Functions -; ============================================================================= - -align 16 -db 'DEBUG: STRING ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_int_to_string -- Convert a binary interger into an string -; IN: RAX = binary integer -; RDI = location to store string -; OUT: RDI = points to end of string -; All other registers preserved -; Min return value is 0 and max return value is 18446744073709551615 so your -; string needs to be able to store at least 21 characters (20 for the digits -; and 1 for the string terminator). -; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s -os_int_to_string: - push rdx - push rcx - push rbx - push rax - - mov rbx, 10 ; base of the decimal system - xor ecx, ecx ; number of digits generated -os_int_to_string_next_divide: - xor edx, edx ; RAX extended to (RDX,RAX) - div rbx ; divide by the number-base - push rdx ; save remainder on the stack - inc rcx ; and count this remainder - cmp rax, 0 ; was the quotient zero? - jne os_int_to_string_next_divide ; no, do another division - -os_int_to_string_next_digit: - pop rax ; else pop recent remainder - add al, '0' ; and convert to a numeral - stosb ; store to memory-buffer - loop os_int_to_string_next_digit ; again for other remainders - xor al, al - stosb ; Store the null terminator at the end of the string - - pop rax - pop rbx - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_to_int -- Convert a string into a binary interger -; IN: RSI = location of string -; OUT: RAX = integer value -; All other registers preserved -; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/uint2rax.s -os_string_to_int: - push rsi - push rdx - push rcx - push rbx - - xor eax, eax ; initialize accumulator - mov rbx, 10 ; decimal-system's radix -os_string_to_int_next_digit: - mov cl, [rsi] ; fetch next character - cmp cl, '0' ; char preceeds '0'? - jb os_string_to_int_invalid ; yes, not a numeral - cmp cl, '9' ; char follows '9'? - ja os_string_to_int_invalid ; yes, not a numeral - mul rbx ; ten times prior sum - and rcx, 0x0F ; convert char to int - add rax, rcx ; add to prior total - inc rsi ; advance source index - jmp os_string_to_int_next_digit ; and check another char - -os_string_to_int_invalid: - pop rbx - pop rcx - pop rdx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_int_to_hex_string -- Convert an integer to a hex string -; IN: RAX = Integer value -; RDI = location to store string -; OUT: All registers preserved -os_int_to_hex_string: - push rdi - push rdx - push rcx - push rbx - push rax - - mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes -os_int_to_hex_string_next_nibble: - rol rax, 4 ; next nibble into AL - mov bl, al ; copy nibble into BL - and rbx, 0x0F ; and convert to word - mov dl, [hextable + rbx] ; lookup ascii numeral - push rax - mov al, dl - stosb - pop rax - loop os_int_to_hex_string_next_nibble ; again for next nibble - xor eax, eax ; clear RAX to 0 - stosb ; Store AL to terminate string - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_hex_string_to_int -- Convert up to 8 hexascii to bin -; IN: RSI = Location of hex asciiz string -; OUT: RAX = binary value of hex string -; All other registers preserved -os_hex_string_to_int: - push rsi - push rcx - push rbx - - cld - xor ebx, ebx -os_hex_string_to_int_loop: - lodsb - mov cl, 4 - cmp al, 'a' - jb os_hex_string_to_int_ok - sub al, 0x20 ; convert to upper case if alpha -os_hex_string_to_int_ok: - sub al, '0' ; check if legal - jc os_hex_string_to_int_exit ; jmp if out of range - cmp al, 9 - jle os_hex_string_to_int_got ; jmp if number is 0-9 - sub al, 7 ; convert to number from A-F or 10-15 - cmp al, 15 ; check if legal - ja os_hex_string_to_int_exit ; jmp if illegal hex char -os_hex_string_to_int_got: - shl rbx, cl - or bl, al - jmp os_hex_string_to_int_loop -os_hex_string_to_int_exit: - mov rax, rbx ; int value stored in RBX, move to RAX - - pop rbx - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_length -- Return length of a string -; IN: RSI = string location -; OUT: RCX = length (not including the NULL terminator) -; All other registers preserved -os_string_length: - push rdi - push rax - - xor ecx, ecx - xor eax, eax - mov rdi, rsi - not rcx - cld - repne scasb ; compare byte at RDI to value in AL - not rcx - dec rcx - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_find_char -- Find first location of character in a string -; IN: RSI = string location -; AL = character to find -; OUT: RAX = location in string, or 0 if char not present -; All other registers preserved -os_string_find_char: - push rsi - push rcx - - mov rcx, 1 ; Counter -- start at first char -os_string_find_char_more: - cmp byte [rsi], al - je os_string_find_char_done - cmp byte [rsi], 0 - je os_string_find_char_not_found - inc rsi - inc rcx - jmp os_string_find_char_more - -os_string_find_char_done: - mov rax, rcx - - pop rcx - pop rsi - ret - -os_string_find_char_not_found: - pop rcx - pop rsi - xor eax, eax ; not found, set RAX to 0 - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_change_char -- Change all instances of a character in a string -; IN: RSI = string location -; AL = character to replace -; BL = replacement character -; OUT: All registers preserved -os_string_change_char: - push rsi - push rcx - push rbx - push rax - - mov cl, al -os_string_change_char_loop: - mov byte al, [rsi] - cmp al, 0 - je os_string_change_char_done - cmp al, cl - jne os_string_change_char_no_change - mov byte [rsi], bl - -os_string_change_char_no_change: - inc rsi - jmp os_string_change_char_loop - -os_string_change_char_done: - pop rax - pop rbx - pop rcx - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_copy -- Copy the contents of one string into another -; IN: RSI = source -; RDI = destination -; OUT: All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_copy: - push rsi - push rdi - push rax - -os_string_copy_more: - lodsb ; Load a character from the source string - stosb - cmp al, 0 ; If source string is empty, quit out - jne os_string_copy_more - - pop rax - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_truncate -- Chop string down to specified number of characters -; IN: RSI = string location -; RAX = number of characters -; OUT: All registers preserved -os_string_truncate: - push rsi - - add rsi, rax - mov byte [rsi], 0x00 - - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_join -- Join two strings into a third string -; IN: RAX = string one -; RBX = string two -; RDI = destination string -; OUT: All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_join: - push rsi - push rdi - push rcx - push rbx - push rax - - mov rsi, rax ; Copy first string to location in RDI - call os_string_copy - call os_string_length ; Get length of first string - add rdi, rcx ; Position at end of first string - mov rsi, rbx ; Add second string onto it - call os_string_copy - - pop rax - pop rbx - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_append -- Append a string to an existing string -; IN: RSI = String to be appended -; RDI = Destination string -; OUT: All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_append: - push rsi - push rdi - push rcx - - xchg rsi, rdi - call os_string_length - xchg rsi, rdi - add rdi, rcx - call os_string_copy - - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_chomp -- Strip leading and trailing spaces from a string -; IN: RSI = string location -; OUT: All registers preserved -os_string_chomp: - push rsi - push rdi - push rcx - push rax - - call os_string_length ; Quick check to see if there are any characters in the string - jrcxz os_string_chomp_done ; No need to work on it if there is no data - - mov rdi, rsi ; RDI will point to the start of the string... - push rdi ; ...while RSI will point to the "actual" start (without the spaces) - add rdi, rcx ; os_string_length stored the length in RCX - -os_string_chomp_findend: ; we start at the end of the string and move backwards until we don't find a space - dec rdi - cmp rsi, rdi ; Check to make sure we are not reading backward past the string start - jg os_string_chomp_fail ; If so then fail (string only contained spaces) - cmp byte [rdi], ' ' - je os_string_chomp_findend - - inc rdi ; we found the real end of the string so null terminate it - mov byte [rdi], 0x00 - pop rdi - -os_string_chomp_start_count: ; read through string until we find a non-space character - cmp byte [rsi], ' ' - jne os_string_chomp_copy - inc rsi - jmp os_string_chomp_start_count - -os_string_chomp_fail: ; In this situataion the string is all spaces - pop rdi ; We are about to bail out so make sure the stack is sane - mov al, 0x00 - stosb - jmp os_string_chomp_done - -; At this point RSI points to the actual start of the string (minus the leading spaces, if any) -; And RDI point to the start of the string - -os_string_chomp_copy: ; Copy a byte from RSI to RDI one byte at a time until we find a NULL - lodsb - stosb - cmp al, 0x00 - jne os_string_chomp_copy - -os_string_chomp_done: - pop rax - pop rcx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_strip -- Removes specified character from a string -; IN: RSI = string location -; AL = character to remove -; OUT: All registers preserved -os_string_strip: - push rsi - push rdi - push rbx - push rax - - mov rdi, rsi - mov bl, al ; copy the char into BL since LODSB and STOSB use AL -os_string_strip_nextchar: - lodsb - stosb - cmp al, 0x00 ; check if we reached the end of the string - je os_string_strip_done ; if so bail out - cmp al, bl ; check to see if the character we read is the interesting char - jne os_string_strip_nextchar ; if not skip to the next character - -os_string_strip_skip: ; if so the fall through to here - dec rdi ; decrement RDI so we overwrite on the next pass - jmp os_string_strip_nextchar - -os_string_strip_done: - pop rax - pop rbx - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_compare -- See if two strings match -; IN: RSI = string one -; RDI = string two -; OUT: Carry flag set if same -os_string_compare: - push rsi - push rdi - push rbx - push rax - -os_string_compare_more: - mov al, [rsi] ; Store string contents - mov bl, [rdi] - cmp al, 0 ; End of first string? - je os_string_compare_terminated - cmp al, bl - jne os_string_compare_not_same - inc rsi - inc rdi - jmp os_string_compare_more - -os_string_compare_not_same: - pop rax - pop rbx - pop rdi - pop rsi - clc - ret - -os_string_compare_terminated: - cmp bl, 0 ; End of second string? - jne os_string_compare_not_same - - pop rax - pop rbx - pop rdi - pop rsi - stc - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_uppercase -- Convert zero-terminated string to uppercase -; IN: RSI = string location -; OUT: All registers preserved -os_string_uppercase: - push rsi - -os_string_uppercase_more: - cmp byte [rsi], 0x00 ; Zero-termination of string? - je os_string_uppercase_done ; If so, quit - cmp byte [rsi], 97 ; In the uppercase A to Z range? - jl os_string_uppercase_noatoz - cmp byte [rsi], 122 - jg os_string_uppercase_noatoz - sub byte [rsi], 0x20 ; If so, convert input char to uppercase - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_noatoz: - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_done: - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_lowercase -- Convert zero-terminated string to lowercase -; IN: RSI = string location -; OUT: All registers preserved -os_string_lowercase: - push rsi - -os_string_lowercase_more: - cmp byte [rsi], 0x00 ; Zero-termination of string? - je os_string_lowercase_done ; If so, quit - cmp byte [rsi], 65 ; In the lowercase A to Z range? - jl os_string_lowercase_noatoz - cmp byte [rsi], 90 - jg os_string_lowercase_noatoz - add byte [rsi], 0x20 ; If so, convert input char to lowercase - inc rsi - jmp os_string_lowercase_more - -os_string_lowercase_noatoz: - inc rsi - jmp os_string_lowercase_more - -os_string_lowercase_done: - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_time_string -- Store the current time in a string in format "HH:MM:SS" -; IN: RDI = location to store string (must be able to fit 9 bytes, 8 data plus null terminator) -; OUT: All registers preserved -os_get_time_string: - push rdi - push rbx - push rax - -os_get_time_string_wait: - mov al, 10 - out 0x70, al - in al, 0x71 - test al, 0x80 ; Is there an update in progress? - jne os_get_time_string_wait ; If so then try again - mov al, 0x04 ; Hours - out 0x70, al - xor eax, eax - in al, 0x71 - cmp al, 9 - jg os_get_time_string_lead_hours - call os_leading_zero -os_get_time_string_lead_hours: - call os_int_to_string - sub rdi, 1 - mov al, ':' - stosb - mov al, 0x02 ; Minutes - out 0x70, al - xor eax, eax - in al, 0x71 - cmp al, 9 - jg os_get_time_string_lead_minutes - call os_leading_zero -os_get_time_string_lead_minutes: - call os_int_to_string - sub rdi, 1 - mov al, ':' - stosb - mov al, 0x00 ; Seconds - out 0x70, al - xor eax, eax - in al, 0x71 - cmp al, 9 - jg os_get_time_string_lead_seconds - call os_leading_zero -os_get_time_string_lead_seconds: - call os_int_to_string - stosb - - pop rax - pop rbx - pop rdi - ret - -os_leading_zero: - push ax - mov al, '0' - stosb - pop ax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_get_date_string -- Store the current time in a string in format "YYYY/MM/DD" -; IN: RDI = location to store string (must be able to fit 11 bytes, 10 data plus null terminator) -; OUT: All registers preserved -; Note: Uses the os_get_time_string_processor function -os_get_date_string: - push rdi - push rbx - push rax - -os_get_date_string_wait: - mov al, 10 - out 0x70, al - in al, 0x71 - test al, 0x80 ; Is there an update in progress? - jne os_get_date_string_wait ; If so then try again -; mov al, 0x32 ; Century -; out 0x70, al - xor eax, eax -; in al, 0x71 - mov al, 20 - call os_int_to_string - sub rdi, 1 - mov al, 0x09 ; Year - out 0x70, al - xor eax, eax - in al, 0x71 - call os_int_to_string - sub rdi, 1 - mov al, '/' - stosb - mov al, 0x08 ; Month - out 0x70, al - xor eax, eax - in al, 0x71 - call os_int_to_string - sub rdi, 1 - mov al, '/' - stosb - mov al, 0x07 ; Day - out 0x70, al - xor eax, eax - in al, 0x71 - call os_int_to_string -; sub rdi, 1 -; mov al, 0x00 ; Terminate the string - stosb - - pop rax - pop rbx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_is_digit -- Check if character is a digit -; IN: AL = ASCII char -; OUT: EQ flag set if numeric -; Note: JE (Jump if Equal) can be used after this function is called -os_is_digit: - cmp al, '0' - jb os_is_digit_not_digit - cmp al, '9' - ja os_is_digit_not_digit - cmp al, al ; To set the equal flag - -os_is_digit_not_digit: - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_is_alpha -- Check if character is a letter -; IN: AL = ASCII char -; OUT: EQ flag set if alpha -; Note: JE (Jump if Equal) can be used after this function is called -os_is_alpha: - cmp al, ' ' - jb os_is_alpha_not_alpha - cmp al, 0x7E - ja os_is_alpha_not_alpha - cmp al, al ; To set the equal flag - -os_is_alpha_not_alpha: - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_parse -- Parse a string into individual words -; IN: RSI = Address of string -; OUT: RCX = word count -; Note: This function will remove "extra" whitespace in the source string -; "This is a test. " will update to "This is a test." -os_string_parse: - push rsi - push rdi - push rax - - xor ecx, ecx ; RCX is our word counter - mov rdi, rsi - - call os_string_chomp ; Remove leading and trailing spaces - - cmp byte [rsi], 0x00 ; Check the first byte - je os_string_parse_done ; If it is a null then bail out - inc rcx ; At this point we know we have at least one word - -os_string_parse_next_char: - lodsb - stosb - cmp al, 0x00 ; Check if we are at the end - je os_string_parse_done ; If so then bail out - cmp al, ' ' ; Is it a space? - je os_string_parse_found_a_space - jmp os_string_parse_next_char ; If not then grab the next char - -os_string_parse_found_a_space: - lodsb ; We found a space.. grab the next char - cmp al, ' ' ; Is it a space as well? - jne os_string_parse_no_more_spaces - jmp os_string_parse_found_a_space - -os_string_parse_no_more_spaces: - dec rsi ; Decrement so the next lodsb will read in the non-space - inc rcx - jmp os_string_parse_next_char - -os_string_parse_done: - pop rax - pop rdi - pop rsi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; String Functions +; ============================================================================= + +align 16 +db 'DEBUG: STRING ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_int_to_string -- Convert a binary interger into an string +; IN: RAX = binary integer +; RDI = location to store string +; OUT: RDI = points to end of string +; All other registers preserved +; Min return value is 0 and max return value is 18446744073709551615 so your +; string needs to be able to store at least 21 characters (20 for the digits +; and 1 for the string terminator). +; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s +os_int_to_string: + push rdx + push rcx + push rbx + push rax + + mov rbx, 10 ; base of the decimal system + xor ecx, ecx ; number of digits generated +os_int_to_string_next_divide: + xor edx, edx ; RAX extended to (RDX,RAX) + div rbx ; divide by the number-base + push rdx ; save remainder on the stack + inc rcx ; and count this remainder + cmp rax, 0 ; was the quotient zero? + jne os_int_to_string_next_divide ; no, do another division + +os_int_to_string_next_digit: + pop rax ; else pop recent remainder + add al, '0' ; and convert to a numeral + stosb ; store to memory-buffer + loop os_int_to_string_next_digit ; again for other remainders + xor al, al + stosb ; Store the null terminator at the end of the string + + pop rax + pop rbx + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_to_int -- Convert a string into a binary interger +; IN: RSI = location of string +; OUT: RAX = integer value +; All other registers preserved +; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/uint2rax.s +os_string_to_int: + push rsi + push rdx + push rcx + push rbx + + xor eax, eax ; initialize accumulator + mov rbx, 10 ; decimal-system's radix +os_string_to_int_next_digit: + mov cl, [rsi] ; fetch next character + cmp cl, '0' ; char preceeds '0'? + jb os_string_to_int_invalid ; yes, not a numeral + cmp cl, '9' ; char follows '9'? + ja os_string_to_int_invalid ; yes, not a numeral + mul rbx ; ten times prior sum + and rcx, 0x0F ; convert char to int + add rax, rcx ; add to prior total + inc rsi ; advance source index + jmp os_string_to_int_next_digit ; and check another char + +os_string_to_int_invalid: + pop rbx + pop rcx + pop rdx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_int_to_hex_string -- Convert an integer to a hex string +; IN: RAX = Integer value +; RDI = location to store string +; OUT: All registers preserved +os_int_to_hex_string: + push rdi + push rdx + push rcx + push rbx + push rax + + mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes +os_int_to_hex_string_next_nibble: + rol rax, 4 ; next nibble into AL + mov bl, al ; copy nibble into BL + and rbx, 0x0F ; and convert to word + mov dl, [hextable + rbx] ; lookup ascii numeral + push rax + mov al, dl + stosb + pop rax + loop os_int_to_hex_string_next_nibble ; again for next nibble + xor eax, eax ; clear RAX to 0 + stosb ; Store AL to terminate string + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_hex_string_to_int -- Convert up to 8 hexascii to bin +; IN: RSI = Location of hex asciiz string +; OUT: RAX = binary value of hex string +; All other registers preserved +os_hex_string_to_int: + push rsi + push rcx + push rbx + + cld + xor ebx, ebx +os_hex_string_to_int_loop: + lodsb + mov cl, 4 + cmp al, 'a' + jb os_hex_string_to_int_ok + sub al, 0x20 ; convert to upper case if alpha +os_hex_string_to_int_ok: + sub al, '0' ; check if legal + jc os_hex_string_to_int_exit ; jmp if out of range + cmp al, 9 + jle os_hex_string_to_int_got ; jmp if number is 0-9 + sub al, 7 ; convert to number from A-F or 10-15 + cmp al, 15 ; check if legal + ja os_hex_string_to_int_exit ; jmp if illegal hex char +os_hex_string_to_int_got: + shl rbx, cl + or bl, al + jmp os_hex_string_to_int_loop +os_hex_string_to_int_exit: + mov rax, rbx ; int value stored in RBX, move to RAX + + pop rbx + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_length -- Return length of a string +; IN: RSI = string location +; OUT: RCX = length (not including the NULL terminator) +; All other registers preserved +os_string_length: + push rdi + push rax + + xor ecx, ecx + xor eax, eax + mov rdi, rsi + not rcx + cld + repne scasb ; compare byte at RDI to value in AL + not rcx + dec rcx + + pop rax + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_find_char -- Find first location of character in a string +; IN: RSI = string location +; AL = character to find +; OUT: RAX = location in string, or 0 if char not present +; All other registers preserved +os_string_find_char: + push rsi + push rcx + + mov rcx, 1 ; Counter -- start at first char +os_string_find_char_more: + cmp byte [rsi], al + je os_string_find_char_done + cmp byte [rsi], 0 + je os_string_find_char_not_found + inc rsi + inc rcx + jmp os_string_find_char_more + +os_string_find_char_done: + mov rax, rcx + + pop rcx + pop rsi + ret + +os_string_find_char_not_found: + pop rcx + pop rsi + xor eax, eax ; not found, set RAX to 0 + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_change_char -- Change all instances of a character in a string +; IN: RSI = string location +; AL = character to replace +; BL = replacement character +; OUT: All registers preserved +os_string_change_char: + push rsi + push rcx + push rbx + push rax + + mov cl, al +os_string_change_char_loop: + mov byte al, [rsi] + cmp al, 0 + je os_string_change_char_done + cmp al, cl + jne os_string_change_char_no_change + mov byte [rsi], bl + +os_string_change_char_no_change: + inc rsi + jmp os_string_change_char_loop + +os_string_change_char_done: + pop rax + pop rbx + pop rcx + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_copy -- Copy the contents of one string into another +; IN: RSI = source +; RDI = destination +; OUT: All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_copy: + push rsi + push rdi + push rax + +os_string_copy_more: + lodsb ; Load a character from the source string + stosb + cmp al, 0 ; If source string is empty, quit out + jne os_string_copy_more + + pop rax + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_truncate -- Chop string down to specified number of characters +; IN: RSI = string location +; RAX = number of characters +; OUT: All registers preserved +os_string_truncate: + push rsi + + add rsi, rax + mov byte [rsi], 0x00 + + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_join -- Join two strings into a third string +; IN: RAX = string one +; RBX = string two +; RDI = destination string +; OUT: All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_join: + push rsi + push rdi + push rcx + push rbx + push rax + + mov rsi, rax ; Copy first string to location in RDI + call os_string_copy + call os_string_length ; Get length of first string + add rdi, rcx ; Position at end of first string + mov rsi, rbx ; Add second string onto it + call os_string_copy + + pop rax + pop rbx + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_append -- Append a string to an existing string +; IN: RSI = String to be appended +; RDI = Destination string +; OUT: All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_append: + push rsi + push rdi + push rcx + + xchg rsi, rdi + call os_string_length + xchg rsi, rdi + add rdi, rcx + call os_string_copy + + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_chomp -- Strip leading and trailing spaces from a string +; IN: RSI = string location +; OUT: All registers preserved +os_string_chomp: + push rsi + push rdi + push rcx + push rax + + call os_string_length ; Quick check to see if there are any characters in the string + jrcxz os_string_chomp_done ; No need to work on it if there is no data + + mov rdi, rsi ; RDI will point to the start of the string... + push rdi ; ...while RSI will point to the "actual" start (without the spaces) + add rdi, rcx ; os_string_length stored the length in RCX + +os_string_chomp_findend: ; we start at the end of the string and move backwards until we don't find a space + dec rdi + cmp rsi, rdi ; Check to make sure we are not reading backward past the string start + jg os_string_chomp_fail ; If so then fail (string only contained spaces) + cmp byte [rdi], ' ' + je os_string_chomp_findend + + inc rdi ; we found the real end of the string so null terminate it + mov byte [rdi], 0x00 + pop rdi + +os_string_chomp_start_count: ; read through string until we find a non-space character + cmp byte [rsi], ' ' + jne os_string_chomp_copy + inc rsi + jmp os_string_chomp_start_count + +os_string_chomp_fail: ; In this situataion the string is all spaces + pop rdi ; We are about to bail out so make sure the stack is sane + mov al, 0x00 + stosb + jmp os_string_chomp_done + +; At this point RSI points to the actual start of the string (minus the leading spaces, if any) +; And RDI point to the start of the string + +os_string_chomp_copy: ; Copy a byte from RSI to RDI one byte at a time until we find a NULL + lodsb + stosb + cmp al, 0x00 + jne os_string_chomp_copy + +os_string_chomp_done: + pop rax + pop rcx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_strip -- Removes specified character from a string +; IN: RSI = string location +; AL = character to remove +; OUT: All registers preserved +os_string_strip: + push rsi + push rdi + push rbx + push rax + + mov rdi, rsi + mov bl, al ; copy the char into BL since LODSB and STOSB use AL +os_string_strip_nextchar: + lodsb + stosb + cmp al, 0x00 ; check if we reached the end of the string + je os_string_strip_done ; if so bail out + cmp al, bl ; check to see if the character we read is the interesting char + jne os_string_strip_nextchar ; if not skip to the next character + +os_string_strip_skip: ; if so the fall through to here + dec rdi ; decrement RDI so we overwrite on the next pass + jmp os_string_strip_nextchar + +os_string_strip_done: + pop rax + pop rbx + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_compare -- See if two strings match +; IN: RSI = string one +; RDI = string two +; OUT: Carry flag set if same +os_string_compare: + push rsi + push rdi + push rbx + push rax + +os_string_compare_more: + mov al, [rsi] ; Store string contents + mov bl, [rdi] + cmp al, 0 ; End of first string? + je os_string_compare_terminated + cmp al, bl + jne os_string_compare_not_same + inc rsi + inc rdi + jmp os_string_compare_more + +os_string_compare_not_same: + pop rax + pop rbx + pop rdi + pop rsi + clc + ret + +os_string_compare_terminated: + cmp bl, 0 ; End of second string? + jne os_string_compare_not_same + + pop rax + pop rbx + pop rdi + pop rsi + stc + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_uppercase -- Convert zero-terminated string to uppercase +; IN: RSI = string location +; OUT: All registers preserved +os_string_uppercase: + push rsi + +os_string_uppercase_more: + cmp byte [rsi], 0x00 ; Zero-termination of string? + je os_string_uppercase_done ; If so, quit + cmp byte [rsi], 97 ; In the uppercase A to Z range? + jl os_string_uppercase_noatoz + cmp byte [rsi], 122 + jg os_string_uppercase_noatoz + sub byte [rsi], 0x20 ; If so, convert input char to uppercase + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_noatoz: + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_done: + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_lowercase -- Convert zero-terminated string to lowercase +; IN: RSI = string location +; OUT: All registers preserved +os_string_lowercase: + push rsi + +os_string_lowercase_more: + cmp byte [rsi], 0x00 ; Zero-termination of string? + je os_string_lowercase_done ; If so, quit + cmp byte [rsi], 65 ; In the lowercase A to Z range? + jl os_string_lowercase_noatoz + cmp byte [rsi], 90 + jg os_string_lowercase_noatoz + add byte [rsi], 0x20 ; If so, convert input char to lowercase + inc rsi + jmp os_string_lowercase_more + +os_string_lowercase_noatoz: + inc rsi + jmp os_string_lowercase_more + +os_string_lowercase_done: + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_time_string -- Store the current time in a string in format "HH:MM:SS" +; IN: RDI = location to store string (must be able to fit 9 bytes, 8 data plus null terminator) +; OUT: All registers preserved +os_get_time_string: + push rdi + push rbx + push rax + +os_get_time_string_wait: + mov al, 10 + out 0x70, al + in al, 0x71 + test al, 0x80 ; Is there an update in progress? + jne os_get_time_string_wait ; If so then try again + mov al, 0x04 ; Hours + out 0x70, al + xor eax, eax + in al, 0x71 + cmp al, 9 + jg os_get_time_string_lead_hours + call os_leading_zero +os_get_time_string_lead_hours: + call os_int_to_string + sub rdi, 1 + mov al, ':' + stosb + mov al, 0x02 ; Minutes + out 0x70, al + xor eax, eax + in al, 0x71 + cmp al, 9 + jg os_get_time_string_lead_minutes + call os_leading_zero +os_get_time_string_lead_minutes: + call os_int_to_string + sub rdi, 1 + mov al, ':' + stosb + mov al, 0x00 ; Seconds + out 0x70, al + xor eax, eax + in al, 0x71 + cmp al, 9 + jg os_get_time_string_lead_seconds + call os_leading_zero +os_get_time_string_lead_seconds: + call os_int_to_string + stosb + + pop rax + pop rbx + pop rdi + ret + +os_leading_zero: + push ax + mov al, '0' + stosb + pop ax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_get_date_string -- Store the current time in a string in format "YYYY/MM/DD" +; IN: RDI = location to store string (must be able to fit 11 bytes, 10 data plus null terminator) +; OUT: All registers preserved +; Note: Uses the os_get_time_string_processor function +os_get_date_string: + push rdi + push rbx + push rax + +os_get_date_string_wait: + mov al, 10 + out 0x70, al + in al, 0x71 + test al, 0x80 ; Is there an update in progress? + jne os_get_date_string_wait ; If so then try again +; mov al, 0x32 ; Century +; out 0x70, al + xor eax, eax +; in al, 0x71 + mov al, 20 + call os_int_to_string + sub rdi, 1 + mov al, 0x09 ; Year + out 0x70, al + xor eax, eax + in al, 0x71 + call os_int_to_string + sub rdi, 1 + mov al, '/' + stosb + mov al, 0x08 ; Month + out 0x70, al + xor eax, eax + in al, 0x71 + call os_int_to_string + sub rdi, 1 + mov al, '/' + stosb + mov al, 0x07 ; Day + out 0x70, al + xor eax, eax + in al, 0x71 + call os_int_to_string +; sub rdi, 1 +; mov al, 0x00 ; Terminate the string + stosb + + pop rax + pop rbx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_is_digit -- Check if character is a digit +; IN: AL = ASCII char +; OUT: EQ flag set if numeric +; Note: JE (Jump if Equal) can be used after this function is called +os_is_digit: + cmp al, '0' + jb os_is_digit_not_digit + cmp al, '9' + ja os_is_digit_not_digit + cmp al, al ; To set the equal flag + +os_is_digit_not_digit: + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_is_alpha -- Check if character is a letter +; IN: AL = ASCII char +; OUT: EQ flag set if alpha +; Note: JE (Jump if Equal) can be used after this function is called +os_is_alpha: + cmp al, ' ' + jb os_is_alpha_not_alpha + cmp al, 0x7E + ja os_is_alpha_not_alpha + cmp al, al ; To set the equal flag + +os_is_alpha_not_alpha: + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_parse -- Parse a string into individual words +; IN: RSI = Address of string +; OUT: RCX = word count +; Note: This function will remove "extra" whitespace in the source string +; "This is a test. " will update to "This is a test." +os_string_parse: + push rsi + push rdi + push rax + + xor ecx, ecx ; RCX is our word counter + mov rdi, rsi + + call os_string_chomp ; Remove leading and trailing spaces + + cmp byte [rsi], 0x00 ; Check the first byte + je os_string_parse_done ; If it is a null then bail out + inc rcx ; At this point we know we have at least one word + +os_string_parse_next_char: + lodsb + stosb + cmp al, 0x00 ; Check if we are at the end + je os_string_parse_done ; If so then bail out + cmp al, ' ' ; Is it a space? + je os_string_parse_found_a_space + jmp os_string_parse_next_char ; If not then grab the next char + +os_string_parse_found_a_space: + lodsb ; We found a space.. grab the next char + cmp al, ' ' ; Is it a space as well? + jne os_string_parse_no_more_spaces + jmp os_string_parse_found_a_space + +os_string_parse_no_more_spaces: + dec rsi ; Decrement so the next lodsb will read in the non-space + inc rcx + jmp os_string_parse_next_char + +os_string_parse_done: + pop rax + pop rdi + pop rsi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/os/sysvar.asm b/amd64/bareMetalOS-0.5.3/os/sysvar.asm index 3ade2787..ad6f6aa6 100644 --- a/amd64/bareMetalOS-0.5.3/os/sysvar.asm +++ b/amd64/bareMetalOS-0.5.3/os/sysvar.asm @@ -1,182 +1,182 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; System Variables -; ============================================================================= - -align 16 -db 'DEBUG: SYSVAR ' -align 16 - -; Constants -hextable: db '0123456789ABCDEF' - -; Strings -system_status_header: db 'BareMetal v0.5.3', 0 -readymsg: db 'BareMetal is ready.', 0 -networkmsg: db 'Network Address: ', 0 -prompt: db '> ', 0 -space: db ' ', 0 -newline: db 13, 0 -appextension: db '.APP', 0 -memory_message: db 'Not enough system memory for CPU stacks! System halted.', 0 -startupapp: db 'startup.app', 0 - -; Memory addresses -hdbuffer0: equ 0x0000000000070000 ; 32768 bytes 0x070000 -> 0x077FFF -hdbuffer1: equ 0x0000000000078000 ; 32768 bytes 0x078000 -> 0x07FFFF -cli_temp_string: equ 0x0000000000080000 ; 1024 bytes 0x080000 -> 0x0803FF -os_temp_string: equ 0x0000000000080400 ; 1024 bytes 0x080400 -> 0x0807FF -secbuffer0: equ 0x0000000000080800 ; 512 bytes 0x080800 -> 0x0809FF -secbuffer1: equ 0x0000000000080A00 ; 512 bytes 0x080A00 -> 0x080BFF -os_args: equ 0x0000000000080C00 -os_KernelStart: equ 0x0000000000100000 ; 65536 bytes 0x100000 -> 0x10FFFF - Location of Kernel -os_SystemVariables: equ 0x0000000000110000 ; 65536 bytes 0x110000 -> 0x11FFFF - Location of System Variables -os_MemoryMap: equ 0x0000000000120000 ; 131072 bytes 0x120000 -> 0x13FFFF - Location of Memory Map - Room to map 256 GiB with 2 MiB pages -os_EthernetBuffer: equ 0x0000000000140000 ; 262144 bytes 0x140000 -> 0x17FFFF - Location of Ethernet RX Ring Buffer - Room for 170 packets -os_screen: equ 0x0000000000180000 ; 4096 bytes 80x25x2 = 4000 -os_ethernet_rx_buffer: equ 0x00000000001C0000 -os_eth_rx_buffer: equ 0x00000000001C8000 -os_ethernet_tx_buffer: equ 0x00000000001D0000 -os_eth_tx_buffer: equ 0x00000000001D8000 -os_eth_temp_buffer: equ 0x00000000001E0000 -cpustatus: equ 0x00000000001FEF00 ; Location of CPU status data (256 bytes) Bit 0 = Avaiable, Bit 1 = Free/Busy -cpuqueue: equ 0x00000000001FF000 ; Location of CPU Queue. Each queue item is 16 bytes. (4KiB before the 2MiB mark, Room for 256 entries) -programlocation: equ 0x0000000000200000 ; Location in memory where programs are loaded (the start of 2MiB) - -; DQ - Starting at offset 0, increments by 0x8 -os_LocalAPICAddress: equ os_SystemVariables + 0x00 -os_IOAPICAddress: equ os_SystemVariables + 0x08 -os_ClockCounter: equ os_SystemVariables + 0x10 -os_RandomSeed: equ os_SystemVariables + 0x18 ; Seed for RNG -screen_cursor_offset: equ os_SystemVariables + 0x20 -hd1_maxlba: equ os_SystemVariables + 0x28 ; 64-bit value since at most it will hold a 48-bit value -os_StackBase: equ os_SystemVariables + 0x30 -os_net_transmit: equ os_SystemVariables + 0x38 -os_net_poll: equ os_SystemVariables + 0x40 -os_net_ack_int: equ os_SystemVariables + 0x48 -os_NetIOBaseMem: equ os_SystemVariables + 0x50 -os_NetMAC: equ os_SystemVariables + 0x58 - -; DD - Starting at offset 128, increments by 4 -cpu_speed: equ os_SystemVariables + 128 ; in MHz -hd1_size: equ os_SystemVariables + 132 ; Size in MiB -ip: equ os_SystemVariables + 136 ; IPv4 Address -sn: equ os_SystemVariables + 140 ; IPv4 Subnet -gw: equ os_SystemVariables + 144 ; IPv4 Gateway - -; DW - Starting at offset 256, increments by 2 -os_MemAmount: equ os_SystemVariables + 256 ; in MiB -os_NumCores: equ os_SystemVariables + 258 -cpuqueuestart: equ os_SystemVariables + 260 -cpuqueuefinish: equ os_SystemVariables + 262 -os_QueueLen: equ os_SystemVariables + 264 -os_QueueLock: equ os_SystemVariables + 266 ; Bit 0 clear for unlocked, set for locked. -os_NetIOAddress: equ os_SystemVariables + 268 -os_EthernetBusyLock: equ os_SystemVariables + 270 - -; DB - Starting at offset 384, increments by 1 -cursorx: equ os_SystemVariables + 384 ; cursor row location -cursory: equ os_SystemVariables + 385 ; cursor column location -scancode: equ os_SystemVariables + 386 -key: equ os_SystemVariables + 387 -key_shift: equ os_SystemVariables + 388 -screen_cursor_x: equ os_SystemVariables + 389 -screen_cursor_y: equ os_SystemVariables + 390 -hd1_enable: equ os_SystemVariables + 391 ; 1 if the drive is there and enabled -hd1_lba48: equ os_SystemVariables + 392 ; 1 if LBA48 is allowed -os_PCIEnabled: equ os_SystemVariables + 393 ; 1 if PCI is detected -os_NetEnabled: equ os_SystemVariables + 394 ; 1 if a supported network card was enabled -os_NetIRQ: equ os_SystemVariables + 395 ; Set to Interrupt line that NIC is connected to -os_NetActivity_TX: equ os_SystemVariables + 396 -os_NetActivity_RX: equ os_SystemVariables + 397 -os_EthernetBuffer_C1: equ os_SystemVariables + 398 ; Counter 1 for the Ethernet RX Ring Buffer -os_EthernetBuffer_C2: equ os_SystemVariables + 399 ; Counter 2 for the Ethernet RX Ring Buffer - - -cpuqueuemax: dw 256 -screen_rows: db 25 ; x -screen_cols: db 80 ; y -os_show_sysstatus: db 1 - -; Function variables -os_debug_dump_reg_stage: db 0x00 - -; File System -fat16_FatStart: dd 0x00000000 -fat16_TotalSectors: dd 0x00000000 -fat16_DataStart: dd 0x00000000 -fat16_RootStart: dd 0x00000000 -fat16_PartitionOffset: dd 0x00000000 -fat16_ReservedSectors: dw 0x0000 -fat16_RootDirEnts: dw 0x0000 -fat16_SectorsPerFat: dw 0x0000 -fat16_BytesPerSector: dw 0x0000 -fat16_SectorsPerCluster: db 0x00 -fat16_Fats: db 0x00 - - -keylayoutlower: -db 0x00, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x0e, 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x1c, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 0, '`', 0, 0, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, ' ', 0 -keylayoutupper: -db 0x00, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x0e, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0x1c, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 0, '~', 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, ' ', 0 -; 0e = backspace -; 1c = enter - -palette: ; These colors are in RGB format. Each color byte is actually 6 bits (0x00 - 0x3F) -db 0x00, 0x00, 0x00 ; 0 Black -db 0x33, 0x00, 0x00 ; 1 Red -db 0x0F, 0x26, 0x01 ; 2 Green -db 0x0D, 0x19, 0x29 ; 3 Blue -db 0x31, 0x28, 0x00 ; 4 Orange -db 0x1D, 0x14, 0x1E ; 5 Purple -db 0x01, 0x26, 0x26 ; 6 Teal -db 0x2A, 0x2A, 0x2A ; 7 Light Gray -db 0x15, 0x15, 0x15 ; 8 Dark Gray -db 0x3B, 0x0A, 0x0A ; 9 Bright Red -db 0x22, 0x38, 0x0D ; 10 Bright Green -db 0x1C, 0x27, 0x33 ; 11 Bright Blue -db 0x3F, 0x3A, 0x13 ; 12 Yellow -db 0x2B, 0x1F, 0x2A ; 13 Bright Purple -db 0x0D, 0x38, 0x38 ; 14 Bright Teal -db 0x3F, 0x3F, 0x3F ; 15 White - - -os_debug_dump_reg_string00: db ' A:', 0 -os_debug_dump_reg_string01: db ' B:', 0 -os_debug_dump_reg_string02: db ' C:', 0 -os_debug_dump_reg_string03: db ' D:', 0 -os_debug_dump_reg_string04: db ' SI:', 0 -os_debug_dump_reg_string05: db ' DI:', 0 -os_debug_dump_reg_string06: db ' BP:', 0 -os_debug_dump_reg_string07: db ' SP:', 0 -os_debug_dump_reg_string08: db ' 8:', 0 -os_debug_dump_reg_string09: db ' 9:', 0 -os_debug_dump_reg_string0A: db ' 10:', 0 -os_debug_dump_reg_string0B: db ' 11:', 0 -os_debug_dump_reg_string0C: db ' 12:', 0 -os_debug_dump_reg_string0D: db ' 13:', 0 -os_debug_dump_reg_string0E: db ' 14:', 0 -os_debug_dump_reg_string0F: db ' 15:', 0 -os_debug_dump_reg_string10: db ' RF:', 0 - -os_debug_dump_flag_string0: db ' C:', 0 -os_debug_dump_flag_string1: db ' Z:', 0 -os_debug_dump_flag_string2: db ' S:', 0 -os_debug_dump_flag_string3: db ' D:', 0 -os_debug_dump_flag_string4: db ' O:', 0 - - -cli_command_string: times 14 db 0 -cli_args: db 0 - -align 16 -this_is_the_end: db 'This is the end.' - -;------------------------------------------------------------------------------ - -SYS64_CODE_SEL equ 8 ; defined by Pure64 - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; System Variables +; ============================================================================= + +align 16 +db 'DEBUG: SYSVAR ' +align 16 + +; Constants +hextable: db '0123456789ABCDEF' + +; Strings +system_status_header: db 'BareMetal v0.5.3', 0 +readymsg: db 'BareMetal is ready.', 0 +networkmsg: db 'Network Address: ', 0 +prompt: db '> ', 0 +space: db ' ', 0 +newline: db 13, 0 +appextension: db '.APP', 0 +memory_message: db 'Not enough system memory for CPU stacks! System halted.', 0 +startupapp: db 'startup.app', 0 + +; Memory addresses +hdbuffer0: equ 0x0000000000070000 ; 32768 bytes 0x070000 -> 0x077FFF +hdbuffer1: equ 0x0000000000078000 ; 32768 bytes 0x078000 -> 0x07FFFF +cli_temp_string: equ 0x0000000000080000 ; 1024 bytes 0x080000 -> 0x0803FF +os_temp_string: equ 0x0000000000080400 ; 1024 bytes 0x080400 -> 0x0807FF +secbuffer0: equ 0x0000000000080800 ; 512 bytes 0x080800 -> 0x0809FF +secbuffer1: equ 0x0000000000080A00 ; 512 bytes 0x080A00 -> 0x080BFF +os_args: equ 0x0000000000080C00 +os_KernelStart: equ 0x0000000000100000 ; 65536 bytes 0x100000 -> 0x10FFFF - Location of Kernel +os_SystemVariables: equ 0x0000000000110000 ; 65536 bytes 0x110000 -> 0x11FFFF - Location of System Variables +os_MemoryMap: equ 0x0000000000120000 ; 131072 bytes 0x120000 -> 0x13FFFF - Location of Memory Map - Room to map 256 GiB with 2 MiB pages +os_EthernetBuffer: equ 0x0000000000140000 ; 262144 bytes 0x140000 -> 0x17FFFF - Location of Ethernet RX Ring Buffer - Room for 170 packets +os_screen: equ 0x0000000000180000 ; 4096 bytes 80x25x2 = 4000 +os_ethernet_rx_buffer: equ 0x00000000001C0000 +os_eth_rx_buffer: equ 0x00000000001C8000 +os_ethernet_tx_buffer: equ 0x00000000001D0000 +os_eth_tx_buffer: equ 0x00000000001D8000 +os_eth_temp_buffer: equ 0x00000000001E0000 +cpustatus: equ 0x00000000001FEF00 ; Location of CPU status data (256 bytes) Bit 0 = Avaiable, Bit 1 = Free/Busy +cpuqueue: equ 0x00000000001FF000 ; Location of CPU Queue. Each queue item is 16 bytes. (4KiB before the 2MiB mark, Room for 256 entries) +programlocation: equ 0x0000000000200000 ; Location in memory where programs are loaded (the start of 2MiB) + +; DQ - Starting at offset 0, increments by 0x8 +os_LocalAPICAddress: equ os_SystemVariables + 0x00 +os_IOAPICAddress: equ os_SystemVariables + 0x08 +os_ClockCounter: equ os_SystemVariables + 0x10 +os_RandomSeed: equ os_SystemVariables + 0x18 ; Seed for RNG +screen_cursor_offset: equ os_SystemVariables + 0x20 +hd1_maxlba: equ os_SystemVariables + 0x28 ; 64-bit value since at most it will hold a 48-bit value +os_StackBase: equ os_SystemVariables + 0x30 +os_net_transmit: equ os_SystemVariables + 0x38 +os_net_poll: equ os_SystemVariables + 0x40 +os_net_ack_int: equ os_SystemVariables + 0x48 +os_NetIOBaseMem: equ os_SystemVariables + 0x50 +os_NetMAC: equ os_SystemVariables + 0x58 + +; DD - Starting at offset 128, increments by 4 +cpu_speed: equ os_SystemVariables + 128 ; in MHz +hd1_size: equ os_SystemVariables + 132 ; Size in MiB +ip: equ os_SystemVariables + 136 ; IPv4 Address +sn: equ os_SystemVariables + 140 ; IPv4 Subnet +gw: equ os_SystemVariables + 144 ; IPv4 Gateway + +; DW - Starting at offset 256, increments by 2 +os_MemAmount: equ os_SystemVariables + 256 ; in MiB +os_NumCores: equ os_SystemVariables + 258 +cpuqueuestart: equ os_SystemVariables + 260 +cpuqueuefinish: equ os_SystemVariables + 262 +os_QueueLen: equ os_SystemVariables + 264 +os_QueueLock: equ os_SystemVariables + 266 ; Bit 0 clear for unlocked, set for locked. +os_NetIOAddress: equ os_SystemVariables + 268 +os_EthernetBusyLock: equ os_SystemVariables + 270 + +; DB - Starting at offset 384, increments by 1 +cursorx: equ os_SystemVariables + 384 ; cursor row location +cursory: equ os_SystemVariables + 385 ; cursor column location +scancode: equ os_SystemVariables + 386 +key: equ os_SystemVariables + 387 +key_shift: equ os_SystemVariables + 388 +screen_cursor_x: equ os_SystemVariables + 389 +screen_cursor_y: equ os_SystemVariables + 390 +hd1_enable: equ os_SystemVariables + 391 ; 1 if the drive is there and enabled +hd1_lba48: equ os_SystemVariables + 392 ; 1 if LBA48 is allowed +os_PCIEnabled: equ os_SystemVariables + 393 ; 1 if PCI is detected +os_NetEnabled: equ os_SystemVariables + 394 ; 1 if a supported network card was enabled +os_NetIRQ: equ os_SystemVariables + 395 ; Set to Interrupt line that NIC is connected to +os_NetActivity_TX: equ os_SystemVariables + 396 +os_NetActivity_RX: equ os_SystemVariables + 397 +os_EthernetBuffer_C1: equ os_SystemVariables + 398 ; Counter 1 for the Ethernet RX Ring Buffer +os_EthernetBuffer_C2: equ os_SystemVariables + 399 ; Counter 2 for the Ethernet RX Ring Buffer + + +cpuqueuemax: dw 256 +screen_rows: db 25 ; x +screen_cols: db 80 ; y +os_show_sysstatus: db 1 + +; Function variables +os_debug_dump_reg_stage: db 0x00 + +; File System +fat16_FatStart: dd 0x00000000 +fat16_TotalSectors: dd 0x00000000 +fat16_DataStart: dd 0x00000000 +fat16_RootStart: dd 0x00000000 +fat16_PartitionOffset: dd 0x00000000 +fat16_ReservedSectors: dw 0x0000 +fat16_RootDirEnts: dw 0x0000 +fat16_SectorsPerFat: dw 0x0000 +fat16_BytesPerSector: dw 0x0000 +fat16_SectorsPerCluster: db 0x00 +fat16_Fats: db 0x00 + + +keylayoutlower: +db 0x00, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x0e, 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x1c, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 0, '`', 0, 0, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, ' ', 0 +keylayoutupper: +db 0x00, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x0e, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0x1c, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 0, '~', 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, ' ', 0 +; 0e = backspace +; 1c = enter + +palette: ; These colors are in RGB format. Each color byte is actually 6 bits (0x00 - 0x3F) +db 0x00, 0x00, 0x00 ; 0 Black +db 0x33, 0x00, 0x00 ; 1 Red +db 0x0F, 0x26, 0x01 ; 2 Green +db 0x0D, 0x19, 0x29 ; 3 Blue +db 0x31, 0x28, 0x00 ; 4 Orange +db 0x1D, 0x14, 0x1E ; 5 Purple +db 0x01, 0x26, 0x26 ; 6 Teal +db 0x2A, 0x2A, 0x2A ; 7 Light Gray +db 0x15, 0x15, 0x15 ; 8 Dark Gray +db 0x3B, 0x0A, 0x0A ; 9 Bright Red +db 0x22, 0x38, 0x0D ; 10 Bright Green +db 0x1C, 0x27, 0x33 ; 11 Bright Blue +db 0x3F, 0x3A, 0x13 ; 12 Yellow +db 0x2B, 0x1F, 0x2A ; 13 Bright Purple +db 0x0D, 0x38, 0x38 ; 14 Bright Teal +db 0x3F, 0x3F, 0x3F ; 15 White + + +os_debug_dump_reg_string00: db ' A:', 0 +os_debug_dump_reg_string01: db ' B:', 0 +os_debug_dump_reg_string02: db ' C:', 0 +os_debug_dump_reg_string03: db ' D:', 0 +os_debug_dump_reg_string04: db ' SI:', 0 +os_debug_dump_reg_string05: db ' DI:', 0 +os_debug_dump_reg_string06: db ' BP:', 0 +os_debug_dump_reg_string07: db ' SP:', 0 +os_debug_dump_reg_string08: db ' 8:', 0 +os_debug_dump_reg_string09: db ' 9:', 0 +os_debug_dump_reg_string0A: db ' 10:', 0 +os_debug_dump_reg_string0B: db ' 11:', 0 +os_debug_dump_reg_string0C: db ' 12:', 0 +os_debug_dump_reg_string0D: db ' 13:', 0 +os_debug_dump_reg_string0E: db ' 14:', 0 +os_debug_dump_reg_string0F: db ' 15:', 0 +os_debug_dump_reg_string10: db ' RF:', 0 + +os_debug_dump_flag_string0: db ' C:', 0 +os_debug_dump_flag_string1: db ' Z:', 0 +os_debug_dump_flag_string2: db ' S:', 0 +os_debug_dump_flag_string3: db ' D:', 0 +os_debug_dump_flag_string4: db ' O:', 0 + + +cli_command_string: times 14 db 0 +cli_args: db 0 + +align 16 +this_is_the_end: db 'This is the end.' + +;------------------------------------------------------------------------------ + +SYS64_CODE_SEL equ 8 ; defined by Pure64 + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/programs/argtest.asm b/amd64/bareMetalOS-0.5.3/programs/argtest.asm index cbb8588b..f9abf388 100644 --- a/amd64/bareMetalOS-0.5.3/programs/argtest.asm +++ b/amd64/bareMetalOS-0.5.3/programs/argtest.asm @@ -1,35 +1,35 @@ -; Argument Test Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm argtest.asm -o argtest.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - call b_get_argc ; Get the number of arguments that were passed - cmp al, 1 ; Was the number 1? - je noargs ; If so then bail out. The first argument is the program name - mov rsi, hello_message ; Load RSI with memory address of string - call b_print_string ; Print the string that RSI points to - mov al, 1 ; Argument values start at 0 so we want the second one - call b_get_argv ; Set RSI to point to the second argument - call b_print_string ; Print the string - call b_print_newline ; Print a new line - jmp fin ; Skip to the end - -noargs: - mov rsi, noargs_message ; Print the error message - call b_print_string - -fin: - -ret ; Return to OS - -hello_message: db 'Hello, ', 0 -noargs_message: db 'Abort: No arguments supplied.', 13, 0 +; Argument Test Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm argtest.asm -o argtest.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + call b_get_argc ; Get the number of arguments that were passed + cmp al, 1 ; Was the number 1? + je noargs ; If so then bail out. The first argument is the program name + mov rsi, hello_message ; Load RSI with memory address of string + call b_print_string ; Print the string that RSI points to + mov al, 1 ; Argument values start at 0 so we want the second one + call b_get_argv ; Set RSI to point to the second argument + call b_print_string ; Print the string + call b_print_newline ; Print a new line + jmp fin ; Skip to the end + +noargs: + mov rsi, noargs_message ; Print the error message + call b_print_string + +fin: + +ret ; Return to OS + +hello_message: db 'Hello, ', 0 +noargs_message: db 'Abort: No arguments supplied.', 13, 0 diff --git a/amd64/bareMetalOS-0.5.3/programs/bf.asm b/amd64/bareMetalOS-0.5.3/programs/bf.asm index 0530659e..85dfdf03 100644 --- a/amd64/bareMetalOS-0.5.3/programs/bf.asm +++ b/amd64/bareMetalOS-0.5.3/programs/bf.asm @@ -1,115 +1,115 @@ -; ============================================================================= -; Brainf*ck -- A 64-bit Brainf*ck interpreter -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; http://en.wikipedia.org/wiki/Brainfuck -; ============================================================================= - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -bf_start: - ; clear memory here - -bf_run: - mov rsi, [codepointer] - lodsb - add qword [codepointer], 1 - cmp al, '>' - je incptr - cmp al, '<' - je decptr - cmp al, '+' - je incdata - cmp al, '-' - je decdata - cmp al, '.' - je outchar - cmp al, ',' - je inchar - cmp al, '[' - je startloop - cmp al, ']' - je endloop - ret - -incptr: - add qword [datapointer], 8 - jmp bf_run - -decptr: - sub qword [datapointer], 8 - jmp bf_run - -incdata: - mov rax, [datapointer] - mov rsi, rax - mov rdi, rax - lodsq - add rax, 1 - stosq - jmp bf_run - -decdata: - mov rax, [datapointer] - mov rsi, rax - mov rdi, rax - lodsq - sub rax, 1 - stosq - jmp bf_run - -outchar: - mov rsi, [datapointer] - lodsq - call b_print_char - jmp bf_run - -inchar: - mov rdi, [datapointer] - xor rax, rax - call b_input_key_wait - stosq - jmp bf_run - -startloop: - mov rsi, [datapointer] - lodsq - cmp rax, 0 - jne bf_run - mov rsi, [codepointer] -startloop_next: - lodsb - cmp al, ']' - jne startloop_next - mov qword [codepointer], rsi - jmp bf_run - -endloop: - xchg bx, bx - mov rsi, [datapointer] - lodsq - cmp rax, 0 - je bf_run - mov rsi, [codepointer] - std -endloop_next: - lodsb - cmp al, '[' - jne endloop_next - add rsi, 1 - mov qword [codepointer], rsi - cld - jmp bf_run - -align 16 -datapointer: dq data -codepointer: dq code - -code: -db '>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.', 0 - -align 16 +; ============================================================================= +; Brainf*ck -- A 64-bit Brainf*ck interpreter +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; http://en.wikipedia.org/wiki/Brainfuck +; ============================================================================= + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +bf_start: + ; clear memory here + +bf_run: + mov rsi, [codepointer] + lodsb + add qword [codepointer], 1 + cmp al, '>' + je incptr + cmp al, '<' + je decptr + cmp al, '+' + je incdata + cmp al, '-' + je decdata + cmp al, '.' + je outchar + cmp al, ',' + je inchar + cmp al, '[' + je startloop + cmp al, ']' + je endloop + ret + +incptr: + add qword [datapointer], 8 + jmp bf_run + +decptr: + sub qword [datapointer], 8 + jmp bf_run + +incdata: + mov rax, [datapointer] + mov rsi, rax + mov rdi, rax + lodsq + add rax, 1 + stosq + jmp bf_run + +decdata: + mov rax, [datapointer] + mov rsi, rax + mov rdi, rax + lodsq + sub rax, 1 + stosq + jmp bf_run + +outchar: + mov rsi, [datapointer] + lodsq + call b_print_char + jmp bf_run + +inchar: + mov rdi, [datapointer] + xor rax, rax + call b_input_key_wait + stosq + jmp bf_run + +startloop: + mov rsi, [datapointer] + lodsq + cmp rax, 0 + jne bf_run + mov rsi, [codepointer] +startloop_next: + lodsb + cmp al, ']' + jne startloop_next + mov qword [codepointer], rsi + jmp bf_run + +endloop: + xchg bx, bx + mov rsi, [datapointer] + lodsq + cmp rax, 0 + je bf_run + mov rsi, [codepointer] + std +endloop_next: + lodsb + cmp al, '[' + jne endloop_next + add rsi, 1 + mov qword [codepointer], rsi + cld + jmp bf_run + +align 16 +datapointer: dq data +codepointer: dq code + +code: +db '>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.', 0 + +align 16 data: \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.3/programs/bmdev.asm b/amd64/bareMetalOS-0.5.3/programs/bmdev.asm index 4072e7eb..181fa2c6 100644 --- a/amd64/bareMetalOS-0.5.3/programs/bmdev.asm +++ b/amd64/bareMetalOS-0.5.3/programs/bmdev.asm @@ -1,86 +1,86 @@ -; ============================================================================= -; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT -; -; Include file for Bare Metal program development (API version 2.0) -; ============================================================================= - - -b_print_string equ 0x0000000000100010 ; Displays text. IN: RSI = message location (zero-terminated string) -b_print_char equ 0x0000000000100020 ; Displays a char. IN: AL = char to display -b_print_char_hex equ 0x0000000000100030 ; Displays a char in hex mode. IN: AL = char to display -b_print_newline equ 0x0000000000100040 ; Print a new line -b_input_key_check equ 0x0000000000100050 ; Scans keyboard for input, but doesn't wait. OUT: AL = ASCII code or 0 if no key pressed -b_input_key_wait equ 0x0000000000100060 ; Waits for keypress and returns key. OUT: AL = key pressed -b_input_string equ 0x0000000000100070 ; Take string from keyboard entry. IN: RDI = location where string will be stored. RCX = max chars to accept -b_delay equ 0x0000000000100080 ; Pause for a set time. IN: RAX = Time in hundredths of a second -b_speaker_tone equ 0x0000000000100090 ; Generate PC speaker tone (call b_speaker_off after). IN: RAX = note frequency -b_speaker_off equ 0x00000000001000A0 ; Shut off the PC speaker -b_speaker_beep equ 0x00000000001000B0 ; Play a standard beep noise -b_move_cursor equ 0x00000000001000C0 ; Move the cursor on screen. IN: AL = column, AH = row -b_string_length equ 0x00000000001000D0 ; Return the length of a string. IN: RSI = string address. OUT: RCX = string length -b_find_char_in_string equ 0x00000000001000E0 ; Find first location of character in a string. IN: RSI = string location, AL = character to find. OUT: RAX = location in string, or 0 if char not present -b_string_copy equ 0x00000000001000F0 ; Copy the contents of one string into another. IN: RSI = source, RDI = destination -b_string_truncate equ 0x0000000000100100 ; Chop string down to specified number of characters. IN: RSI = string location, RAX = number of characters -b_string_join equ 0x0000000000100110 ; Join two strings into a third string. IN: RAX = string one, RBX = string two, RDI = destination string -b_string_chomp equ 0x0000000000100120 ; Strip leading and trailing spaces from a string. IN: RSI = string location -b_string_strip equ 0x0000000000100130 ; Removes specified character from a string. IN: RSI = string location, AL = character to remove -b_string_compare equ 0x0000000000100140 ; See if two strings match. IN: RSI = string one, RDI = string two. OUT: Carry flag set if same -b_string_uppercase equ 0x0000000000100150 ; Convert a string to all uppercase characters. IN: RSI = string address -b_string_lowercase equ 0x0000000000100160 ; Convert a string to all lowercase characters. IN: RSI = string address -b_int_to_string equ 0x0000000000100170 ; Convert an integer to a string. IN: RAX = interger. OUT: RDI = destination string -b_string_to_int equ 0x0000000000100180 ; Convert a string to an interger. IN: RSI = source string. OUT: RAX = interger -b_debug_dump_reg equ 0x0000000000100190 ; Dump the registers to the screen -b_debug_dump_mem equ 0x00000000001001A0 ; Dump contents of memory to the screen. IN: RSI = Start of memory address to dump, RCX = number of bytes to dump -b_debug_dump_rax equ 0x00000000001001B0 ; Dump the content of RAX (64-bit) to the screen -b_debug_dump_eax equ 0x00000000001001C0 ; Dump the content of EAX (32-bit) to the screen -b_debug_dump_ax equ 0x00000000001001D0 ; Dump the content of AX (16-bit) to the screen -b_debug_dump_al equ 0x00000000001001E0 ; Dump the content of AL (8-bit) to the screen -b_smp_reset equ 0x00000000001001F0 ; Resets a CPU/Core. IN: AL = CPU # -b_smp_get_id equ 0x0000000000100200 ; Returns the APIC ID of the CPU that ran this function. OUT: RAX = CPU's APIC ID number -b_smp_enqueue equ 0x0000000000100210 ; Add a workload to the processing queue. IN: RAX = Code to execute, RBX = Variable/Data to work on -b_smp_dequeue equ 0x0000000000100220 ; Dequeue a workload from the processing queue. OUT: RAX = Code to execute, RBX = Variable/Data to work on -b_serial_send equ 0x0000000000100230 ; Send a byte over the primary serial port. IN: AL = Byte to send over serial port -b_serial_recv equ 0x0000000000100240 ; Receive a byte from the primary serial port. OUT: AL = Byte recevied, Carry flag is set if a byte was received (otherwise AL is trashed) -b_string_parse equ 0x0000000000100250 ; Parse a string into individual words. IN: RSI = Address of string. OUT: RCX = word count -b_get_argc equ 0x0000000000100260 ; Return the number arguments passed to the program. OUT: AL = Number of arguments -b_get_argv equ 0x0000000000100270 ; Get the value of an argument that was passed to the program. IN: AL = Argument number. OUT: RSI = Start of numbered argument string -b_smp_queuelen equ 0x0000000000100280 ; Returns the number of items in the processing queue. OUT: RAX = number of items in processing queue -b_smp_wait equ 0x0000000000100290 ; Wait until all other CPU Cores are finished processing -b_get_timecounter equ 0x00000000001002A0 ; Get the current RTC clock couter value. OUT: RAX = Time in eights of a second since clock started -b_string_append equ 0x00000000001002B0 ; Append a string to an existing string. IN: RSI = String to be appended, RDI = Destination string -b_int_to_hex_string equ 0x00000000001002C0 ; Convert an integer to a hex string. IN: RAX = Integer value. RDI = location to store string -b_hex_string_to_int equ 0x00000000001002D0 ; Convert up to 8 hexascii to bin. IN: RSI = Location of hex asciiz string. OUT: RAX = binary value of hex string -b_string_change_char equ 0x00000000001002E0 ; Change all instances of a character in a string. IN: RSI = string location, AL = character to replace, BL = replacement character -b_is_digit equ 0x00000000001002F0 ; Check if character is a digit. IN: AL = ASCII char. OUT: EQ flag set if numeric -b_is_alpha equ 0x0000000000100300 ; Check if character is a letter. IN: AL = ASCII char. OUT: EQ flag set if alpha -b_file_read equ 0x0000000000100310 ; Read a file from disk into memory. IN: RSI = Address of filename string, RDI = Memory location where file will be loaded to. OUT: Carry is set if the file was not found or an error occured -b_file_write equ 0x0000000000100320 ; Write memory to a file on disk. IN: RSI = Memory location of data to be written, RDI = Address of filename string, RCX = Number of bytes to write. OUT: Carry is set if an error occured -b_file_delete equ 0x0000000000100330 ; Delete a file from disk. IN: RSI = Memory location of file name to delete. OUT: Carry is set if the file was not found or an error occured -b_file_get_list equ 0x0000000000100340 ; Generate a list of files on disk. IN: RDI = Location to store list. OUT: RDI = pointer to end of list -b_smp_run equ 0x0000000000100350 ; Call the function address in RAX. IN: RAX = Memory location of code to run -b_smp_lock equ 0x0000000000100360 ; Lock a variable. IN: RAX = Memory address of variable -b_smp_unlock equ 0x0000000000100370 ; Unlock a variable. IN: RAX = Memory address of variable -b_print_string_with_color equ 0x0000000000100380 ; Displays text in colour. IN: RSI = message location (zero-terminated string), BL = colour -b_print_char_with_color equ 0x0000000000100390 ; Displays a char in colour. IN: AL = char to display, BL = colour -b_ethernet_tx equ 0x00000000001003A0 ; Transmit a packet via Ethernet. IN: RSI = Memory location where data is stored, RDI = Pointer to 48 bit destination address, BX = Type of packet (If set to 0 then the EtherType will be set to the length of data), CX = Length of data -b_ethernet_rx equ 0x00000000001003B0 ; Polls the Ethernet card for received data. IN: RDI = Memory location where packet will be stored. OUT: RCX = Length of packet -b_mem_allocate equ 0x00000000001003C0 ; Allocates the requested number of 2 MiB pages. IN: RCX = Number of pages to allocate. OUT: RAX = Starting address, RCX = Number of pages allocated (Set to the value asked for or 0 on failure) -b_mem_release equ 0x00000000001003D0 ; Frees the requested number of 2 MiB pages. IN: RAX = Starting address, RCX = Number of pages to free. OUT: RCX = Number of pages freed -b_mem_get_free equ 0x00000000001003E0 ; Returns the number of 2 MiB pages that are available. OUT: RCX = Number of free 2 MiB pages -b_smp_numcores equ 0x00000000001003F0 ; Returns the number of cores in this computer. OUT: RAX = number of cores in this computer -b_file_get_size equ 0x0000000000100400 ; Return the size of a file on disk. IN: RSI = Address of filename string. OUT: RCX = Size in bytes, Carry is set if the file was not found or an error occured -b_ethernet_avail equ 0x0000000000100410 ; Check if Ethernet is available. IN: Nothing. OUT: RAX = Set to 1 if Ethernet is enabled on host -b_print_char_hex_with_color equ 0x0000000000100420 ; Displays a char in hex mode with color. IN: AL = char to display, BL = colour -b_screen_clear equ 0x0000000000100440 ; Clear the screen -b_show_cursor equ 0x0000000000100450 ; Turns on cursor in text mode -b_hide_cursor equ 0x0000000000100460 ; Turns off cursor in text mode -b_show_statusbar equ 0x0000000000100470 ; Show the system status bar -b_hide_statusbar equ 0x0000000000100480 ; Hide the system status bar -b_screen_update equ 0x0000000000100490 ; Manually refresh the screen from the frame buffer -b_print_chars equ 0x00000000001004A0 ; Displays text. IN: RSI = message location (A string, not zero-terminated), RCX = number of chars to print -b_print_chars_with_color equ 0x00000000001004B0 ; Displays text with color. IN: RSI = message location (A string, not zero-terminated), BL = color, RCX = number of chars to print - - -; ============================================================================= -; EOF +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT +; +; Include file for Bare Metal program development (API version 2.0) +; ============================================================================= + + +b_print_string equ 0x0000000000100010 ; Displays text. IN: RSI = message location (zero-terminated string) +b_print_char equ 0x0000000000100020 ; Displays a char. IN: AL = char to display +b_print_char_hex equ 0x0000000000100030 ; Displays a char in hex mode. IN: AL = char to display +b_print_newline equ 0x0000000000100040 ; Print a new line +b_input_key_check equ 0x0000000000100050 ; Scans keyboard for input, but doesn't wait. OUT: AL = ASCII code or 0 if no key pressed +b_input_key_wait equ 0x0000000000100060 ; Waits for keypress and returns key. OUT: AL = key pressed +b_input_string equ 0x0000000000100070 ; Take string from keyboard entry. IN: RDI = location where string will be stored. RCX = max chars to accept +b_delay equ 0x0000000000100080 ; Pause for a set time. IN: RAX = Time in hundredths of a second +b_speaker_tone equ 0x0000000000100090 ; Generate PC speaker tone (call b_speaker_off after). IN: RAX = note frequency +b_speaker_off equ 0x00000000001000A0 ; Shut off the PC speaker +b_speaker_beep equ 0x00000000001000B0 ; Play a standard beep noise +b_move_cursor equ 0x00000000001000C0 ; Move the cursor on screen. IN: AL = column, AH = row +b_string_length equ 0x00000000001000D0 ; Return the length of a string. IN: RSI = string address. OUT: RCX = string length +b_find_char_in_string equ 0x00000000001000E0 ; Find first location of character in a string. IN: RSI = string location, AL = character to find. OUT: RAX = location in string, or 0 if char not present +b_string_copy equ 0x00000000001000F0 ; Copy the contents of one string into another. IN: RSI = source, RDI = destination +b_string_truncate equ 0x0000000000100100 ; Chop string down to specified number of characters. IN: RSI = string location, RAX = number of characters +b_string_join equ 0x0000000000100110 ; Join two strings into a third string. IN: RAX = string one, RBX = string two, RDI = destination string +b_string_chomp equ 0x0000000000100120 ; Strip leading and trailing spaces from a string. IN: RSI = string location +b_string_strip equ 0x0000000000100130 ; Removes specified character from a string. IN: RSI = string location, AL = character to remove +b_string_compare equ 0x0000000000100140 ; See if two strings match. IN: RSI = string one, RDI = string two. OUT: Carry flag set if same +b_string_uppercase equ 0x0000000000100150 ; Convert a string to all uppercase characters. IN: RSI = string address +b_string_lowercase equ 0x0000000000100160 ; Convert a string to all lowercase characters. IN: RSI = string address +b_int_to_string equ 0x0000000000100170 ; Convert an integer to a string. IN: RAX = interger. OUT: RDI = destination string +b_string_to_int equ 0x0000000000100180 ; Convert a string to an interger. IN: RSI = source string. OUT: RAX = interger +b_debug_dump_reg equ 0x0000000000100190 ; Dump the registers to the screen +b_debug_dump_mem equ 0x00000000001001A0 ; Dump contents of memory to the screen. IN: RSI = Start of memory address to dump, RCX = number of bytes to dump +b_debug_dump_rax equ 0x00000000001001B0 ; Dump the content of RAX (64-bit) to the screen +b_debug_dump_eax equ 0x00000000001001C0 ; Dump the content of EAX (32-bit) to the screen +b_debug_dump_ax equ 0x00000000001001D0 ; Dump the content of AX (16-bit) to the screen +b_debug_dump_al equ 0x00000000001001E0 ; Dump the content of AL (8-bit) to the screen +b_smp_reset equ 0x00000000001001F0 ; Resets a CPU/Core. IN: AL = CPU # +b_smp_get_id equ 0x0000000000100200 ; Returns the APIC ID of the CPU that ran this function. OUT: RAX = CPU's APIC ID number +b_smp_enqueue equ 0x0000000000100210 ; Add a workload to the processing queue. IN: RAX = Code to execute, RBX = Variable/Data to work on +b_smp_dequeue equ 0x0000000000100220 ; Dequeue a workload from the processing queue. OUT: RAX = Code to execute, RBX = Variable/Data to work on +b_serial_send equ 0x0000000000100230 ; Send a byte over the primary serial port. IN: AL = Byte to send over serial port +b_serial_recv equ 0x0000000000100240 ; Receive a byte from the primary serial port. OUT: AL = Byte recevied, Carry flag is set if a byte was received (otherwise AL is trashed) +b_string_parse equ 0x0000000000100250 ; Parse a string into individual words. IN: RSI = Address of string. OUT: RCX = word count +b_get_argc equ 0x0000000000100260 ; Return the number arguments passed to the program. OUT: AL = Number of arguments +b_get_argv equ 0x0000000000100270 ; Get the value of an argument that was passed to the program. IN: AL = Argument number. OUT: RSI = Start of numbered argument string +b_smp_queuelen equ 0x0000000000100280 ; Returns the number of items in the processing queue. OUT: RAX = number of items in processing queue +b_smp_wait equ 0x0000000000100290 ; Wait until all other CPU Cores are finished processing +b_get_timecounter equ 0x00000000001002A0 ; Get the current RTC clock couter value. OUT: RAX = Time in eights of a second since clock started +b_string_append equ 0x00000000001002B0 ; Append a string to an existing string. IN: RSI = String to be appended, RDI = Destination string +b_int_to_hex_string equ 0x00000000001002C0 ; Convert an integer to a hex string. IN: RAX = Integer value. RDI = location to store string +b_hex_string_to_int equ 0x00000000001002D0 ; Convert up to 8 hexascii to bin. IN: RSI = Location of hex asciiz string. OUT: RAX = binary value of hex string +b_string_change_char equ 0x00000000001002E0 ; Change all instances of a character in a string. IN: RSI = string location, AL = character to replace, BL = replacement character +b_is_digit equ 0x00000000001002F0 ; Check if character is a digit. IN: AL = ASCII char. OUT: EQ flag set if numeric +b_is_alpha equ 0x0000000000100300 ; Check if character is a letter. IN: AL = ASCII char. OUT: EQ flag set if alpha +b_file_read equ 0x0000000000100310 ; Read a file from disk into memory. IN: RSI = Address of filename string, RDI = Memory location where file will be loaded to. OUT: Carry is set if the file was not found or an error occured +b_file_write equ 0x0000000000100320 ; Write memory to a file on disk. IN: RSI = Memory location of data to be written, RDI = Address of filename string, RCX = Number of bytes to write. OUT: Carry is set if an error occured +b_file_delete equ 0x0000000000100330 ; Delete a file from disk. IN: RSI = Memory location of file name to delete. OUT: Carry is set if the file was not found or an error occured +b_file_get_list equ 0x0000000000100340 ; Generate a list of files on disk. IN: RDI = Location to store list. OUT: RDI = pointer to end of list +b_smp_run equ 0x0000000000100350 ; Call the function address in RAX. IN: RAX = Memory location of code to run +b_smp_lock equ 0x0000000000100360 ; Lock a variable. IN: RAX = Memory address of variable +b_smp_unlock equ 0x0000000000100370 ; Unlock a variable. IN: RAX = Memory address of variable +b_print_string_with_color equ 0x0000000000100380 ; Displays text in colour. IN: RSI = message location (zero-terminated string), BL = colour +b_print_char_with_color equ 0x0000000000100390 ; Displays a char in colour. IN: AL = char to display, BL = colour +b_ethernet_tx equ 0x00000000001003A0 ; Transmit a packet via Ethernet. IN: RSI = Memory location where data is stored, RDI = Pointer to 48 bit destination address, BX = Type of packet (If set to 0 then the EtherType will be set to the length of data), CX = Length of data +b_ethernet_rx equ 0x00000000001003B0 ; Polls the Ethernet card for received data. IN: RDI = Memory location where packet will be stored. OUT: RCX = Length of packet +b_mem_allocate equ 0x00000000001003C0 ; Allocates the requested number of 2 MiB pages. IN: RCX = Number of pages to allocate. OUT: RAX = Starting address, RCX = Number of pages allocated (Set to the value asked for or 0 on failure) +b_mem_release equ 0x00000000001003D0 ; Frees the requested number of 2 MiB pages. IN: RAX = Starting address, RCX = Number of pages to free. OUT: RCX = Number of pages freed +b_mem_get_free equ 0x00000000001003E0 ; Returns the number of 2 MiB pages that are available. OUT: RCX = Number of free 2 MiB pages +b_smp_numcores equ 0x00000000001003F0 ; Returns the number of cores in this computer. OUT: RAX = number of cores in this computer +b_file_get_size equ 0x0000000000100400 ; Return the size of a file on disk. IN: RSI = Address of filename string. OUT: RCX = Size in bytes, Carry is set if the file was not found or an error occured +b_ethernet_avail equ 0x0000000000100410 ; Check if Ethernet is available. IN: Nothing. OUT: RAX = Set to 1 if Ethernet is enabled on host +b_print_char_hex_with_color equ 0x0000000000100420 ; Displays a char in hex mode with color. IN: AL = char to display, BL = colour +b_screen_clear equ 0x0000000000100440 ; Clear the screen +b_show_cursor equ 0x0000000000100450 ; Turns on cursor in text mode +b_hide_cursor equ 0x0000000000100460 ; Turns off cursor in text mode +b_show_statusbar equ 0x0000000000100470 ; Show the system status bar +b_hide_statusbar equ 0x0000000000100480 ; Hide the system status bar +b_screen_update equ 0x0000000000100490 ; Manually refresh the screen from the frame buffer +b_print_chars equ 0x00000000001004A0 ; Displays text. IN: RSI = message location (A string, not zero-terminated), RCX = number of chars to print +b_print_chars_with_color equ 0x00000000001004B0 ; Displays text with color. IN: RSI = message location (A string, not zero-terminated), BL = color, RCX = number of chars to print + + +; ============================================================================= +; EOF diff --git a/amd64/bareMetalOS-0.5.3/programs/ethtool.asm b/amd64/bareMetalOS-0.5.3/programs/ethtool.asm index e83151ad..dacadebe 100644 --- a/amd64/bareMetalOS-0.5.3/programs/ethtool.asm +++ b/amd64/bareMetalOS-0.5.3/programs/ethtool.asm @@ -1,72 +1,72 @@ -; ----------------------------------------------------------------- -; EthTool v0.1 - Ethernet debugging tool -; Ian Seyler @ Return Infinity -; ----------------------------------------------------------------- - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -ethtool: - - mov rsi, startstring - call b_print_string - -ethtool_command: - call b_input_key_wait - or al, 00100000b ; Convert character to lowercase if it is not already - - cmp al, 's' - je ethtool_send - cmp al, 'r' - je ethtool_receive - cmp al, 'q' - je ethtool_finish - jmp ethtool_command ; Didn't get any key we were expecting so try again. - -ethtool_finish: - call b_print_newline - ret ; Back to OS - -ethtool_send: - mov rsi, sendstring - call b_print_string - mov rdi, broadcastaddress - mov rsi, startstring - mov rbx, 0xABBA - mov rcx, 63 - call b_ethernet_tx - mov rsi, sentstring - call b_print_string - jmp ethtool_command - -ethtool_receive: - mov rsi, receivestring - call b_print_string - mov rdi, EthernetBuffer - call b_ethernet_rx - cmp rcx, 0 - je ethtool_receive_nopacket - mov rsi, receiveddata - call b_print_string - mov rsi, EthernetBuffer - call b_debug_dump_mem - jmp ethtool_command - -ethtool_receive_nopacket: - mov rsi, receivednothingstring - call b_print_string - jmp ethtool_command - -; ----------------------------------------------------------------- - -startstring: db 'EthTool: S to send a packet, R to recieve a packet, Q to quit.', 0 -sendstring: db 13, 'Sending packet, ', 0 -sentstring: db 'Sent', 0 -receivestring: db 13, 'Receiving packet, ', 0 -receivednothingstring: db 'Nothing there', 0 -receiveddata: db 'Data received', 13, 0 -broadcastaddress: db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 +; ----------------------------------------------------------------- +; EthTool v0.1 - Ethernet debugging tool +; Ian Seyler @ Return Infinity +; ----------------------------------------------------------------- + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +ethtool: + + mov rsi, startstring + call b_print_string + +ethtool_command: + call b_input_key_wait + or al, 00100000b ; Convert character to lowercase if it is not already + + cmp al, 's' + je ethtool_send + cmp al, 'r' + je ethtool_receive + cmp al, 'q' + je ethtool_finish + jmp ethtool_command ; Didn't get any key we were expecting so try again. + +ethtool_finish: + call b_print_newline + ret ; Back to OS + +ethtool_send: + mov rsi, sendstring + call b_print_string + mov rdi, broadcastaddress + mov rsi, startstring + mov rbx, 0xABBA + mov rcx, 63 + call b_ethernet_tx + mov rsi, sentstring + call b_print_string + jmp ethtool_command + +ethtool_receive: + mov rsi, receivestring + call b_print_string + mov rdi, EthernetBuffer + call b_ethernet_rx + cmp rcx, 0 + je ethtool_receive_nopacket + mov rsi, receiveddata + call b_print_string + mov rsi, EthernetBuffer + call b_debug_dump_mem + jmp ethtool_command + +ethtool_receive_nopacket: + mov rsi, receivednothingstring + call b_print_string + jmp ethtool_command + +; ----------------------------------------------------------------- + +startstring: db 'EthTool: S to send a packet, R to recieve a packet, Q to quit.', 0 +sendstring: db 13, 'Sending packet, ', 0 +sentstring: db 'Sent', 0 +receivestring: db 13, 'Receiving packet, ', 0 +receivednothingstring: db 'Nothing there', 0 +receiveddata: db 'Data received', 13, 0 +broadcastaddress: db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 EthernetBuffer: db 0 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.3/programs/hello.asm b/amd64/bareMetalOS-0.5.3/programs/hello.asm index c5892469..d2d34e86 100644 --- a/amd64/bareMetalOS-0.5.3/programs/hello.asm +++ b/amd64/bareMetalOS-0.5.3/programs/hello.asm @@ -1,20 +1,20 @@ -; Hello World Assembly Test Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm hello.asm -o hello.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - mov rsi, hello_message ; Load RSI with memory address of string - call b_print_string ; Print the string that RSI points to - -ret ; Return to OS - -hello_message: db 'Hello, world!', 13, 0 +; Hello World Assembly Test Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm hello.asm -o hello.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + mov rsi, hello_message ; Load RSI with memory address of string + call b_print_string ; Print the string that RSI points to + +ret ; Return to OS + +hello_message: db 'Hello, world!', 13, 0 diff --git a/amd64/bareMetalOS-0.5.3/programs/keyboard.asm b/amd64/bareMetalOS-0.5.3/programs/keyboard.asm index 0830aeac..8480d99e 100644 --- a/amd64/bareMetalOS-0.5.3/programs/keyboard.asm +++ b/amd64/bareMetalOS-0.5.3/programs/keyboard.asm @@ -1,111 +1,111 @@ -; ----------------------------------------------------------------- -; Music keyboard -; Based on keyboard.asm from MikeOS -; Use Z key rightwards for an octave -; ----------------------------------------------------------------- - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -music_keyboard: - - mov rsi, startstring - call b_print_string - call b_print_newline - -.retry: - call b_input_key_wait - -; And start matching keys with notes - - cmp al, 'z' - jne .x - mov al, 'C' - call b_print_char ; Print note - mov ax, 4000 - jmp .playnote - -.x: - cmp al, 'x' - jne .c - mov al, 'D' - call b_print_char ; Print note - mov ax, 3600 - jmp .playnote - -.c: - cmp al, 'c' - jne .v - mov al, 'E' - call b_print_char ; Print note - mov ax, 3200 - jmp .playnote - -.v: - cmp al, 'v' - jne .b - mov al, 'F' - call b_print_char ; Print note - mov ax, 3000 - jmp .playnote - -.b: - cmp al, 'b' - jne .n - mov al, 'G' - call b_print_char ; Print note - mov ax, 2700 - jmp .playnote - -.n: - cmp al, 'n' - jne .m - mov al, 'A' - call b_print_char ; Print note - mov ax, 2400 - jmp .playnote - -.m: - cmp al, 'm' - jne .comma - mov al, 'B' - call b_print_char - mov ax, 2100 - jmp .playnote - -.comma: - cmp al, ',' - jne .space - mov al, 'C' - call b_print_char - mov ax, 2000 - jmp .playnote - -.space: - cmp al, ' ' - jne .q - call b_speaker_off - jmp .retry - -.playnote: - call b_speaker_tone - jmp .retry - -.q: - cmp al, 'q' - je .end - cmp al, 'Q' - je .end - jmp .retry ; Didn't get any key we were expecting so try again. - -.end: - call b_speaker_off - call b_print_newline - ret ; Back to OS - -; ----------------------------------------------------------------- - +; ----------------------------------------------------------------- +; Music keyboard +; Based on keyboard.asm from MikeOS +; Use Z key rightwards for an octave +; ----------------------------------------------------------------- + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +music_keyboard: + + mov rsi, startstring + call b_print_string + call b_print_newline + +.retry: + call b_input_key_wait + +; And start matching keys with notes + + cmp al, 'z' + jne .x + mov al, 'C' + call b_print_char ; Print note + mov ax, 4000 + jmp .playnote + +.x: + cmp al, 'x' + jne .c + mov al, 'D' + call b_print_char ; Print note + mov ax, 3600 + jmp .playnote + +.c: + cmp al, 'c' + jne .v + mov al, 'E' + call b_print_char ; Print note + mov ax, 3200 + jmp .playnote + +.v: + cmp al, 'v' + jne .b + mov al, 'F' + call b_print_char ; Print note + mov ax, 3000 + jmp .playnote + +.b: + cmp al, 'b' + jne .n + mov al, 'G' + call b_print_char ; Print note + mov ax, 2700 + jmp .playnote + +.n: + cmp al, 'n' + jne .m + mov al, 'A' + call b_print_char ; Print note + mov ax, 2400 + jmp .playnote + +.m: + cmp al, 'm' + jne .comma + mov al, 'B' + call b_print_char + mov ax, 2100 + jmp .playnote + +.comma: + cmp al, ',' + jne .space + mov al, 'C' + call b_print_char + mov ax, 2000 + jmp .playnote + +.space: + cmp al, ' ' + jne .q + call b_speaker_off + jmp .retry + +.playnote: + call b_speaker_tone + jmp .retry + +.q: + cmp al, 'q' + je .end + cmp al, 'Q' + je .end + jmp .retry ; Didn't get any key we were expecting so try again. + +.end: + call b_speaker_off + call b_print_newline + ret ; Back to OS + +; ----------------------------------------------------------------- + startstring: db 'Musical keyboard. Use "Z"-"," to play notes. Space to stop the note. Q to quit.', 0 \ No newline at end of file diff --git a/amd64/bareMetalOS-0.5.3/programs/libBareMetal.h b/amd64/bareMetalOS-0.5.3/programs/libBareMetal.h index d89b1573..ad2696ca 100644 --- a/amd64/bareMetalOS-0.5.3/programs/libBareMetal.h +++ b/amd64/bareMetalOS-0.5.3/programs/libBareMetal.h @@ -1,80 +1,80 @@ -// ============================================================================= -// BareMetal -- a 64-bit OS written in Assembly for x86-64 systems -// Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -// -// The BareMetal OS C/C++ library header. -// -// Version 2.0 -// -// This allows for a C/C++ program to access OS functions available in BareMetal OS -// ============================================================================= - - -void b_print_string(const char *str); -void b_print_char(char chr); -void b_print_char_hex(char chr); -void b_print_newline(void); -void b_print_string_with_color(const char *str, unsigned char clr); -void b_print_char_with_color(char chr, unsigned char clr); -void b_print_char_hex_with_color(char chr, unsigned char clr); - - -unsigned char b_input_get_key(void); -unsigned char b_input_wait_for_key(void); -unsigned long b_input_string(unsigned char *str, unsigned long nbr); - - -unsigned long b_string_length(const unsigned char *str); -unsigned long b_string_find_char(const unsigned char *str, unsigned char chr); -void b_os_string_copy(unsigned char *dst, const unsigned char *src); -void b_int_to_string(unsigned long nbr, unsigned char *str); -unsigned long b_string_to_int(const unsigned char *str); - - -void b_delay(unsigned long nbr); -unsigned long b_get_argc(); -char* b_get_argv(unsigned char nbr); -unsigned long b_get_timercounter(void); - - -void b_debug_dump_mem(void *data, unsigned int size); - - -void b_serial_send(unsigned char chr); -unsigned char b_serial_recv(void); - - -void b_file_read(const unsigned char *name, void *mem); -void b_file_write(void *data, const unsigned char *name, unsigned int size); -void b_file_delete(const unsigned char *name); - - -unsigned long b_smp_enqueue(void *ptr, unsigned long var); -unsigned long b_smp_dequeue(unsigned long *var); -void b_smp_run(unsigned long ptr, unsigned long var); -unsigned long b_smp_queuelen(void); -void b_smp_wait(void); -void b_smp_lock(unsigned long ptr); -void b_smp_unlock(unsigned long ptr); -unsigned long b_smp_get_id(void); -unsigned long b_smp_numcores(void); - - -unsigned long b_mem_allocate(unsigned long *mem, unsigned long nbr); -unsigned long b_mem_release(unsigned long *mem, unsigned long nbr); -unsigned long b_mem_get_free(void); - - -void b_speaker_tone(unsigned long nbr); -void b_speaker_off(void); -void b_speaker_beep(void); - - -void b_ethernet_tx(void *mem, void *dest, unsigned short type, unsigned short len); -void b_ethernet_tx_raw(void *mem, unsigned short len); -unsigned long b_ethernet_rx(void *mem); -unsigned long b_ethernet_avail(); - - -// ============================================================================= -// EOF +// ============================================================================= +// BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +// Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +// +// The BareMetal OS C/C++ library header. +// +// Version 2.0 +// +// This allows for a C/C++ program to access OS functions available in BareMetal OS +// ============================================================================= + + +void b_print_string(const char *str); +void b_print_char(char chr); +void b_print_char_hex(char chr); +void b_print_newline(void); +void b_print_string_with_color(const char *str, unsigned char clr); +void b_print_char_with_color(char chr, unsigned char clr); +void b_print_char_hex_with_color(char chr, unsigned char clr); + + +unsigned char b_input_get_key(void); +unsigned char b_input_wait_for_key(void); +unsigned long b_input_string(unsigned char *str, unsigned long nbr); + + +unsigned long b_string_length(const unsigned char *str); +unsigned long b_string_find_char(const unsigned char *str, unsigned char chr); +void b_os_string_copy(unsigned char *dst, const unsigned char *src); +void b_int_to_string(unsigned long nbr, unsigned char *str); +unsigned long b_string_to_int(const unsigned char *str); + + +void b_delay(unsigned long nbr); +unsigned long b_get_argc(); +char* b_get_argv(unsigned char nbr); +unsigned long b_get_timercounter(void); + + +void b_debug_dump_mem(void *data, unsigned int size); + + +void b_serial_send(unsigned char chr); +unsigned char b_serial_recv(void); + + +void b_file_read(const unsigned char *name, void *mem); +void b_file_write(void *data, const unsigned char *name, unsigned int size); +void b_file_delete(const unsigned char *name); + + +unsigned long b_smp_enqueue(void *ptr, unsigned long var); +unsigned long b_smp_dequeue(unsigned long *var); +void b_smp_run(unsigned long ptr, unsigned long var); +unsigned long b_smp_queuelen(void); +void b_smp_wait(void); +void b_smp_lock(unsigned long ptr); +void b_smp_unlock(unsigned long ptr); +unsigned long b_smp_get_id(void); +unsigned long b_smp_numcores(void); + + +unsigned long b_mem_allocate(unsigned long *mem, unsigned long nbr); +unsigned long b_mem_release(unsigned long *mem, unsigned long nbr); +unsigned long b_mem_get_free(void); + + +void b_speaker_tone(unsigned long nbr); +void b_speaker_off(void); +void b_speaker_beep(void); + + +void b_ethernet_tx(void *mem, void *dest, unsigned short type, unsigned short len); +void b_ethernet_tx_raw(void *mem, unsigned short len); +unsigned long b_ethernet_rx(void *mem); +unsigned long b_ethernet_avail(); + + +// ============================================================================= +// EOF diff --git a/amd64/bareMetalOS-0.5.3/programs/mbasic.asm b/amd64/bareMetalOS-0.5.3/programs/mbasic.asm index 385a460c..e83564b3 100644 --- a/amd64/bareMetalOS-0.5.3/programs/mbasic.asm +++ b/amd64/bareMetalOS-0.5.3/programs/mbasic.asm @@ -1,2436 +1,2436 @@ -; ================================================================== -; MikeOS -- The Mike Operating System kernel -; Copyright (C) 2006 - 2011 MikeOS Developers -- see doc/LICENSE.TXT -; -; BASIC CODE INTERPRETER -; ================================================================== - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -; ------------------------------------------------------------------ -; Token types - -%DEFINE VARIABLE 1 -%DEFINE STRING_VAR 2 -%DEFINE NUMBER 3 -%DEFINE STRING 4 -%DEFINE QUOTE 5 -%DEFINE CHAR 6 -%DEFINE UNKNOWN 7 -%DEFINE LABEL 8 - - -; ------------------------------------------------------------------ -; The BASIC interpreter execution starts here... - -b_run_basic: - mov [orig_stack], rsp ; Save stack pointer -- we might jump to the - ; error printing code and quit in the middle - ; some nested loops, and we want to preserve - ; the stack - mov rax, basic_prog ;embedded test program for a quick DOS test - mov rbx, 8192 ;default size for test program (not critical) - mov [load_point], rax ; rax was passed as starting location of code - - mov [prog], rax ; prog = pointer to current execution point in code - - add rbx, rax ; We were passed the .BAS byte size in rbx - sub rbx, 2 - mov [prog_end], rbx ; Make note of program end point - - - call clear_ram ; Clear variables etc. from previous run - ; of a BASIC program - - - -mainloop: - call get_token ; Get a token from the start of the line - - cmp rax, STRING ; Is the type a string of characters? - je .keyword ; If so, let's see if it's a keyword to process - - cmp rax, VARIABLE ; If it's a variable at the start of the line, - je near assign ; this is an assign (eg "X = Y + 5") - - cmp rax, STRING_VAR ; Same for a string variable (eg $1) - je near assign - - cmp rax, LABEL ; Don't need to do anything here - skip - je mainloop - - mov rsi, err_syntax ; Otherwise show an error and quit - jmp error - - -.keyword: - mov rsi, token ; Start trying to match commands - - mov rdi, alert_cmd - call b_string_compare - jc near do_alert - - mov rdi, call_cmd - call b_string_compare - jc near do_call - - mov rdi, cls_cmd - call b_string_compare - jc near do_cls - - mov rdi, cursor_cmd - call b_string_compare - jc near do_cursor - - mov rdi, curschar_cmd - call b_string_compare - jc near do_curschar - - mov rdi, end_cmd - call b_string_compare - jc near do_end - - mov rdi, for_cmd - call b_string_compare - jc near do_for - - mov rdi, getkey_cmd - call b_string_compare - jc near do_getkey - - mov rdi, gosub_cmd - call b_string_compare - jc near do_gosub - - mov rdi, goto_cmd - call b_string_compare - jc near do_goto - - mov rdi, input_cmd - call b_string_compare - jc near do_input - - mov rdi, if_cmd - call b_string_compare - jc near do_if - - mov rdi, load_cmd - call b_string_compare - jc near do_load - - mov rdi, move_cmd - call b_string_compare - jc near do_move - - mov rdi, next_cmd - call b_string_compare - jc near do_next - - mov rdi, pause_cmd - call b_string_compare - jc near do_pause - - mov rdi, peek_cmd - call b_string_compare - jc near do_peek - - mov rdi, poke_cmd - call b_string_compare - jc near do_poke - - mov rdi, port_cmd - call b_string_compare - jc near do_port - - mov rdi, print_cmd - call b_string_compare - jc near do_print - - mov rdi, rand_cmd - call b_string_compare - jc near do_rand - - mov rdi, rem_cmd - call b_string_compare - jc near do_rem - - mov rdi, return_cmd - call b_string_compare - jc near do_return - - mov rdi, save_cmd - call b_string_compare - jc near do_save - - mov rdi, serial_cmd - call b_string_compare - jc near do_serial - - mov rdi, sound_cmd - call b_string_compare - jc near do_sound - - mov rdi, waitkey_cmd - call b_string_compare - jc near do_waitkey - - mov rsi, err_cmd_unknown ; Command not found? - jmp error - - -; ------------------------------------------------------------------ -; CLEAR RAM - -clear_ram: - xor eax, eax - - mov rdi, variables - mov rcx, 52 - rep stosb - - mov rdi, for_variables - mov rcx, 52 - rep stosb - - mov rdi, for_code_points - mov rcx, 52 - rep stosb - - mov byte [gosub_depth], 0 - - mov rdi, gosub_points - mov rcx, 20 - rep stosb - - mov rdi, string_vars - mov rcx, 1024 - rep stosb - - ret - - -; ------------------------------------------------------------------ -; ASSIGNMENT - -assign: - cmp rax, VARIABLE ; Are we starting with a number var? - je .do_num_var - - mov rdi, string_vars ; Otherwise it's a string var - mov rax, 128 - mul rbx ; (rbx = string number, passed back from get_token) - add rdi, rax - - push rdi - - call get_token - mov byte al, [token] - cmp al, '=' - jne near .error - - call get_token - cmp rax, QUOTE - je .second_is_quote - - cmp rax, STRING_VAR - jne near .error - - mov rsi, string_vars ; Otherwise it's a string var - mov rax, 128 - mul rbx ; (rbx = string number, passed back from get_token) - add rsi, rax - - pop rdi - call b_string_copy - - jmp mainloop - - -.second_is_quote: - mov rsi, token - pop rdi - call b_string_copy - - jmp mainloop - - -.do_num_var: - xor rax, rax - mov byte al, [token] - mov byte [.tmp], al - - call get_token - mov byte al, [token] - cmp al, '=' - jne near .error - - call get_token - cmp rax, NUMBER - je .second_is_num - - cmp rax, VARIABLE - je .second_is_variable - - cmp rax, STRING - je near .second_is_string - - cmp rax, UNKNOWN - jne near .error - - mov byte al, [token] ; Address of string var? - cmp al, '&' - jne near .error - - call get_token ; Let's see if there's a string var - cmp rax, STRING_VAR - jne near .error - - mov rdi, string_vars - mov rax, 128 - mul rbx - add rdi, rax - - mov rbx, rdi - - mov byte al, [.tmp] - call set_var - - jmp mainloop - - -.second_is_variable: - xor rax, rax - mov byte al, [token] - - call get_var - mov rbx, rax - mov byte al, [.tmp] - call set_var - - jmp .check_for_more - - -.second_is_num: - mov rsi, token - call b_string_to_int - - mov rbx, rax ; Number to insert in variable table - - xor rax, rax - mov byte al, [.tmp] - - call set_var - - - ; The assignment could be simply "X = 5" etc. Or it could be - ; "X = Y + 5" -- ie more complicated. So here we check to see if - ; there's a delimiter... - -.check_for_more: - mov rax, [prog] ; Save code location in case there's no delimiter - mov [.tmp_loc], rax - - call get_token ; Any more to deal with in this assignment? - mov byte al, [token] - cmp al, '+' - je .theres_more - cmp al, '-' - je .theres_more - cmp al, '*' - je .theres_more - cmp al, '/' - je .theres_more - cmp al, '%' - je .theres_more - - mov rax, [.tmp_loc] ; Not a delimiter, so step back before the token - mov [prog], rax ; that we just grabbed - - jmp mainloop ; And go back to the code interpreter! - - -.theres_more: - mov byte [.delim], al - - call get_token - cmp rax, VARIABLE - je .handle_variable - - mov rsi, token - call b_string_to_int - mov rbx, rax - - xor rax, rax - mov byte al, [.tmp] - - call get_var ; This also points rsi at right place in variable table - - cmp byte [.delim], '+' - jne .not_plus - - add rax, rbx - jmp .finish - -.not_plus: - cmp byte [.delim], '-' - jne .not_minus - - sub rax, rbx - jmp .finish - -.not_minus: - cmp byte [.delim], '*' - jne .not_times - - mul rbx - jmp .finish - -.not_times: - cmp byte [.delim], '/' - jne .not_divide - - xor rdx, rdx - div rbx - jmp .finish - -.not_divide: - xor rdx, rdx - div rbx - mov rax, rdx ; Get remainder - -.finish: - mov rbx, rax - mov byte al, [.tmp] - call set_var - - jmp .check_for_more - - -.handle_variable: - xor rax, rax - mov byte al, [token] - - call get_var - - mov rbx, rax - - xor rax, rax - mov byte al, [.tmp] - - call get_var - - cmp byte [.delim], '+' - jne .vnot_plus - - add rax, rbx - jmp .vfinish - -.vnot_plus: - cmp byte [.delim], '-' - jne .vnot_minus - - sub rax, rbx - jmp .vfinish - -.vnot_minus: - cmp byte [.delim], '*' - jne .vnot_times - - mul rbx - jmp .vfinish - -.vnot_times: - cmp byte [.delim], '/' - jne .vnot_divide - - mov dx, 0 - div rbx - jmp .finish - -.vnot_divide: - mov dx, 0 - div rbx - mov rax, rdx ; Get remainder - -.vfinish: - mov rbx, rax - mov byte al, [.tmp] - call set_var - - jmp .check_for_more - - -.second_is_string: - mov rdi, token - mov rsi, progstart_keyword - call b_string_compare - je .is_progstart - - mov rsi, ramstart_keyword - call b_string_compare - je .is_ramstart - - jmp .error - -.is_progstart: - xor rax, rax - mov byte al, [.tmp] - - mov rbx, [load_point] - call set_var - - jmp mainloop - - - -.is_ramstart: - xor rax, rax - mov byte al, [.tmp] - - mov rbx, [prog_end] - inc rbx - inc rbx - inc rbx - call set_var - - jmp mainloop - - -.error: - mov rsi, err_syntax - jmp error - - - .tmp db 0 - .tmp_loc dq 0 - .delim db 0 - - -; ================================================================== -; SPECIFIC COMMAND CODE STARTS HERE - -; ------------------------------------------------------------------ -; ALERT - -do_alert: - call get_token - - cmp rax, QUOTE - je .is_quote - - mov rsi, err_syntax - jmp error - -.is_quote: - mov rax, token ; First string for alert box - xor rbx, rbx ; Others are blank - xor rcx, rcx - mov dx, 0 ; One-choice box - jmp mainloop - - -; ------------------------------------------------------------------ -; CALL - -do_call: - call get_token - cmp rax, NUMBER - je .is_number - - xor rax, rax - mov byte al, [token] - call get_var - jmp .execute_call - -.is_number: - mov rsi, token - call b_string_to_int - -.execute_call: - xor rbx, rbx - xor rcx, rcx - mov dx, 0 - mov rdi, 0 - mov rsi, 0 - - call rax - - jmp mainloop - - - -; ------------------------------------------------------------------ -; CLS - -do_cls: - call b_screen_clear - jmp mainloop - - -; ------------------------------------------------------------------ -; CURSOR - -do_cursor: - call get_token - - mov rsi, token - mov rdi, .on_str - call b_string_compare - jc .turn_on - - mov rsi, token - mov rdi, .off_str - call b_string_compare - jc .turn_off - - mov rsi, err_syntax - jmp error - -.turn_on: - call b_show_cursor - jmp mainloop - -.turn_off: - call b_hide_cursor - jmp mainloop - - - .on_str db "ON", 0 - .off_str db "OFF", 0 - - -; ------------------------------------------------------------------ -; CURSCHAR - -do_curschar: - call get_token - - cmp rax, VARIABLE - je .is_ok - - mov rsi, err_syntax - jmp error - -.is_ok: - xor rax, rax - mov byte al, [token] - - push rax ; Store variable we're going to use - -; mov ah, 08h -; xor rbx, rbx -; int 10h ; Get char at current cursor location - - xor rbx, rbx ; We only want the lower byte (the char, not attribute) - mov bl, al - - pop rax ; Get the variable back - - call set_var ; And store the value - - jmp mainloop - - -; ------------------------------------------------------------------ -; END - -do_end: - mov rsp, [orig_stack] - ret - - -; ------------------------------------------------------------------ -; FOR - -do_for: - call get_token ; Get the variable we're using in this loop - - cmp rax, VARIABLE - jne near .error - - xor rax, rax - mov byte al, [token] - mov byte [.tmp_var], al ; Store it in a temporary location for now - - call get_token - - xor rax, rax ; Check it's followed up with '=' - mov byte al, [token] - cmp al, '=' - jne .error - - call get_token ; Next we want a number - - cmp rax, NUMBER - jne .error - - mov rsi, token ; Convert it - call b_string_to_int - - - ; At this stage, we've read something like "FOR X = 1" - ; so let's store that 1 in the variable table - - mov rbx, rax - xor rax, rax - mov byte al, [.tmp_var] - call set_var - - - call get_token ; Next we're looking for "TO" - - cmp rax, STRING - jne .error - - mov rax, token - call b_string_uppercase - - mov rsi, token - mov rdi, .to_string - call b_string_compare - jnc .error - - ; So now we're at "FOR X = 1 TO" - - call get_token - - cmp rax, NUMBER - jne .error - - mov rsi, token ; Get target number - call b_string_to_int - - mov rbx, rax - - xor rax, rax - mov byte al, [.tmp_var] - - sub al, 65 ; Store target number in table - mov rdi, for_variables - add rdi, rax - add rdi, rax - mov rax, rbx - stosw - - - ; So we've got the variable, assigned it the starting number, and put into - ; our table the limit it should reach. But we also need to store the point in - ; code after the FOR line we should return to if NEXT X doesn't complete the loop... -; xor rax, rax - xor rax, rax -; xor eax, eax - mov byte al, [.tmp_var] - - sub al, 65 ; Store code position to return to in table - mov rdi, for_code_points -; add rdi, rax -; add rdi, rax - shl rax, 3 - add rdi, rax - mov rax, [prog] - stosq - - jmp mainloop - - -.error: - mov rsi, err_syntax - jmp error - - - .tmp_var db 0 - .to_string db 'TO', 0 - - -; ------------------------------------------------------------------ -; GETKEY - -do_getkey: - call get_token - cmp rax, VARIABLE - je .is_variable - - mov rsi, err_syntax - jmp error - -.is_variable: - xor rax, rax - mov byte al, [token] - - push rax - - call b_input_key_check - - xor rbx, rbx - mov bl, al - - pop rax - - call set_var - - jmp mainloop - - -; ------------------------------------------------------------------ -; GOSUB - -do_gosub: - call get_token ; Get the number (label) - - cmp rax, STRING - je .is_ok - - mov rsi, err_goto_notlabel - jmp error - -.is_ok: - mov rsi, token ; Back up this label - mov rdi, .tmp_token - call b_string_copy - - mov rax, .tmp_token - call b_string_length - - mov rdi, .tmp_token ; Add ':' char to end for searching - add rdi, rax - mov al, ':' - stosb - mov al, 0 - stosb - - inc byte [gosub_depth] - - xor rax, rax - mov byte al, [gosub_depth] ; Get current GOSUB nest level - - cmp al, 9 - jle .within_limit - - mov rsi, err_nest_limit - jmp error - -.within_limit: - mov rdi, gosub_points ; Move into our table of pointers - add rdi, rax ; Table is words (not bytes) - add rdi, rax - mov rax, [prog] - stosw ; Store current location before jump - - - mov rax, [load_point] - mov [prog], rax ; Return to start of program to find label - -.loop: - call get_token - - cmp rax, LABEL - jne .line_loop - - mov rsi, token - mov rdi, .tmp_token - call b_string_compare - jc mainloop - -.line_loop: ; Go to end of line - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - cmp al, 10 - jne .line_loop - - mov rax, [prog] - mov rbx, [prog_end] - cmp rax, rbx - jg .past_end - - jmp .loop - -.past_end: - mov rsi, err_label_notfound - jmp error - - .tmp_token times 30 db 0 - - -; ------------------------------------------------------------------ -; GOTO - -do_goto: - call get_token ; Get the next token - - cmp rax, STRING - je .is_ok - - mov rsi, err_goto_notlabel - jmp error - -.is_ok: - mov rsi, token ; Back up this label - mov rdi, .tmp_token - call b_string_copy - - mov rax, .tmp_token - call b_string_length - - mov rdi, .tmp_token ; Add ':' char to end for searching - add rdi, rax - mov al, ':' - stosb - mov al, 0 - stosb - - mov rax, [load_point] - mov [prog], rax ; Return to start of program to find label - -.loop: - call get_token - - cmp rax, LABEL - jne .line_loop - - mov rsi, token - mov rdi, .tmp_token - call b_string_compare - jc mainloop - -.line_loop: ; Go to end of line - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - - cmp al, 10 - jne .line_loop - - mov rax, [prog] - mov rbx, [prog_end] - cmp rax, rbx - jg .past_end - - jmp .loop - -.past_end: - mov rsi, err_label_notfound - jmp error - - .tmp_token times 30 db 0 - - -; ------------------------------------------------------------------ -; IF - -do_if: - call get_token - - cmp rax, VARIABLE ; If can only be followed by a variable - je .num_var - - cmp rax, STRING_VAR - je near .string_var - - mov rsi, err_syntax - jmp error - -.num_var: - xor rax, rax - mov byte al, [token] - call get_var - - mov rdx, rax ; Store value of first part of comparison - - call get_token ; Get the delimiter - mov byte al, [token] - cmp al, '=' - je .equals - cmp al, '>' - je .greater - cmp al, '<' - je .less - - mov rsi, err_syntax ; If not one of the above, error out - jmp error - -.equals: - call get_token ; Is this 'X = Y' (equals another variable?) - - cmp rax, CHAR - je .equals_char - - mov byte al, [token] - call is_letter - jc .equals_var - - mov rsi, token ; Otherwise it's, eg 'X = 1' (a number) - call b_string_to_int - - cmp rax, rdx ; On to the THEN bit if 'X = num' matches - je near .on_to_then - - jmp .finish_line ; Otherwise skip the rest of the line - -.equals_char: - xor rax, rax - mov byte al, [token] - - cmp rax, rdx - je near .on_to_then - - jmp .finish_line - -.equals_var: - xor rax, rax - mov byte al, [token] - - call get_var - - cmp rax, rdx ; Do the variables match? - je near .on_to_then ; On to the THEN bit if so - - jmp .finish_line ; Otherwise skip the rest of the line - -.greater: - call get_token ; Greater than a variable or number? - mov byte al, [token] - call is_letter - jc .greater_var - - mov rsi, token ; Must be a number here... - call b_string_to_int - - cmp rax, rdx - jl near .on_to_then - - jmp .finish_line - -.greater_var: ; Variable in this case - xor rax, rax - mov byte al, [token] - - call get_var - - cmp rax, rdx ; Make the comparison! - jl .on_to_then - - jmp .finish_line - -.less: - call get_token - mov byte al, [token] - call is_letter - jc .less_var - - mov rsi, token - call b_string_to_int - - cmp rax, rdx - jg .on_to_then - - jmp .finish_line - -.less_var: - xor rax, rax - mov byte al, [token] - - call get_var - - cmp rax, rdx - jg .on_to_then - - jmp .finish_line - -.string_var: - mov byte [.tmp_string_var], bl - - call get_token - - mov byte al, [token] - cmp al, '=' - jne .error - - call get_token - cmp rax, STRING_VAR - je .second_is_string_var - - cmp rax, QUOTE - jne .error - - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - mov rdi, token - call b_string_compare - je .on_to_then - - jmp .finish_line - -.second_is_string_var: - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - - mov rdi, string_vars - xor rbx, rbx - mov byte bl, [.tmp_string_var] - mov rax, 128 - mul rbx - add rdi, rax - - call b_string_compare - jc .on_to_then - - jmp .finish_line - -.on_to_then: - call get_token - - mov rsi, token - mov rdi, then_keyword - call b_string_compare - - jc .then_present - - mov rsi, err_syntax - jmp error - -.then_present: ; Continue rest of line like any other command! - jmp mainloop - -.finish_line: ; IF wasn't fulfilled, so skip rest of line - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - cmp al, 10 - jne .finish_line - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - .tmp_string_var db 0 - - -; ------------------------------------------------------------------ -; INPUT - -do_input: - mov al, 0 ; Clear string from previous usage - mov rdi, .tmpstring - mov rcx, 128 - rep stosb - - call get_token - - cmp rax, VARIABLE ; We can only INPUT to variables! - je .number_var - - cmp rax, STRING_VAR - je .string_var - - mov rsi, err_syntax - jmp error - -.number_var: - mov rdi, .tmpstring ; Get input from the user - mov rcx, 50 - call b_input_string - - mov rsi, .tmpstring - call b_string_length - cmp rcx, 0 - jne .char_entered - - mov byte [.tmpstring], '0' ; If enter hit, fill variable with zero - mov byte [.tmpstring + 1], 0 - -.char_entered: - mov rsi, .tmpstring ; Convert to integer format - call b_string_to_int - mov rbx, rax - - xor rax, rax - mov byte al, [token] ; Get the variable where we're storing it... - call set_var ; ...and store it! - - call b_print_newline - - jmp mainloop - -.string_var: - push rbx - - mov rdi, .tmpstring - mov rcx, 50 - call b_input_string - - mov rsi, .tmpstring - mov rdi, string_vars - - pop rbx - - mov rax, 128 - mul rbx - - add rdi, rax - call b_string_copy - - call b_print_newline - - jmp mainloop - - .tmpstring times 128 db 0 - - -; ------------------------------------------------------------------ -; LOAD - -do_load: - call get_token - cmp rax, QUOTE - je .is_quote - - cmp rax, STRING_VAR - jne .error - - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - jmp .get_position - -.is_quote: - mov rsi, token - -.get_position: - mov rax, rsi -; call b_file_exists - jc .file_not_exists - - mov rdx, rax ; Store for now - - call get_token - - cmp rax, VARIABLE - je .second_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.load_part: - mov rcx, rax - - mov rax, rdx - -; call b_load_file - - xor rax, rax - mov byte al, 'S' - call set_var - - xor rax, rax - mov byte al, 'R' - xor rbx, rbx - call set_var - - jmp mainloop - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .load_part - -.file_not_exists: - xor rax, rax - mov byte al, 'R' - mov rbx, 1 - call set_var - - call get_token ; Skip past the loading point -- unnecessary now - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - -; ------------------------------------------------------------------ -; MOVE - -do_move: - call get_token - - cmp rax, VARIABLE - je .first_is_var - - mov rsi, token - call b_string_to_int - mov dl, al - jmp .onto_second - -.first_is_var: - xor rax, rax - mov byte al, [token] - call get_var - mov dl, al - -.onto_second: - call get_token - - cmp rax, VARIABLE - je .second_is_var - - mov rsi, token - call b_string_to_int - mov dh, al - jmp .finish - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - mov dh, al - -.finish: - call b_move_cursor - - jmp mainloop - - -; ------------------------------------------------------------------ -; NEXT - -do_next: - call get_token - - cmp rax, VARIABLE ; NEXT must be followed by a variable - jne .error - - xor rax, rax - mov byte al, [token] - call get_var - - inc rax ; NEXT increments the variable, of course! - - mov rbx, rax - - xor rax, rax - mov byte al, [token] - - sub al, 65 - mov rsi, for_variables - add rsi, rax - add rsi, rax - lodsw ; Get the target number from the table - - inc rax ; (Make the loop inclusive of target number) - cmp rax, rbx ; Do the variable and target match? - je .loop_finished - - xor rax, rax ; If not, store the updated variable - mov byte al, [token] - call set_var - - xor rax, rax ; Find the code point and go back - mov byte al, [token] - sub al, 65 - mov rsi, for_code_points -; add rsi, rax -; add rsi, rax - shl rax, 3 - add rsi, rax - lodsq - - mov [prog], rax - jmp mainloop - -.loop_finished: - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - -; ------------------------------------------------------------------ -; PAUSE - -do_pause: - call get_token - - cmp rax, VARIABLE - je .is_var - - mov rsi, token - call b_string_to_int - jmp .finish - -.is_var: - xor rax, rax - mov byte al, [token] - call get_var - -.finish: -; call b_pause - jmp mainloop - - -; ------------------------------------------------------------------ -; PEEK - -do_peek: - call get_token - - cmp rax, VARIABLE - jne .error - - xor rax, rax - mov byte al, [token] - mov byte [.tmp_var], al - - call get_token - - cmp rax, VARIABLE - je .dereference - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.store: - mov rsi, rax - xor rbx, rbx - mov byte bl, [rsi] - xor rax, rax - mov byte al, [.tmp_var] - call set_var - - jmp mainloop - -.dereference: - mov byte al, [token] - call get_var - jmp .store - -.error: - mov rsi, err_syntax - jmp error - - - .tmp_var db 0 - - -; ------------------------------------------------------------------ -; POKE - -do_poke: - call get_token - - cmp rax, VARIABLE - je .first_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - - cmp rax, 255 - jg .error - - mov byte [.first_value], al - jmp .onto_second - - -.first_is_var: - xor rax, rax - mov byte al, [token] - call get_var - - mov byte [.first_value], al - -.onto_second: - call get_token - - cmp rax, VARIABLE - je .second_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.got_value: - mov rdi, rax - xor rax, rax - mov byte al, [.first_value] - mov byte [rdi], al - - jmp mainloop - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .got_value - -.error: - mov rsi, err_syntax - jmp error - - .first_value db 0 - - -; ------------------------------------------------------------------ -; PORT - -do_port: - call get_token - mov rsi, token - - mov rdi, .out_cmd - call b_string_compare - jc .do_out_cmd - - mov rdi, .in_cmd - call b_string_compare - jc .do_in_cmd - - jmp .error - -.do_out_cmd: - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int ; Now rax = port number - mov rdx, rax - - call get_token - cmp rax, NUMBER - je .out_is_num - - cmp rax, VARIABLE - je .out_is_var - - jmp .error - -.out_is_num: - mov rsi, token - call b_string_to_int -; call b_port_byte_out - jmp mainloop - -.out_is_var: - xor rax, rax - mov byte al, [token] - call get_var - -; call b_port_byte_out - jmp mainloop - -.do_in_cmd: - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - mov rdx, rax - - call get_token - cmp rax, VARIABLE - jne .error - - mov byte cl, [token] - -; call b_port_byte_in - xor rbx, rbx - mov bl, al - - mov al, cl - call set_var - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - - .out_cmd db "OUT", 0 - .in_cmd db "IN", 0 - - -; ------------------------------------------------------------------ -; PRINT - -do_print: - call get_token ; Get part after PRINT - - cmp rax, QUOTE ; What type is it? - je .print_quote - - cmp rax, VARIABLE ; Numerical variable (eg X) - je .print_var - - cmp rax, STRING_VAR ; String variable (eg $1) - je .print_string_var - - cmp rax, STRING ; Special keyword (eg CHR or HEX) - je .print_keyword - - mov rsi, err_print_type ; We only print quoted strings and vars! - jmp error - -.print_var: - xor rax, rax - mov byte al, [token] - call get_var ; Get its value - mov rdi, tstring - mov rsi, rdi - call b_int_to_string ; Convert to string - call b_print_string - - jmp .newline_or_not - -.print_quote: ; If it's quoted text, print it - mov rsi, token - call b_print_string - - jmp .newline_or_not - -.print_string_var: - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - call b_print_string - - jmp .newline_or_not - -.print_keyword: - mov rsi, token - mov rdi, chr_keyword - call b_string_compare - jc .is_chr - - mov rdi, hex_keyword - call b_string_compare - jc .is_hex - - mov rsi, err_syntax - jmp error - -.is_chr: - call get_token - - cmp rax, VARIABLE - jne .error - - xor rax, rax - mov byte al, [token] - call get_var - -; mov ah, 0Eh -; int 10h - - jmp .newline_or_not - -.is_hex: - call get_token - - cmp rax, VARIABLE - jne .error - - xor rax, rax - mov byte al, [token] - call get_var - - call b_debug_dump_al ;print_2hex - - jmp .newline_or_not - -.error: - mov rsi, err_syntax - jmp error - -.newline_or_not: - ; We want to see if the command ends with ';' -- which means that - ; we shouldn't print a newline after it finishes. So we store the - ; current program location to pop ahead and see if there's the ';' - ; character -- otherwise we put the program location back and resume - ; the main loop - mov rax, [prog] - mov [.tmp_loc], rax - - call get_token - cmp rax, UNKNOWN - jne .ignore - - xor rax, rax - mov al, [token] - cmp al, ';' - jne .ignore - - jmp mainloop ; And go back to interpreting the code! - -.ignore: - call b_print_newline - - mov rax, [.tmp_loc] - mov [prog], rax - - jmp mainloop - - .tmp_loc dq 0 - - -; ------------------------------------------------------------------ -; RAND - -do_rand: - call get_token - cmp rax, VARIABLE - jne .error - - mov byte al, [token] - mov byte [.tmp], al - - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - mov [.num1], rax - - call get_token - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - mov [.num2], rax - - mov rax, [.num1] - mov rbx, [.num2] -; call b_get_random - - mov rbx, rcx - xor rax, rax - mov byte al, [.tmp] - call set_var - - jmp mainloop - - .tmp db 0 - .num1 dq 0 - .num2 dq 0 - -.error: - mov rsi, err_syntax - jmp error - - -; ------------------------------------------------------------------ -; REM - -do_rem: - mov rsi, [prog] - mov byte al, [rsi] - inc qword [prog] - cmp al, 10 ; Find end of line after REM - jne do_rem - - jmp mainloop - - -; ------------------------------------------------------------------ -; RETURN - -do_return: - xor rax, rax - mov byte al, [gosub_depth] - cmp al, 0 - jne .is_ok - - mov rsi, err_return - jmp error - -.is_ok: - mov rsi, gosub_points - add rsi, rax ; Table is words (not bytes) - add rsi, rax - lodsw - mov [prog], rax - dec byte [gosub_depth] - - jmp mainloop - - -; ------------------------------------------------------------------ -; SAVE - -do_save: - call get_token - cmp rax, QUOTE - je .is_quote - - cmp rax, STRING_VAR - jne near .error - - mov rsi, string_vars - mov rax, 128 - mul rbx - add rsi, rax - jmp .get_position - -.is_quote: - mov rsi, token - -.get_position: - mov rdi, .tmp_filename - call b_string_copy - - call get_token - - cmp rax, VARIABLE - je .second_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.set_data_loc: - mov [.data_loc], rax - - call get_token - - cmp rax, VARIABLE - je .third_is_var - - cmp rax, NUMBER - jne .error - - mov rsi, token - call b_string_to_int - -.set_data_size: - mov [.data_size], rax - - mov rax, .tmp_filename - mov rbx, [.data_loc] - mov rcx, [.data_size] - -; call b_write_file - jc .save_failure - - xor rax, rax - mov byte al, 'R' - xor rbx, rbx - call set_var - - jmp mainloop - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .set_data_loc - -.third_is_var: - xor rax, rax - mov byte al, [token] - call get_var - jmp .set_data_size - -.save_failure: - xor rax, rax - mov byte al, 'R' - mov rbx, 1 - call set_var - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - - .filename_loc dw 0 - .data_loc dw 0 - .data_size dw 0 - - .tmp_filename times 15 db 0 - - -; ------------------------------------------------------------------ -; SERIAL - -do_serial: - call get_token - mov rsi, token - - mov rdi, .on_cmd - call b_string_compare - jc .do_on_cmd - - mov rdi, .send_cmd - call b_string_compare - jc .do_send_cmd - - mov rdi, .rec_cmd - call b_string_compare - jc .do_rec_cmd - - jmp .error - -.do_on_cmd: - call get_token - cmp rax, NUMBER - je .do_on_cmd_ok - jmp .error - -.do_on_cmd_ok: - mov rsi, token - call b_string_to_int - cmp rax, 1200 - je .on_cmd_slow_mode - cmp rax, 9600 - je .on_cmd_fast_mode - - jmp .error - -.on_cmd_fast_mode: - xor rax, rax -; call b_serial_port_enable - jmp mainloop - -.on_cmd_slow_mode: - mov rax, 1 -; call b_serial_port_enable - jmp mainloop - -.do_send_cmd: - call get_token - cmp rax, NUMBER - je .send_number - - cmp rax, VARIABLE - je .send_variable - - jmp .error - -.send_number: - mov rsi, token - call b_string_to_int -; call b_send_via_serial - jmp mainloop - -.send_variable: - xor rax, rax - mov byte al, [token] - call get_var -; call b_send_via_serial - jmp mainloop - -.do_rec_cmd: - call get_token - cmp rax, VARIABLE - jne .error - - mov byte al, [token] - - xor rcx, rcx - mov cl, al -; call b_get_via_serial - - xor rbx, rbx - mov bl, al - mov al, cl - call set_var - - jmp mainloop - -.error: - mov rsi, err_syntax - jmp error - - .on_cmd db "ON", 0 - .send_cmd db "SEND", 0 - .rec_cmd db "REC", 0 - - -; ------------------------------------------------------------------ -; SOUND - -do_sound: - call get_token - - cmp rax, VARIABLE - je .first_is_var - - mov rsi, token - call b_string_to_int - jmp .done_first - -.first_is_var: - xor rax, rax - mov byte al, [token] - call get_var - -.done_first: - call b_speaker_tone - - call get_token - - cmp rax, VARIABLE - je .second_is_var - - mov rsi, token - call b_string_to_int - jmp .finish - -.second_is_var: - xor rax, rax - mov byte al, [token] - call get_var - -.finish: -; call b_pause - call b_speaker_off - - jmp mainloop - - -; ------------------------------------------------------------------ -; WAITKEY - -do_waitkey: - call get_token - cmp rax, VARIABLE - je .is_variable - - mov rsi, err_syntax - jmp error - -.is_variable: - xor rax, rax - mov byte al, [token] - - push rax - - call b_input_key_wait - - cmp rax, 48E0h - je .up_pressed - - cmp rax, 50E0h - je .down_pressed - - cmp rax, 4BE0h - je .left_pressed - - cmp rax, 4DE0h - je .right_pressed - -.store: - xor rbx, rbx - mov bl, al - - pop rax - - call set_var - - jmp mainloop - -.up_pressed: - mov rax, 1 - jmp .store - -.down_pressed: - mov rax, 2 - jmp .store - -.left_pressed: - mov rax, 3 - jmp .store - -.right_pressed: - mov rax, 4 - jmp .store - - -; ================================================================== -; INTERNAL ROUTINES FOR INTERPRETER - -; ------------------------------------------------------------------ -; Get value of variable character specified in AL (eg 'A') - -get_var: - sub al, 65 - mov rsi, variables - add rsi, rax - add rsi, rax - lodsw - ret - - -; ------------------------------------------------------------------ -; Set value of variable character specified in AL (eg 'A') -; with number specified in rbx - -set_var: - mov ah, 0 - sub al, 65 ; Remove ASCII codes before 'A' - - mov rdi, variables ; Find position in table (of words) - add rdi, rax - add rdi, rax - mov rax, rbx - stosw - ret - - -; ------------------------------------------------------------------ -; Get token from current position in prog - -get_token: - mov rsi, [prog] - lodsb - - cmp al, 13 - je .newline - - cmp al, 10 - je .newline - - cmp al, ' ' - je .newline - - call is_number - jc get_number_token - - cmp al, '"' - je get_quote_token - - cmp al, 39 ; Quote mark (') - je get_char_token - - cmp al, '$' - je near get_string_var_token - - jmp get_string_token - -.newline: - inc qword [prog] - jmp get_token - -get_number_token: - mov rsi, [prog] - mov rdi, token - -.loop: - lodsb - cmp al, 13 - je .done - cmp al, 10 - je .done - cmp al, ' ' - je .done - call is_number - jc .fine - - mov rsi, err_char_in_num - jmp error - -.fine: - stosb - inc qword [prog] - jmp .loop - -.done: - mov al, 0 ; Zero-terminate the token - stosb - - mov rax, NUMBER ; Pass back the token type - ret - -get_char_token: - inc qword [prog] ; Move past first quote (') - - mov rsi, [prog] - lodsb - - mov byte [token], al - - lodsb - cmp al, 39 ; Needs to finish with another quote - je .is_ok - - mov rsi, err_quote_term - jmp error - -.is_ok: - inc qword [prog] - inc qword [prog] - - mov rax, CHAR - ret - -get_quote_token: - inc qword [prog] ; Move past first quote (") char - mov qword rsi, [prog] - mov rdi, token -.loop: - lodsb - cmp al, '"' - je .done - cmp al, 10 - je .error - stosb - inc qword [prog] - jmp .loop - -.done: - mov al, 0 ; Zero-terminate the token - stosb - inc qword [prog] ; Move past final quote - - mov rax, QUOTE ; Pass back token type - ret - -.error: - mov rsi, err_quote_term - jmp error - -get_string_var_token: - lodsb - xor rbx, rbx ; If it's a string var, pass number of string in rbx - mov bl, al - sub bl, 49 - - inc qword [prog] - inc qword [prog] - - mov rax, STRING_VAR - ret - -get_string_token: - mov qword rsi, [prog] - mov rdi, token -.loop: - lodsb - cmp al, 13 - je .done - cmp al, 10 - je .done - cmp al, ' ' - je .done - stosb - inc qword [prog] - jmp .loop -.done: - mov al, 0 ; Zero-terminate the token - stosb - - mov rax, token - call b_string_uppercase - - mov rsi, token - call b_string_length ; How long was the token? - cmp rcx, 1 ; If 1 char, it's a variable or delimiter - je .is_not_string - - mov rsi, token ; If the token ends with ':', it's a label - add rsi, rax - dec rsi - lodsb - cmp al, ':' - je .is_label - - mov rax, STRING ; Otherwise it's a general string of characters - ret - -.is_label: - mov rax, LABEL - ret - -.is_not_string: - mov byte al, [token] - call is_letter - jc .is_var - - mov rax, UNKNOWN - ret - -.is_var: - mov rax, VARIABLE ; Otherwise probably a variable - ret - - -; ------------------------------------------------------------------ -; Set carry flag if AL contains ASCII number - -is_number: - cmp al, 48 - jl .not_number - cmp al, 57 - jg .not_number - stc - ret -.not_number: - clc - ret - - -; ------------------------------------------------------------------ -; Set carry flag if AL contains ASCII letter - -is_letter: - cmp al, 65 - jl .not_letter - cmp al, 90 - jg .not_letter - stc - ret - -.not_letter: - clc - ret - - -; ------------------------------------------------------------------ -; Print error message and quit out - -error: - call b_print_newline - call b_print_string ; Print error message - call b_print_newline - - mov rsp, [orig_stack] ; Restore the stack to as it was when BASIC started - - ret ; And finish - - - ; Error messages text... - - err_char_in_num db "Error: unexpected character in number", 0 - err_quote_term db "Error: quoted string or character not terminated correctly", 0 - err_print_type db "Error: PRINT command not followed by quoted text or variable", 0 - err_cmd_unknown db "Error: unknown command", 0 - err_goto_notlabel db "Error: GOTO or GOSUB not followed by label", 0 - err_label_notfound db "Error: GOTO or GOSUB label not found", 0 - err_return db "Error: RETURN without GOSUB", 0 - err_nest_limit db "Error: FOR or GOSUB nest limit exceeded", 0 - err_next db "Error: NEXT without FOR", 0 - err_syntax db "Error: syntax error", 0 - - - -; ================================================================== -; DATA SECTION - - orig_stack dq 0 ; Original stack location when BASIC started - - prog dq 0 ; Pointer to current location in BASIC code - prog_end dq 0 ; Pointer to final byte of BASIC code - - load_point dq 0 - - token_type db 0 ; Type of last token read (eg NUMBER, VARIABLE) - token times 255 db 0 ; Storage space for the token - tstring times 255 db 0 - -align 16 - variables times 26 dq 0 ; Storage space for variables A to Z -align 16 - for_variables times 26 dq 0 ; Storage for FOR loops -align 16 - for_code_points times 26 dq 0 ; Storage for code positions where FOR loops start - - alert_cmd db "ALERT", 0 - call_cmd db "CALL", 0 - cls_cmd db "CLS", 0 - cursor_cmd db "CURSOR", 0 - curschar_cmd db "CURSCHAR", 0 - end_cmd db "END", 0 - for_cmd db "FOR", 0 - gosub_cmd db "GOSUB", 0 - goto_cmd db "GOTO", 0 - getkey_cmd db "GETKEY", 0 - if_cmd db "IF", 0 - input_cmd db "INPUT", 0 - load_cmd db "LOAD", 0 - move_cmd db "MOVE", 0 - next_cmd db "NEXT", 0 - pause_cmd db "PAUSE", 0 - peek_cmd db "PEEK", 0 - poke_cmd db "POKE", 0 - port_cmd db "PORT", 0 - print_cmd db "PRINT", 0 - rem_cmd db "REM", 0 - rand_cmd db "RAND", 0 - return_cmd db "RETURN", 0 - save_cmd db "SAVE", 0 - serial_cmd db "SERIAL", 0 - sound_cmd db "SOUND", 0 - waitkey_cmd db "WAITKEY", 0 - - then_keyword db "THEN", 0 - chr_keyword db "CHR", 0 - hex_keyword db "HEX", 0 - - progstart_keyword db "PROGSTART", 0 - ramstart_keyword db "RAMSTART", 0 - - gosub_depth db 0 - gosub_points times 10 dq 0 ; Points in code to RETURN to - - string_vars times 1024 db 0 ; 8 * 128 byte strings - - -; ------------------------------------------------------------------ -basic_prog: - DB 'CLS',13,10 - DB 'PRINT "Please type your name: ";',13,10 - DB 'INPUT $N',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT "Hello ";',13,10 - DB 'PRINT $N;',13,10 - DB 'PRINT ", welcome to MikeOS Basic (in 64-bit mode)!"',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT "It supports FOR...NEXT loops and simple integer maths..."',13,10 - DB 'PRINT ""',13,10 - DB 'FOR I = 1 TO 15',13,10 - DB 'J = I * I',13,10 - DB 'K = J * I',13,10 - DB 'L = K * I',13,10 - DB 'PRINT I ;',13,10 - DB 'PRINT " ";',13,10 - DB 'PRINT J ;',13,10 - DB 'PRINT " ";',13,10 - DB 'PRINT K ;',13,10 - DB 'PRINT " ";',13,10 - DB 'PRINT L',13,10 - DB 'NEXT I',13,10 - DB 'PRINT ""',13,10 - DB 'PRINT " ...and IF...THEN and GOSUB and lots of other stuff. Bye!"',13,10 - DB 'END',13,10 +; ================================================================== +; MikeOS -- The Mike Operating System kernel +; Copyright (C) 2006 - 2011 MikeOS Developers -- see doc/LICENSE.TXT +; +; BASIC CODE INTERPRETER +; ================================================================== + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +; ------------------------------------------------------------------ +; Token types + +%DEFINE VARIABLE 1 +%DEFINE STRING_VAR 2 +%DEFINE NUMBER 3 +%DEFINE STRING 4 +%DEFINE QUOTE 5 +%DEFINE CHAR 6 +%DEFINE UNKNOWN 7 +%DEFINE LABEL 8 + + +; ------------------------------------------------------------------ +; The BASIC interpreter execution starts here... + +b_run_basic: + mov [orig_stack], rsp ; Save stack pointer -- we might jump to the + ; error printing code and quit in the middle + ; some nested loops, and we want to preserve + ; the stack + mov rax, basic_prog ;embedded test program for a quick DOS test + mov rbx, 8192 ;default size for test program (not critical) + mov [load_point], rax ; rax was passed as starting location of code + + mov [prog], rax ; prog = pointer to current execution point in code + + add rbx, rax ; We were passed the .BAS byte size in rbx + sub rbx, 2 + mov [prog_end], rbx ; Make note of program end point + + + call clear_ram ; Clear variables etc. from previous run + ; of a BASIC program + + + +mainloop: + call get_token ; Get a token from the start of the line + + cmp rax, STRING ; Is the type a string of characters? + je .keyword ; If so, let's see if it's a keyword to process + + cmp rax, VARIABLE ; If it's a variable at the start of the line, + je near assign ; this is an assign (eg "X = Y + 5") + + cmp rax, STRING_VAR ; Same for a string variable (eg $1) + je near assign + + cmp rax, LABEL ; Don't need to do anything here - skip + je mainloop + + mov rsi, err_syntax ; Otherwise show an error and quit + jmp error + + +.keyword: + mov rsi, token ; Start trying to match commands + + mov rdi, alert_cmd + call b_string_compare + jc near do_alert + + mov rdi, call_cmd + call b_string_compare + jc near do_call + + mov rdi, cls_cmd + call b_string_compare + jc near do_cls + + mov rdi, cursor_cmd + call b_string_compare + jc near do_cursor + + mov rdi, curschar_cmd + call b_string_compare + jc near do_curschar + + mov rdi, end_cmd + call b_string_compare + jc near do_end + + mov rdi, for_cmd + call b_string_compare + jc near do_for + + mov rdi, getkey_cmd + call b_string_compare + jc near do_getkey + + mov rdi, gosub_cmd + call b_string_compare + jc near do_gosub + + mov rdi, goto_cmd + call b_string_compare + jc near do_goto + + mov rdi, input_cmd + call b_string_compare + jc near do_input + + mov rdi, if_cmd + call b_string_compare + jc near do_if + + mov rdi, load_cmd + call b_string_compare + jc near do_load + + mov rdi, move_cmd + call b_string_compare + jc near do_move + + mov rdi, next_cmd + call b_string_compare + jc near do_next + + mov rdi, pause_cmd + call b_string_compare + jc near do_pause + + mov rdi, peek_cmd + call b_string_compare + jc near do_peek + + mov rdi, poke_cmd + call b_string_compare + jc near do_poke + + mov rdi, port_cmd + call b_string_compare + jc near do_port + + mov rdi, print_cmd + call b_string_compare + jc near do_print + + mov rdi, rand_cmd + call b_string_compare + jc near do_rand + + mov rdi, rem_cmd + call b_string_compare + jc near do_rem + + mov rdi, return_cmd + call b_string_compare + jc near do_return + + mov rdi, save_cmd + call b_string_compare + jc near do_save + + mov rdi, serial_cmd + call b_string_compare + jc near do_serial + + mov rdi, sound_cmd + call b_string_compare + jc near do_sound + + mov rdi, waitkey_cmd + call b_string_compare + jc near do_waitkey + + mov rsi, err_cmd_unknown ; Command not found? + jmp error + + +; ------------------------------------------------------------------ +; CLEAR RAM + +clear_ram: + xor eax, eax + + mov rdi, variables + mov rcx, 52 + rep stosb + + mov rdi, for_variables + mov rcx, 52 + rep stosb + + mov rdi, for_code_points + mov rcx, 52 + rep stosb + + mov byte [gosub_depth], 0 + + mov rdi, gosub_points + mov rcx, 20 + rep stosb + + mov rdi, string_vars + mov rcx, 1024 + rep stosb + + ret + + +; ------------------------------------------------------------------ +; ASSIGNMENT + +assign: + cmp rax, VARIABLE ; Are we starting with a number var? + je .do_num_var + + mov rdi, string_vars ; Otherwise it's a string var + mov rax, 128 + mul rbx ; (rbx = string number, passed back from get_token) + add rdi, rax + + push rdi + + call get_token + mov byte al, [token] + cmp al, '=' + jne near .error + + call get_token + cmp rax, QUOTE + je .second_is_quote + + cmp rax, STRING_VAR + jne near .error + + mov rsi, string_vars ; Otherwise it's a string var + mov rax, 128 + mul rbx ; (rbx = string number, passed back from get_token) + add rsi, rax + + pop rdi + call b_string_copy + + jmp mainloop + + +.second_is_quote: + mov rsi, token + pop rdi + call b_string_copy + + jmp mainloop + + +.do_num_var: + xor rax, rax + mov byte al, [token] + mov byte [.tmp], al + + call get_token + mov byte al, [token] + cmp al, '=' + jne near .error + + call get_token + cmp rax, NUMBER + je .second_is_num + + cmp rax, VARIABLE + je .second_is_variable + + cmp rax, STRING + je near .second_is_string + + cmp rax, UNKNOWN + jne near .error + + mov byte al, [token] ; Address of string var? + cmp al, '&' + jne near .error + + call get_token ; Let's see if there's a string var + cmp rax, STRING_VAR + jne near .error + + mov rdi, string_vars + mov rax, 128 + mul rbx + add rdi, rax + + mov rbx, rdi + + mov byte al, [.tmp] + call set_var + + jmp mainloop + + +.second_is_variable: + xor rax, rax + mov byte al, [token] + + call get_var + mov rbx, rax + mov byte al, [.tmp] + call set_var + + jmp .check_for_more + + +.second_is_num: + mov rsi, token + call b_string_to_int + + mov rbx, rax ; Number to insert in variable table + + xor rax, rax + mov byte al, [.tmp] + + call set_var + + + ; The assignment could be simply "X = 5" etc. Or it could be + ; "X = Y + 5" -- ie more complicated. So here we check to see if + ; there's a delimiter... + +.check_for_more: + mov rax, [prog] ; Save code location in case there's no delimiter + mov [.tmp_loc], rax + + call get_token ; Any more to deal with in this assignment? + mov byte al, [token] + cmp al, '+' + je .theres_more + cmp al, '-' + je .theres_more + cmp al, '*' + je .theres_more + cmp al, '/' + je .theres_more + cmp al, '%' + je .theres_more + + mov rax, [.tmp_loc] ; Not a delimiter, so step back before the token + mov [prog], rax ; that we just grabbed + + jmp mainloop ; And go back to the code interpreter! + + +.theres_more: + mov byte [.delim], al + + call get_token + cmp rax, VARIABLE + je .handle_variable + + mov rsi, token + call b_string_to_int + mov rbx, rax + + xor rax, rax + mov byte al, [.tmp] + + call get_var ; This also points rsi at right place in variable table + + cmp byte [.delim], '+' + jne .not_plus + + add rax, rbx + jmp .finish + +.not_plus: + cmp byte [.delim], '-' + jne .not_minus + + sub rax, rbx + jmp .finish + +.not_minus: + cmp byte [.delim], '*' + jne .not_times + + mul rbx + jmp .finish + +.not_times: + cmp byte [.delim], '/' + jne .not_divide + + xor rdx, rdx + div rbx + jmp .finish + +.not_divide: + xor rdx, rdx + div rbx + mov rax, rdx ; Get remainder + +.finish: + mov rbx, rax + mov byte al, [.tmp] + call set_var + + jmp .check_for_more + + +.handle_variable: + xor rax, rax + mov byte al, [token] + + call get_var + + mov rbx, rax + + xor rax, rax + mov byte al, [.tmp] + + call get_var + + cmp byte [.delim], '+' + jne .vnot_plus + + add rax, rbx + jmp .vfinish + +.vnot_plus: + cmp byte [.delim], '-' + jne .vnot_minus + + sub rax, rbx + jmp .vfinish + +.vnot_minus: + cmp byte [.delim], '*' + jne .vnot_times + + mul rbx + jmp .vfinish + +.vnot_times: + cmp byte [.delim], '/' + jne .vnot_divide + + mov dx, 0 + div rbx + jmp .finish + +.vnot_divide: + mov dx, 0 + div rbx + mov rax, rdx ; Get remainder + +.vfinish: + mov rbx, rax + mov byte al, [.tmp] + call set_var + + jmp .check_for_more + + +.second_is_string: + mov rdi, token + mov rsi, progstart_keyword + call b_string_compare + je .is_progstart + + mov rsi, ramstart_keyword + call b_string_compare + je .is_ramstart + + jmp .error + +.is_progstart: + xor rax, rax + mov byte al, [.tmp] + + mov rbx, [load_point] + call set_var + + jmp mainloop + + + +.is_ramstart: + xor rax, rax + mov byte al, [.tmp] + + mov rbx, [prog_end] + inc rbx + inc rbx + inc rbx + call set_var + + jmp mainloop + + +.error: + mov rsi, err_syntax + jmp error + + + .tmp db 0 + .tmp_loc dq 0 + .delim db 0 + + +; ================================================================== +; SPECIFIC COMMAND CODE STARTS HERE + +; ------------------------------------------------------------------ +; ALERT + +do_alert: + call get_token + + cmp rax, QUOTE + je .is_quote + + mov rsi, err_syntax + jmp error + +.is_quote: + mov rax, token ; First string for alert box + xor rbx, rbx ; Others are blank + xor rcx, rcx + mov dx, 0 ; One-choice box + jmp mainloop + + +; ------------------------------------------------------------------ +; CALL + +do_call: + call get_token + cmp rax, NUMBER + je .is_number + + xor rax, rax + mov byte al, [token] + call get_var + jmp .execute_call + +.is_number: + mov rsi, token + call b_string_to_int + +.execute_call: + xor rbx, rbx + xor rcx, rcx + mov dx, 0 + mov rdi, 0 + mov rsi, 0 + + call rax + + jmp mainloop + + + +; ------------------------------------------------------------------ +; CLS + +do_cls: + call b_screen_clear + jmp mainloop + + +; ------------------------------------------------------------------ +; CURSOR + +do_cursor: + call get_token + + mov rsi, token + mov rdi, .on_str + call b_string_compare + jc .turn_on + + mov rsi, token + mov rdi, .off_str + call b_string_compare + jc .turn_off + + mov rsi, err_syntax + jmp error + +.turn_on: + call b_show_cursor + jmp mainloop + +.turn_off: + call b_hide_cursor + jmp mainloop + + + .on_str db "ON", 0 + .off_str db "OFF", 0 + + +; ------------------------------------------------------------------ +; CURSCHAR + +do_curschar: + call get_token + + cmp rax, VARIABLE + je .is_ok + + mov rsi, err_syntax + jmp error + +.is_ok: + xor rax, rax + mov byte al, [token] + + push rax ; Store variable we're going to use + +; mov ah, 08h +; xor rbx, rbx +; int 10h ; Get char at current cursor location + + xor rbx, rbx ; We only want the lower byte (the char, not attribute) + mov bl, al + + pop rax ; Get the variable back + + call set_var ; And store the value + + jmp mainloop + + +; ------------------------------------------------------------------ +; END + +do_end: + mov rsp, [orig_stack] + ret + + +; ------------------------------------------------------------------ +; FOR + +do_for: + call get_token ; Get the variable we're using in this loop + + cmp rax, VARIABLE + jne near .error + + xor rax, rax + mov byte al, [token] + mov byte [.tmp_var], al ; Store it in a temporary location for now + + call get_token + + xor rax, rax ; Check it's followed up with '=' + mov byte al, [token] + cmp al, '=' + jne .error + + call get_token ; Next we want a number + + cmp rax, NUMBER + jne .error + + mov rsi, token ; Convert it + call b_string_to_int + + + ; At this stage, we've read something like "FOR X = 1" + ; so let's store that 1 in the variable table + + mov rbx, rax + xor rax, rax + mov byte al, [.tmp_var] + call set_var + + + call get_token ; Next we're looking for "TO" + + cmp rax, STRING + jne .error + + mov rax, token + call b_string_uppercase + + mov rsi, token + mov rdi, .to_string + call b_string_compare + jnc .error + + ; So now we're at "FOR X = 1 TO" + + call get_token + + cmp rax, NUMBER + jne .error + + mov rsi, token ; Get target number + call b_string_to_int + + mov rbx, rax + + xor rax, rax + mov byte al, [.tmp_var] + + sub al, 65 ; Store target number in table + mov rdi, for_variables + add rdi, rax + add rdi, rax + mov rax, rbx + stosw + + + ; So we've got the variable, assigned it the starting number, and put into + ; our table the limit it should reach. But we also need to store the point in + ; code after the FOR line we should return to if NEXT X doesn't complete the loop... +; xor rax, rax + xor rax, rax +; xor eax, eax + mov byte al, [.tmp_var] + + sub al, 65 ; Store code position to return to in table + mov rdi, for_code_points +; add rdi, rax +; add rdi, rax + shl rax, 3 + add rdi, rax + mov rax, [prog] + stosq + + jmp mainloop + + +.error: + mov rsi, err_syntax + jmp error + + + .tmp_var db 0 + .to_string db 'TO', 0 + + +; ------------------------------------------------------------------ +; GETKEY + +do_getkey: + call get_token + cmp rax, VARIABLE + je .is_variable + + mov rsi, err_syntax + jmp error + +.is_variable: + xor rax, rax + mov byte al, [token] + + push rax + + call b_input_key_check + + xor rbx, rbx + mov bl, al + + pop rax + + call set_var + + jmp mainloop + + +; ------------------------------------------------------------------ +; GOSUB + +do_gosub: + call get_token ; Get the number (label) + + cmp rax, STRING + je .is_ok + + mov rsi, err_goto_notlabel + jmp error + +.is_ok: + mov rsi, token ; Back up this label + mov rdi, .tmp_token + call b_string_copy + + mov rax, .tmp_token + call b_string_length + + mov rdi, .tmp_token ; Add ':' char to end for searching + add rdi, rax + mov al, ':' + stosb + mov al, 0 + stosb + + inc byte [gosub_depth] + + xor rax, rax + mov byte al, [gosub_depth] ; Get current GOSUB nest level + + cmp al, 9 + jle .within_limit + + mov rsi, err_nest_limit + jmp error + +.within_limit: + mov rdi, gosub_points ; Move into our table of pointers + add rdi, rax ; Table is words (not bytes) + add rdi, rax + mov rax, [prog] + stosw ; Store current location before jump + + + mov rax, [load_point] + mov [prog], rax ; Return to start of program to find label + +.loop: + call get_token + + cmp rax, LABEL + jne .line_loop + + mov rsi, token + mov rdi, .tmp_token + call b_string_compare + jc mainloop + +.line_loop: ; Go to end of line + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + cmp al, 10 + jne .line_loop + + mov rax, [prog] + mov rbx, [prog_end] + cmp rax, rbx + jg .past_end + + jmp .loop + +.past_end: + mov rsi, err_label_notfound + jmp error + + .tmp_token times 30 db 0 + + +; ------------------------------------------------------------------ +; GOTO + +do_goto: + call get_token ; Get the next token + + cmp rax, STRING + je .is_ok + + mov rsi, err_goto_notlabel + jmp error + +.is_ok: + mov rsi, token ; Back up this label + mov rdi, .tmp_token + call b_string_copy + + mov rax, .tmp_token + call b_string_length + + mov rdi, .tmp_token ; Add ':' char to end for searching + add rdi, rax + mov al, ':' + stosb + mov al, 0 + stosb + + mov rax, [load_point] + mov [prog], rax ; Return to start of program to find label + +.loop: + call get_token + + cmp rax, LABEL + jne .line_loop + + mov rsi, token + mov rdi, .tmp_token + call b_string_compare + jc mainloop + +.line_loop: ; Go to end of line + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + + cmp al, 10 + jne .line_loop + + mov rax, [prog] + mov rbx, [prog_end] + cmp rax, rbx + jg .past_end + + jmp .loop + +.past_end: + mov rsi, err_label_notfound + jmp error + + .tmp_token times 30 db 0 + + +; ------------------------------------------------------------------ +; IF + +do_if: + call get_token + + cmp rax, VARIABLE ; If can only be followed by a variable + je .num_var + + cmp rax, STRING_VAR + je near .string_var + + mov rsi, err_syntax + jmp error + +.num_var: + xor rax, rax + mov byte al, [token] + call get_var + + mov rdx, rax ; Store value of first part of comparison + + call get_token ; Get the delimiter + mov byte al, [token] + cmp al, '=' + je .equals + cmp al, '>' + je .greater + cmp al, '<' + je .less + + mov rsi, err_syntax ; If not one of the above, error out + jmp error + +.equals: + call get_token ; Is this 'X = Y' (equals another variable?) + + cmp rax, CHAR + je .equals_char + + mov byte al, [token] + call is_letter + jc .equals_var + + mov rsi, token ; Otherwise it's, eg 'X = 1' (a number) + call b_string_to_int + + cmp rax, rdx ; On to the THEN bit if 'X = num' matches + je near .on_to_then + + jmp .finish_line ; Otherwise skip the rest of the line + +.equals_char: + xor rax, rax + mov byte al, [token] + + cmp rax, rdx + je near .on_to_then + + jmp .finish_line + +.equals_var: + xor rax, rax + mov byte al, [token] + + call get_var + + cmp rax, rdx ; Do the variables match? + je near .on_to_then ; On to the THEN bit if so + + jmp .finish_line ; Otherwise skip the rest of the line + +.greater: + call get_token ; Greater than a variable or number? + mov byte al, [token] + call is_letter + jc .greater_var + + mov rsi, token ; Must be a number here... + call b_string_to_int + + cmp rax, rdx + jl near .on_to_then + + jmp .finish_line + +.greater_var: ; Variable in this case + xor rax, rax + mov byte al, [token] + + call get_var + + cmp rax, rdx ; Make the comparison! + jl .on_to_then + + jmp .finish_line + +.less: + call get_token + mov byte al, [token] + call is_letter + jc .less_var + + mov rsi, token + call b_string_to_int + + cmp rax, rdx + jg .on_to_then + + jmp .finish_line + +.less_var: + xor rax, rax + mov byte al, [token] + + call get_var + + cmp rax, rdx + jg .on_to_then + + jmp .finish_line + +.string_var: + mov byte [.tmp_string_var], bl + + call get_token + + mov byte al, [token] + cmp al, '=' + jne .error + + call get_token + cmp rax, STRING_VAR + je .second_is_string_var + + cmp rax, QUOTE + jne .error + + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + mov rdi, token + call b_string_compare + je .on_to_then + + jmp .finish_line + +.second_is_string_var: + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + + mov rdi, string_vars + xor rbx, rbx + mov byte bl, [.tmp_string_var] + mov rax, 128 + mul rbx + add rdi, rax + + call b_string_compare + jc .on_to_then + + jmp .finish_line + +.on_to_then: + call get_token + + mov rsi, token + mov rdi, then_keyword + call b_string_compare + + jc .then_present + + mov rsi, err_syntax + jmp error + +.then_present: ; Continue rest of line like any other command! + jmp mainloop + +.finish_line: ; IF wasn't fulfilled, so skip rest of line + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + cmp al, 10 + jne .finish_line + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + .tmp_string_var db 0 + + +; ------------------------------------------------------------------ +; INPUT + +do_input: + mov al, 0 ; Clear string from previous usage + mov rdi, .tmpstring + mov rcx, 128 + rep stosb + + call get_token + + cmp rax, VARIABLE ; We can only INPUT to variables! + je .number_var + + cmp rax, STRING_VAR + je .string_var + + mov rsi, err_syntax + jmp error + +.number_var: + mov rdi, .tmpstring ; Get input from the user + mov rcx, 50 + call b_input_string + + mov rsi, .tmpstring + call b_string_length + cmp rcx, 0 + jne .char_entered + + mov byte [.tmpstring], '0' ; If enter hit, fill variable with zero + mov byte [.tmpstring + 1], 0 + +.char_entered: + mov rsi, .tmpstring ; Convert to integer format + call b_string_to_int + mov rbx, rax + + xor rax, rax + mov byte al, [token] ; Get the variable where we're storing it... + call set_var ; ...and store it! + + call b_print_newline + + jmp mainloop + +.string_var: + push rbx + + mov rdi, .tmpstring + mov rcx, 50 + call b_input_string + + mov rsi, .tmpstring + mov rdi, string_vars + + pop rbx + + mov rax, 128 + mul rbx + + add rdi, rax + call b_string_copy + + call b_print_newline + + jmp mainloop + + .tmpstring times 128 db 0 + + +; ------------------------------------------------------------------ +; LOAD + +do_load: + call get_token + cmp rax, QUOTE + je .is_quote + + cmp rax, STRING_VAR + jne .error + + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + jmp .get_position + +.is_quote: + mov rsi, token + +.get_position: + mov rax, rsi +; call b_file_exists + jc .file_not_exists + + mov rdx, rax ; Store for now + + call get_token + + cmp rax, VARIABLE + je .second_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.load_part: + mov rcx, rax + + mov rax, rdx + +; call b_load_file + + xor rax, rax + mov byte al, 'S' + call set_var + + xor rax, rax + mov byte al, 'R' + xor rbx, rbx + call set_var + + jmp mainloop + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .load_part + +.file_not_exists: + xor rax, rax + mov byte al, 'R' + mov rbx, 1 + call set_var + + call get_token ; Skip past the loading point -- unnecessary now + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + +; ------------------------------------------------------------------ +; MOVE + +do_move: + call get_token + + cmp rax, VARIABLE + je .first_is_var + + mov rsi, token + call b_string_to_int + mov dl, al + jmp .onto_second + +.first_is_var: + xor rax, rax + mov byte al, [token] + call get_var + mov dl, al + +.onto_second: + call get_token + + cmp rax, VARIABLE + je .second_is_var + + mov rsi, token + call b_string_to_int + mov dh, al + jmp .finish + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + mov dh, al + +.finish: + call b_move_cursor + + jmp mainloop + + +; ------------------------------------------------------------------ +; NEXT + +do_next: + call get_token + + cmp rax, VARIABLE ; NEXT must be followed by a variable + jne .error + + xor rax, rax + mov byte al, [token] + call get_var + + inc rax ; NEXT increments the variable, of course! + + mov rbx, rax + + xor rax, rax + mov byte al, [token] + + sub al, 65 + mov rsi, for_variables + add rsi, rax + add rsi, rax + lodsw ; Get the target number from the table + + inc rax ; (Make the loop inclusive of target number) + cmp rax, rbx ; Do the variable and target match? + je .loop_finished + + xor rax, rax ; If not, store the updated variable + mov byte al, [token] + call set_var + + xor rax, rax ; Find the code point and go back + mov byte al, [token] + sub al, 65 + mov rsi, for_code_points +; add rsi, rax +; add rsi, rax + shl rax, 3 + add rsi, rax + lodsq + + mov [prog], rax + jmp mainloop + +.loop_finished: + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + +; ------------------------------------------------------------------ +; PAUSE + +do_pause: + call get_token + + cmp rax, VARIABLE + je .is_var + + mov rsi, token + call b_string_to_int + jmp .finish + +.is_var: + xor rax, rax + mov byte al, [token] + call get_var + +.finish: +; call b_pause + jmp mainloop + + +; ------------------------------------------------------------------ +; PEEK + +do_peek: + call get_token + + cmp rax, VARIABLE + jne .error + + xor rax, rax + mov byte al, [token] + mov byte [.tmp_var], al + + call get_token + + cmp rax, VARIABLE + je .dereference + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.store: + mov rsi, rax + xor rbx, rbx + mov byte bl, [rsi] + xor rax, rax + mov byte al, [.tmp_var] + call set_var + + jmp mainloop + +.dereference: + mov byte al, [token] + call get_var + jmp .store + +.error: + mov rsi, err_syntax + jmp error + + + .tmp_var db 0 + + +; ------------------------------------------------------------------ +; POKE + +do_poke: + call get_token + + cmp rax, VARIABLE + je .first_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + + cmp rax, 255 + jg .error + + mov byte [.first_value], al + jmp .onto_second + + +.first_is_var: + xor rax, rax + mov byte al, [token] + call get_var + + mov byte [.first_value], al + +.onto_second: + call get_token + + cmp rax, VARIABLE + je .second_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.got_value: + mov rdi, rax + xor rax, rax + mov byte al, [.first_value] + mov byte [rdi], al + + jmp mainloop + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .got_value + +.error: + mov rsi, err_syntax + jmp error + + .first_value db 0 + + +; ------------------------------------------------------------------ +; PORT + +do_port: + call get_token + mov rsi, token + + mov rdi, .out_cmd + call b_string_compare + jc .do_out_cmd + + mov rdi, .in_cmd + call b_string_compare + jc .do_in_cmd + + jmp .error + +.do_out_cmd: + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int ; Now rax = port number + mov rdx, rax + + call get_token + cmp rax, NUMBER + je .out_is_num + + cmp rax, VARIABLE + je .out_is_var + + jmp .error + +.out_is_num: + mov rsi, token + call b_string_to_int +; call b_port_byte_out + jmp mainloop + +.out_is_var: + xor rax, rax + mov byte al, [token] + call get_var + +; call b_port_byte_out + jmp mainloop + +.do_in_cmd: + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + mov rdx, rax + + call get_token + cmp rax, VARIABLE + jne .error + + mov byte cl, [token] + +; call b_port_byte_in + xor rbx, rbx + mov bl, al + + mov al, cl + call set_var + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + + .out_cmd db "OUT", 0 + .in_cmd db "IN", 0 + + +; ------------------------------------------------------------------ +; PRINT + +do_print: + call get_token ; Get part after PRINT + + cmp rax, QUOTE ; What type is it? + je .print_quote + + cmp rax, VARIABLE ; Numerical variable (eg X) + je .print_var + + cmp rax, STRING_VAR ; String variable (eg $1) + je .print_string_var + + cmp rax, STRING ; Special keyword (eg CHR or HEX) + je .print_keyword + + mov rsi, err_print_type ; We only print quoted strings and vars! + jmp error + +.print_var: + xor rax, rax + mov byte al, [token] + call get_var ; Get its value + mov rdi, tstring + mov rsi, rdi + call b_int_to_string ; Convert to string + call b_print_string + + jmp .newline_or_not + +.print_quote: ; If it's quoted text, print it + mov rsi, token + call b_print_string + + jmp .newline_or_not + +.print_string_var: + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + call b_print_string + + jmp .newline_or_not + +.print_keyword: + mov rsi, token + mov rdi, chr_keyword + call b_string_compare + jc .is_chr + + mov rdi, hex_keyword + call b_string_compare + jc .is_hex + + mov rsi, err_syntax + jmp error + +.is_chr: + call get_token + + cmp rax, VARIABLE + jne .error + + xor rax, rax + mov byte al, [token] + call get_var + +; mov ah, 0Eh +; int 10h + + jmp .newline_or_not + +.is_hex: + call get_token + + cmp rax, VARIABLE + jne .error + + xor rax, rax + mov byte al, [token] + call get_var + + call b_debug_dump_al ;print_2hex + + jmp .newline_or_not + +.error: + mov rsi, err_syntax + jmp error + +.newline_or_not: + ; We want to see if the command ends with ';' -- which means that + ; we shouldn't print a newline after it finishes. So we store the + ; current program location to pop ahead and see if there's the ';' + ; character -- otherwise we put the program location back and resume + ; the main loop + mov rax, [prog] + mov [.tmp_loc], rax + + call get_token + cmp rax, UNKNOWN + jne .ignore + + xor rax, rax + mov al, [token] + cmp al, ';' + jne .ignore + + jmp mainloop ; And go back to interpreting the code! + +.ignore: + call b_print_newline + + mov rax, [.tmp_loc] + mov [prog], rax + + jmp mainloop + + .tmp_loc dq 0 + + +; ------------------------------------------------------------------ +; RAND + +do_rand: + call get_token + cmp rax, VARIABLE + jne .error + + mov byte al, [token] + mov byte [.tmp], al + + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + mov [.num1], rax + + call get_token + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + mov [.num2], rax + + mov rax, [.num1] + mov rbx, [.num2] +; call b_get_random + + mov rbx, rcx + xor rax, rax + mov byte al, [.tmp] + call set_var + + jmp mainloop + + .tmp db 0 + .num1 dq 0 + .num2 dq 0 + +.error: + mov rsi, err_syntax + jmp error + + +; ------------------------------------------------------------------ +; REM + +do_rem: + mov rsi, [prog] + mov byte al, [rsi] + inc qword [prog] + cmp al, 10 ; Find end of line after REM + jne do_rem + + jmp mainloop + + +; ------------------------------------------------------------------ +; RETURN + +do_return: + xor rax, rax + mov byte al, [gosub_depth] + cmp al, 0 + jne .is_ok + + mov rsi, err_return + jmp error + +.is_ok: + mov rsi, gosub_points + add rsi, rax ; Table is words (not bytes) + add rsi, rax + lodsw + mov [prog], rax + dec byte [gosub_depth] + + jmp mainloop + + +; ------------------------------------------------------------------ +; SAVE + +do_save: + call get_token + cmp rax, QUOTE + je .is_quote + + cmp rax, STRING_VAR + jne near .error + + mov rsi, string_vars + mov rax, 128 + mul rbx + add rsi, rax + jmp .get_position + +.is_quote: + mov rsi, token + +.get_position: + mov rdi, .tmp_filename + call b_string_copy + + call get_token + + cmp rax, VARIABLE + je .second_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.set_data_loc: + mov [.data_loc], rax + + call get_token + + cmp rax, VARIABLE + je .third_is_var + + cmp rax, NUMBER + jne .error + + mov rsi, token + call b_string_to_int + +.set_data_size: + mov [.data_size], rax + + mov rax, .tmp_filename + mov rbx, [.data_loc] + mov rcx, [.data_size] + +; call b_write_file + jc .save_failure + + xor rax, rax + mov byte al, 'R' + xor rbx, rbx + call set_var + + jmp mainloop + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .set_data_loc + +.third_is_var: + xor rax, rax + mov byte al, [token] + call get_var + jmp .set_data_size + +.save_failure: + xor rax, rax + mov byte al, 'R' + mov rbx, 1 + call set_var + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + + .filename_loc dw 0 + .data_loc dw 0 + .data_size dw 0 + + .tmp_filename times 15 db 0 + + +; ------------------------------------------------------------------ +; SERIAL + +do_serial: + call get_token + mov rsi, token + + mov rdi, .on_cmd + call b_string_compare + jc .do_on_cmd + + mov rdi, .send_cmd + call b_string_compare + jc .do_send_cmd + + mov rdi, .rec_cmd + call b_string_compare + jc .do_rec_cmd + + jmp .error + +.do_on_cmd: + call get_token + cmp rax, NUMBER + je .do_on_cmd_ok + jmp .error + +.do_on_cmd_ok: + mov rsi, token + call b_string_to_int + cmp rax, 1200 + je .on_cmd_slow_mode + cmp rax, 9600 + je .on_cmd_fast_mode + + jmp .error + +.on_cmd_fast_mode: + xor rax, rax +; call b_serial_port_enable + jmp mainloop + +.on_cmd_slow_mode: + mov rax, 1 +; call b_serial_port_enable + jmp mainloop + +.do_send_cmd: + call get_token + cmp rax, NUMBER + je .send_number + + cmp rax, VARIABLE + je .send_variable + + jmp .error + +.send_number: + mov rsi, token + call b_string_to_int +; call b_send_via_serial + jmp mainloop + +.send_variable: + xor rax, rax + mov byte al, [token] + call get_var +; call b_send_via_serial + jmp mainloop + +.do_rec_cmd: + call get_token + cmp rax, VARIABLE + jne .error + + mov byte al, [token] + + xor rcx, rcx + mov cl, al +; call b_get_via_serial + + xor rbx, rbx + mov bl, al + mov al, cl + call set_var + + jmp mainloop + +.error: + mov rsi, err_syntax + jmp error + + .on_cmd db "ON", 0 + .send_cmd db "SEND", 0 + .rec_cmd db "REC", 0 + + +; ------------------------------------------------------------------ +; SOUND + +do_sound: + call get_token + + cmp rax, VARIABLE + je .first_is_var + + mov rsi, token + call b_string_to_int + jmp .done_first + +.first_is_var: + xor rax, rax + mov byte al, [token] + call get_var + +.done_first: + call b_speaker_tone + + call get_token + + cmp rax, VARIABLE + je .second_is_var + + mov rsi, token + call b_string_to_int + jmp .finish + +.second_is_var: + xor rax, rax + mov byte al, [token] + call get_var + +.finish: +; call b_pause + call b_speaker_off + + jmp mainloop + + +; ------------------------------------------------------------------ +; WAITKEY + +do_waitkey: + call get_token + cmp rax, VARIABLE + je .is_variable + + mov rsi, err_syntax + jmp error + +.is_variable: + xor rax, rax + mov byte al, [token] + + push rax + + call b_input_key_wait + + cmp rax, 48E0h + je .up_pressed + + cmp rax, 50E0h + je .down_pressed + + cmp rax, 4BE0h + je .left_pressed + + cmp rax, 4DE0h + je .right_pressed + +.store: + xor rbx, rbx + mov bl, al + + pop rax + + call set_var + + jmp mainloop + +.up_pressed: + mov rax, 1 + jmp .store + +.down_pressed: + mov rax, 2 + jmp .store + +.left_pressed: + mov rax, 3 + jmp .store + +.right_pressed: + mov rax, 4 + jmp .store + + +; ================================================================== +; INTERNAL ROUTINES FOR INTERPRETER + +; ------------------------------------------------------------------ +; Get value of variable character specified in AL (eg 'A') + +get_var: + sub al, 65 + mov rsi, variables + add rsi, rax + add rsi, rax + lodsw + ret + + +; ------------------------------------------------------------------ +; Set value of variable character specified in AL (eg 'A') +; with number specified in rbx + +set_var: + mov ah, 0 + sub al, 65 ; Remove ASCII codes before 'A' + + mov rdi, variables ; Find position in table (of words) + add rdi, rax + add rdi, rax + mov rax, rbx + stosw + ret + + +; ------------------------------------------------------------------ +; Get token from current position in prog + +get_token: + mov rsi, [prog] + lodsb + + cmp al, 13 + je .newline + + cmp al, 10 + je .newline + + cmp al, ' ' + je .newline + + call is_number + jc get_number_token + + cmp al, '"' + je get_quote_token + + cmp al, 39 ; Quote mark (') + je get_char_token + + cmp al, '$' + je near get_string_var_token + + jmp get_string_token + +.newline: + inc qword [prog] + jmp get_token + +get_number_token: + mov rsi, [prog] + mov rdi, token + +.loop: + lodsb + cmp al, 13 + je .done + cmp al, 10 + je .done + cmp al, ' ' + je .done + call is_number + jc .fine + + mov rsi, err_char_in_num + jmp error + +.fine: + stosb + inc qword [prog] + jmp .loop + +.done: + mov al, 0 ; Zero-terminate the token + stosb + + mov rax, NUMBER ; Pass back the token type + ret + +get_char_token: + inc qword [prog] ; Move past first quote (') + + mov rsi, [prog] + lodsb + + mov byte [token], al + + lodsb + cmp al, 39 ; Needs to finish with another quote + je .is_ok + + mov rsi, err_quote_term + jmp error + +.is_ok: + inc qword [prog] + inc qword [prog] + + mov rax, CHAR + ret + +get_quote_token: + inc qword [prog] ; Move past first quote (") char + mov qword rsi, [prog] + mov rdi, token +.loop: + lodsb + cmp al, '"' + je .done + cmp al, 10 + je .error + stosb + inc qword [prog] + jmp .loop + +.done: + mov al, 0 ; Zero-terminate the token + stosb + inc qword [prog] ; Move past final quote + + mov rax, QUOTE ; Pass back token type + ret + +.error: + mov rsi, err_quote_term + jmp error + +get_string_var_token: + lodsb + xor rbx, rbx ; If it's a string var, pass number of string in rbx + mov bl, al + sub bl, 49 + + inc qword [prog] + inc qword [prog] + + mov rax, STRING_VAR + ret + +get_string_token: + mov qword rsi, [prog] + mov rdi, token +.loop: + lodsb + cmp al, 13 + je .done + cmp al, 10 + je .done + cmp al, ' ' + je .done + stosb + inc qword [prog] + jmp .loop +.done: + mov al, 0 ; Zero-terminate the token + stosb + + mov rax, token + call b_string_uppercase + + mov rsi, token + call b_string_length ; How long was the token? + cmp rcx, 1 ; If 1 char, it's a variable or delimiter + je .is_not_string + + mov rsi, token ; If the token ends with ':', it's a label + add rsi, rax + dec rsi + lodsb + cmp al, ':' + je .is_label + + mov rax, STRING ; Otherwise it's a general string of characters + ret + +.is_label: + mov rax, LABEL + ret + +.is_not_string: + mov byte al, [token] + call is_letter + jc .is_var + + mov rax, UNKNOWN + ret + +.is_var: + mov rax, VARIABLE ; Otherwise probably a variable + ret + + +; ------------------------------------------------------------------ +; Set carry flag if AL contains ASCII number + +is_number: + cmp al, 48 + jl .not_number + cmp al, 57 + jg .not_number + stc + ret +.not_number: + clc + ret + + +; ------------------------------------------------------------------ +; Set carry flag if AL contains ASCII letter + +is_letter: + cmp al, 65 + jl .not_letter + cmp al, 90 + jg .not_letter + stc + ret + +.not_letter: + clc + ret + + +; ------------------------------------------------------------------ +; Print error message and quit out + +error: + call b_print_newline + call b_print_string ; Print error message + call b_print_newline + + mov rsp, [orig_stack] ; Restore the stack to as it was when BASIC started + + ret ; And finish + + + ; Error messages text... + + err_char_in_num db "Error: unexpected character in number", 0 + err_quote_term db "Error: quoted string or character not terminated correctly", 0 + err_print_type db "Error: PRINT command not followed by quoted text or variable", 0 + err_cmd_unknown db "Error: unknown command", 0 + err_goto_notlabel db "Error: GOTO or GOSUB not followed by label", 0 + err_label_notfound db "Error: GOTO or GOSUB label not found", 0 + err_return db "Error: RETURN without GOSUB", 0 + err_nest_limit db "Error: FOR or GOSUB nest limit exceeded", 0 + err_next db "Error: NEXT without FOR", 0 + err_syntax db "Error: syntax error", 0 + + + +; ================================================================== +; DATA SECTION + + orig_stack dq 0 ; Original stack location when BASIC started + + prog dq 0 ; Pointer to current location in BASIC code + prog_end dq 0 ; Pointer to final byte of BASIC code + + load_point dq 0 + + token_type db 0 ; Type of last token read (eg NUMBER, VARIABLE) + token times 255 db 0 ; Storage space for the token + tstring times 255 db 0 + +align 16 + variables times 26 dq 0 ; Storage space for variables A to Z +align 16 + for_variables times 26 dq 0 ; Storage for FOR loops +align 16 + for_code_points times 26 dq 0 ; Storage for code positions where FOR loops start + + alert_cmd db "ALERT", 0 + call_cmd db "CALL", 0 + cls_cmd db "CLS", 0 + cursor_cmd db "CURSOR", 0 + curschar_cmd db "CURSCHAR", 0 + end_cmd db "END", 0 + for_cmd db "FOR", 0 + gosub_cmd db "GOSUB", 0 + goto_cmd db "GOTO", 0 + getkey_cmd db "GETKEY", 0 + if_cmd db "IF", 0 + input_cmd db "INPUT", 0 + load_cmd db "LOAD", 0 + move_cmd db "MOVE", 0 + next_cmd db "NEXT", 0 + pause_cmd db "PAUSE", 0 + peek_cmd db "PEEK", 0 + poke_cmd db "POKE", 0 + port_cmd db "PORT", 0 + print_cmd db "PRINT", 0 + rem_cmd db "REM", 0 + rand_cmd db "RAND", 0 + return_cmd db "RETURN", 0 + save_cmd db "SAVE", 0 + serial_cmd db "SERIAL", 0 + sound_cmd db "SOUND", 0 + waitkey_cmd db "WAITKEY", 0 + + then_keyword db "THEN", 0 + chr_keyword db "CHR", 0 + hex_keyword db "HEX", 0 + + progstart_keyword db "PROGSTART", 0 + ramstart_keyword db "RAMSTART", 0 + + gosub_depth db 0 + gosub_points times 10 dq 0 ; Points in code to RETURN to + + string_vars times 1024 db 0 ; 8 * 128 byte strings + + +; ------------------------------------------------------------------ +basic_prog: + DB 'CLS',13,10 + DB 'PRINT "Please type your name: ";',13,10 + DB 'INPUT $N',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT "Hello ";',13,10 + DB 'PRINT $N;',13,10 + DB 'PRINT ", welcome to MikeOS Basic (in 64-bit mode)!"',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT "It supports FOR...NEXT loops and simple integer maths..."',13,10 + DB 'PRINT ""',13,10 + DB 'FOR I = 1 TO 15',13,10 + DB 'J = I * I',13,10 + DB 'K = J * I',13,10 + DB 'L = K * I',13,10 + DB 'PRINT I ;',13,10 + DB 'PRINT " ";',13,10 + DB 'PRINT J ;',13,10 + DB 'PRINT " ";',13,10 + DB 'PRINT K ;',13,10 + DB 'PRINT " ";',13,10 + DB 'PRINT L',13,10 + DB 'NEXT I',13,10 + DB 'PRINT ""',13,10 + DB 'PRINT " ...and IF...THEN and GOSUB and lots of other stuff. Bye!"',13,10 + DB 'END',13,10 diff --git a/amd64/bareMetalOS-0.5.3/programs/nibbles.asm b/amd64/bareMetalOS-0.5.3/programs/nibbles.asm index 4c425a1e..b5b5d462 100644 --- a/amd64/bareMetalOS-0.5.3/programs/nibbles.asm +++ b/amd64/bareMetalOS-0.5.3/programs/nibbles.asm @@ -1,116 +1,116 @@ -; The classic game of Nibbles -; Written by Ian Seyler -; -; BareMetal compile: -; nasm argtest.asm -o argtest.app - -; Game field is surrounded by a border. Play area is 38 x 23 - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - call b_hide_statusbar - call b_hide_cursor - call b_screen_clear - - mov rdi, os_screen ; Screen framebuffer - - mov eax, 0x15DB15DB - mov rcx, 41 - rep stosd ; Draw the top wall - - mov rcx, 23 -nextside: ; Draw the side walls - add rdi, 152 - stosd - stosd - sub rcx, 1 - cmp rcx, 0 - jne nextside - - mov rcx, 39 - rep stosd ; Draw the bottom wall - - call b_screen_update ; Copy the screen buffer to video memory - - - -gameloop: - cmp byte [direction], 1 - je move_up - cmp byte [direction], 2 - je move_right - cmp byte [direction], 3 - je move_down - cmp byte [direction], 4 - je move_left - jmp fin ; Fatal error - -move_up: - sub byte [head_x], 1 - jmp drawworm -move_right: - add byte [head_y], 1 - jmp drawworm -move_down: - add byte [head_x], 1 - jmp drawworm -move_left: - sub byte [head_y], 1 - jmp drawworm - -drawworm: - mov rax, 1 - call b_delay - mov ah, byte [head_y] - shl ah, 1 - mov al, byte [head_x] - call b_move_cursor - mov al, 219 - call b_print_char - call b_print_char - call b_input_key_check - cmp al, 'w' - je go_up - cmp al, 'a' - je go_left - cmp al, 's' - je go_down - cmp al, 'd' - je go_right - cmp al, 'q' - je fin - jmp gameloop - -go_up: - mov byte [direction], 1 - jmp gameloop - -go_left: - mov byte [direction], 4 - jmp gameloop - -go_down: - mov byte [direction], 3 - jmp gameloop - -go_right: - mov byte [direction], 2 - jmp gameloop - -fin: - call b_screen_clear - mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner - call b_move_cursor - call b_show_cursor - call b_show_statusbar - ret ; Return to OS - -head_x: db 5 -head_y: db 5 -direction: db 2 ; 1 up, 2 right, 3 down, 4 left - -os_screen: equ 0x0000000000180000 ; This is the address for the text screen frame buffer. It gets copied to video memory via b_update_screen +; The classic game of Nibbles +; Written by Ian Seyler +; +; BareMetal compile: +; nasm argtest.asm -o argtest.app + +; Game field is surrounded by a border. Play area is 38 x 23 + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + call b_hide_statusbar + call b_hide_cursor + call b_screen_clear + + mov rdi, os_screen ; Screen framebuffer + + mov eax, 0x15DB15DB + mov rcx, 41 + rep stosd ; Draw the top wall + + mov rcx, 23 +nextside: ; Draw the side walls + add rdi, 152 + stosd + stosd + sub rcx, 1 + cmp rcx, 0 + jne nextside + + mov rcx, 39 + rep stosd ; Draw the bottom wall + + call b_screen_update ; Copy the screen buffer to video memory + + + +gameloop: + cmp byte [direction], 1 + je move_up + cmp byte [direction], 2 + je move_right + cmp byte [direction], 3 + je move_down + cmp byte [direction], 4 + je move_left + jmp fin ; Fatal error + +move_up: + sub byte [head_x], 1 + jmp drawworm +move_right: + add byte [head_y], 1 + jmp drawworm +move_down: + add byte [head_x], 1 + jmp drawworm +move_left: + sub byte [head_y], 1 + jmp drawworm + +drawworm: + mov rax, 1 + call b_delay + mov ah, byte [head_y] + shl ah, 1 + mov al, byte [head_x] + call b_move_cursor + mov al, 219 + call b_print_char + call b_print_char + call b_input_key_check + cmp al, 'w' + je go_up + cmp al, 'a' + je go_left + cmp al, 's' + je go_down + cmp al, 'd' + je go_right + cmp al, 'q' + je fin + jmp gameloop + +go_up: + mov byte [direction], 1 + jmp gameloop + +go_left: + mov byte [direction], 4 + jmp gameloop + +go_down: + mov byte [direction], 3 + jmp gameloop + +go_right: + mov byte [direction], 2 + jmp gameloop + +fin: + call b_screen_clear + mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner + call b_move_cursor + call b_show_cursor + call b_show_statusbar + ret ; Return to OS + +head_x: db 5 +head_y: db 5 +direction: db 2 ; 1 up, 2 right, 3 down, 4 left + +os_screen: equ 0x0000000000180000 ; This is the address for the text screen frame buffer. It gets copied to video memory via b_update_screen diff --git a/amd64/bareMetalOS-0.5.3/programs/smptest.asm b/amd64/bareMetalOS-0.5.3/programs/smptest.asm index 90b4a4b3..2678dd38 100644 --- a/amd64/bareMetalOS-0.5.3/programs/smptest.asm +++ b/amd64/bareMetalOS-0.5.3/programs/smptest.asm @@ -1,64 +1,64 @@ -; SMP Test Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm smptest.asm -o smptest.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - mov rax, ap_print_id ; Our code to run on all CPUs - xor rbx, rbx ; Clear RBX as there is no argument - mov rcx, 64 ; Number of instances to spawn - -spawn: - call b_smp_enqueue - sub rcx, 1 - cmp rcx, 0 - jne spawn - -bsp: - call b_smp_dequeue ; Try to dequeue a workload - jc emptyqueue ; If carry is set then the queue is empty - call b_smp_run ; Otherwise run the workload - jne bsp ; If it is not empty try to do another workload - -emptyqueue: - call b_smp_wait ; Wait for all other processors to finish - call b_print_newline - -ret ; Return to OS - - -; This procedure will be executed by each of the processors -; It requires mutually exclusive access while it creates the string and prints to the screen -; We must insure that only one CPU at a time can execute this code, so we employ a 'spinlock'. -ap_print_id: - mov rcx, 0x1FFFFF -delay: - dec rcx - cmp rcx, 0 - jne delay - -grablock: - bt word [mutex], 0 ; Check if the mutex is free - jnc grablock ; If not check it again - - lock ; The mutex was free, lock the bus - btr word [mutex], 0 ; Try to grab the mutex - jnc grablock ; Jump if we were unsuccessful - - call b_smp_get_id ; Get the local APIC ID - call b_debug_dump_al ; Print the APIC ID - mov al, ' ' - call b_print_char - - bts word [mutex], 0 ; Release the mutex -ret - - mutex dw 1 ; The MUTual-EXclustion flag +; SMP Test Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm smptest.asm -o smptest.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + mov rax, ap_print_id ; Our code to run on all CPUs + xor rbx, rbx ; Clear RBX as there is no argument + mov rcx, 64 ; Number of instances to spawn + +spawn: + call b_smp_enqueue + sub rcx, 1 + cmp rcx, 0 + jne spawn + +bsp: + call b_smp_dequeue ; Try to dequeue a workload + jc emptyqueue ; If carry is set then the queue is empty + call b_smp_run ; Otherwise run the workload + jne bsp ; If it is not empty try to do another workload + +emptyqueue: + call b_smp_wait ; Wait for all other processors to finish + call b_print_newline + +ret ; Return to OS + + +; This procedure will be executed by each of the processors +; It requires mutually exclusive access while it creates the string and prints to the screen +; We must insure that only one CPU at a time can execute this code, so we employ a 'spinlock'. +ap_print_id: + mov rcx, 0x1FFFFF +delay: + dec rcx + cmp rcx, 0 + jne delay + +grablock: + bt word [mutex], 0 ; Check if the mutex is free + jnc grablock ; If not check it again + + lock ; The mutex was free, lock the bus + btr word [mutex], 0 ; Try to grab the mutex + jnc grablock ; Jump if we were unsuccessful + + call b_smp_get_id ; Get the local APIC ID + call b_debug_dump_al ; Print the APIC ID + mov al, ' ' + call b_print_char + + bts word [mutex], 0 ; Release the mutex +ret + + mutex dw 1 ; The MUTual-EXclustion flag diff --git a/amd64/bareMetalOS-0.5.3/programs/sysinfo.asm b/amd64/bareMetalOS-0.5.3/programs/sysinfo.asm index 9294a412..a7f8c22d 100644 --- a/amd64/bareMetalOS-0.5.3/programs/sysinfo.asm +++ b/amd64/bareMetalOS-0.5.3/programs/sysinfo.asm @@ -1,235 +1,235 @@ -; System Information Program (v1.0, July 6 2010) -; Written by Ian Seyler -; -; BareMetal compile: -; nasm sysinfo.asm -o sysinfo.app - - -[BITS 64] -[ORG 0x0000000000200000] - -%INCLUDE "bmdev.asm" - -start: ; Start of program label - - mov rsi, startmessage ; Load RSI with memory address of string - call b_print_string ; Print the string that RSI points to - -;Get processor brand string - xor rax, rax - mov rdi, tstring - mov eax, 0x80000002 - cpuid - stosd - mov eax, ebx - stosd - mov eax, ecx - stosd - mov eax, edx - stosd - mov eax, 0x80000003 - cpuid - stosd - mov eax, ebx - stosd - mov eax, ecx - stosd - mov eax, edx - stosd - mov eax, 0x80000004 - cpuid - stosd - mov eax, ebx - stosd - mov eax, ecx - stosd - mov eax, edx - stosd - xor al, al - stosb ; Terminate the string - mov rsi, tstring - call b_string_parse - mov rsi, cpustringmsg - call b_print_string - mov rsi, tstring - call b_print_string - -; Number of cores - call b_print_newline - mov rsi, numcoresmsg - call b_print_string - xor rax, rax - mov rsi, 0x5012 - lodsw - mov rdi, tstring - call b_int_to_string - mov rsi, tstring - call b_print_string - -; Speed - call b_print_newline - mov rsi, speedmsg - call b_print_string - xor rax, rax - mov rsi, 0x5010 - lodsw - mov rdi, tstring - call b_int_to_string - mov rsi, tstring - call b_print_string - mov rsi, mhzmsg - call b_print_string - -; L1 code/data cache info - call b_print_newline - mov eax, 0x80000005 ; L1 cache info - cpuid - mov eax, edx ; EDX bits 31 - 24 store code L1 cache size in KBs - shr eax, 24 - mov rdi, tstring - call b_int_to_string - mov rsi, l1ccachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - call b_print_newline - mov eax, ecx ; ECX bits 31 - 24 store data L1 cache size in KBs - shr eax, 24 - mov rdi, tstring - call b_int_to_string - mov rsi, l1dcachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - -; L2/L3 cache info - call b_print_newline - mov eax, 0x80000006 ; L2/L3 cache info - cpuid - mov eax, ecx ; ecx bits 31 - 16 store unified L2 cache size in KBs - shr eax, 16 - mov rdi, tstring - call b_int_to_string - mov rsi, l2ucachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - - call b_print_newline - mov eax, edx ; edx bits 31 - 18 store unified L3 cache size in 512 KB chunks - shr eax, 18 - and eax, 0x3FFFF ; Clear bits 18 - 31 - shl eax, 9 ; Convert the value for 512 KB chunks to KBs (Multiply by 512) - mov rdi, tstring - call b_int_to_string - mov rsi, l3ucachemsg - call b_print_string - mov rsi, tstring - call b_print_string - mov rsi, kbmsg - call b_print_string - -;CPU features - call b_print_newline - mov rsi, cpufeatures - call b_print_string - mov rax, 1 - cpuid - -checksse: - test edx, 00000010000000000000000000000000b - jz checksse2 - mov rsi, sse - call b_print_string - -checksse2: - test edx, 00000100000000000000000000000000b - jz checksse3 - mov rsi, sse2 - call b_print_string - -checksse3: - test ecx, 00000000000000000000000000000001b - jz checkssse3 - mov rsi, sse3 - call b_print_string - -checkssse3: - test ecx, 00000000000000000000001000000000b - jz checksse41 - mov rsi, ssse3 - call b_print_string - -checksse41: - test ecx, 00000000000010000000000000000000b - jz checksse42 - mov rsi, sse41 - call b_print_string - -checksse42: - test ecx, 00000000000100000000000000000000b - jz checkaes - mov rsi, sse42 - call b_print_string - -checkaes: - test ecx, 00000010000000000000000000000000b - jz checkavx - mov rsi, aes - call b_print_string - -checkavx: - test ecx, 00010000000000000000000000000000b - jz endit - mov rsi, avx - call b_print_string - -endit: -;RAM - call b_print_newline - mov rsi, memmessage - call b_print_string - xor rax, rax - mov rsi, 0x5020 - lodsw - mov rdi, tstring - call b_int_to_string - mov rsi, tstring - call b_print_string - mov rsi, mbmsg - call b_print_string - - - call b_print_newline - -ret ; Return to OS - -startmessage: db 'System Information:', 13, 0 -cpustringmsg: db 'CPU String: ', 0 -numcoresmsg: db 'Number of cores: ', 0 -speedmsg: db 'Detected speed: ', 0 -l1ccachemsg: db 'L1 code cache: ', 0 -l1dcachemsg: db 'L1 data cache: ', 0 -l2ucachemsg: db 'L2 unified cache: ', 0 -l3ucachemsg: db 'L3 unified cache: ', 0 -cpufeatures: db 'CPU features: ', 0 -kbmsg: db ' KiB', 0 -mbmsg: db ' MiB', 0 -mhzmsg: db ' MHz', 0 -sse: db 'SSE ', 0 -sse2: db 'SSE2 ', 0 -sse3: db 'SSE3 ', 0 -ssse3: db 'SSSE3 ', 0 -sse41: db 'SSE4.1 ', 0 -sse42: db 'SSE4.2 ', 0 -aes: db 'AES ', 0 -avx: db 'AVX ', 0 -memmessage: db 'RAM: ', 0 - +; System Information Program (v1.0, July 6 2010) +; Written by Ian Seyler +; +; BareMetal compile: +; nasm sysinfo.asm -o sysinfo.app + + +[BITS 64] +[ORG 0x0000000000200000] + +%INCLUDE "bmdev.asm" + +start: ; Start of program label + + mov rsi, startmessage ; Load RSI with memory address of string + call b_print_string ; Print the string that RSI points to + +;Get processor brand string + xor rax, rax + mov rdi, tstring + mov eax, 0x80000002 + cpuid + stosd + mov eax, ebx + stosd + mov eax, ecx + stosd + mov eax, edx + stosd + mov eax, 0x80000003 + cpuid + stosd + mov eax, ebx + stosd + mov eax, ecx + stosd + mov eax, edx + stosd + mov eax, 0x80000004 + cpuid + stosd + mov eax, ebx + stosd + mov eax, ecx + stosd + mov eax, edx + stosd + xor al, al + stosb ; Terminate the string + mov rsi, tstring + call b_string_parse + mov rsi, cpustringmsg + call b_print_string + mov rsi, tstring + call b_print_string + +; Number of cores + call b_print_newline + mov rsi, numcoresmsg + call b_print_string + xor rax, rax + mov rsi, 0x5012 + lodsw + mov rdi, tstring + call b_int_to_string + mov rsi, tstring + call b_print_string + +; Speed + call b_print_newline + mov rsi, speedmsg + call b_print_string + xor rax, rax + mov rsi, 0x5010 + lodsw + mov rdi, tstring + call b_int_to_string + mov rsi, tstring + call b_print_string + mov rsi, mhzmsg + call b_print_string + +; L1 code/data cache info + call b_print_newline + mov eax, 0x80000005 ; L1 cache info + cpuid + mov eax, edx ; EDX bits 31 - 24 store code L1 cache size in KBs + shr eax, 24 + mov rdi, tstring + call b_int_to_string + mov rsi, l1ccachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + call b_print_newline + mov eax, ecx ; ECX bits 31 - 24 store data L1 cache size in KBs + shr eax, 24 + mov rdi, tstring + call b_int_to_string + mov rsi, l1dcachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + +; L2/L3 cache info + call b_print_newline + mov eax, 0x80000006 ; L2/L3 cache info + cpuid + mov eax, ecx ; ecx bits 31 - 16 store unified L2 cache size in KBs + shr eax, 16 + mov rdi, tstring + call b_int_to_string + mov rsi, l2ucachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + + call b_print_newline + mov eax, edx ; edx bits 31 - 18 store unified L3 cache size in 512 KB chunks + shr eax, 18 + and eax, 0x3FFFF ; Clear bits 18 - 31 + shl eax, 9 ; Convert the value for 512 KB chunks to KBs (Multiply by 512) + mov rdi, tstring + call b_int_to_string + mov rsi, l3ucachemsg + call b_print_string + mov rsi, tstring + call b_print_string + mov rsi, kbmsg + call b_print_string + +;CPU features + call b_print_newline + mov rsi, cpufeatures + call b_print_string + mov rax, 1 + cpuid + +checksse: + test edx, 00000010000000000000000000000000b + jz checksse2 + mov rsi, sse + call b_print_string + +checksse2: + test edx, 00000100000000000000000000000000b + jz checksse3 + mov rsi, sse2 + call b_print_string + +checksse3: + test ecx, 00000000000000000000000000000001b + jz checkssse3 + mov rsi, sse3 + call b_print_string + +checkssse3: + test ecx, 00000000000000000000001000000000b + jz checksse41 + mov rsi, ssse3 + call b_print_string + +checksse41: + test ecx, 00000000000010000000000000000000b + jz checksse42 + mov rsi, sse41 + call b_print_string + +checksse42: + test ecx, 00000000000100000000000000000000b + jz checkaes + mov rsi, sse42 + call b_print_string + +checkaes: + test ecx, 00000010000000000000000000000000b + jz checkavx + mov rsi, aes + call b_print_string + +checkavx: + test ecx, 00010000000000000000000000000000b + jz endit + mov rsi, avx + call b_print_string + +endit: +;RAM + call b_print_newline + mov rsi, memmessage + call b_print_string + xor rax, rax + mov rsi, 0x5020 + lodsw + mov rdi, tstring + call b_int_to_string + mov rsi, tstring + call b_print_string + mov rsi, mbmsg + call b_print_string + + + call b_print_newline + +ret ; Return to OS + +startmessage: db 'System Information:', 13, 0 +cpustringmsg: db 'CPU String: ', 0 +numcoresmsg: db 'Number of cores: ', 0 +speedmsg: db 'Detected speed: ', 0 +l1ccachemsg: db 'L1 code cache: ', 0 +l1dcachemsg: db 'L1 data cache: ', 0 +l2ucachemsg: db 'L2 unified cache: ', 0 +l3ucachemsg: db 'L3 unified cache: ', 0 +cpufeatures: db 'CPU features: ', 0 +kbmsg: db ' KiB', 0 +mbmsg: db ' MiB', 0 +mhzmsg: db ' MHz', 0 +sse: db 'SSE ', 0 +sse2: db 'SSE2 ', 0 +sse3: db 'SSE3 ', 0 +ssse3: db 'SSSE3 ', 0 +sse41: db 'SSE4.1 ', 0 +sse42: db 'SSE4.2 ', 0 +aes: db 'AES ', 0 +avx: db 'AVX ', 0 +memmessage: db 'RAM: ', 0 + tstring: times 50 db 0 \ No newline at end of file diff --git a/amd64/pure64-0.5.0/README.TXT b/amd64/pure64-0.5.0/README.TXT index 0b940081..7f4e0802 100644 --- a/amd64/pure64-0.5.0/README.TXT +++ b/amd64/pure64-0.5.0/README.TXT @@ -1,18 +1,18 @@ -=============================================================================== -Pure64 v0.5.0 Distribution -Copyright (C) 2007-2012 www.returninfinity.com -=============================================================================== - -Pure64 is a second stage bootloader for 64-bit PC's with compatible Intel or -AMD processors. The loader gets the computer into a full 64-bit state with no -legacy compatibility layers. Pure64 also enables and configures all available -Cores/CPUs in the computer. An information table is stored in memory after -Pure64 is finished that stores important details about the computer. - -This distribution contains the Pure64 second stage boot loader. It also -contains some example software that Pure64 can load as well as the FAT16 -bootsector that loads Pure64. - -For documentation please see www.returninfinity.com/pure64.html - -=============================================================================== +=============================================================================== +Pure64 v0.5.0 Distribution +Copyright (C) 2007-2012 www.returninfinity.com +=============================================================================== + +Pure64 is a second stage bootloader for 64-bit PC's with compatible Intel or +AMD processors. The loader gets the computer into a full 64-bit state with no +legacy compatibility layers. Pure64 also enables and configures all available +Cores/CPUs in the computer. An information table is stored in memory after +Pure64 is finished that stores important details about the computer. + +This distribution contains the Pure64 second stage boot loader. It also +contains some example software that Pure64 can load as well as the FAT16 +bootsector that loads Pure64. + +For documentation please see www.returninfinity.com/pure64.html + +=============================================================================== diff --git a/amd64/pure64-0.5.0/bootsector/boot16b.asm b/amd64/pure64-0.5.0/bootsector/boot16b.asm index 8aced397..f4eafa6d 100644 --- a/amd64/pure64-0.5.0/bootsector/boot16b.asm +++ b/amd64/pure64-0.5.0/bootsector/boot16b.asm @@ -1,252 +1,252 @@ -USE16 -org 0x7C00 - -entry: - jmp short begin - nop - -%define bsOemName bp+0x03 ; OEM label (8) -%define bsBytesPerSec bp+0x0B ; bytes/sector (dw) -%define bsSecsPerClust bp+0x0D ; sectors/allocation unit (db) -%define bsResSectors bp+0x0E ; # reserved sectors (dw) -%define bsFATs bp+0x10 ; # of fats (db) -%define bsRootDirEnts bp+0x11 ; Max # of root dir entries (dw) -%define bsSectors bp+0x13 ; # sectors total in image (dw) -%define bsMedia bp+0x15 ; media descriptor (db) -%define bsSecsPerFat bp+0x16 ; # sectors in a fat (dw) -%define bsSecsPerTrack bp+0x18 ; # sectors/track -%define bsHeads bp+0x1A ; # heads (dw) -%define bsHidden bp+0x1C ; # hidden sectors (dd) -%define bsSectorHuge bp+0x20 ; # sectors if > 65536 (dd) -%define bsDriveNumber bp+0x24 ; (dw) -%define bsSigniture bp+0x26 ; (db) -%define bsVolumeSerial bp+0x27 ; (dd) -%define bsVolumeLabel bp+0x2B ; (11) -%define bsSysID bp+0x36 ; (8) - -times 0x3B db 0 ; Code starts at offset 0x3E - -begin: - mov [bsDriveNumber], dl ; BIOS passes drive number in DL - xor eax, eax - xor esi, esi - xor edi, edi - mov ds, ax - mov es, ax - mov bp, 0x7c00 - -; Make sure the screen is set to 80x25 color text mode - mov ax, 0x0003 ; Set to normal (80x25 text) video mode - int 0x10 - -; Print message - mov si, msg_Load - call print_string_16 - -; read in the root cluster -; check for the filename -; if found save the starting cluster -; if not then error - -;fatstart = bsResSectors - -;rootcluster = bsResSectors + (bsFATs * bsSecsPerFat) -; 4 + (2 * 254) = sector 512 - -;datastart = bsResSectors + (bsFATs * bsSecsPerFat) + ((bsRootDirEnts * 32) / bsBytesPerSec) -; 4 + (2 * 254) + ((512 * 32) / 512) = sector 544 - -;cluster X starting sector -; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart - -; 0x7C5C as of Jan 6, 2010 -getoffset: - xor eax, eax - mov bx, 0x8000 - call readsector ; Read the MBR to 0x8000 - mov eax, [0x81C6] ; Grab the dword at 0x01C6 (num of sectors between MBR and first sector in partition) - mov [secoffset], eax ; Save it for later use - xor eax, eax - -ff: - mov ax, [bsSecsPerFat] - shl ax, 1 ; quick multiply by two - add ax, [bsResSectors] - mov [rootstart], ax - - mov bx, [bsRootDirEnts] - shr bx, 4 ; bx = (bx * 32) / 512 - add bx, ax ; BX now holds the datastart sector number - mov [datastart], bx - -ff_next_sector: - mov bx, 0x8000 - mov si, bx - mov di, bx - add eax, [secoffset] - call readsector - -; Search for file name, and find start cluster. -ff_next_entry: - mov cx, 11 - mov si, loadername - repe cmpsb - jz ff_done ; note that di now is at dirent+11 - - add di, byte 0x20 - and di, byte -0x20 - cmp di, [bsBytesPerSec] - jnz ff_next_entry - ; load next sector - dec dx ; next sector in cluster - jnz ff_next_sector - -ff_done: - add di, 15 - mov ax, [di] ; AX now holds the starting cluster # - -; At this point we have found the file we want and know the cluster where the file starts - - mov bx, 0x8000 ; We want to load to 0x0000:0x8000 -loadfile: - call readcluster - cmp ax, 0xFFF8 ; Have we reached the end cluster marker? - jg loadfile ; If not then load another - - jmp 0x0000:0x8000 - - - -;------------------------------------------------------------------------------ -; Read a sector from a disk, using LBA -; input: EAX - 32-bit DOS sector number -; ES:BX - destination buffer -; output: ES:BX points one byte after the last byte read -; EAX - next sector -readsector: - push dx - push si - push di - -read_it: - push eax ; Save the sector number - mov di, sp ; remember parameter block end - - push byte 0 ; other half of the 32 bits at [C] - push byte 0 ; [C] sector number high 32bit - push eax ; [8] sector number low 32bit - push es ; [6] buffer segment - push bx ; [4] buffer offset - push byte 1 ; [2] 1 sector (word) - push byte 16 ; [0] size of parameter block (word) - - mov si, sp - mov dl, [bsDriveNumber] - mov ah, 42h ; EXTENDED READ - int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 - - mov sp, di ; remove parameter block from stack - pop eax ; Restore the sector number - - jnc read_ok ; jump if no error - - push ax - xor ah, ah ; else, reset and retry - int 0x13 - pop ax - jmp read_it - -read_ok: - inc eax ; next sector - add bx, 512 ; Add bytes per sector - jnc no_incr_es ; if overflow... - -incr_es: - mov dx, es - add dh, 0x10 ; ...add 1000h to ES - mov es, dx - -no_incr_es: - pop di - pop si - pop dx - ret -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; Read a cluster from a disk partition, using LBA -; input: AX - 16-bit cluster number -; ES:BX - destination buffer -; output: ES:BX points one byte after the last byte read -; AX - next cluster -readcluster: - push cx - mov [tcluster], ax ; save our cluster value -;cluster X starting sector -; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart - xor cx, cx - sub ax, 2 - mov cl, byte [bsSecsPerClust] - imul cx ; EAX now holds starting sector - add ax, word [datastart] ; add the datastart offset - - xor cx, cx - mov cl, byte [bsSecsPerClust] - add eax, [secoffset] -readcluster_nextsector: - call readsector - dec cx - cmp cx, 0 - jne readcluster_nextsector - -; Great! We read a cluster.. now find out where the next cluster is - push bx ; save our memory pointer - mov bx, 0x7E00 ; load a sector from the root cluster here - push bx - mov ax, [bsResSectors] - add eax, [secoffset] - call readsector - pop bx ; bx points to 0x7e00 again - mov ax, [tcluster] ; ax holds the cluster # we just read - shl ax, 1 ; multipy by 2 - add bx, ax - mov ax, [bx] - - pop bx ; restore our memory pointer - pop cx - - ret -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; 16-bit Function to print a sting to the screen -; input: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -.repeat: - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - - -msg_Load db "Loading... ", 0 -msg_Error db "No " -loadername db "PURE64 SYS", 0 -kernelname db "KERNEL64SYS", 0 -datastart dw 0x0000 -rootstart dw 0x0000 -tcluster dw 0x0000 -secoffset dd 0x00000000 - -times 510-$+$$ db 0 - -sign dw 0xAA55 +USE16 +org 0x7C00 + +entry: + jmp short begin + nop + +%define bsOemName bp+0x03 ; OEM label (8) +%define bsBytesPerSec bp+0x0B ; bytes/sector (dw) +%define bsSecsPerClust bp+0x0D ; sectors/allocation unit (db) +%define bsResSectors bp+0x0E ; # reserved sectors (dw) +%define bsFATs bp+0x10 ; # of fats (db) +%define bsRootDirEnts bp+0x11 ; Max # of root dir entries (dw) +%define bsSectors bp+0x13 ; # sectors total in image (dw) +%define bsMedia bp+0x15 ; media descriptor (db) +%define bsSecsPerFat bp+0x16 ; # sectors in a fat (dw) +%define bsSecsPerTrack bp+0x18 ; # sectors/track +%define bsHeads bp+0x1A ; # heads (dw) +%define bsHidden bp+0x1C ; # hidden sectors (dd) +%define bsSectorHuge bp+0x20 ; # sectors if > 65536 (dd) +%define bsDriveNumber bp+0x24 ; (dw) +%define bsSigniture bp+0x26 ; (db) +%define bsVolumeSerial bp+0x27 ; (dd) +%define bsVolumeLabel bp+0x2B ; (11) +%define bsSysID bp+0x36 ; (8) + +times 0x3B db 0 ; Code starts at offset 0x3E + +begin: + mov [bsDriveNumber], dl ; BIOS passes drive number in DL + xor eax, eax + xor esi, esi + xor edi, edi + mov ds, ax + mov es, ax + mov bp, 0x7c00 + +; Make sure the screen is set to 80x25 color text mode + mov ax, 0x0003 ; Set to normal (80x25 text) video mode + int 0x10 + +; Print message + mov si, msg_Load + call print_string_16 + +; read in the root cluster +; check for the filename +; if found save the starting cluster +; if not then error + +;fatstart = bsResSectors + +;rootcluster = bsResSectors + (bsFATs * bsSecsPerFat) +; 4 + (2 * 254) = sector 512 + +;datastart = bsResSectors + (bsFATs * bsSecsPerFat) + ((bsRootDirEnts * 32) / bsBytesPerSec) +; 4 + (2 * 254) + ((512 * 32) / 512) = sector 544 + +;cluster X starting sector +; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart + +; 0x7C5C as of Jan 6, 2010 +getoffset: + xor eax, eax + mov bx, 0x8000 + call readsector ; Read the MBR to 0x8000 + mov eax, [0x81C6] ; Grab the dword at 0x01C6 (num of sectors between MBR and first sector in partition) + mov [secoffset], eax ; Save it for later use + xor eax, eax + +ff: + mov ax, [bsSecsPerFat] + shl ax, 1 ; quick multiply by two + add ax, [bsResSectors] + mov [rootstart], ax + + mov bx, [bsRootDirEnts] + shr bx, 4 ; bx = (bx * 32) / 512 + add bx, ax ; BX now holds the datastart sector number + mov [datastart], bx + +ff_next_sector: + mov bx, 0x8000 + mov si, bx + mov di, bx + add eax, [secoffset] + call readsector + +; Search for file name, and find start cluster. +ff_next_entry: + mov cx, 11 + mov si, loadername + repe cmpsb + jz ff_done ; note that di now is at dirent+11 + + add di, byte 0x20 + and di, byte -0x20 + cmp di, [bsBytesPerSec] + jnz ff_next_entry + ; load next sector + dec dx ; next sector in cluster + jnz ff_next_sector + +ff_done: + add di, 15 + mov ax, [di] ; AX now holds the starting cluster # + +; At this point we have found the file we want and know the cluster where the file starts + + mov bx, 0x8000 ; We want to load to 0x0000:0x8000 +loadfile: + call readcluster + cmp ax, 0xFFF8 ; Have we reached the end cluster marker? + jg loadfile ; If not then load another + + jmp 0x0000:0x8000 + + + +;------------------------------------------------------------------------------ +; Read a sector from a disk, using LBA +; input: EAX - 32-bit DOS sector number +; ES:BX - destination buffer +; output: ES:BX points one byte after the last byte read +; EAX - next sector +readsector: + push dx + push si + push di + +read_it: + push eax ; Save the sector number + mov di, sp ; remember parameter block end + + push byte 0 ; other half of the 32 bits at [C] + push byte 0 ; [C] sector number high 32bit + push eax ; [8] sector number low 32bit + push es ; [6] buffer segment + push bx ; [4] buffer offset + push byte 1 ; [2] 1 sector (word) + push byte 16 ; [0] size of parameter block (word) + + mov si, sp + mov dl, [bsDriveNumber] + mov ah, 42h ; EXTENDED READ + int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 + + mov sp, di ; remove parameter block from stack + pop eax ; Restore the sector number + + jnc read_ok ; jump if no error + + push ax + xor ah, ah ; else, reset and retry + int 0x13 + pop ax + jmp read_it + +read_ok: + inc eax ; next sector + add bx, 512 ; Add bytes per sector + jnc no_incr_es ; if overflow... + +incr_es: + mov dx, es + add dh, 0x10 ; ...add 1000h to ES + mov es, dx + +no_incr_es: + pop di + pop si + pop dx + ret +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; Read a cluster from a disk partition, using LBA +; input: AX - 16-bit cluster number +; ES:BX - destination buffer +; output: ES:BX points one byte after the last byte read +; AX - next cluster +readcluster: + push cx + mov [tcluster], ax ; save our cluster value +;cluster X starting sector +; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart + xor cx, cx + sub ax, 2 + mov cl, byte [bsSecsPerClust] + imul cx ; EAX now holds starting sector + add ax, word [datastart] ; add the datastart offset + + xor cx, cx + mov cl, byte [bsSecsPerClust] + add eax, [secoffset] +readcluster_nextsector: + call readsector + dec cx + cmp cx, 0 + jne readcluster_nextsector + +; Great! We read a cluster.. now find out where the next cluster is + push bx ; save our memory pointer + mov bx, 0x7E00 ; load a sector from the root cluster here + push bx + mov ax, [bsResSectors] + add eax, [secoffset] + call readsector + pop bx ; bx points to 0x7e00 again + mov ax, [tcluster] ; ax holds the cluster # we just read + shl ax, 1 ; multipy by 2 + add bx, ax + mov ax, [bx] + + pop bx ; restore our memory pointer + pop cx + + ret +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; 16-bit Function to print a sting to the screen +; input: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +.repeat: + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + + +msg_Load db "Loading... ", 0 +msg_Error db "No " +loadername db "PURE64 SYS", 0 +kernelname db "KERNEL64SYS", 0 +datastart dw 0x0000 +rootstart dw 0x0000 +tcluster dw 0x0000 +secoffset dd 0x00000000 + +times 510-$+$$ db 0 + +sign dw 0xAA55 diff --git a/amd64/pure64-0.5.0/bootsector/fat16mbr.asm b/amd64/pure64-0.5.0/bootsector/fat16mbr.asm index 17a80979..ecc99084 100644 --- a/amd64/pure64-0.5.0/bootsector/fat16mbr.asm +++ b/amd64/pure64-0.5.0/bootsector/fat16mbr.asm @@ -1,131 +1,131 @@ -USE16 -org 0x7C00 - -entry: - cli - mov [DriveNumber], dl ; BIOS passes drive number in DL - xor ax, ax - mov ss, ax - mov sp, 0x7C00 - mov si, sp - push ax - pop es - push ax - pop ds - sti - -; Copy MBR sector to 0x0600 and jump there - cld - mov di, 0x0600 - mov cx, 0x0100 - repne movsw - jmp 0x0000:0x0621 -; 0x0621 - -; Print message - mov si, msg_Load - call print_string_16 - - mov si, 0x07BE - cmp byte [si], 0x80 - jne NoActivePartition - - mov ecx, [0x07C6] - mov bx, 0x7C00 - xor esi, esi - xor edi, edi - mov si, bx - mov di, bx - add eax, ecx - call readsector - jmp 0x0000:0x7C00 - -NoActivePartition: - mov si, msg_NoPartition - call print_string_16 - jmp $ - - -;------------------------------------------------------------------------------ -; Read a sector from a disk, using LBA -; input: EAX - 32-bit DOS sector number -; ES:BX - destination buffer -; output: ES:BX points one byte after the last byte read -; EAX - next sector -readsector: - push dx - push si - push di - -read_it: - push eax ; Save the sector number - mov di, sp ; remember parameter block end - - push byte 0 ; other half of the 32 bits at [C] - push byte 0 ; [C] sector number high 32bit - push eax ; [8] sector number low 32bit - push es ; [6] buffer segment - push bx ; [4] buffer offset - push byte 1 ; [2] 1 sector (word) - push byte 16 ; [0] size of parameter block (word) - - mov si, sp - mov dl, [DriveNumber] - mov ah, 42h ; EXTENDED READ - int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 - - mov sp, di ; remove parameter block from stack - pop eax ; Restore the sector number - - jnc read_ok ; jump if no error - - push ax - xor ah, ah ; else, reset and retry - int 0x13 - pop ax - jmp read_it - -read_ok: - inc eax ; next sector - add bx, 512 ; Add bytes per sector - jnc no_incr_es ; if overflow... - -incr_es: - mov dx, es - add dh, 0x10 ; ...add 1000h to ES - mov es, dx - -no_incr_es: - pop di - pop si - pop dx - ret -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; 16-bit Function to print a sting to the screen -; input: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -.repeat: - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - -msg_Load db "Loading... ", 0 -msg_NoPartition db "No active partition found" -DriveNumber db 0x00 - -times 446-$+$$ db 0 - -tables db "XXXXXXXXXXXXXXXX DO NOT OVERWRITE THIS AREA!!! XXXXXXXXXXXXXXXX" ; 64 bytes in length - -sign dw 0xAA55 +USE16 +org 0x7C00 + +entry: + cli + mov [DriveNumber], dl ; BIOS passes drive number in DL + xor ax, ax + mov ss, ax + mov sp, 0x7C00 + mov si, sp + push ax + pop es + push ax + pop ds + sti + +; Copy MBR sector to 0x0600 and jump there + cld + mov di, 0x0600 + mov cx, 0x0100 + repne movsw + jmp 0x0000:0x0621 +; 0x0621 + +; Print message + mov si, msg_Load + call print_string_16 + + mov si, 0x07BE + cmp byte [si], 0x80 + jne NoActivePartition + + mov ecx, [0x07C6] + mov bx, 0x7C00 + xor esi, esi + xor edi, edi + mov si, bx + mov di, bx + add eax, ecx + call readsector + jmp 0x0000:0x7C00 + +NoActivePartition: + mov si, msg_NoPartition + call print_string_16 + jmp $ + + +;------------------------------------------------------------------------------ +; Read a sector from a disk, using LBA +; input: EAX - 32-bit DOS sector number +; ES:BX - destination buffer +; output: ES:BX points one byte after the last byte read +; EAX - next sector +readsector: + push dx + push si + push di + +read_it: + push eax ; Save the sector number + mov di, sp ; remember parameter block end + + push byte 0 ; other half of the 32 bits at [C] + push byte 0 ; [C] sector number high 32bit + push eax ; [8] sector number low 32bit + push es ; [6] buffer segment + push bx ; [4] buffer offset + push byte 1 ; [2] 1 sector (word) + push byte 16 ; [0] size of parameter block (word) + + mov si, sp + mov dl, [DriveNumber] + mov ah, 42h ; EXTENDED READ + int 0x13 ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651 + + mov sp, di ; remove parameter block from stack + pop eax ; Restore the sector number + + jnc read_ok ; jump if no error + + push ax + xor ah, ah ; else, reset and retry + int 0x13 + pop ax + jmp read_it + +read_ok: + inc eax ; next sector + add bx, 512 ; Add bytes per sector + jnc no_incr_es ; if overflow... + +incr_es: + mov dx, es + add dh, 0x10 ; ...add 1000h to ES + mov es, dx + +no_incr_es: + pop di + pop si + pop dx + ret +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; 16-bit Function to print a sting to the screen +; input: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +.repeat: + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + +msg_Load db "Loading... ", 0 +msg_NoPartition db "No active partition found" +DriveNumber db 0x00 + +times 446-$+$$ db 0 + +tables db "XXXXXXXXXXXXXXXX DO NOT OVERWRITE THIS AREA!!! XXXXXXXXXXXXXXXX" ; 64 bytes in length + +sign dw 0xAA55 diff --git a/amd64/pure64-0.5.0/bootsector/pxestart.asm b/amd64/pure64-0.5.0/bootsector/pxestart.asm index 100ccdf4..9d7c0d87 100644 --- a/amd64/pure64-0.5.0/bootsector/pxestart.asm +++ b/amd64/pure64-0.5.0/bootsector/pxestart.asm @@ -1,68 +1,68 @@ -; ============================================================================= -; Pure64 PXE Start -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; This is a stub file for chainloading Pure64 and a Kernel via PXE. -; -; You will need to uncomment the PURE64_CHAIN_LOADING line in pure64.asm -; -; Windows - copy /b pxestart.bin + pure64.sys + kernel64.sys pxeboot.bin -; Unix - cat pxestart.bin pure64.sys kernel64.sys > pxeboot.bin -; -; Max size of the resulting pxeboot.bin is 33792 bytes. 1K for the PXE loader -; stub and up to 32KiB for the code/data. PXE loads the file to address -; 0x00007C00 (Just like a boot sector). -; -; File Sizes -; pxestart.bin 1024 bytes -; pure64.sys 7168 bytes -; kernel64.sys 16384 bytes (or so) -; ============================================================================= - - -USE16 -org 0x7C00 - -start: - xor eax, eax - xor esi, esi - xor edi, edi - mov ds, ax - mov es, ax - mov bp, 0x7c00 - -; Make sure the screen is set to 80x25 color text mode - mov ax, 0x0003 ; Set to normal (80x25 text) video mode - int 0x10 - -; Print message - mov si, msg_Load - call print_string_16 - - jmp 0x0000:0x8000 - -;------------------------------------------------------------------------------ -; 16-bit Function to print a sting to the screen -; input: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -.repeat: - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - - -msg_Load db "Loading via PXE... ", 0 - -times 510-$+$$ db 0 ; Pad out for a normal boot sector - -sign dw 0xAA55 - -times 1024-$+$$ db 0 ; Padding so that Pure64 will be aligned at 0x8000 +; ============================================================================= +; Pure64 PXE Start -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; This is a stub file for chainloading Pure64 and a Kernel via PXE. +; +; You will need to uncomment the PURE64_CHAIN_LOADING line in pure64.asm +; +; Windows - copy /b pxestart.bin + pure64.sys + kernel64.sys pxeboot.bin +; Unix - cat pxestart.bin pure64.sys kernel64.sys > pxeboot.bin +; +; Max size of the resulting pxeboot.bin is 33792 bytes. 1K for the PXE loader +; stub and up to 32KiB for the code/data. PXE loads the file to address +; 0x00007C00 (Just like a boot sector). +; +; File Sizes +; pxestart.bin 1024 bytes +; pure64.sys 7168 bytes +; kernel64.sys 16384 bytes (or so) +; ============================================================================= + + +USE16 +org 0x7C00 + +start: + xor eax, eax + xor esi, esi + xor edi, edi + mov ds, ax + mov es, ax + mov bp, 0x7c00 + +; Make sure the screen is set to 80x25 color text mode + mov ax, 0x0003 ; Set to normal (80x25 text) video mode + int 0x10 + +; Print message + mov si, msg_Load + call print_string_16 + + jmp 0x0000:0x8000 + +;------------------------------------------------------------------------------ +; 16-bit Function to print a sting to the screen +; input: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +.repeat: + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + + +msg_Load db "Loading via PXE... ", 0 + +times 510-$+$$ db 0 ; Pad out for a normal boot sector + +sign dw 0xAA55 + +times 1024-$+$$ db 0 ; Padding so that Pure64 will be aligned at 0x8000 diff --git a/amd64/pure64-0.5.0/docs/CREDITS.TXT b/amd64/pure64-0.5.0/docs/CREDITS.TXT index 5a627833..c38f6a3f 100644 --- a/amd64/pure64-0.5.0/docs/CREDITS.TXT +++ b/amd64/pure64-0.5.0/docs/CREDITS.TXT @@ -1,17 +1,17 @@ -=============================================================================== -Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -=============================================================================== - - -PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) - - * Ian Seyler -- ian.seyler@returninfinity.com - - -DEVELOPMENT AND TESTING - - * Members of OSDev.org - - -=============================================================================== +=============================================================================== +Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +=============================================================================== + + +PROJECT ADMIN (MAIN CODE AND DOCUMENTATION) + + * Ian Seyler -- ian.seyler@returninfinity.com + + +DEVELOPMENT AND TESTING + + * Members of OSDev.org + + +=============================================================================== diff --git a/amd64/pure64-0.5.0/docs/LICENSE.TXT b/amd64/pure64-0.5.0/docs/LICENSE.TXT index a1eef3d4..ebbeafd0 100644 --- a/amd64/pure64-0.5.0/docs/LICENSE.TXT +++ b/amd64/pure64-0.5.0/docs/LICENSE.TXT @@ -1,35 +1,35 @@ -=============================================================================== -Pure64 -- License -=============================================================================== - -Copyright (C) 2008-2012 Return Infinity -- http://www.returninfinity.com - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name Pure64 nor the names of any Pure64 contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -=============================================================================== +=============================================================================== +Pure64 -- License +=============================================================================== + +Copyright (C) 2008-2012 Return Infinity -- http://www.returninfinity.com + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name Pure64 nor the names of any Pure64 contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY RETURN INFINITY AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL RETURN INFINITY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +=============================================================================== diff --git a/amd64/pure64-0.5.0/kernel_asm/kernel64.asm b/amd64/pure64-0.5.0/kernel_asm/kernel64.asm index 29b3f8c5..95693e05 100644 --- a/amd64/pure64-0.5.0/kernel_asm/kernel64.asm +++ b/amd64/pure64-0.5.0/kernel_asm/kernel64.asm @@ -1,20 +1,20 @@ -; ============================================================================= -; 64-bit Assembly example for Pure64 -; Written by Ian Seyler (www.returninfinity.com) -; -; Assemble with NASM or YASM -; ============================================================================= - - -USE64 -[ORG 0x0000000000100000] - -start: - -; put your code here - -end: -jmp end - -; ============================================================================= -; EOF +; ============================================================================= +; 64-bit Assembly example for Pure64 +; Written by Ian Seyler (www.returninfinity.com) +; +; Assemble with NASM or YASM +; ============================================================================= + + +USE64 +[ORG 0x0000000000100000] + +start: + +; put your code here + +end: +jmp end + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/fat16.asm b/amd64/pure64-0.5.0/src/fat16.asm index 06c573ea..af44af74 100644 --- a/amd64/pure64-0.5.0/src/fat16.asm +++ b/amd64/pure64-0.5.0/src/fat16.asm @@ -1,162 +1,162 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; FAT16 functions -; ============================================================================= - - -; ----------------------------------------------------------------------------- -; readcluster -- Read a cluster from the FAT16 partition -; IN: AX - (cluster) -; RDI - (memory location to store at least 32KB) -; OUT: AX - (next cluster) -; RDI - points one byte after the last byte read -readcluster: - push rsi - push rdx - push rcx - push rbx - - and rax, 0x000000000000FFFF ; Clear the top 48 bits - mov rbx, rax ; Save the cluster number to be used later - - cmp ax, 2 ; If less than 2 then bail out... - jl near readcluster_bailout ; as clusters start at 2 - -; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start - xor rcx, rcx - mov cl, byte [fat16_SectorsPerCluster] - push rcx ; Save the number of sectors per cluster - sub ax, 2 - imul cx ; EAX now holds starting sector - add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - - pop rcx ; Restore the number of sectors per cluster - call readsectors ; Read one cluster of sectors - cmp rcx, 0 - je readcluster_error - -; Calculate the next cluster -; Psuedo-code -; tint1 = Cluster / 256 <- Dump the remainder -; sector_to_read = tint1 + ReservedSectors -; tint2 = (Cluster - (tint1 * 256)) * 2 - push rdi - mov rdi, hdbuffer1 ; Read to this temporary buffer - mov rsi, rdi ; Copy buffer address to RSI - push rbx ; Save the original cluster value - shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder - movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - add rax, rbx ; Add the sector offset - mov rcx, 1 - call readsectors - cmp rcx, 0 - je readcluster_error - pop rax ; Get our original cluster value back - shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) - sub rax, rbx ; RAX is now pointed to the offset within the sector - shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) - add rsi, rax - lodsw ; AX now holds the next cluster - pop rdi - - jmp readcluster_end - -readcluster_bailout: - xor ax, ax - -readcluster_end: - pop rbx - pop rcx - pop rdx - pop rsi -ret - -readcluster_error: - mov rsi, readcluster_err_msg - call os_print_string - jmp exception_gate_halt -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; findfile -- -; IN: RSI(Pointer to file name, must be in 'FILENAMEEXT" format) -; OUT: AX(Staring cluster), 0x0 if not found -; Notes: Only searches the root sector.. not the following sectors. -findfile: - push rsi - push rdi - push rdx - push rcx - push rbx - - clc ; Clear carry - xor rax, rax - mov eax, [fat16_RootStart] ; eax points to the first sector of the root - add eax, [fat16_PartitionOffset] ; Add the offset to the partition - mov rdx, rax ; Save the sector value - -os_fat16_find_file_read_sector: - mov rdi, hdbuffer1 - push rdi - mov rcx, 1 - call readsectors - cmp rcx, 0 - je os_fat16_find_file_error - pop rdi - mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 - -os_fat16_find_file_next_entry: - cmp byte [rdi], 0x00 ; end of records - je os_fat16_find_file_notfound - - mov rcx, 11 - push rsi - repe cmpsb - pop rsi - mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at - jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 - - add rdi, byte 0x20 - and rdi, byte -0x20 - dec rbx - cmp rbx, 0 - jne os_fat16_find_file_next_entry - -; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. - - add rdx, 1 - mov rax, rdx - jmp os_fat16_find_file_read_sector - -os_fat16_find_file_notfound: - stc ; Set carry - xor rax, rax - -os_fat16_find_file_done: - cmp ax, 0x0000 ; BUG HERE - jne wut ; Carry is not being set properly in this function - stc -wut: - pop rbx - pop rcx - pop rdx - pop rdi - pop rsi -ret - -os_fat16_find_file_error: - mov rsi, findfile_err_msg - call os_print_string - jmp exception_gate_halt -; ----------------------------------------------------------------------------- - -readcluster_err_msg: db 'Error reading cluster', 0 -findfile_err_msg: db 'Error finding file', 0 - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; FAT16 functions +; ============================================================================= + + +; ----------------------------------------------------------------------------- +; readcluster -- Read a cluster from the FAT16 partition +; IN: AX - (cluster) +; RDI - (memory location to store at least 32KB) +; OUT: AX - (next cluster) +; RDI - points one byte after the last byte read +readcluster: + push rsi + push rdx + push rcx + push rbx + + and rax, 0x000000000000FFFF ; Clear the top 48 bits + mov rbx, rax ; Save the cluster number to be used later + + cmp ax, 2 ; If less than 2 then bail out... + jl near readcluster_bailout ; as clusters start at 2 + +; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start + xor rcx, rcx + mov cl, byte [fat16_SectorsPerCluster] + push rcx ; Save the number of sectors per cluster + sub ax, 2 + imul cx ; EAX now holds starting sector + add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + + pop rcx ; Restore the number of sectors per cluster + call readsectors ; Read one cluster of sectors + cmp rcx, 0 + je readcluster_error + +; Calculate the next cluster +; Psuedo-code +; tint1 = Cluster / 256 <- Dump the remainder +; sector_to_read = tint1 + ReservedSectors +; tint2 = (Cluster - (tint1 * 256)) * 2 + push rdi + mov rdi, hdbuffer1 ; Read to this temporary buffer + mov rsi, rdi ; Copy buffer address to RSI + push rbx ; Save the original cluster value + shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder + movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + add rax, rbx ; Add the sector offset + mov rcx, 1 + call readsectors + cmp rcx, 0 + je readcluster_error + pop rax ; Get our original cluster value back + shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT) + sub rax, rbx ; RAX is now pointed to the offset within the sector + shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit) + add rsi, rax + lodsw ; AX now holds the next cluster + pop rdi + + jmp readcluster_end + +readcluster_bailout: + xor ax, ax + +readcluster_end: + pop rbx + pop rcx + pop rdx + pop rsi +ret + +readcluster_error: + mov rsi, readcluster_err_msg + call os_print_string + jmp exception_gate_halt +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; findfile -- +; IN: RSI(Pointer to file name, must be in 'FILENAMEEXT" format) +; OUT: AX(Staring cluster), 0x0 if not found +; Notes: Only searches the root sector.. not the following sectors. +findfile: + push rsi + push rdi + push rdx + push rcx + push rbx + + clc ; Clear carry + xor rax, rax + mov eax, [fat16_RootStart] ; eax points to the first sector of the root + add eax, [fat16_PartitionOffset] ; Add the offset to the partition + mov rdx, rax ; Save the sector value + +os_fat16_find_file_read_sector: + mov rdi, hdbuffer1 + push rdi + mov rcx, 1 + call readsectors + cmp rcx, 0 + je os_fat16_find_file_error + pop rdi + mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16 + +os_fat16_find_file_next_entry: + cmp byte [rdi], 0x00 ; end of records + je os_fat16_find_file_notfound + + mov rcx, 11 + push rsi + repe cmpsb + pop rsi + mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at + jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11 + + add rdi, byte 0x20 + and rdi, byte -0x20 + dec rbx + cmp rbx, 0 + jne os_fat16_find_file_next_entry + +; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector. + + add rdx, 1 + mov rax, rdx + jmp os_fat16_find_file_read_sector + +os_fat16_find_file_notfound: + stc ; Set carry + xor rax, rax + +os_fat16_find_file_done: + cmp ax, 0x0000 ; BUG HERE + jne wut ; Carry is not being set properly in this function + stc +wut: + pop rbx + pop rcx + pop rdx + pop rdi + pop rsi +ret + +os_fat16_find_file_error: + mov rsi, findfile_err_msg + call os_print_string + jmp exception_gate_halt +; ----------------------------------------------------------------------------- + +readcluster_err_msg: db 'Error reading cluster', 0 +findfile_err_msg: db 'Error finding file', 0 + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/init_acpi.asm b/amd64/pure64-0.5.0/src/init_acpi.asm index 701f9886..6367d5e4 100644 --- a/amd64/pure64-0.5.0/src/init_acpi.asm +++ b/amd64/pure64-0.5.0/src/init_acpi.asm @@ -1,258 +1,258 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT ACPI -; ============================================================================= - - -init_acpi: - mov rsi, 0x00000000000E0000 ; Start looking for the Root System Description Pointer Structure - mov rbx, 'RSD PTR ' ; This in the Signature for the ACPI Structure Table (0x2052545020445352) -searchingforACPI: - lodsq ; Load a quad word from RSI and store in RAX, then increment RSI by 8 - cmp rax, rbx - je foundACPI - cmp rsi, 0x00000000000FFFFF ; Keep looking until we get here - jge noACPI ; ACPI tables couldn't be found, Fail. - jmp searchingforACPI - -foundACPI: ; Found a Pointer Structure, verify the checksum - push rsi - xor ebx, ebx - mov ecx, 20 ; As per the spec only the first 20 bytes matter - sub rsi, 8 ; Bytes 0 thru 19 must sum to zero -nextchecksum: - lodsb ; Get a byte - add bl, al ; Add it to the running total - sub cl, 1 - cmp cl, 0 - jne nextchecksum - pop rsi - cmp bl, 0 - jne searchingforACPI ; Checksum didn't check out? Then keep looking. - - lodsb ; Checksum - lodsd ; OEMID (First 4 bytes) - lodsw ; OEMID (Last 2 bytes) - lodsb ; Grab the Revision value (0 is v1.0, 1 is v2.0, 2 is v3.0, etc) - add al, 49 - mov [0x000B8098], al ; Print the ACPI version number - sub al, 49 - cmp al, 0 - je foundACPIv1 ; If AL is 0 then the system is using ACPI v1.0 - jmp foundACPIv2 ; Otherwise it is v2.0 or higher - -foundACPIv1: - xor eax, eax - lodsd ; Grab the 32 bit physical address of the RSDT (Offset 16). - mov rsi, rax ; RSI now points to the RSDT - lodsd ; Grab the Signiture - cmp eax, 'RSDT' ; Make sure the signiture is valid - jne novalidacpi ; Not the same? Bail out - sub rsi, 4 - mov [os_ACPITableAddress], rsi ; Save the RSDT Table Address - add rsi, 4 - xor eax, eax - lodsd ; Length - add rsi, 28 ; Skip to the Entry offset - sub eax, 36 ; EAX holds the table size. Subtract the preamble - shr eax, 2 ; Divide by 4 - mov rdx, rax ; RDX is the entry count - xor ecx, ecx -foundACPIv1_nextentry: - lodsd - push rax - add ecx, 1 - cmp ecx, edx - je findAPICTable - jmp foundACPIv1_nextentry - -foundACPIv2: - lodsd ; RSDT Address - lodsd ; Length - lodsq ; Grab the 64 bit physical address of the XSDT (Offset 24). - mov rsi, rax ; RSI now points to the XSDT - lodsd ; Grab the Signiture - cmp eax, 'XSDT' ; Make sure the signiture is valid - jne novalidacpi ; Not the same? Bail out - sub rsi, 4 - mov [os_ACPITableAddress], rsi ; Save the XSDT Table Address - add rsi, 4 - xor eax, eax - lodsd ; Length - add rsi, 28 ; Skip to the start of the Entries (offset 36) - sub eax, 36 ; EAX holds the table size. Subtract the preamble - shr eax, 3 ; Divide by 8 - mov rdx, rax ; RDX is the entry count - xor ecx, ecx -foundACPIv2_nextentry: - lodsq - push rax - add ecx, 1 - cmp ecx, edx - jne foundACPIv2_nextentry - -findAPICTable: - mov al, '3' ; Search for the APIC table - mov [0x000B809C], al - mov al, '4' - mov [0x000B809E], al - mov ebx, 'APIC' ; Signature for the Multiple APIC Description Table - xor ecx, ecx -searchingforAPIC: - pop rsi - lodsd - add ecx, 1 - cmp eax, ebx - je foundAPICTable - cmp ecx, edx - jne searchingforAPIC - jmp noACPIAPIC - -fixstack: - pop rax - add ecx, 1 - -foundAPICTable: - ; fix the stack - cmp ecx, edx - jne fixstack - - lodsd ; Length of MADT in bytes - mov ecx, eax ; Store the length in ECX - xor ebx, ebx ; EBX is the counter - lodsb ; Revision - lodsb ; Checksum - lodsd ; OEMID (First 4 bytes) - lodsw ; OEMID (Last 2 bytes) - lodsq ; OEM Table ID - lodsd ; OEM Revision - lodsd ; Creator ID - lodsd ; Creator Revision - xor eax, eax - lodsd ; Local APIC Address - mov [os_LocalAPICAddress], rax ; Save the Address of the Local APIC - lodsd ; Flags - add ebx, 44 - mov rdi, 0x0000000000005100 ; Valid CPU IDs - -readAPICstructures: - cmp ebx, ecx - jge init_smp_acpi_done -; mov al, ' ' -; call os_print_char -; call os_print_char - lodsb ; APIC Structure Type -; call os_debug_dump_al -; push rax -; mov al, ' ' -; call os_print_char -; pop rax - cmp al, 0x00 ; Processor Local APIC - je APICapic - cmp al, 0x01 ; I/O APIC - je APICioapic - cmp al, 0x02 ; Interrupt Source Override - je APICinterruptsourceoverride -; cmp al, 0x03 ; Non-maskable Interrupt Source (NMI) -; je APICnmi -; cmp al, 0x04 ; Local APIC NMI -; je APIClocalapicnmi -; cmp al, 0x05 ; Local APIC Address Override -; je APICaddressoverride - cmp al, 0x09 ; Processor Local x2APIC - je APICx2apic -; cmp al, 0x0A ; Local x2APIC NMI -; je APICx2nmi - - jmp APICignore - -APICapic: - xor eax, eax - xor edx, edx - lodsb ; Length (will be set to 8) - add ebx, eax - lodsb ; ACPI Processor ID - lodsb ; APIC ID - xchg eax, edx ; Save the APIC ID to EDX - lodsd ; Flags (Bit 0 set if enabled/usable) - bt eax, 0 ; Test to see if usable - jnc readAPICstructures ; Read the next structure if CPU not usable - inc word [cpu_detected] - xchg eax, edx ; Restore the APIC ID back to EAX - stosb - jmp readAPICstructures ; Read the next structure - -APICioapic: - xor eax, eax - lodsb ; Length (will be set to 12) - add ebx, eax - lodsb ; IO APIC ID - lodsb ; Reserved - xor eax, eax - lodsd ; IO APIC Address - push rdi - mov rdi, os_IOAPICAddress - xor ecx, ecx - mov cl, [os_IOAPICCount] - shl cx, 3 ; Quick multiply by 8 - add rdi, rcx - stosd ; Store the IO APIC Address - lodsd ; System Vector Base - stosd ; Store the IO APIC Vector Base - pop rdi - inc byte [os_IOAPICCount] - jmp readAPICstructures ; Read the next structure - -APICinterruptsourceoverride: - xor eax, eax - lodsb ; Length (will be set to 10) - add ebx, eax - lodsb ; Bus - lodsb ; Source -; call os_debug_dump_al -; mov al, ' ' -; call os_print_char - lodsd ; Global System Interrupt -; call os_debug_dump_eax - lodsw ; Flags - jmp readAPICstructures ; Read the next structure - -APICx2apic: - xor eax, eax - xor edx, edx - lodsb ; Length (will be set to 16) - lodsw ; Reserved; Must be Zero - lodsd - xchg eax, edx ; Save the x2APIC ID to EDX - lodsd ; Flags (Bit 0 set if enabled/usable) - bt eax, 0 ; Test to see if usable - jnc APICx2apicEnd ; Read the next structure if CPU not usable - xchg eax, edx ; Restore the x2APIC ID back to EAX - call os_debug_dump_eax - call os_print_newline - ; Save the ID's somewhere -APICx2apicEnd: - lodsd ; ACPI Processor UID - jmp readAPICstructures ; Read the next structure - -APICignore: - xor eax, eax - lodsb ; We have a type that we ignore, read the next byte - add ebx, eax - add rsi, rax - sub rsi, 2 ; For the two bytes just read - jmp readAPICstructures ; Read the next structure - -init_smp_acpi_done: - ret - -noACPI: -noACPIAPIC: -novalidacpi: - mov al, 'X' - mov [0x000B809A], al - jmp $ -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT ACPI +; ============================================================================= + + +init_acpi: + mov rsi, 0x00000000000E0000 ; Start looking for the Root System Description Pointer Structure + mov rbx, 'RSD PTR ' ; This in the Signature for the ACPI Structure Table (0x2052545020445352) +searchingforACPI: + lodsq ; Load a quad word from RSI and store in RAX, then increment RSI by 8 + cmp rax, rbx + je foundACPI + cmp rsi, 0x00000000000FFFFF ; Keep looking until we get here + jge noACPI ; ACPI tables couldn't be found, Fail. + jmp searchingforACPI + +foundACPI: ; Found a Pointer Structure, verify the checksum + push rsi + xor ebx, ebx + mov ecx, 20 ; As per the spec only the first 20 bytes matter + sub rsi, 8 ; Bytes 0 thru 19 must sum to zero +nextchecksum: + lodsb ; Get a byte + add bl, al ; Add it to the running total + sub cl, 1 + cmp cl, 0 + jne nextchecksum + pop rsi + cmp bl, 0 + jne searchingforACPI ; Checksum didn't check out? Then keep looking. + + lodsb ; Checksum + lodsd ; OEMID (First 4 bytes) + lodsw ; OEMID (Last 2 bytes) + lodsb ; Grab the Revision value (0 is v1.0, 1 is v2.0, 2 is v3.0, etc) + add al, 49 + mov [0x000B8098], al ; Print the ACPI version number + sub al, 49 + cmp al, 0 + je foundACPIv1 ; If AL is 0 then the system is using ACPI v1.0 + jmp foundACPIv2 ; Otherwise it is v2.0 or higher + +foundACPIv1: + xor eax, eax + lodsd ; Grab the 32 bit physical address of the RSDT (Offset 16). + mov rsi, rax ; RSI now points to the RSDT + lodsd ; Grab the Signiture + cmp eax, 'RSDT' ; Make sure the signiture is valid + jne novalidacpi ; Not the same? Bail out + sub rsi, 4 + mov [os_ACPITableAddress], rsi ; Save the RSDT Table Address + add rsi, 4 + xor eax, eax + lodsd ; Length + add rsi, 28 ; Skip to the Entry offset + sub eax, 36 ; EAX holds the table size. Subtract the preamble + shr eax, 2 ; Divide by 4 + mov rdx, rax ; RDX is the entry count + xor ecx, ecx +foundACPIv1_nextentry: + lodsd + push rax + add ecx, 1 + cmp ecx, edx + je findAPICTable + jmp foundACPIv1_nextentry + +foundACPIv2: + lodsd ; RSDT Address + lodsd ; Length + lodsq ; Grab the 64 bit physical address of the XSDT (Offset 24). + mov rsi, rax ; RSI now points to the XSDT + lodsd ; Grab the Signiture + cmp eax, 'XSDT' ; Make sure the signiture is valid + jne novalidacpi ; Not the same? Bail out + sub rsi, 4 + mov [os_ACPITableAddress], rsi ; Save the XSDT Table Address + add rsi, 4 + xor eax, eax + lodsd ; Length + add rsi, 28 ; Skip to the start of the Entries (offset 36) + sub eax, 36 ; EAX holds the table size. Subtract the preamble + shr eax, 3 ; Divide by 8 + mov rdx, rax ; RDX is the entry count + xor ecx, ecx +foundACPIv2_nextentry: + lodsq + push rax + add ecx, 1 + cmp ecx, edx + jne foundACPIv2_nextentry + +findAPICTable: + mov al, '3' ; Search for the APIC table + mov [0x000B809C], al + mov al, '4' + mov [0x000B809E], al + mov ebx, 'APIC' ; Signature for the Multiple APIC Description Table + xor ecx, ecx +searchingforAPIC: + pop rsi + lodsd + add ecx, 1 + cmp eax, ebx + je foundAPICTable + cmp ecx, edx + jne searchingforAPIC + jmp noACPIAPIC + +fixstack: + pop rax + add ecx, 1 + +foundAPICTable: + ; fix the stack + cmp ecx, edx + jne fixstack + + lodsd ; Length of MADT in bytes + mov ecx, eax ; Store the length in ECX + xor ebx, ebx ; EBX is the counter + lodsb ; Revision + lodsb ; Checksum + lodsd ; OEMID (First 4 bytes) + lodsw ; OEMID (Last 2 bytes) + lodsq ; OEM Table ID + lodsd ; OEM Revision + lodsd ; Creator ID + lodsd ; Creator Revision + xor eax, eax + lodsd ; Local APIC Address + mov [os_LocalAPICAddress], rax ; Save the Address of the Local APIC + lodsd ; Flags + add ebx, 44 + mov rdi, 0x0000000000005100 ; Valid CPU IDs + +readAPICstructures: + cmp ebx, ecx + jge init_smp_acpi_done +; mov al, ' ' +; call os_print_char +; call os_print_char + lodsb ; APIC Structure Type +; call os_debug_dump_al +; push rax +; mov al, ' ' +; call os_print_char +; pop rax + cmp al, 0x00 ; Processor Local APIC + je APICapic + cmp al, 0x01 ; I/O APIC + je APICioapic + cmp al, 0x02 ; Interrupt Source Override + je APICinterruptsourceoverride +; cmp al, 0x03 ; Non-maskable Interrupt Source (NMI) +; je APICnmi +; cmp al, 0x04 ; Local APIC NMI +; je APIClocalapicnmi +; cmp al, 0x05 ; Local APIC Address Override +; je APICaddressoverride + cmp al, 0x09 ; Processor Local x2APIC + je APICx2apic +; cmp al, 0x0A ; Local x2APIC NMI +; je APICx2nmi + + jmp APICignore + +APICapic: + xor eax, eax + xor edx, edx + lodsb ; Length (will be set to 8) + add ebx, eax + lodsb ; ACPI Processor ID + lodsb ; APIC ID + xchg eax, edx ; Save the APIC ID to EDX + lodsd ; Flags (Bit 0 set if enabled/usable) + bt eax, 0 ; Test to see if usable + jnc readAPICstructures ; Read the next structure if CPU not usable + inc word [cpu_detected] + xchg eax, edx ; Restore the APIC ID back to EAX + stosb + jmp readAPICstructures ; Read the next structure + +APICioapic: + xor eax, eax + lodsb ; Length (will be set to 12) + add ebx, eax + lodsb ; IO APIC ID + lodsb ; Reserved + xor eax, eax + lodsd ; IO APIC Address + push rdi + mov rdi, os_IOAPICAddress + xor ecx, ecx + mov cl, [os_IOAPICCount] + shl cx, 3 ; Quick multiply by 8 + add rdi, rcx + stosd ; Store the IO APIC Address + lodsd ; System Vector Base + stosd ; Store the IO APIC Vector Base + pop rdi + inc byte [os_IOAPICCount] + jmp readAPICstructures ; Read the next structure + +APICinterruptsourceoverride: + xor eax, eax + lodsb ; Length (will be set to 10) + add ebx, eax + lodsb ; Bus + lodsb ; Source +; call os_debug_dump_al +; mov al, ' ' +; call os_print_char + lodsd ; Global System Interrupt +; call os_debug_dump_eax + lodsw ; Flags + jmp readAPICstructures ; Read the next structure + +APICx2apic: + xor eax, eax + xor edx, edx + lodsb ; Length (will be set to 16) + lodsw ; Reserved; Must be Zero + lodsd + xchg eax, edx ; Save the x2APIC ID to EDX + lodsd ; Flags (Bit 0 set if enabled/usable) + bt eax, 0 ; Test to see if usable + jnc APICx2apicEnd ; Read the next structure if CPU not usable + xchg eax, edx ; Restore the x2APIC ID back to EAX + call os_debug_dump_eax + call os_print_newline + ; Save the ID's somewhere +APICx2apicEnd: + lodsd ; ACPI Processor UID + jmp readAPICstructures ; Read the next structure + +APICignore: + xor eax, eax + lodsb ; We have a type that we ignore, read the next byte + add ebx, eax + add rsi, rax + sub rsi, 2 ; For the two bytes just read + jmp readAPICstructures ; Read the next structure + +init_smp_acpi_done: + ret + +noACPI: +noACPIAPIC: +novalidacpi: + mov al, 'X' + mov [0x000B809A], al + jmp $ +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/init_cpu.asm b/amd64/pure64-0.5.0/src/init_cpu.asm index 2fe3e847..2190aab2 100644 --- a/amd64/pure64-0.5.0/src/init_cpu.asm +++ b/amd64/pure64-0.5.0/src/init_cpu.asm @@ -1,192 +1,192 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT CPU -; ============================================================================= - - -init_cpu: - -; Check for Prefetcher and L2 Cache support -; mov r15b, 1 ; Set MSR support to 1 -; xor eax, eax -; mov al, 1 ; Access CPUID leaf 1 -; cpuid -; shr rax, 8 ; Family now in AL (lowest 4 bits) -; and al, 0x0F ; Clear the high 4 bits -; cmp al, 0x0F -; jne init_cpu_msrok ; If Family is not 0xF then jump -; mov r15b, 0 ; If it is 0xF (Older P4/Xeon) then set MSR support to 0 -;init_cpu_msrok: - -; Disable Cache - mov rax, cr0 - btr rax, 29 ; Clear No Write Thru (Bit 29) - bts rax, 30 ; Set Cache Disable (Bit 30) - mov cr0, rax - -; Flush Cache - wbinvd - -; Diable Paging Global Extensions - mov rax, cr4 - btr rax, 7 ; Clear Paging Global Extensions (Bit 7) - mov cr4, rax - mov rax, cr3 - mov cr3, rax - -; Skip next portion if MSR support doesn't exist -; cmp r15b, 0 -; je init_cpu_skip1 - -; Disable Prefetchers (Not supported on P4 or Atom) -; mov ecx, 0x000001A0 -; rdmsr -; or eax, 0x00080200 ; Set Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) -; or edx, 0x000000A0 ; Set DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) -; wrmsr - -; Disable L2 Cache (Not supported on P4 or Atom) -; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache -; rdmsr -; btr eax, 8 ; Clear L2 Enabled (Bit 8) -; wrmsr - -;init_cpu_skip1: - -; Disable MTRRs and Configure default memory type to UC - mov ecx, 0x000002FF - rdmsr - and eax, 0xFFFFF300 ; Clear MTRR Enable (Bit 11), Fixed Range MTRR Enable (Bit 10), and Default Memory Type (Bits 7:0) to UC (0x00) - wrmsr - -; Setup variable-size address ranges -; Cache 0-64 MiB as type 6 (WB) cache -; See example in Intel Volume 3A. Example Base and Mask Calculations -; mov ecx, 0x00000200 ; MTRR_Phys_Base_MSR(0) -; mov edx, 0x00000000 ; Base is EDX:EAX, 0x0000000000000006 -; mov eax, 0x00000006 ; Type 6 (write-back cache) -; wrmsr -; mov ecx, 0x00000201 ; MTRR_Phys_Mask_MSR(0) -;; mov edx, 0x00000000 ; Mask is EDX:EAX, 0x0000000001000800 (Because bochs sucks) -;; mov eax, 0x01000800 ; Bit 11 set for Valid -; mov edx, 0x0000000F ; Mask is EDX:EAX, 0x0000000F80000800 (2 GiB) -; mov eax, 0x80000800 ; Bit 11 set for Valid -; wrmsr - -; MTRR notes: -; Base 0x0000000000000000 = 0 MiB -; Base 0x0000000080000000 = 2048 MiB, 2048 is 0x800 -; Base 0x0000000100000000 = 4096 MiB, 4096 is 0x1000 -; Mask 0x0000000F80000000 = 2048 MiB, 0xFFFFFFFFF - F80000000 = 7FFFFFFF = 2147483647 (~2 GiB) -; Mask 0x0000000FC0000000 = 1024 MiB, 0xFFFFFFFFF - FC0000000 = 3FFFFFFF = 1073741823 (~1 GiB) -; Mask 0x0000000FFC000000 = 64 MiB, 0xFFFFFFFFF - FFC000000 = 3FFFFFF = 67108863 (~64 MiB) - -; Enable MTRRs - mov ecx, 0x000002FF - rdmsr - bts eax, 11 ; Set MTRR Enable (Bit 11), Only enables Variable Range MTRR's - wrmsr - -; Flush Cache - wbinvd - -; Skip next portion if MSR support doesn't exist -; cmp r15b, 0 -; je init_cpu_skip2 - -; Enable L2 Cache (Not supported on P4 or Atom) -; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache -; rdmsr -; bts eax, 8 ; Set L2 Enabled (Bit 8) -; wrmsr - -; Enable Prefetchers (Not supported on P4 or Atom) -; mov ecx, 0x000001A0 -; rdmsr -; and eax, 0xFFF7FDFF ; Clear Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) -; and edx, 0xFFFFFFAF ; Clear DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) -; wrmsr - -;init_cpu_skip2: - -; Enable Cache - mov rax, cr0 - btr rax, 29 ; Clear No Write Thru (Bit 29) - btr rax, 30 ; Clear CD (Bit 30) - mov cr0, rax - -; Enable Paging Global Extensions -; mov rax, cr4 -; bts rax, 7 ; Set Paging Global Extensions (Bit 7) -; mov cr4, rax - -; Enable Floating Point - mov rax, cr0 - bts rax, 1 ; Set Monitor co-processor (Bit 1) - btr rax, 2 ; Clear Emulation (Bit 2) - mov cr0, rax - -; Enable SSE - mov rax, cr4 - bts rax, 9 ; Set Operating System Support for FXSAVE and FXSTOR instructions (Bit 9) - bts rax, 10 ; Set Operating System Support for Unmasked SIMD Floating-Point Exceptions (Bit 10) - mov cr4, rax - -; Enable Math Co-processor - finit - -; Enable and Configure Local APIC - mov rsi, [os_LocalAPICAddress] - cmp rsi, 0x00000000 - je noMP ; Skip MP init if we didn't get a valid LAPIC address - - xor eax, eax ; Clear Task Priority (bits 7:4) and Priority Sub-Class (bits 3:0) - mov dword [rsi+0x80], eax ; Task Priority Register (TPR) - - mov eax, 0x01000000 ; Set bits 31-24 for all cores to be in Group 1 - mov dword [rsi+0xD0], eax ; Logical Destination Register - - xor eax, eax - sub eax, 1 ; Set EAX to 0xFFFFFFFF; Bits 31-28 set for Flat Mode - mov dword [rsi+0xE0], eax ; Destination Format Register - - mov eax, dword [rsi+0xF0] ; Spurious Interrupt Vector Register - mov al, 0xF8 - bts eax, 8 ; Enable APIC (Set bit 8) - mov dword [rsi+0xF0], eax - - mov eax, dword [rsi+0x320] ; LVT Timer Register - bts eax, 16 ; Set bit 16 for mask interrupts - mov dword [rsi+0x320], eax - -; mov eax, dword [rsi+0x350] ; LVT LINT0 Register -; mov al, 0 ;Set interrupt vector (bits 7:0) -; bts eax, 8 ;Delivery Mode (111b==ExtlNT] (bits 10:8) -; bts eax, 9 -; bts eax, 10 -; bts eax, 15 ;bit15:Set trigger mode to Level (0== Edge, 1== Level) -; btr eax, 16 ;bit16:unmask interrupts (0==Unmasked, 1== Masked) -; mov dword [rsi+0x350], eax - -; mov eax, dword [rsi+0x360] ; LVT LINT1 Register -; mov al, 0 ;Set interrupt vector (bits 7:0) -; bts eax, 8 ;Delivery Mode (111b==ExtlNT] (bits 10:8) -; bts eax, 9 -; bts eax, 10 -; bts eax, 15 ;bit15:Set trigger mode to Edge (0== Edge, 1== Level) -; btr eax, 16 ;bit16:unmask interrupts (0==Unmasked, 1== Masked) -; mov dword [rsi+0x360], eax - -; mov eax, dword [rsi+0x370] ; LVT Error Register -; mov al, 0 ;Set interrupt vector (bits 7:0) -; bts eax, 16 ;bit16:Mask interrupts (0==Unmasked, 1== Masked) -; mov dword [rsi+0x370], eax - - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT CPU +; ============================================================================= + + +init_cpu: + +; Check for Prefetcher and L2 Cache support +; mov r15b, 1 ; Set MSR support to 1 +; xor eax, eax +; mov al, 1 ; Access CPUID leaf 1 +; cpuid +; shr rax, 8 ; Family now in AL (lowest 4 bits) +; and al, 0x0F ; Clear the high 4 bits +; cmp al, 0x0F +; jne init_cpu_msrok ; If Family is not 0xF then jump +; mov r15b, 0 ; If it is 0xF (Older P4/Xeon) then set MSR support to 0 +;init_cpu_msrok: + +; Disable Cache + mov rax, cr0 + btr rax, 29 ; Clear No Write Thru (Bit 29) + bts rax, 30 ; Set Cache Disable (Bit 30) + mov cr0, rax + +; Flush Cache + wbinvd + +; Diable Paging Global Extensions + mov rax, cr4 + btr rax, 7 ; Clear Paging Global Extensions (Bit 7) + mov cr4, rax + mov rax, cr3 + mov cr3, rax + +; Skip next portion if MSR support doesn't exist +; cmp r15b, 0 +; je init_cpu_skip1 + +; Disable Prefetchers (Not supported on P4 or Atom) +; mov ecx, 0x000001A0 +; rdmsr +; or eax, 0x00080200 ; Set Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) +; or edx, 0x000000A0 ; Set DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) +; wrmsr + +; Disable L2 Cache (Not supported on P4 or Atom) +; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache +; rdmsr +; btr eax, 8 ; Clear L2 Enabled (Bit 8) +; wrmsr + +;init_cpu_skip1: + +; Disable MTRRs and Configure default memory type to UC + mov ecx, 0x000002FF + rdmsr + and eax, 0xFFFFF300 ; Clear MTRR Enable (Bit 11), Fixed Range MTRR Enable (Bit 10), and Default Memory Type (Bits 7:0) to UC (0x00) + wrmsr + +; Setup variable-size address ranges +; Cache 0-64 MiB as type 6 (WB) cache +; See example in Intel Volume 3A. Example Base and Mask Calculations +; mov ecx, 0x00000200 ; MTRR_Phys_Base_MSR(0) +; mov edx, 0x00000000 ; Base is EDX:EAX, 0x0000000000000006 +; mov eax, 0x00000006 ; Type 6 (write-back cache) +; wrmsr +; mov ecx, 0x00000201 ; MTRR_Phys_Mask_MSR(0) +;; mov edx, 0x00000000 ; Mask is EDX:EAX, 0x0000000001000800 (Because bochs sucks) +;; mov eax, 0x01000800 ; Bit 11 set for Valid +; mov edx, 0x0000000F ; Mask is EDX:EAX, 0x0000000F80000800 (2 GiB) +; mov eax, 0x80000800 ; Bit 11 set for Valid +; wrmsr + +; MTRR notes: +; Base 0x0000000000000000 = 0 MiB +; Base 0x0000000080000000 = 2048 MiB, 2048 is 0x800 +; Base 0x0000000100000000 = 4096 MiB, 4096 is 0x1000 +; Mask 0x0000000F80000000 = 2048 MiB, 0xFFFFFFFFF - F80000000 = 7FFFFFFF = 2147483647 (~2 GiB) +; Mask 0x0000000FC0000000 = 1024 MiB, 0xFFFFFFFFF - FC0000000 = 3FFFFFFF = 1073741823 (~1 GiB) +; Mask 0x0000000FFC000000 = 64 MiB, 0xFFFFFFFFF - FFC000000 = 3FFFFFF = 67108863 (~64 MiB) + +; Enable MTRRs + mov ecx, 0x000002FF + rdmsr + bts eax, 11 ; Set MTRR Enable (Bit 11), Only enables Variable Range MTRR's + wrmsr + +; Flush Cache + wbinvd + +; Skip next portion if MSR support doesn't exist +; cmp r15b, 0 +; je init_cpu_skip2 + +; Enable L2 Cache (Not supported on P4 or Atom) +; mov ecx, 0x0000011E ; Control register 3: used to configure the L2 Cache +; rdmsr +; bts eax, 8 ; Set L2 Enabled (Bit 8) +; wrmsr + +; Enable Prefetchers (Not supported on P4 or Atom) +; mov ecx, 0x000001A0 +; rdmsr +; and eax, 0xFFF7FDFF ; Clear Hardware Prefetcher Disable (Bit 9) and Adjacent Cache Line Prefetch Disable (Bit 19) +; and edx, 0xFFFFFFAF ; Clear DCU Prefetcher Disable (Bit 37) and IP Prefetcher Disable (Bit 39) +; wrmsr + +;init_cpu_skip2: + +; Enable Cache + mov rax, cr0 + btr rax, 29 ; Clear No Write Thru (Bit 29) + btr rax, 30 ; Clear CD (Bit 30) + mov cr0, rax + +; Enable Paging Global Extensions +; mov rax, cr4 +; bts rax, 7 ; Set Paging Global Extensions (Bit 7) +; mov cr4, rax + +; Enable Floating Point + mov rax, cr0 + bts rax, 1 ; Set Monitor co-processor (Bit 1) + btr rax, 2 ; Clear Emulation (Bit 2) + mov cr0, rax + +; Enable SSE + mov rax, cr4 + bts rax, 9 ; Set Operating System Support for FXSAVE and FXSTOR instructions (Bit 9) + bts rax, 10 ; Set Operating System Support for Unmasked SIMD Floating-Point Exceptions (Bit 10) + mov cr4, rax + +; Enable Math Co-processor + finit + +; Enable and Configure Local APIC + mov rsi, [os_LocalAPICAddress] + cmp rsi, 0x00000000 + je noMP ; Skip MP init if we didn't get a valid LAPIC address + + xor eax, eax ; Clear Task Priority (bits 7:4) and Priority Sub-Class (bits 3:0) + mov dword [rsi+0x80], eax ; Task Priority Register (TPR) + + mov eax, 0x01000000 ; Set bits 31-24 for all cores to be in Group 1 + mov dword [rsi+0xD0], eax ; Logical Destination Register + + xor eax, eax + sub eax, 1 ; Set EAX to 0xFFFFFFFF; Bits 31-28 set for Flat Mode + mov dword [rsi+0xE0], eax ; Destination Format Register + + mov eax, dword [rsi+0xF0] ; Spurious Interrupt Vector Register + mov al, 0xF8 + bts eax, 8 ; Enable APIC (Set bit 8) + mov dword [rsi+0xF0], eax + + mov eax, dword [rsi+0x320] ; LVT Timer Register + bts eax, 16 ; Set bit 16 for mask interrupts + mov dword [rsi+0x320], eax + +; mov eax, dword [rsi+0x350] ; LVT LINT0 Register +; mov al, 0 ;Set interrupt vector (bits 7:0) +; bts eax, 8 ;Delivery Mode (111b==ExtlNT] (bits 10:8) +; bts eax, 9 +; bts eax, 10 +; bts eax, 15 ;bit15:Set trigger mode to Level (0== Edge, 1== Level) +; btr eax, 16 ;bit16:unmask interrupts (0==Unmasked, 1== Masked) +; mov dword [rsi+0x350], eax + +; mov eax, dword [rsi+0x360] ; LVT LINT1 Register +; mov al, 0 ;Set interrupt vector (bits 7:0) +; bts eax, 8 ;Delivery Mode (111b==ExtlNT] (bits 10:8) +; bts eax, 9 +; bts eax, 10 +; bts eax, 15 ;bit15:Set trigger mode to Edge (0== Edge, 1== Level) +; btr eax, 16 ;bit16:unmask interrupts (0==Unmasked, 1== Masked) +; mov dword [rsi+0x360], eax + +; mov eax, dword [rsi+0x370] ; LVT Error Register +; mov al, 0 ;Set interrupt vector (bits 7:0) +; bts eax, 16 ;bit16:Mask interrupts (0==Unmasked, 1== Masked) +; mov dword [rsi+0x370], eax + + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/init_hdd.asm b/amd64/pure64-0.5.0/src/init_hdd.asm index 26214967..6317caa6 100644 --- a/amd64/pure64-0.5.0/src/init_hdd.asm +++ b/amd64/pure64-0.5.0/src/init_hdd.asm @@ -1,271 +1,271 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT HDD -; ============================================================================= - -; The code below only utilizes the Master drive on the Primary ATA Bus. -; Port IO is hard-coded to Primary : 0x01F0 - 0x01F7, 0x03F6 -; Secondary Bus would be 0x0170 - 0x0177, 0x0376 - -hdd_setup: -; Probe for PATA hard drive - mov dx, 0x01F0 - mov [ata_base], dx - add dx, 7 ; Primary ATA Regular Status Byte - in al, dx - cmp al, 0xFF ; Check for "float" value - je hdd_setup_try_sata ; No drive detected - test al, 0xA9 ; Is ERR, DRQ, DF, or BSY set? - jne hdd_setup_err_read - jmp hdd_setup_load_sector - -; Probe for a hard drive controller -hdd_setup_try_sata: - xor ebx, ebx - xor ecx, ecx -findcontroller: - cmp bx, 256 ; Search up to 256 buses - je hdd_setup_err_drive ; No drive detected - cmp cl, 32 ; Up to 32 devices per bus - jne findcontroller_1 - add bx, 1 - xor ecx, ecx -findcontroller_1: - mov dl, 2 ; We want the Class/Device code - call os_pci_read_reg - add cl, 1 - shr rax, 16 - cmp ax, 0x0106 ; Mass storage device, SATA - jne findcontroller - sub cl, 1 - mov dl, 9 - call os_pci_read_reg ; BAR5 (AHCI Base Address Register) - mov [sata_base], eax - call os_debug_dump_eax - call os_print_newline - mov rsi, rax - lodsd - call os_debug_dump_eax - call os_print_newline - bt rax, 18 - jnc legacy_mode_ok - push rsi - mov rsi, no_sata_legacy - call os_print_string - pop rsi - jmp $ -legacy_mode_ok: - mov rdi, rsi - lodsd - call os_debug_dump_eax - call os_print_newline - xor eax, eax - stosd - -;jmp $ - - mov dl, 4 ; BAR0 - call os_pci_read_reg - and ax, 0xFFFC ; AX now holds the Base IO Address (clear the low 2 bits) -; call os_debug_dump_eax - mov dx, ax - mov [ata_base], dx - in al, dx - cmp al, 0xFF ; Check for "float" value - je hdd_setup_err_drive ; No drive detected - test al, 0xA9 ; Is ERR, DRQ, DF, or BSY set? - jne hdd_setup_err_read - -; Read first sector of HDD into memory -hdd_setup_load_sector: - xor rax, rax ; We want sector 0 - mov rdi, hdbuffer - push rdi - mov rcx, 1 ; Read one sector - call readsectors - pop rdi - cmp rcx, 0 - je hdd_setup_err_read - - cmp byte [cfg_mbr], 0x01 ; Did we boot from a MBR drive - jne hdd_setup_no_mbr ; If not then we already have the correct sector - -; Grab the partition offset value for the first partition - mov eax, [rdi+0x01C6] - mov [fat16_PartitionOffset], eax - -; Read the first sector of the first partition - mov rdi, hdbuffer - push rdi - mov rcx, 1 - call readsectors - pop rdi - cmp rcx, 0 - je hdd_setup_err_read - -hdd_setup_no_mbr: -; Get the values we need to start using fat16 - mov ax, [rdi+0x0b] - mov [fat16_BytesPerSector], ax ; This will probably be 512 - mov al, [rdi+0x0d] - mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) - mov ax, [rdi+0x0e] - mov [fat16_ReservedSectors], ax - mov [fat16_FatStart], eax - mov al, [rdi+0x10] - mov [fat16_Fats], al ; This will probably be 2 - mov ax, [rdi+0x11] - mov [fat16_RootDirEnts], ax - mov ax, [rdi+0x16] - mov [fat16_SectorsPerFat], ax - -; Find out how many sectors are on the disk - xor eax, eax - mov ax, [rdi+0x13] - cmp ax, 0x0000 - jne lessthan65536sectors - mov eax, [rdi+0x20] -lessthan65536sectors: - mov [fat16_TotalSectors], eax - -; Calculate the size in MiB - xor rax, rax - mov eax, [fat16_TotalSectors] - mov [hd1_maxlba], rax - shr rax, 11 ; rax = rax * 512 / 1048576 - mov [hd1_size], eax ; in mebibytes (MiB) - -; Create a string of the harddrive size - mov rdi, hdtempstring - call os_int_to_string - - xor rax, rax - xor rbx, rbx - mov ax, [fat16_SectorsPerFat] - shl ax, 1 ; quick multiply by two - add ax, [fat16_ReservedSectors] - mov [fat16_RootStart], eax - mov bx, [fat16_RootDirEnts] - shr ebx, 4 ; bx = (bx * 32) / 512 - add ebx, eax ; BX now holds the datastart sector number - mov [fat16_DataStart], ebx - -ret - -hdd_setup_err_drive: - mov rsi, hdd_setup_no_drive - call os_print_string - jmp exception_gate_halt - -hdd_setup_err_read: - mov rsi, hdd_setup_read_error - call os_print_string - jmp exception_gate_halt - -; ----------------------------------------------------------------------------- -; readsectors -- Read sectors on the hard drive -; IN: RAX = starting sector to read -; RCX = number of sectors to read (1 - 256) -; RDI = memory location to store sectors -; OUT: RAX = RAX + number of sectors that were read -; RCX = number of sectors that were read (0 on error) -; RDI = RDI + (number of sectors * 512) -; All other registers preserved -readsectors: - push rdx - push rcx - push rbx - push rax - - push rcx ; Save RCX for use in the read loop - mov rbx, rcx ; Store number of sectors to read - cmp rcx, 0 - je readsectors_fail ; Try to read nothing? Fail! - cmp rcx, 256 - jg readsectors_fail ; Over 256? Fail! - jne readsectors_skip ; Not 256? No need to modify CL - xor rcx, rcx ; 0 translates to 256 -readsectors_skip: - - push rax ; Save RAX since we are about to overwrite it - mov dx, [ata_base] - ;mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 - add dx, 2 - mov al, cl ; Read CL sectors - out dx, al - pop rax ; Restore RAX which is our sector number - inc dx ; 0x01F3 - LBA Low Port 7:0 - out dx, al - inc dx ; 0x01F4 - LBA Mid Port 15:8 - shr rax, 8 - out dx, al - inc dx ; 0x01F5 - LBA High Port 23:16 - shr rax, 8 - out dx, al - inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) - shr rax, 8 - and al, 00001111b ; Clear bits 4-7 just to be safe - or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) - out dx, al - inc dx ; 0x01F7 - Command Port - mov al, 0x20 ; Read sector(s). 0x24 if LBA48 - out dx, al - - mov rcx, 4 -readsectors_wait: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_retry - test al, 0x08 ; DRQ set? - jne readsectors_dataready -readsectors_retry: - dec rcx - jg readsectors_wait -readsectors_nextsector: - in al, dx ; Read status from 0x01F7 - test al, 0x80 ; BSY flag set? - jne readsectors_nextsector - test al, 0x21 ; ERR or DF set? - jne readsectors_fail - -readsectors_dataready: - sub dx, 7 ; Data port (0x1F0) - mov rcx, 256 ; Read - rep insw ; Copy a 512 byte sector to RDI - add dx, 7 ; Set DX back to status register (0x01F7) - in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ - in al, dx - in al, dx - in al, dx - - dec rbx ; RBX is the "sectors to read" counter - cmp rbx, 0 - jne readsectors_nextsector - - test al, 0x21 ; ERR or DF set? - jne readsectors_fail - - pop rcx - pop rax - pop rbx - add rax, rcx - pop rcx - pop rdx -ret - -readsectors_fail: - pop rcx - pop rax - pop rbx - pop rcx - pop rdx - xor rcx, rcx ; Set RCX to 0 since nothing was read -ret -; ----------------------------------------------------------------------------- - -no_sata_legacy: db "SATA Controller only suppports native mode!", 13, 0 - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT HDD +; ============================================================================= + +; The code below only utilizes the Master drive on the Primary ATA Bus. +; Port IO is hard-coded to Primary : 0x01F0 - 0x01F7, 0x03F6 +; Secondary Bus would be 0x0170 - 0x0177, 0x0376 + +hdd_setup: +; Probe for PATA hard drive + mov dx, 0x01F0 + mov [ata_base], dx + add dx, 7 ; Primary ATA Regular Status Byte + in al, dx + cmp al, 0xFF ; Check for "float" value + je hdd_setup_try_sata ; No drive detected + test al, 0xA9 ; Is ERR, DRQ, DF, or BSY set? + jne hdd_setup_err_read + jmp hdd_setup_load_sector + +; Probe for a hard drive controller +hdd_setup_try_sata: + xor ebx, ebx + xor ecx, ecx +findcontroller: + cmp bx, 256 ; Search up to 256 buses + je hdd_setup_err_drive ; No drive detected + cmp cl, 32 ; Up to 32 devices per bus + jne findcontroller_1 + add bx, 1 + xor ecx, ecx +findcontroller_1: + mov dl, 2 ; We want the Class/Device code + call os_pci_read_reg + add cl, 1 + shr rax, 16 + cmp ax, 0x0106 ; Mass storage device, SATA + jne findcontroller + sub cl, 1 + mov dl, 9 + call os_pci_read_reg ; BAR5 (AHCI Base Address Register) + mov [sata_base], eax + call os_debug_dump_eax + call os_print_newline + mov rsi, rax + lodsd + call os_debug_dump_eax + call os_print_newline + bt rax, 18 + jnc legacy_mode_ok + push rsi + mov rsi, no_sata_legacy + call os_print_string + pop rsi + jmp $ +legacy_mode_ok: + mov rdi, rsi + lodsd + call os_debug_dump_eax + call os_print_newline + xor eax, eax + stosd + +;jmp $ + + mov dl, 4 ; BAR0 + call os_pci_read_reg + and ax, 0xFFFC ; AX now holds the Base IO Address (clear the low 2 bits) +; call os_debug_dump_eax + mov dx, ax + mov [ata_base], dx + in al, dx + cmp al, 0xFF ; Check for "float" value + je hdd_setup_err_drive ; No drive detected + test al, 0xA9 ; Is ERR, DRQ, DF, or BSY set? + jne hdd_setup_err_read + +; Read first sector of HDD into memory +hdd_setup_load_sector: + xor rax, rax ; We want sector 0 + mov rdi, hdbuffer + push rdi + mov rcx, 1 ; Read one sector + call readsectors + pop rdi + cmp rcx, 0 + je hdd_setup_err_read + + cmp byte [cfg_mbr], 0x01 ; Did we boot from a MBR drive + jne hdd_setup_no_mbr ; If not then we already have the correct sector + +; Grab the partition offset value for the first partition + mov eax, [rdi+0x01C6] + mov [fat16_PartitionOffset], eax + +; Read the first sector of the first partition + mov rdi, hdbuffer + push rdi + mov rcx, 1 + call readsectors + pop rdi + cmp rcx, 0 + je hdd_setup_err_read + +hdd_setup_no_mbr: +; Get the values we need to start using fat16 + mov ax, [rdi+0x0b] + mov [fat16_BytesPerSector], ax ; This will probably be 512 + mov al, [rdi+0x0d] + mov [fat16_SectorsPerCluster], al ; This will be 128 or less (Max cluster size is 64KiB) + mov ax, [rdi+0x0e] + mov [fat16_ReservedSectors], ax + mov [fat16_FatStart], eax + mov al, [rdi+0x10] + mov [fat16_Fats], al ; This will probably be 2 + mov ax, [rdi+0x11] + mov [fat16_RootDirEnts], ax + mov ax, [rdi+0x16] + mov [fat16_SectorsPerFat], ax + +; Find out how many sectors are on the disk + xor eax, eax + mov ax, [rdi+0x13] + cmp ax, 0x0000 + jne lessthan65536sectors + mov eax, [rdi+0x20] +lessthan65536sectors: + mov [fat16_TotalSectors], eax + +; Calculate the size in MiB + xor rax, rax + mov eax, [fat16_TotalSectors] + mov [hd1_maxlba], rax + shr rax, 11 ; rax = rax * 512 / 1048576 + mov [hd1_size], eax ; in mebibytes (MiB) + +; Create a string of the harddrive size + mov rdi, hdtempstring + call os_int_to_string + + xor rax, rax + xor rbx, rbx + mov ax, [fat16_SectorsPerFat] + shl ax, 1 ; quick multiply by two + add ax, [fat16_ReservedSectors] + mov [fat16_RootStart], eax + mov bx, [fat16_RootDirEnts] + shr ebx, 4 ; bx = (bx * 32) / 512 + add ebx, eax ; BX now holds the datastart sector number + mov [fat16_DataStart], ebx + +ret + +hdd_setup_err_drive: + mov rsi, hdd_setup_no_drive + call os_print_string + jmp exception_gate_halt + +hdd_setup_err_read: + mov rsi, hdd_setup_read_error + call os_print_string + jmp exception_gate_halt + +; ----------------------------------------------------------------------------- +; readsectors -- Read sectors on the hard drive +; IN: RAX = starting sector to read +; RCX = number of sectors to read (1 - 256) +; RDI = memory location to store sectors +; OUT: RAX = RAX + number of sectors that were read +; RCX = number of sectors that were read (0 on error) +; RDI = RDI + (number of sectors * 512) +; All other registers preserved +readsectors: + push rdx + push rcx + push rbx + push rax + + push rcx ; Save RCX for use in the read loop + mov rbx, rcx ; Store number of sectors to read + cmp rcx, 0 + je readsectors_fail ; Try to read nothing? Fail! + cmp rcx, 256 + jg readsectors_fail ; Over 256? Fail! + jne readsectors_skip ; Not 256? No need to modify CL + xor rcx, rcx ; 0 translates to 256 +readsectors_skip: + + push rax ; Save RAX since we are about to overwrite it + mov dx, [ata_base] + ;mov dx, 0x01F2 ; 0x01F2 - Sector count Port 7:0 + add dx, 2 + mov al, cl ; Read CL sectors + out dx, al + pop rax ; Restore RAX which is our sector number + inc dx ; 0x01F3 - LBA Low Port 7:0 + out dx, al + inc dx ; 0x01F4 - LBA Mid Port 15:8 + shr rax, 8 + out dx, al + inc dx ; 0x01F5 - LBA High Port 23:16 + shr rax, 8 + out dx, al + inc dx ; 0x01F6 - Device Port. Bit 6 set for LBA mode, Bit 4 for device (0 = master, 1 = slave), Bits 3-0 for LBA "Extra High" (27:24) + shr rax, 8 + and al, 00001111b ; Clear bits 4-7 just to be safe + or al, 01000000b ; Turn bit 6 on since we want to use LBA addressing, leave device at 0 (master) + out dx, al + inc dx ; 0x01F7 - Command Port + mov al, 0x20 ; Read sector(s). 0x24 if LBA48 + out dx, al + + mov rcx, 4 +readsectors_wait: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_retry + test al, 0x08 ; DRQ set? + jne readsectors_dataready +readsectors_retry: + dec rcx + jg readsectors_wait +readsectors_nextsector: + in al, dx ; Read status from 0x01F7 + test al, 0x80 ; BSY flag set? + jne readsectors_nextsector + test al, 0x21 ; ERR or DF set? + jne readsectors_fail + +readsectors_dataready: + sub dx, 7 ; Data port (0x1F0) + mov rcx, 256 ; Read + rep insw ; Copy a 512 byte sector to RDI + add dx, 7 ; Set DX back to status register (0x01F7) + in al, dx ; Delay ~400ns to allow drive to set new values of BSY and DRQ + in al, dx + in al, dx + in al, dx + + dec rbx ; RBX is the "sectors to read" counter + cmp rbx, 0 + jne readsectors_nextsector + + test al, 0x21 ; ERR or DF set? + jne readsectors_fail + + pop rcx + pop rax + pop rbx + add rax, rcx + pop rcx + pop rdx +ret + +readsectors_fail: + pop rcx + pop rax + pop rbx + pop rcx + pop rdx + xor rcx, rcx ; Set RCX to 0 since nothing was read +ret +; ----------------------------------------------------------------------------- + +no_sata_legacy: db "SATA Controller only suppports native mode!", 13, 0 + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/init_ioapic.asm b/amd64/pure64-0.5.0/src/init_ioapic.asm index ce03e77d..20484610 100644 --- a/amd64/pure64-0.5.0/src/init_ioapic.asm +++ b/amd64/pure64-0.5.0/src/init_ioapic.asm @@ -1,154 +1,154 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT IO-APIC -; ============================================================================= - - -init_ioapic: - mov al, 0x70 ; IMCR access - out 0x22, al - mov al, 0x01 ; set bit 1 for SMP mode - out 0x23, al - - xor eax, eax - mov rcx, 1 ; Register 1 - IOAPIC VERSION REGISTER - call ioapic_reg_read - shr eax, 16 ; Extract bytes 16-23 (Maximum Redirection Entry) - and eax, 0xFF ; Clear bits 16-31 - add eax, 1 - mov rcx, rax - xor rax, rax - mov eax, dword [rsi+0x20] ; Grab the BSP APIC ID; stored in bits 31:24 - shr rax, 24 ; AL now holds the BSP CPU's APIC ID - shl rax, 56 - bts rax, 16 ; Interrupt Mask Enabled -initentry: ; Initialize all entries 1:1 - dec rcx - call ioapic_entry_write - cmp rcx, 0 - jne initentry - - ; Enable the Keyboard - mov rcx, 1 ; IRQ value - mov rax, 0x21 ; Interrupt value - call ioapic_entry_write - - ; Enable the RTC - mov rcx, 8 ; IRQ value - mov rax, 0x28 ; Interrupt value - call ioapic_entry_write - - ; Set the periodic flag in the RTC - mov al, 0x0B ; Status Register B - out 0x70, al ; Select the address - in al, 0x71 ; Read the current settings - push rax - mov al, 0x0B ; Status Register B - out 0x70, al ; Select the address - pop rax - bts ax, 6 ; Set Periodic(6) - out 0x71, al ; Write the new settings - - sti ; Enable interrupts - - ; Acknowledge the RTC - mov al, 0x0C ; Status Register C - out 0x70, al ; Select the address - in al, 0x71 ; Read the current settings - - ret - - -; ----------------------------------------------------------------------------- -; ioapic_reg_write -- Write to an I/O APIC register -; IN: EAX = Value to write -; ECX = Index of register -; OUT: Nothing. All registers preserved -ioapic_reg_write: - push rsi - mov rsi, [os_IOAPICAddress] - mov dword [rsi], ecx ; Write index to register selector - mov dword [rsi + 0x10], eax ; Write data to window register - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; ioapic_reg_read -- Read from an I/O APIC register -; IN: ECX = Index of register -; OUT: EAX = Value of register -; All other registers preserved -ioapic_reg_read: - push rsi - mov rsi, [os_IOAPICAddress] - mov dword [rsi], ecx ; Write index to register selector - mov eax, dword [rsi + 0x10] ; Read data from window register - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; ioapic_entry_write -- Write to an I/O APIC entry in the redirection table -; IN: RAX = Data to write to entry -; ECX = Index of the entry -; OUT: Nothing. All registers preserved -ioapic_entry_write: - push rax - push rcx - - ; Calculate index for lower DWORD - shl rcx, 1 ; Quick multiply by 2 - add rcx, 0x10 ; IO Redirection tables start at 0x10 - - ; Write lower DWORD - call ioapic_reg_write - - ; Write higher DWORD - shr rax, 32 - add rcx, 1 - call ioapic_reg_write - - pop rcx - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; ioapic_entry_read -- Read an I/O APIC entry from the redirection table -; IN: ECX = Index of the entry -; OUT: RAX = Data that was read -; All other registers preserved -ioapic_entry_read: - push rbx - push rcx - - ; Calculate index for lower DWORD - shl rcx, 1 ; Quick multiply by 2 - add rcx, 0x10 ; IO Redirection tables start at 0x10 - - ; Read lower DWORD - call ioapic_reg_read - mov rbx, rax - - ; Read higher DWORD - add rcx, 1 - call ioapic_reg_read - - ; Combine - shr rax, 32 - or rbx, rax - xchg rbx, rax - - pop rcx - pop rbx - ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT IO-APIC +; ============================================================================= + + +init_ioapic: + mov al, 0x70 ; IMCR access + out 0x22, al + mov al, 0x01 ; set bit 1 for SMP mode + out 0x23, al + + xor eax, eax + mov rcx, 1 ; Register 1 - IOAPIC VERSION REGISTER + call ioapic_reg_read + shr eax, 16 ; Extract bytes 16-23 (Maximum Redirection Entry) + and eax, 0xFF ; Clear bits 16-31 + add eax, 1 + mov rcx, rax + xor rax, rax + mov eax, dword [rsi+0x20] ; Grab the BSP APIC ID; stored in bits 31:24 + shr rax, 24 ; AL now holds the BSP CPU's APIC ID + shl rax, 56 + bts rax, 16 ; Interrupt Mask Enabled +initentry: ; Initialize all entries 1:1 + dec rcx + call ioapic_entry_write + cmp rcx, 0 + jne initentry + + ; Enable the Keyboard + mov rcx, 1 ; IRQ value + mov rax, 0x21 ; Interrupt value + call ioapic_entry_write + + ; Enable the RTC + mov rcx, 8 ; IRQ value + mov rax, 0x28 ; Interrupt value + call ioapic_entry_write + + ; Set the periodic flag in the RTC + mov al, 0x0B ; Status Register B + out 0x70, al ; Select the address + in al, 0x71 ; Read the current settings + push rax + mov al, 0x0B ; Status Register B + out 0x70, al ; Select the address + pop rax + bts ax, 6 ; Set Periodic(6) + out 0x71, al ; Write the new settings + + sti ; Enable interrupts + + ; Acknowledge the RTC + mov al, 0x0C ; Status Register C + out 0x70, al ; Select the address + in al, 0x71 ; Read the current settings + + ret + + +; ----------------------------------------------------------------------------- +; ioapic_reg_write -- Write to an I/O APIC register +; IN: EAX = Value to write +; ECX = Index of register +; OUT: Nothing. All registers preserved +ioapic_reg_write: + push rsi + mov rsi, [os_IOAPICAddress] + mov dword [rsi], ecx ; Write index to register selector + mov dword [rsi + 0x10], eax ; Write data to window register + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; ioapic_reg_read -- Read from an I/O APIC register +; IN: ECX = Index of register +; OUT: EAX = Value of register +; All other registers preserved +ioapic_reg_read: + push rsi + mov rsi, [os_IOAPICAddress] + mov dword [rsi], ecx ; Write index to register selector + mov eax, dword [rsi + 0x10] ; Read data from window register + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; ioapic_entry_write -- Write to an I/O APIC entry in the redirection table +; IN: RAX = Data to write to entry +; ECX = Index of the entry +; OUT: Nothing. All registers preserved +ioapic_entry_write: + push rax + push rcx + + ; Calculate index for lower DWORD + shl rcx, 1 ; Quick multiply by 2 + add rcx, 0x10 ; IO Redirection tables start at 0x10 + + ; Write lower DWORD + call ioapic_reg_write + + ; Write higher DWORD + shr rax, 32 + add rcx, 1 + call ioapic_reg_write + + pop rcx + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; ioapic_entry_read -- Read an I/O APIC entry from the redirection table +; IN: ECX = Index of the entry +; OUT: RAX = Data that was read +; All other registers preserved +ioapic_entry_read: + push rbx + push rcx + + ; Calculate index for lower DWORD + shl rcx, 1 ; Quick multiply by 2 + add rcx, 0x10 ; IO Redirection tables start at 0x10 + + ; Read lower DWORD + call ioapic_reg_read + mov rbx, rax + + ; Read higher DWORD + add rcx, 1 + call ioapic_reg_read + + ; Combine + shr rax, 32 + or rbx, rax + xchg rbx, rax + + pop rcx + pop rbx + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/init_isa.asm b/amd64/pure64-0.5.0/src/init_isa.asm index c7da318c..9a1a2b0d 100644 --- a/amd64/pure64-0.5.0/src/init_isa.asm +++ b/amd64/pure64-0.5.0/src/init_isa.asm @@ -1,153 +1,153 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT ISA -; ============================================================================= - - -isa_setup: - mov edi, 0x00004000 ; Clear out memory for the E820 map - xor eax, eax - mov ecx, 2048 - rep stosd - -; Get the BIOS E820 Memory Map -; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map -; inputs: es:di -> destination buffer for 24 byte entries -; outputs: bp = entry count, trashes all registers except esi -do_e820: - mov edi, 0x00004000 ; location that memory map will be stored to - xor ebx, ebx ; ebx must be 0 to start - xor bp, bp ; keep an entry count in bp - mov edx, 0x0534D4150 ; Place "SMAP" into edx - mov eax, 0xe820 - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes - int 0x15 - jc nomemmap ; carry set on first call means "unsupported function" - mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? - cmp eax, edx ; on success, eax must have been reset to "SMAP" - jne nomemmap - test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) - je nomemmap - jmp jmpin -e820lp: - mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes again - int 0x15 - jc memmapend ; carry set means "end of list already reached" - mov edx, 0x0534D4150 ; repair potentially trashed register -jmpin: - jcxz skipent ; skip any 0 length entries - cmp cl, 20 ; got a 24 byte ACPI 3.X response? - jbe notext - test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? - je skipent -notext: - mov ecx, [es:di + 8] ; get lower dword of memory region length - test ecx, ecx ; is the qword == 0? - jne goodent - mov ecx, [es:di + 12] ; get upper dword of memory region length - jecxz skipent ; if length qword is 0, skip entry -goodent: - inc bp ; got a good entry: ++count, move to next storage spot - add di, 32 -skipent: - test ebx, ebx ; if ebx resets to 0, list is complete - jne e820lp -nomemmap: - mov byte [cfg_e820], 0 ; No memory map function -memmapend: - xor eax, eax ; Create a blank record for termination (32 bytes) - mov ecx, 8 - rep stosd - -; Enable the A20 gate -set_A20: - in al, 0x64 - test al, 0x02 - jnz set_A20 - mov al, 0xD1 - out 0x64, al -check_A20: - in al, 0x64 - test al, 0x02 - jnz check_A20 - mov al, 0xDF - out 0x60, al - -; Set up RTC -; Port 0x70 is RTC Address, and 0x71 is RTC Data -; http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt -rtc_poll: - mov al, 0x0A ; Status Register A - out 0x70, al ; Select the address - in al, 0x71 ; Read the data - test al, 0x80 ; Is there an update in process? - jne rtc_poll ; If so then keep polling - mov al, 0x0A ; Status Register A - out 0x70, al ; Select the address - mov al, 00100110b ; UIP (0), RTC@32.768KHz (010), Rate@1024Hz (0110) - out 0x71, al ; Write the data - -; VBE init - cmp byte [cfg_vesa], 1 ; Check if VESA should be enabled - jne VBEdone ; If not then skip VESA init - - mov edi, VBEModeInfoBlock ; VBE data will be stored at this address - mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm - ; CX queries the mode, it should be in the form 0x41XX as bit 14 is set for LFB and bit 8 is set for VESA mode - ; 0x4112 is 640x480x24bit 0x4129 is 640x480x32bit - ; 0x4115 is 800x600x24bit 0x412E is 800x600x32bit - ; 0x4118 is 1024x768x24bit 0x4138 is 1024x768x32bit - ; 0x411B is 1280x1024x24bit 0x413D is 1280x1024x32bit - mov cx, 0x4112 ; Put your desired mode here - mov bx, cx ; Mode is saved to BX for the set command later - int 0x10 - - cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful - jne VBEfail - cmp byte[VBEModeInfoBlock.BitsPerPixel], 24 ; Make sure this matches the number of bits for the mode! - jne VBEfail ; If set bit mode was unsucessful then bail out - - mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm - int 0x10 - cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful - jne VBEfail - - jmp VBEdone - -VBEfail: - mov byte [cfg_vesa], 0 ; Clear the VESA config as it was not sucessful - -VBEdone: - - ; Remap PIC IRQ's - mov al, 00010001b ; begin PIC 1 initialization - out 0x20, al - mov al, 00010001b ; begin PIC 2 initialization - out 0xA0, al - mov al, 0x20 ; IRQ 0-7: interrupts 20h-27h - out 0x21, al - mov al, 0x28 ; IRQ 8-15: interrupts 28h-2Fh - out 0xA1, al - mov al, 4 - out 0x21, al - mov al, 2 - out 0xA1, al - mov al, 1 - out 0x21, al - out 0xA1, al - - ; Mask all PIC interrupts - mov al, 0xFF - out 0x21, al - out 0xA1, al - -ret - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT ISA +; ============================================================================= + + +isa_setup: + mov edi, 0x00004000 ; Clear out memory for the E820 map + xor eax, eax + mov ecx, 2048 + rep stosd + +; Get the BIOS E820 Memory Map +; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map +; inputs: es:di -> destination buffer for 24 byte entries +; outputs: bp = entry count, trashes all registers except esi +do_e820: + mov edi, 0x00004000 ; location that memory map will be stored to + xor ebx, ebx ; ebx must be 0 to start + xor bp, bp ; keep an entry count in bp + mov edx, 0x0534D4150 ; Place "SMAP" into edx + mov eax, 0xe820 + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes + int 0x15 + jc nomemmap ; carry set on first call means "unsupported function" + mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? + cmp eax, edx ; on success, eax must have been reset to "SMAP" + jne nomemmap + test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) + je nomemmap + jmp jmpin +e820lp: + mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes again + int 0x15 + jc memmapend ; carry set means "end of list already reached" + mov edx, 0x0534D4150 ; repair potentially trashed register +jmpin: + jcxz skipent ; skip any 0 length entries + cmp cl, 20 ; got a 24 byte ACPI 3.X response? + jbe notext + test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? + je skipent +notext: + mov ecx, [es:di + 8] ; get lower dword of memory region length + test ecx, ecx ; is the qword == 0? + jne goodent + mov ecx, [es:di + 12] ; get upper dword of memory region length + jecxz skipent ; if length qword is 0, skip entry +goodent: + inc bp ; got a good entry: ++count, move to next storage spot + add di, 32 +skipent: + test ebx, ebx ; if ebx resets to 0, list is complete + jne e820lp +nomemmap: + mov byte [cfg_e820], 0 ; No memory map function +memmapend: + xor eax, eax ; Create a blank record for termination (32 bytes) + mov ecx, 8 + rep stosd + +; Enable the A20 gate +set_A20: + in al, 0x64 + test al, 0x02 + jnz set_A20 + mov al, 0xD1 + out 0x64, al +check_A20: + in al, 0x64 + test al, 0x02 + jnz check_A20 + mov al, 0xDF + out 0x60, al + +; Set up RTC +; Port 0x70 is RTC Address, and 0x71 is RTC Data +; http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt +rtc_poll: + mov al, 0x0A ; Status Register A + out 0x70, al ; Select the address + in al, 0x71 ; Read the data + test al, 0x80 ; Is there an update in process? + jne rtc_poll ; If so then keep polling + mov al, 0x0A ; Status Register A + out 0x70, al ; Select the address + mov al, 00100110b ; UIP (0), RTC@32.768KHz (010), Rate@1024Hz (0110) + out 0x71, al ; Write the data + +; VBE init + cmp byte [cfg_vesa], 1 ; Check if VESA should be enabled + jne VBEdone ; If not then skip VESA init + + mov edi, VBEModeInfoBlock ; VBE data will be stored at this address + mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm + ; CX queries the mode, it should be in the form 0x41XX as bit 14 is set for LFB and bit 8 is set for VESA mode + ; 0x4112 is 640x480x24bit 0x4129 is 640x480x32bit + ; 0x4115 is 800x600x24bit 0x412E is 800x600x32bit + ; 0x4118 is 1024x768x24bit 0x4138 is 1024x768x32bit + ; 0x411B is 1280x1024x24bit 0x413D is 1280x1024x32bit + mov cx, 0x4112 ; Put your desired mode here + mov bx, cx ; Mode is saved to BX for the set command later + int 0x10 + + cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful + jne VBEfail + cmp byte[VBEModeInfoBlock.BitsPerPixel], 24 ; Make sure this matches the number of bits for the mode! + jne VBEfail ; If set bit mode was unsucessful then bail out + + mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm + int 0x10 + cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and sucessful + jne VBEfail + + jmp VBEdone + +VBEfail: + mov byte [cfg_vesa], 0 ; Clear the VESA config as it was not sucessful + +VBEdone: + + ; Remap PIC IRQ's + mov al, 00010001b ; begin PIC 1 initialization + out 0x20, al + mov al, 00010001b ; begin PIC 2 initialization + out 0xA0, al + mov al, 0x20 ; IRQ 0-7: interrupts 20h-27h + out 0x21, al + mov al, 0x28 ; IRQ 8-15: interrupts 28h-2Fh + out 0xA1, al + mov al, 4 + out 0x21, al + mov al, 2 + out 0xA1, al + mov al, 1 + out 0x21, al + out 0xA1, al + + ; Mask all PIC interrupts + mov al, 0xFF + out 0x21, al + out 0xA1, al + +ret + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/init_smp.asm b/amd64/pure64-0.5.0/src/init_smp.asm index 0e1136ec..43135748 100644 --- a/amd64/pure64-0.5.0/src/init_smp.asm +++ b/amd64/pure64-0.5.0/src/init_smp.asm @@ -1,156 +1,156 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT SMP -; ============================================================================= - - -smp_setup: - mov al, '5' ; Start of MP init - mov [0x000B809C], al - mov al, '0' - mov [0x000B809E], al -; mov al, 'S' -; call serial_send_64 - -; Check if we want the AP's to be enabled.. if not then skip to end -; cmp byte [cfg_smpinit], 1 ; Check if SMP should be enabled -; jne noMP ; If not then skip SMP init - -; Step 3: Start the AP's one by one - xor eax, eax - xor edx, edx - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the BSP CPU's APIC ID - mov dl, al ; Store BSP APIC ID in DL - - mov al, '8' ; Start the AP's - mov [0x000B809E], al - - mov rsi, 0x0000000000005100 - xor eax, eax - xor ecx, ecx - mov cx, [cpu_detected] -smp_send_INIT: - cmp cx, 0 - je smp_send_INIT_done - lodsb - - cmp al, dl ; Is it the BSP? - je smp_send_INIT_skipcore - - ; Broadcast 'INIT' IPI to APIC ID in AL - mov rdi, [os_LocalAPICAddress] - shl eax, 24 - mov dword [rdi+0x310], eax ; Interrupt Command Register (ICR); bits 63-32 - mov eax, 0x00004500 - mov dword [rdi+0x300], eax ; Interrupt Command Register (ICR); bits 31-0 -smp_send_INIT_verify: - mov eax, [rdi+0x300] ; Interrupt Command Register (ICR); bits 31-0 - bt eax, 12 ; Verify that the command completed - jc smp_send_INIT_verify - -smp_send_INIT_skipcore: - dec cl - jmp smp_send_INIT - -smp_send_INIT_done: - - mov rax, [os_Counter_RTC] - add rax, 10 -wait1: - mov rbx, [os_Counter_RTC] - cmp rax, rbx - jg wait1 -; mov al, 'i' -; call serial_send_64 - - mov rsi, 0x0000000000005100 - xor ecx, ecx - mov cx, [cpu_detected] -smp_send_SIPI: - cmp cx, 0 - je smp_send_SIPI_done - lodsb - - cmp al, dl ; Is it the BSP? - je smp_send_SIPI_skipcore - - ; Broadcast 'Startup' IPI to destination using vector 0x08 to specify entry-point is at the memory-address 0x00008000 - mov rdi, [os_LocalAPICAddress] - shl eax, 24 - mov dword [rdi+0x310], eax ; Interrupt Command Register (ICR); bits 63-32 - mov eax, 0x00004608 ; Vector 0x08 - mov dword [rdi+0x300], eax ; Interrupt Command Register (ICR); bits 31-0 -smp_send_SIPI_verify: - mov eax, [rdi+0x300] ; Interrupt Command Register (ICR); bits 31-0 - bt eax, 12 ; Verify that the command completed - jc smp_send_SIPI_verify - -smp_send_SIPI_skipcore: - dec cl - jmp smp_send_SIPI - -smp_send_SIPI_done: - - mov al, 'A' - mov [0x000B809E], al -; mov al, 'S' -; call serial_send_64 - -; Let things settle (Give the AP's some time to finish) - mov rax, [os_Counter_RTC] - add rax, 20 -wait3: - mov rbx, [os_Counter_RTC] - cmp rax, rbx - jg wait3 - -; Step 4: Finish up -noMP: - lock - inc word [cpu_activated] ; BSP adds one here - - xor eax, eax - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) - mov [os_BSP], eax ; Store the BSP APIC ID - - mov al, 'C' - mov [0x000B809E], al - -; Calculate speed of CPU (At this point the RTC is firing at 1024Hz) - cpuid - xor edx, edx - xor eax, eax - mov rcx, [os_Counter_RTC] - add rcx, 10 - rdtsc - push rax -speedtest: - mov rbx, [os_Counter_RTC] - cmp rbx, rcx - jl speedtest - rdtsc - pop rdx - sub rax, rdx - xor edx, edx - mov rcx, 10240 - div rcx - mov [cpu_speed], ax - - mov al, 'E' - mov [0x000B809E], al - - cli ; Disable Interrupts - - ret - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT SMP +; ============================================================================= + + +smp_setup: + mov al, '5' ; Start of MP init + mov [0x000B809C], al + mov al, '0' + mov [0x000B809E], al +; mov al, 'S' +; call serial_send_64 + +; Check if we want the AP's to be enabled.. if not then skip to end +; cmp byte [cfg_smpinit], 1 ; Check if SMP should be enabled +; jne noMP ; If not then skip SMP init + +; Step 3: Start the AP's one by one + xor eax, eax + xor edx, edx + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the BSP CPU's APIC ID + mov dl, al ; Store BSP APIC ID in DL + + mov al, '8' ; Start the AP's + mov [0x000B809E], al + + mov rsi, 0x0000000000005100 + xor eax, eax + xor ecx, ecx + mov cx, [cpu_detected] +smp_send_INIT: + cmp cx, 0 + je smp_send_INIT_done + lodsb + + cmp al, dl ; Is it the BSP? + je smp_send_INIT_skipcore + + ; Broadcast 'INIT' IPI to APIC ID in AL + mov rdi, [os_LocalAPICAddress] + shl eax, 24 + mov dword [rdi+0x310], eax ; Interrupt Command Register (ICR); bits 63-32 + mov eax, 0x00004500 + mov dword [rdi+0x300], eax ; Interrupt Command Register (ICR); bits 31-0 +smp_send_INIT_verify: + mov eax, [rdi+0x300] ; Interrupt Command Register (ICR); bits 31-0 + bt eax, 12 ; Verify that the command completed + jc smp_send_INIT_verify + +smp_send_INIT_skipcore: + dec cl + jmp smp_send_INIT + +smp_send_INIT_done: + + mov rax, [os_Counter_RTC] + add rax, 10 +wait1: + mov rbx, [os_Counter_RTC] + cmp rax, rbx + jg wait1 +; mov al, 'i' +; call serial_send_64 + + mov rsi, 0x0000000000005100 + xor ecx, ecx + mov cx, [cpu_detected] +smp_send_SIPI: + cmp cx, 0 + je smp_send_SIPI_done + lodsb + + cmp al, dl ; Is it the BSP? + je smp_send_SIPI_skipcore + + ; Broadcast 'Startup' IPI to destination using vector 0x08 to specify entry-point is at the memory-address 0x00008000 + mov rdi, [os_LocalAPICAddress] + shl eax, 24 + mov dword [rdi+0x310], eax ; Interrupt Command Register (ICR); bits 63-32 + mov eax, 0x00004608 ; Vector 0x08 + mov dword [rdi+0x300], eax ; Interrupt Command Register (ICR); bits 31-0 +smp_send_SIPI_verify: + mov eax, [rdi+0x300] ; Interrupt Command Register (ICR); bits 31-0 + bt eax, 12 ; Verify that the command completed + jc smp_send_SIPI_verify + +smp_send_SIPI_skipcore: + dec cl + jmp smp_send_SIPI + +smp_send_SIPI_done: + + mov al, 'A' + mov [0x000B809E], al +; mov al, 'S' +; call serial_send_64 + +; Let things settle (Give the AP's some time to finish) + mov rax, [os_Counter_RTC] + add rax, 20 +wait3: + mov rbx, [os_Counter_RTC] + cmp rax, rbx + jg wait3 + +; Step 4: Finish up +noMP: + lock + inc word [cpu_activated] ; BSP adds one here + + xor eax, eax + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) + mov [os_BSP], eax ; Store the BSP APIC ID + + mov al, 'C' + mov [0x000B809E], al + +; Calculate speed of CPU (At this point the RTC is firing at 1024Hz) + cpuid + xor edx, edx + xor eax, eax + mov rcx, [os_Counter_RTC] + add rcx, 10 + rdtsc + push rax +speedtest: + mov rbx, [os_Counter_RTC] + cmp rbx, rcx + jl speedtest + rdtsc + pop rdx + sub rax, rdx + xor edx, edx + mov rcx, 10240 + div rcx + mov [cpu_speed], ax + + mov al, 'E' + mov [0x000B809E], al + + cli ; Disable Interrupts + + ret + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/init_smp_ap.asm b/amd64/pure64-0.5.0/src/init_smp_ap.asm index f8aa3199..5c29f7d7 100644 --- a/amd64/pure64-0.5.0/src/init_smp_ap.asm +++ b/amd64/pure64-0.5.0/src/init_smp_ap.asm @@ -1,178 +1,178 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; INIT SMP AP -; ============================================================================= - -USE16 - -mp_ap_setup: - nop - jmp 0x0000:clearcs_ap - -clearcs_ap: - -; Enable the A20 gate -set_A20_ap: - in al, 0x64 - test al, 0x02 - jnz set_A20_ap - mov al, 0xD1 - out 0x64, al -check_A20_ap: - in al, 0x64 - test al, 0x02 - jnz check_A20_ap - mov al, 0xDF - out 0x60, al - -; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. - lgdt [cs:GDTR32] ; load GDT register - - mov eax, cr0 ; switch to 32-bit protected mode - or al, 1 - mov cr0, eax - - jmp 8:startap32 - -align 16 - - -; ============================================================================= -; 32-bit mode -USE32 - -startap32: - mov eax, 16 ; load 4 GB data descriptor - mov ds, ax ; to all data segment registers - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor esi, esi - xor edi, edi - xor ebp, ebp - mov esp, 0x8000 ; Set a known free location for the stack - -; Load the GDT - lgdt [GDTR64] - -; Enable extended properties - mov eax, cr4 - or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4) - mov cr4, eax - -; Point cr3 at PML4 - mov eax, 0x00002008 ; Write-thru (Bit 3) - mov cr3, eax - -; Enable long mode and SYSCALL/SYSRET - mov ecx, 0xC0000080 ; EFER MSR number - rdmsr ; Read EFER - or eax, 0x00000101 ; LME (Bit 8) - wrmsr ; Write EFER - -; Enable paging to activate long mode - mov eax, cr0 - or eax, 0x80000000 ; PG (Bit 31) - mov cr0, eax - -; Make the jump directly from 16-bit real mode to 64-bit long mode - jmp SYS64_CODE_SEL:startap64 - -align 16 - - -; ============================================================================= -; 64-bit mode -USE64 - -startap64: - xor rax, rax ; aka r0 - xor rbx, rbx ; aka r3 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor rbp, rbp ; aka r5 - xor rsp, rsp ; aka r4 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - mov ds, ax ; Clear the legacy segment registers - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - - mov rax, clearcs64_ap - jmp rax - nop -clearcs64_ap: - xor rax, rax - - ; Reset the stack. Each CPU gets a 1024-byte unique stack location - mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... - add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. - lodsd ; Load a 32-bit value. We only want the high 8 bits - shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID - shl rax, 10 ; shift left 10 bits for a 1024byte stack - add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in - mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that - - lgdt [GDTR64] ; Load the GDT - lidt [IDTR64] ; load IDT register - -; Enable Local APIC on AP - mov rsi, [os_LocalAPICAddress] - add rsi, 0x00f0 ; Offset to Spurious Interrupt Register - mov rdi, rsi - lodsd - or eax, 0000000100000000b - stosd - - call init_cpu ; Setup CPU - -; Make sure exceptions are working. -; xor rax, rax -; xor rbx, rbx -; xor rcx, rcx -; xor rdx, rdx -; div rax - - lock - inc word [cpu_activated] - xor eax, eax - mov rsi, [os_LocalAPICAddress] - add rsi, 0x20 ; Add the offset for the APIC ID location - lodsd ; APIC ID is stored in bits 31:24 - shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) - mov rdi, 0x00005700 ; The location where the cpu values are stored - add rdi, rax ; RDI points to infomap CPU area + APIC ID. ex F701 would be APIC ID 1 - mov al, 1 - stosb - sti ; Activate interrupts for SMP - jmp ap_sleep - -align 16 -.apmsg db 'THE_AP_SPIN_ZONE' -align 16 - -ap_sleep: - hlt ; Suspend CPU until an interrupt is received. opcode for hlt is 0xF4 - jmp ap_sleep ; just-in-case of an NMI - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; INIT SMP AP +; ============================================================================= + +USE16 + +mp_ap_setup: + nop + jmp 0x0000:clearcs_ap + +clearcs_ap: + +; Enable the A20 gate +set_A20_ap: + in al, 0x64 + test al, 0x02 + jnz set_A20_ap + mov al, 0xD1 + out 0x64, al +check_A20_ap: + in al, 0x64 + test al, 0x02 + jnz check_A20_ap + mov al, 0xDF + out 0x60, al + +; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. + lgdt [cs:GDTR32] ; load GDT register + + mov eax, cr0 ; switch to 32-bit protected mode + or al, 1 + mov cr0, eax + + jmp 8:startap32 + +align 16 + + +; ============================================================================= +; 32-bit mode +USE32 + +startap32: + mov eax, 16 ; load 4 GB data descriptor + mov ds, ax ; to all data segment registers + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + xor eax, eax + xor ebx, ebx + xor ecx, ecx + xor edx, edx + xor esi, esi + xor edi, edi + xor ebp, ebp + mov esp, 0x8000 ; Set a known free location for the stack + +; Load the GDT + lgdt [GDTR64] + +; Enable extended properties + mov eax, cr4 + or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4) + mov cr4, eax + +; Point cr3 at PML4 + mov eax, 0x00002008 ; Write-thru (Bit 3) + mov cr3, eax + +; Enable long mode and SYSCALL/SYSRET + mov ecx, 0xC0000080 ; EFER MSR number + rdmsr ; Read EFER + or eax, 0x00000101 ; LME (Bit 8) + wrmsr ; Write EFER + +; Enable paging to activate long mode + mov eax, cr0 + or eax, 0x80000000 ; PG (Bit 31) + mov cr0, eax + +; Make the jump directly from 16-bit real mode to 64-bit long mode + jmp SYS64_CODE_SEL:startap64 + +align 16 + + +; ============================================================================= +; 64-bit mode +USE64 + +startap64: + xor rax, rax ; aka r0 + xor rbx, rbx ; aka r3 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor rbp, rbp ; aka r5 + xor rsp, rsp ; aka r4 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + mov ds, ax ; Clear the legacy segment registers + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + mov rax, clearcs64_ap + jmp rax + nop +clearcs64_ap: + xor rax, rax + + ; Reset the stack. Each CPU gets a 1024-byte unique stack location + mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... + add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. + lodsd ; Load a 32-bit value. We only want the high 8 bits + shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID + shl rax, 10 ; shift left 10 bits for a 1024byte stack + add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in + mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that + + lgdt [GDTR64] ; Load the GDT + lidt [IDTR64] ; load IDT register + +; Enable Local APIC on AP + mov rsi, [os_LocalAPICAddress] + add rsi, 0x00f0 ; Offset to Spurious Interrupt Register + mov rdi, rsi + lodsd + or eax, 0000000100000000b + stosd + + call init_cpu ; Setup CPU + +; Make sure exceptions are working. +; xor rax, rax +; xor rbx, rbx +; xor rcx, rcx +; xor rdx, rdx +; div rax + + lock + inc word [cpu_activated] + xor eax, eax + mov rsi, [os_LocalAPICAddress] + add rsi, 0x20 ; Add the offset for the APIC ID location + lodsd ; APIC ID is stored in bits 31:24 + shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255) + mov rdi, 0x00005700 ; The location where the cpu values are stored + add rdi, rax ; RDI points to infomap CPU area + APIC ID. ex F701 would be APIC ID 1 + mov al, 1 + stosb + sti ; Activate interrupts for SMP + jmp ap_sleep + +align 16 +.apmsg db 'THE_AP_SPIN_ZONE' +align 16 + +ap_sleep: + hlt ; Suspend CPU until an interrupt is received. opcode for hlt is 0xF4 + jmp ap_sleep ; just-in-case of an NMI + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/interrupt.asm b/amd64/pure64-0.5.0/src/interrupt.asm index 88b7127e..cf7162a3 100644 --- a/amd64/pure64-0.5.0/src/interrupt.asm +++ b/amd64/pure64-0.5.0/src/interrupt.asm @@ -1,238 +1,238 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Interrupts -; ============================================================================= - - -; ----------------------------------------------------------------------------- -; Default exception handler -exception_gate: - mov rsi, int_string - call os_print_string - mov rsi, exc_string - call os_print_string -exception_gate_halt: - cli ; Disable interrupts - hlt ; Halt the system - jmp exception_gate_halt -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Default interrupt handler -interrupt_gate: ; handler for all other interrupts - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Keyboard interrupt. IRQ 0x01, INT 0x21 -; This IRQ runs whenever there is input on the keyboard -align 16 -keyboard: - push rdi - push rax - - xor rax, rax - - in al, 0x60 ; Get the scancode from the keyboard - test al, 0x80 - jz keydown - jmp keyboard_done - -keydown: - mov [0x000B8088], al ; Dump the scancode to the screen - - mov rax, [os_Counter_RTC] - add rax, 10 - mov [os_Counter_RTC], rax - -keyboard_done: - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC - add rdi, 0xB0 - xor eax, eax - stosd - - pop rax - pop rdi - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Real-time clock interrupt. IRQ 0x08, INT 0x28 -align 16 -rtc: - push rdi - push rax - - add qword [os_Counter_RTC], 1 ; 64-bit counter started at bootup - - mov al, 'R' - mov [0x000B8092], al - mov rax, [os_Counter_RTC] - and al, 1 ; Clear all but lowest bit (Can only be 0 or 1) - add al, 48 - mov [0x000B8094], al - mov al, 0x0C ; Select RTC register C - out 0x70, al ; Port 0x70 is the RTC index, and 0x71 is the RTC data - in al, 0x71 ; Read the value in register C - - mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC - add rdi, 0xB0 - xor eax, eax - stosd - - pop rax - pop rdi - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; Spurious interrupt. INT 0xFF -align 16 -spurious: ; handler for spurious interrupts - mov al, 'S' - mov [0x000B8080], al - iretq -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; CPU Exception Gates -exception_gate_00: - mov al, 0x00 - jmp exception_gate_main - -exception_gate_01: - mov al, 0x01 - jmp exception_gate_main - -exception_gate_02: - mov al, 0x02 - jmp exception_gate_main - -exception_gate_03: - mov al, 0x03 - jmp exception_gate_main - -exception_gate_04: - mov al, 0x04 - jmp exception_gate_main - -exception_gate_05: - mov al, 0x05 - jmp exception_gate_main - -exception_gate_06: - mov al, 0x06 - jmp exception_gate_main - -exception_gate_07: - mov al, 0x07 - jmp exception_gate_main - -exception_gate_08: - mov al, 0x08 - jmp exception_gate_main - -exception_gate_09: - mov al, 0x09 - jmp exception_gate_main - -exception_gate_10: - mov al, 0x0A - jmp exception_gate_main - -exception_gate_11: - mov al, 0x0B - jmp exception_gate_main - -exception_gate_12: - mov al, 0x0C - jmp exception_gate_main - -exception_gate_13: - mov al, 0x0D - jmp exception_gate_main - -exception_gate_14: - mov al, 0x0E - jmp exception_gate_main - -exception_gate_15: - mov al, 0x0F - jmp exception_gate_main - -exception_gate_16: - mov al, 0x10 - jmp exception_gate_main - -exception_gate_17: - mov al, 0x11 - jmp exception_gate_main - -exception_gate_18: - mov al, 0x12 - jmp exception_gate_main - -exception_gate_19: - mov al, 0x13 - jmp exception_gate_main - -exception_gate_main: - call os_print_newline - mov rsi, int_string - call os_print_string - mov rsi, exc_string00 - and rax, 0xFF ; Clear out everything in RAX except for AL - mov bl, 8 - mul bl ; AX = AL x BL - add rsi, rax ; Use the value in RAX as an offset to get to the right message - call os_print_string - mov rsi, adr_string - call os_print_string - mov rax, [rsp] - mov rdi, os_dump_reg_tstring - call os_int_to_hex_string ; Convert the register value to a hex string - mov rsi, os_dump_reg_tstring - call os_print_string ; Print the hex string - call os_print_newline - call os_dump_regs - -exception_gate_main_hang: - nop - jmp exception_gate_main_hang ; Hang. User must reset machine at this point - -; Strings for the error messages -int_string db 'Pure64 - Exception ', 0 -adr_string db ' @ 0x', 0 -exc_string db '?? - Unknown', 0 -align 16 -exc_string00 db '00 - DE', 0 -exc_string01 db '01 - DB', 0 -exc_string02 db '02 ', 0 -exc_string03 db '03 - BP', 0 -exc_string04 db '04 - OF', 0 -exc_string05 db '05 - BR', 0 -exc_string06 db '06 - UD', 0 -exc_string07 db '07 - NM', 0 -exc_string08 db '08 - DF', 0 -exc_string09 db '09 ', 0 ; No longer generated on new CPU's -exc_string10 db '10 - TS', 0 -exc_string11 db '11 - NP', 0 -exc_string12 db '12 - SS', 0 -exc_string13 db '13 - GP', 0 -exc_string14 db '14 - PF', 0 -exc_string15 db '15 ', 0 -exc_string16 db '16 - MF', 0 -exc_string17 db '17 - AC', 0 -exc_string18 db '18 - MC', 0 -exc_string19 db '19 - XM', 0 - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Interrupts +; ============================================================================= + + +; ----------------------------------------------------------------------------- +; Default exception handler +exception_gate: + mov rsi, int_string + call os_print_string + mov rsi, exc_string + call os_print_string +exception_gate_halt: + cli ; Disable interrupts + hlt ; Halt the system + jmp exception_gate_halt +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Default interrupt handler +interrupt_gate: ; handler for all other interrupts + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Keyboard interrupt. IRQ 0x01, INT 0x21 +; This IRQ runs whenever there is input on the keyboard +align 16 +keyboard: + push rdi + push rax + + xor rax, rax + + in al, 0x60 ; Get the scancode from the keyboard + test al, 0x80 + jz keydown + jmp keyboard_done + +keydown: + mov [0x000B8088], al ; Dump the scancode to the screen + + mov rax, [os_Counter_RTC] + add rax, 10 + mov [os_Counter_RTC], rax + +keyboard_done: + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC + add rdi, 0xB0 + xor eax, eax + stosd + + pop rax + pop rdi + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Real-time clock interrupt. IRQ 0x08, INT 0x28 +align 16 +rtc: + push rdi + push rax + + add qword [os_Counter_RTC], 1 ; 64-bit counter started at bootup + + mov al, 'R' + mov [0x000B8092], al + mov rax, [os_Counter_RTC] + and al, 1 ; Clear all but lowest bit (Can only be 0 or 1) + add al, 48 + mov [0x000B8094], al + mov al, 0x0C ; Select RTC register C + out 0x70, al ; Port 0x70 is the RTC index, and 0x71 is the RTC data + in al, 0x71 ; Read the value in register C + + mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC + add rdi, 0xB0 + xor eax, eax + stosd + + pop rax + pop rdi + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Spurious interrupt. INT 0xFF +align 16 +spurious: ; handler for spurious interrupts + mov al, 'S' + mov [0x000B8080], al + iretq +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; CPU Exception Gates +exception_gate_00: + mov al, 0x00 + jmp exception_gate_main + +exception_gate_01: + mov al, 0x01 + jmp exception_gate_main + +exception_gate_02: + mov al, 0x02 + jmp exception_gate_main + +exception_gate_03: + mov al, 0x03 + jmp exception_gate_main + +exception_gate_04: + mov al, 0x04 + jmp exception_gate_main + +exception_gate_05: + mov al, 0x05 + jmp exception_gate_main + +exception_gate_06: + mov al, 0x06 + jmp exception_gate_main + +exception_gate_07: + mov al, 0x07 + jmp exception_gate_main + +exception_gate_08: + mov al, 0x08 + jmp exception_gate_main + +exception_gate_09: + mov al, 0x09 + jmp exception_gate_main + +exception_gate_10: + mov al, 0x0A + jmp exception_gate_main + +exception_gate_11: + mov al, 0x0B + jmp exception_gate_main + +exception_gate_12: + mov al, 0x0C + jmp exception_gate_main + +exception_gate_13: + mov al, 0x0D + jmp exception_gate_main + +exception_gate_14: + mov al, 0x0E + jmp exception_gate_main + +exception_gate_15: + mov al, 0x0F + jmp exception_gate_main + +exception_gate_16: + mov al, 0x10 + jmp exception_gate_main + +exception_gate_17: + mov al, 0x11 + jmp exception_gate_main + +exception_gate_18: + mov al, 0x12 + jmp exception_gate_main + +exception_gate_19: + mov al, 0x13 + jmp exception_gate_main + +exception_gate_main: + call os_print_newline + mov rsi, int_string + call os_print_string + mov rsi, exc_string00 + and rax, 0xFF ; Clear out everything in RAX except for AL + mov bl, 8 + mul bl ; AX = AL x BL + add rsi, rax ; Use the value in RAX as an offset to get to the right message + call os_print_string + mov rsi, adr_string + call os_print_string + mov rax, [rsp] + mov rdi, os_dump_reg_tstring + call os_int_to_hex_string ; Convert the register value to a hex string + mov rsi, os_dump_reg_tstring + call os_print_string ; Print the hex string + call os_print_newline + call os_dump_regs + +exception_gate_main_hang: + nop + jmp exception_gate_main_hang ; Hang. User must reset machine at this point + +; Strings for the error messages +int_string db 'Pure64 - Exception ', 0 +adr_string db ' @ 0x', 0 +exc_string db '?? - Unknown', 0 +align 16 +exc_string00 db '00 - DE', 0 +exc_string01 db '01 - DB', 0 +exc_string02 db '02 ', 0 +exc_string03 db '03 - BP', 0 +exc_string04 db '04 - OF', 0 +exc_string05 db '05 - BR', 0 +exc_string06 db '06 - UD', 0 +exc_string07 db '07 - NM', 0 +exc_string08 db '08 - DF', 0 +exc_string09 db '09 ', 0 ; No longer generated on new CPU's +exc_string10 db '10 - TS', 0 +exc_string11 db '11 - NP', 0 +exc_string12 db '12 - SS', 0 +exc_string13 db '13 - GP', 0 +exc_string14 db '14 - PF', 0 +exc_string15 db '15 ', 0 +exc_string16 db '16 - MF', 0 +exc_string17 db '17 - AC', 0 +exc_string18 db '18 - MC', 0 +exc_string19 db '19 - XM', 0 + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/pci.asm b/amd64/pure64-0.5.0/src/pci.asm index 1aa5a789..7f024dde 100644 --- a/amd64/pure64-0.5.0/src/pci.asm +++ b/amd64/pure64-0.5.0/src/pci.asm @@ -1,65 +1,65 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; PCI Functions. http://wiki.osdev.org/PCI -; ============================================================================= - -align 16 -db 'DEBUG: PCI ' -align 16 - - -; ----------------------------------------------------------------------------- -; os_pci_read_reg -- Read a register from a PCI device -; IN: BL = Bus number -; CL = Device/Slot number -; DL = Register number -; OUT: EAX = Register information -; All other registers preserved -os_pci_read_reg: - push rdx - push rcx - push rbx - - shl ebx, 16 ; Move Bus number to bits 23 - 16 - shl ecx, 11 ; Move Device number to bits 15 - 11 - mov bx, cx - shl edx, 2 - mov bl, dl - and ebx, 0x00ffffff ; Clear bits 31 - 24 - or ebx, 0x80000000 ; Set bit 31 - mov eax, ebx - mov dx, PCI_CONFIG_ADDRESS - out dx, eax - mov dx, PCI_CONFIG_DATA - in eax, dx - - pop rbx - pop rcx - pop rdx -ret -; ----------------------------------------------------------------------------- - -;Configuration Mechanism One has two IO port rages associated with it. -;The address port (0xcf8-0xcfb) and the data port (0xcfc-0xcff). -;A configuration cycle consists of writing to the address port to specify which device and register you want to access and then reading or writing the data to the data port. - -PCI_CONFIG_ADDRESS EQU 0x0CF8 -PCI_CONFIG_DATA EQU 0x0CFC - -;ddress dd 10000000000000000000000000000000b -; /\ /\ /\ /\ /\ /\ -; E Res Bus Dev F Reg 0 -; Bits -; 31 Enable bit = set to 1 -; 30 - 24 Reserved = set to 0 -; 23 - 16 Bus number = 256 options -; 15 - 11 Device/Slot number = 32 options -; 10 - 8 Function number = will leave at 0 (8 options) -; 7 - 2 Register number = will leave at 0 (64 options) 64 x 4 bytes = 256 bytes worth of accessible registers -; 1 - 0 Set to 0 - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; PCI Functions. http://wiki.osdev.org/PCI +; ============================================================================= + +align 16 +db 'DEBUG: PCI ' +align 16 + + +; ----------------------------------------------------------------------------- +; os_pci_read_reg -- Read a register from a PCI device +; IN: BL = Bus number +; CL = Device/Slot number +; DL = Register number +; OUT: EAX = Register information +; All other registers preserved +os_pci_read_reg: + push rdx + push rcx + push rbx + + shl ebx, 16 ; Move Bus number to bits 23 - 16 + shl ecx, 11 ; Move Device number to bits 15 - 11 + mov bx, cx + shl edx, 2 + mov bl, dl + and ebx, 0x00ffffff ; Clear bits 31 - 24 + or ebx, 0x80000000 ; Set bit 31 + mov eax, ebx + mov dx, PCI_CONFIG_ADDRESS + out dx, eax + mov dx, PCI_CONFIG_DATA + in eax, dx + + pop rbx + pop rcx + pop rdx +ret +; ----------------------------------------------------------------------------- + +;Configuration Mechanism One has two IO port rages associated with it. +;The address port (0xcf8-0xcfb) and the data port (0xcfc-0xcff). +;A configuration cycle consists of writing to the address port to specify which device and register you want to access and then reading or writing the data to the data port. + +PCI_CONFIG_ADDRESS EQU 0x0CF8 +PCI_CONFIG_DATA EQU 0x0CFC + +;ddress dd 10000000000000000000000000000000b +; /\ /\ /\ /\ /\ /\ +; E Res Bus Dev F Reg 0 +; Bits +; 31 Enable bit = set to 1 +; 30 - 24 Reserved = set to 0 +; 23 - 16 Bus number = 256 options +; 15 - 11 Device/Slot number = 32 options +; 10 - 8 Function number = will leave at 0 (8 options) +; 7 - 2 Register number = will leave at 0 (64 options) 64 x 4 bytes = 256 bytes worth of accessible registers +; 1 - 0 Set to 0 + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/pure64.asm b/amd64/pure64-0.5.0/src/pure64.asm index b8471b9e..b6efc7a0 100644 --- a/amd64/pure64-0.5.0/src/pure64.asm +++ b/amd64/pure64-0.5.0/src/pure64.asm @@ -1,833 +1,833 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; Loaded from the first stage. Gather information about the system while -; in 16-bit mode (BIOS is still accessable), setup a minimal 64-bit -; enviroment, load the 64-bit kernel from the filesystem into memory and -; jump to it! -; ============================================================================= - - -; %define PURE64_CHAIN_LOADING -; If this is defined, Pure64 will chainload the kernel attached to the end of the pure64.sys binary -; Windows - copy /b pure64.sys + kernel64.sys -; Unix - cat pure64.sys kernel64.sys > pure64.sys -; Max size of the resulting pure64.sys is 28672 bytes - - -USE16 -ORG 0x00008000 -start: - cli ; Disable all interrupts - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor esi, esi - xor edi, edi - xor ebp, ebp - mov ds, ax - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - mov esp, 0x8000 ; Set a known free location for the stack - -align 16 - jmp start16 ; This command will be overwritten with 'NOP's before the AP's are started - -%include "init_smp_ap.asm" ; Our AP code is at 0x8000 - -align 16 -db '16' -align 16 - -USE16 -start16: - jmp 0x0000:clearcs - -clearcs: - mov ax, [0x07FE] ; MBR sector is copied to 0x0600 - cmp ax, 0xAA55 ; Check if the word at 0x07FE is set to 0xAA55 (Boot sector marker) - jne no_mbr - mov byte [cfg_mbr], 1 ; Set for booting from a disk with a MBR -no_mbr: - -; Configure serial port - xor dx, dx ; First serial port - mov ax, 0000000011100011b ; 9600 baud, no parity, 1 stop bit, 8 data bits - int 0x14 -; mov si, pure64 -;banner: -; lodsb -; cmp al, 0x00 -; je bannerdone -; call serial_send_16 -; jmp banner -;bannerdone: - -; Make sure the screen is set to 80x25 color text mode - mov ax, 0x0003 ; Set to normal (80x25 text) video mode - int 0x10 - -; Print message - mov si, initStartupMsg - call print_string_16 - -; Check to make sure the CPU supports 64-bit mode... If not then bail out - mov eax, 0x80000000 ; Extended-function 8000000h. - cpuid ; Is largest extended function - cmp eax, 0x80000000 ; any function > 80000000h? - jbe no_long_mode ; If not, no long mode. - mov eax, 0x80000001 ; Extended-function 8000001h. - cpuid ; Now EDX = extended-features flags. - bt edx, 29 ; Test if long mode is supported. - jnc no_long_mode ; Exit if not supported. - -; mov al, '0' -; call serial_send_16 - - call isa_setup ; Setup legacy hardware - -; mov al, 'F' -; call serial_send_16 - -; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. - lgdt [cs:GDTR32] ; Load GDT register - -; mov al, '-' -; call serial_send_16 - - mov eax, cr0 - or al, 0x01 ; Set protected mode bit - mov cr0, eax - - jmp 8:start32 ; Jump to 32-bit protected mode - -; 16-bit function to print a sting to the screen -print_string_16: ; Output string in SI to screen - pusha - mov ah, 0x0E ; int 0x10 teletype function -print_string_16_repeat: - lodsb ; Get char from string - cmp al, 0 - je print_string_16_done ; If char is zero, end of string - int 0x10 ; Otherwise, print it - jmp print_string_16_repeat -print_string_16_done: - popa - ret - -; 16-bit function to send a char our via serial -;serial_send_16: -; push edx -; push eax ; Save EAX since the serial line status check clobbers AL -; mov dx, 0x03FD ; Serial Line Status register -;serial_send_wait_16: -; in al, dx -; bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag -; jnc serial_send_wait_16 ; If the bit is not set then the queue isn't ready for another byte -; pop eax ; Get the byte back from the stack -; mov dx, 0x03F8 ; Serial data register -; out dx, al ; Send the byte -; pop edx -; ret - -; Display an error message that the CPU does not support 64-bit mode -no_long_mode: - mov si, no64msg - call print_string_16 - -buffer_test: - in al, 0x64 - test al, 0x01 - jz buffer_empty - in al, 0x60 - jmp buffer_test - -buffer_empty: - in al, 0x64 ; wait for key pressed - test al, 0x01 - jz buffer_empty - - int 0xff ; reboot by causing a triple fault - jmp $ - -%include "init_isa.asm" - -align 16 -GDTR32: ; Global Descriptors Table Register -dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) -dq gdt32 ; linear address of GDT - -align 16 -gdt32: -dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null desciptor -dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code desciptor -dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 32-bit data desciptor -gdt32_end: - -align 16 -db '32' -align 16 - - -; ============================================================================= -; 32-bit mode -USE32 - -start32: - mov eax, 16 ; load 4 GB data descriptor - mov ds, ax ; to all data segment registers - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor esi, esi - xor edi, edi - xor ebp, ebp - mov esp, 0x8000 ; Set a known free location for the stack - -; Debug - mov al, '2' ; Now in 32-bit protected mode - mov [0x000B809C], al - mov al, '0' - mov [0x000B809E], al -; mov al, '0' -; call serial_send_32 - -; Clear out the first 4096 bytes of memory. This will store the 64-bit IDT, GDT, PML4, and PDP - mov ecx, 1024 - xor eax, eax - mov edi, eax - rep stosd - -; Clear memory for the Page Descriptor Entries (0x10000 - 0x4FFFF) - mov edi, 0x00010000 - mov ecx, 65536 - rep stosd - -; Copy the GDT to its final location in memory - mov esi, gdt64 - mov edi, 0x00001000 ; GDT address - mov ecx, (gdt64_end - gdt64) - rep movsb ; Move it to final pos. - -; Create the Level 4 Page Map. (Maps 4GBs of 2MB pages) -; First create a PML4 entry. -; PML4 is stored at 0x0000000000002000, create the first entry there -; A single PML4 entry can map 512GB with 2MB pages. - cld - mov edi, 0x00002000 ; Create a PML4 entry for the first 4GB of RAM - mov eax, 0x00003007 - stosd - xor eax, eax - stosd - - mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) - mov eax, 0x00003007 ; The higher half is identity mapped to the lower half - stosd - xor eax, eax - stosd - -; Create the PDP entries. -; The first PDP is stored at 0x0000000000003000, create the first entries there -; A single PDP entry can map 1GB with 2MB pages - mov ecx, 64 ; number of PDPE's to make.. each PDPE maps 1GB of physical memory - mov edi, 0x00003000 - mov eax, 0x00010007 ; location of first PD -create_pdpe: - stosd - push eax - xor eax, eax - stosd - pop eax - add eax, 0x00001000 ; 4K later (512 records x 8 bytes) - dec ecx - cmp ecx, 0 - jne create_pdpe - -; Create the PD entries. -; PD entries are stored starting at 0x0000000000010000 and ending at 0x000000000004FFFF (256 KiB) -; This gives us room to map 64 GiB with 2 MiB pages - mov edi, 0x00010000 - mov eax, 0x0000008F ; Bit 7 must be set to 1 as we have 2 MiB pages - xor ecx, ecx -pd_again: ; Create a 2 MiB page - stosd - push eax - xor eax, eax - stosd - pop eax - add eax, 0x00200000 - inc ecx - cmp ecx, 2048 - jne pd_again ; Create 2048 2 MiB page maps. - -; mov al, '3' -; call serial_send_32 - -; Load the GDT - lgdt [GDTR64] - -; mov al, '4' -; call serial_send_32 - -; Enable extended properties - mov eax, cr4 - or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4) - mov cr4, eax - -; mov al, '5' -; call serial_send_32 - -; Point cr3 at PML4 - mov eax, 0x00002008 ; Write-thru (Bit 3) - mov cr3, eax - -; mov al, '6' -; call serial_send_32 - -; Enable long mode and SYSCALL/SYSRET - mov ecx, 0xC0000080 ; EFER MSR number - rdmsr ; Read EFER - or eax, 0x00000101 ; LME (Bit 8) - wrmsr ; Write EFER - -; mov al, '7' -; call serial_send_32 - -; Debug - mov al, '1' ; About to make the jump into 64-bit mode - mov [0x000B809C], al - mov al, 'E' - mov [0x000B809E], al - -; mov al, '-' -; call serial_send_32 - -; Enable paging to activate long mode - mov eax, cr0 - or eax, 0x80000000 ; PG (Bit 31) - mov cr0, eax - - jmp SYS64_CODE_SEL:start64 ; Jump to 64-bit mode - -; 32-bit function to send a char our via serial -;serial_send_32: -; push edx -; push eax ; Save EAX since the serial line status check clobbers AL -; mov dx, 0x03FD ; Serial Line Status register -;serial_send_wait_32: -; in al, dx -; bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag -; jnc serial_send_wait_32 ; If the bit is not set then the queue isn't ready for another byte -; pop eax ; Get the byte back from the stack -; mov dx, 0x03F8 ; Serial data register -; out dx, al ; Send the byte -; pop edx -; ret - -align 16 -db '64' -align 16 - - -; ============================================================================= -; 64-bit mode -USE64 - -start64: -; Debug - mov al, '4' ; Now in 64-bit mode - mov [0x000B809C], al - mov al, '0' - mov [0x000B809E], al -; mov al, '0' -; call serial_send_64 - - mov al, 2 - mov ah, 22 - call os_move_cursor - - xor rax, rax ; aka r0 - xor rbx, rbx ; aka r3 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor rbp, rbp ; aka r5 - mov rsp, 0x8000 ; aka r4 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - mov ds, ax ; Clear the legacy segment registers - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - - mov rax, clearcs64 ; Do a proper 64-bit jump. Should not be needed as the ... - jmp rax ; ... jmp SYS64_CODE_SEL:start64 would have sent us ... - nop ; .. out of compatibilty mode and into 64-bit mode -clearcs64: - xor rax, rax - - lgdt [GDTR64] ; Reload the GDT - -; Debug - mov al, '2' - mov [0x000B809E], al -; mov al, '2' -; call serial_send_64 - -; Patch Pure64 AP code ; The AP's will be told to start execution at 0x8000 - mov edi, 0x00008030 ; We need to remove the BSP Jump call to get the AP's - mov eax, 0x90909090 ; to fall through to the AP Init code - stosd - -; Build the rest of the page tables (4GiB+) - mov rcx, 0x0000000000000000 - mov rax, 0x000000010000008F - mov rdi, 0x0000000000014000 -buildem: - stosq - add rax, 0x0000000000200000 - add rcx, 1 - cmp rcx, 30720 ; Another 60 GiB (We already mapped 4 GiB) - jne buildem - ; We have 64 GiB mapped now - -; Build a temporary IDT - xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) - - mov rcx, 32 -make_exception_gates: ; make gates for exception handlers - mov rax, exception_gate - push rax ; save the exception gate to the stack for later use - stosw ; store the low word (15..0) of the address - mov ax, SYS64_CODE_SEL - stosw ; store the segment selector - mov ax, 0x8E00 - stosw ; store exception gate marker - pop rax ; get the exception gate back - shr rax, 16 - stosw ; store the high word (31..16) of the address - shr rax, 16 - stosd ; store the extra high dword (63..32) of the address. - xor rax, rax - stosd ; reserved - dec rcx - jnz make_exception_gates - - mov rcx, 256-32 -make_interrupt_gates: ; make gates for the other interrupts - mov rax, interrupt_gate - push rax ; save the interrupt gate to the stack for later use - stosw ; store the low word (15..0) of the address - mov ax, SYS64_CODE_SEL - stosw ; store the segment selector - mov ax, 0x8F00 - stosw ; store interrupt gate marker - pop rax ; get the interrupt gate back - shr rax, 16 - stosw ; store the high word (31..16) of the address - shr rax, 16 - stosd ; store the extra high dword (63..32) of the address. - xor rax, rax - stosd ; reserved - dec rcx - jnz make_interrupt_gates - - ; Set up the exception gates for all of the CPU exceptions - ; The following code will be seriously busted if the exception gates are moved above 16MB - mov word [0x00*16], exception_gate_00 - mov word [0x01*16], exception_gate_01 - mov word [0x02*16], exception_gate_02 - mov word [0x03*16], exception_gate_03 - mov word [0x04*16], exception_gate_04 - mov word [0x05*16], exception_gate_05 - mov word [0x06*16], exception_gate_06 - mov word [0x07*16], exception_gate_07 - mov word [0x08*16], exception_gate_08 - mov word [0x09*16], exception_gate_09 - mov word [0x0A*16], exception_gate_10 - mov word [0x0B*16], exception_gate_11 - mov word [0x0C*16], exception_gate_12 - mov word [0x0D*16], exception_gate_13 - mov word [0x0E*16], exception_gate_14 - mov word [0x0F*16], exception_gate_15 - mov word [0x10*16], exception_gate_16 - mov word [0x11*16], exception_gate_17 - mov word [0x12*16], exception_gate_18 - mov word [0x13*16], exception_gate_19 - - mov rdi, 0x21 ; Set up Keyboard IRQ handler - mov rax, keyboard - call create_gate - mov rdi, 0x28 ; Set up RTC IRQ handler - mov rax, rtc - call create_gate - mov rdi, 0xF8 ; Set up Spurious handler - mov rax, spurious - call create_gate - - lidt [IDTR64] ; load IDT register - -; Debug - mov al, '4' - mov [0x000B809E], al -; mov al, '5' -; call serial_send_64 - -; Clear memory 0xf000 - 0xf7ff for the infomap (2048 bytes) - xor rax, rax - mov rcx, 256 - mov rdi, 0x000000000000F000 -clearmapnext: - stosq - dec rcx - cmp rcx, 0 - jne clearmapnext - - call init_acpi ; Find and process the ACPI tables - - call init_cpu ; Setup CPU - - call init_ioapic ; Setup the IO-APIC(s), also activate interrupts - -; Debug - mov al, '6' ; CPU Init complete - mov [0x000B809E], al -; mov al, '6' -; call serial_send_64 - -; Make sure exceptions are working. -; xor rax, rax -; xor rbx, rbx -; xor rcx, rcx -; xor rdx, rdx -; div rax - - call hdd_setup ; Gather Hard Drive information - -; Debug - mov al, '8' ; HDD Init complete - mov [0x000B809E], al -; mov al, '8' -; call serial_send_64 - -; Find init64.cfg -; mov rbx, configname -; call findfile -; cmp rbx, 0 -; je near noconfig ; If the config file was not found we just use the default settings. - mov al, 1 - mov byte [cfg_default], al ; We have a config file - -; Read in the first cluster of init64.cfg -; mov rdi, 0x0000000000100000 -; call readcluster - -; Parse init64.cfg -; Get Kernel name -; get SMP setting - -; noconfig: - -; Init of SMP - call smp_setup - -; Reset the stack to the proper location (was set to 0x8000 previously) - mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... - add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. - lodsd ; Load a 32-bit value. We only want the high 8 bits - shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID - shl rax, 10 ; shift left 10 bits for a 1024byte stack - add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in - mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that - -; Debug - mov al, '6' ; SMP Init complete - mov [0x000B809C], al - mov al, '0' - mov [0x000B809E], al -; mov al, 'E' -; call serial_send_64 - -; Calculate amount of usable RAM from Memory Map - xor rcx, rcx - mov rsi, 0x0000000000004000 ; E820 Map location -readnextrecord: - lodsq - lodsq - lodsd - cmp eax, 0 ; Are we at the end? - je endmemcalc - cmp eax, 1 ; Usuable RAM - je goodmem - cmp eax, 3 ; ACPI Reclaimable - je goodmem - cmp eax, 6 ; BIOS Reclaimable - je goodmem - lodsd - lodsq - jmp readnextrecord -goodmem: - sub rsi, 12 - lodsq - add rcx, rax - lodsq - lodsq - jmp readnextrecord - -endmemcalc: - shr rcx, 20 ; Value is in bytes so do a quick divide by 1048576 to get MiB's - add cx, 1 ; The BIOS will usually report actual memory minus 1 - and cx, 0xFFFE ; Make sure it is an even number (in case we added 1 to an even number) - mov word [mem_amount], cx - -; Debug - mov al, '2' - mov [0x000B809E], al - -; Convert CPU speed value to string - xor rax, rax - mov ax, [cpu_speed] - mov rdi, speedtempstring - call os_int_to_string - -; Convert CPU amount value to string - xor rax, rax - mov ax, [cpu_activated] - mov rdi, cpu_amount_string - call os_int_to_string - -; Convert RAM amount value to string - xor rax, rax - mov ax, [mem_amount] - mov rdi, memtempstring - call os_int_to_string - -; Build the infomap - xor rdi, rdi - mov di, 0x5000 - mov rax, [os_ACPITableAddress] - stosq - mov eax, [os_BSP] - stosd - - mov di, 0x5010 - mov ax, [cpu_speed] - stosw - mov ax, [cpu_activated] - stosw - mov ax, [cpu_detected] - stosw - - mov di, 0x5020 - mov ax, [mem_amount] - stosw - - mov di, 0x5030 - mov al, [cfg_mbr] - stosb - mov al, [os_IOAPICCount] - stosb - - mov di, 0x5040 - mov eax, [VBEModeInfoBlock.PhysBasePtr] - stosd - mov ax, [VBEModeInfoBlock.XResolution] - stosw - mov ax, [VBEModeInfoBlock.YResolution] - stosw - - mov di, 0x5060 - mov rax, [os_LocalAPICAddress] - stosq - xor ecx, ecx - mov cl, [os_IOAPICCount] - mov rsi, os_IOAPICAddress -nextIOAPIC: - lodsq - stosq - sub cl, 1 - cmp cl, 0 - jne nextIOAPIC - -; Initialization is now complete... write a message to the screen - mov rsi, msg_done - call os_print_string - -; Write an extra message if we are using the default config - cmp byte [cfg_default], 1 - je nodefaultconfig - mov al, 2 - mov ah, 28 - call os_move_cursor - mov rsi, msg_noconfig - call os_print_string -nodefaultconfig: - -; Debug - mov al, '4' - mov [0x000B809E], al - -; Print info on CPU, MEM, and HD - mov ax, 0x0004 - call os_move_cursor - mov rsi, msg_CPU - call os_print_string - mov rsi, speedtempstring - call os_print_string - mov rsi, msg_mhz - call os_print_string - mov rsi, cpu_amount_string - call os_print_string - - mov rsi, msg_MEM - call os_print_string - mov rsi, memtempstring - call os_print_string - mov rsi, msg_mb - call os_print_string - - mov rsi, msg_HDD - call os_print_string - mov rsi, hdtempstring - call os_print_string - mov rsi, msg_mb - call os_print_string - -; ============================================================================= -%ifdef PURE64_CHAIN_LOADING - mov rsi, 0x8000+7168 ; Memory offset to end of pure64.sys - mov rdi, 0x100000 ; Destination address at the 1MiB mark - mov rcx, 0x1000 ; For up to 32KiB kernel (4096 x 8) - rep movsq ; Copy 8 bytes at a time - jmp fini ; Print starting message and jump to kernel -%endif -; ============================================================================= - -; Print a message that the kernel is being loaded - mov ax, 0x0006 - call os_move_cursor - mov rsi, msg_loadingkernel - call os_print_string - -; Find the kernel file - mov rsi, kernelname - call findfile - cmp ax, 0x0000 - je near nokernel - -; Debug - push rax - mov al, '6' - mov [0x000B809E], al - pop rax - -; Load 64-bit kernel from drive to 0x0000000000010000 - mov rdi, 0x0000000000100000 -readfile_getdata: - push rax - mov al, '.' ; Show loading progress - call os_print_char - pop rax - call readcluster ; store in memory - cmp ax, 0xFFFF ; Value for end of cluster chain. - jne readfile_getdata ; Are there more clusters? If so then read again.. if not fall through. - -; Print a message that the kernel has been loaded - mov rsi, msg_done - call os_print_string - -fini: ; For chainloading - -; Print a message that the kernel is being started - mov ax, 0x0008 - call os_move_cursor - mov rsi, msg_startingkernel - call os_print_string - -; Debug -; mov al, ' ' ; Clear the debug messages -; mov [0x000B809A], al -; mov [0x000B809C], al -; mov [0x000B809E], al - -; mov al, '-' -; call serial_send_64 - -; Clear all registers (skip the stack pointer) - xor rax, rax ; aka r0 - xor rbx, rbx ; aka r3 - xor rcx, rcx ; aka r1 - xor rdx, rdx ; aka r2 - xor rsi, rsi ; aka r6 - xor rdi, rdi ; aka r7 - xor rbp, rbp ; aka r5 - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - jmp 0x0000000000100000 ; Jump to the kernel - -nokernel: - mov al, 6 - mov ah, 0 - call os_move_cursor - mov rsi, kernelerror - call os_print_string -nokernelhalt: - hlt - jmp nokernelhalt - -; 64-bit function to send a char our via serial -;serial_send_64: -; push rdx -; push rax ; Save RAX since the serial line status check clobbers AL -; mov dx, 0x03FD ; Serial Line Status register -;serial_send_wait_64: -; in al, dx -; bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag -; jnc serial_send_wait_64 ; If the bit is not set then the queue isn't ready for another byte -; pop rax ; Get the byte back from the stack -; mov dx, 0x03F8 ; Serial data register -; out dx, al ; Send the byte -; pop rdx -; ret - -%include "init_cpu.asm" -%include "init_acpi.asm" -%include "init_ioapic.asm" -%include "init_hdd.asm" -%include "init_smp.asm" -%include "syscalls.asm" -%include "interrupt.asm" -%include "pci.asm" -%include "fat16.asm" -%include "sysvar.asm" - -; Pad to an even KB file (6 KiB) -times 7168-($-$$) db 0x90 - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; Loaded from the first stage. Gather information about the system while +; in 16-bit mode (BIOS is still accessable), setup a minimal 64-bit +; enviroment, load the 64-bit kernel from the filesystem into memory and +; jump to it! +; ============================================================================= + + +; %define PURE64_CHAIN_LOADING +; If this is defined, Pure64 will chainload the kernel attached to the end of the pure64.sys binary +; Windows - copy /b pure64.sys + kernel64.sys +; Unix - cat pure64.sys kernel64.sys > pure64.sys +; Max size of the resulting pure64.sys is 28672 bytes + + +USE16 +ORG 0x00008000 +start: + cli ; Disable all interrupts + xor eax, eax + xor ebx, ebx + xor ecx, ecx + xor edx, edx + xor esi, esi + xor edi, edi + xor ebp, ebp + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + mov esp, 0x8000 ; Set a known free location for the stack + +align 16 + jmp start16 ; This command will be overwritten with 'NOP's before the AP's are started + +%include "init_smp_ap.asm" ; Our AP code is at 0x8000 + +align 16 +db '16' +align 16 + +USE16 +start16: + jmp 0x0000:clearcs + +clearcs: + mov ax, [0x07FE] ; MBR sector is copied to 0x0600 + cmp ax, 0xAA55 ; Check if the word at 0x07FE is set to 0xAA55 (Boot sector marker) + jne no_mbr + mov byte [cfg_mbr], 1 ; Set for booting from a disk with a MBR +no_mbr: + +; Configure serial port + xor dx, dx ; First serial port + mov ax, 0000000011100011b ; 9600 baud, no parity, 1 stop bit, 8 data bits + int 0x14 +; mov si, pure64 +;banner: +; lodsb +; cmp al, 0x00 +; je bannerdone +; call serial_send_16 +; jmp banner +;bannerdone: + +; Make sure the screen is set to 80x25 color text mode + mov ax, 0x0003 ; Set to normal (80x25 text) video mode + int 0x10 + +; Print message + mov si, initStartupMsg + call print_string_16 + +; Check to make sure the CPU supports 64-bit mode... If not then bail out + mov eax, 0x80000000 ; Extended-function 8000000h. + cpuid ; Is largest extended function + cmp eax, 0x80000000 ; any function > 80000000h? + jbe no_long_mode ; If not, no long mode. + mov eax, 0x80000001 ; Extended-function 8000001h. + cpuid ; Now EDX = extended-features flags. + bt edx, 29 ; Test if long mode is supported. + jnc no_long_mode ; Exit if not supported. + +; mov al, '0' +; call serial_send_16 + + call isa_setup ; Setup legacy hardware + +; mov al, 'F' +; call serial_send_16 + +; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. + lgdt [cs:GDTR32] ; Load GDT register + +; mov al, '-' +; call serial_send_16 + + mov eax, cr0 + or al, 0x01 ; Set protected mode bit + mov cr0, eax + + jmp 8:start32 ; Jump to 32-bit protected mode + +; 16-bit function to print a sting to the screen +print_string_16: ; Output string in SI to screen + pusha + mov ah, 0x0E ; int 0x10 teletype function +print_string_16_repeat: + lodsb ; Get char from string + cmp al, 0 + je print_string_16_done ; If char is zero, end of string + int 0x10 ; Otherwise, print it + jmp print_string_16_repeat +print_string_16_done: + popa + ret + +; 16-bit function to send a char our via serial +;serial_send_16: +; push edx +; push eax ; Save EAX since the serial line status check clobbers AL +; mov dx, 0x03FD ; Serial Line Status register +;serial_send_wait_16: +; in al, dx +; bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag +; jnc serial_send_wait_16 ; If the bit is not set then the queue isn't ready for another byte +; pop eax ; Get the byte back from the stack +; mov dx, 0x03F8 ; Serial data register +; out dx, al ; Send the byte +; pop edx +; ret + +; Display an error message that the CPU does not support 64-bit mode +no_long_mode: + mov si, no64msg + call print_string_16 + +buffer_test: + in al, 0x64 + test al, 0x01 + jz buffer_empty + in al, 0x60 + jmp buffer_test + +buffer_empty: + in al, 0x64 ; wait for key pressed + test al, 0x01 + jz buffer_empty + + int 0xff ; reboot by causing a triple fault + jmp $ + +%include "init_isa.asm" + +align 16 +GDTR32: ; Global Descriptors Table Register +dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) +dq gdt32 ; linear address of GDT + +align 16 +gdt32: +dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null desciptor +dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code desciptor +dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 32-bit data desciptor +gdt32_end: + +align 16 +db '32' +align 16 + + +; ============================================================================= +; 32-bit mode +USE32 + +start32: + mov eax, 16 ; load 4 GB data descriptor + mov ds, ax ; to all data segment registers + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + xor eax, eax + xor ebx, ebx + xor ecx, ecx + xor edx, edx + xor esi, esi + xor edi, edi + xor ebp, ebp + mov esp, 0x8000 ; Set a known free location for the stack + +; Debug + mov al, '2' ; Now in 32-bit protected mode + mov [0x000B809C], al + mov al, '0' + mov [0x000B809E], al +; mov al, '0' +; call serial_send_32 + +; Clear out the first 4096 bytes of memory. This will store the 64-bit IDT, GDT, PML4, and PDP + mov ecx, 1024 + xor eax, eax + mov edi, eax + rep stosd + +; Clear memory for the Page Descriptor Entries (0x10000 - 0x4FFFF) + mov edi, 0x00010000 + mov ecx, 65536 + rep stosd + +; Copy the GDT to its final location in memory + mov esi, gdt64 + mov edi, 0x00001000 ; GDT address + mov ecx, (gdt64_end - gdt64) + rep movsb ; Move it to final pos. + +; Create the Level 4 Page Map. (Maps 4GBs of 2MB pages) +; First create a PML4 entry. +; PML4 is stored at 0x0000000000002000, create the first entry there +; A single PML4 entry can map 512GB with 2MB pages. + cld + mov edi, 0x00002000 ; Create a PML4 entry for the first 4GB of RAM + mov eax, 0x00003007 + stosd + xor eax, eax + stosd + + mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) + mov eax, 0x00003007 ; The higher half is identity mapped to the lower half + stosd + xor eax, eax + stosd + +; Create the PDP entries. +; The first PDP is stored at 0x0000000000003000, create the first entries there +; A single PDP entry can map 1GB with 2MB pages + mov ecx, 64 ; number of PDPE's to make.. each PDPE maps 1GB of physical memory + mov edi, 0x00003000 + mov eax, 0x00010007 ; location of first PD +create_pdpe: + stosd + push eax + xor eax, eax + stosd + pop eax + add eax, 0x00001000 ; 4K later (512 records x 8 bytes) + dec ecx + cmp ecx, 0 + jne create_pdpe + +; Create the PD entries. +; PD entries are stored starting at 0x0000000000010000 and ending at 0x000000000004FFFF (256 KiB) +; This gives us room to map 64 GiB with 2 MiB pages + mov edi, 0x00010000 + mov eax, 0x0000008F ; Bit 7 must be set to 1 as we have 2 MiB pages + xor ecx, ecx +pd_again: ; Create a 2 MiB page + stosd + push eax + xor eax, eax + stosd + pop eax + add eax, 0x00200000 + inc ecx + cmp ecx, 2048 + jne pd_again ; Create 2048 2 MiB page maps. + +; mov al, '3' +; call serial_send_32 + +; Load the GDT + lgdt [GDTR64] + +; mov al, '4' +; call serial_send_32 + +; Enable extended properties + mov eax, cr4 + or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4) + mov cr4, eax + +; mov al, '5' +; call serial_send_32 + +; Point cr3 at PML4 + mov eax, 0x00002008 ; Write-thru (Bit 3) + mov cr3, eax + +; mov al, '6' +; call serial_send_32 + +; Enable long mode and SYSCALL/SYSRET + mov ecx, 0xC0000080 ; EFER MSR number + rdmsr ; Read EFER + or eax, 0x00000101 ; LME (Bit 8) + wrmsr ; Write EFER + +; mov al, '7' +; call serial_send_32 + +; Debug + mov al, '1' ; About to make the jump into 64-bit mode + mov [0x000B809C], al + mov al, 'E' + mov [0x000B809E], al + +; mov al, '-' +; call serial_send_32 + +; Enable paging to activate long mode + mov eax, cr0 + or eax, 0x80000000 ; PG (Bit 31) + mov cr0, eax + + jmp SYS64_CODE_SEL:start64 ; Jump to 64-bit mode + +; 32-bit function to send a char our via serial +;serial_send_32: +; push edx +; push eax ; Save EAX since the serial line status check clobbers AL +; mov dx, 0x03FD ; Serial Line Status register +;serial_send_wait_32: +; in al, dx +; bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag +; jnc serial_send_wait_32 ; If the bit is not set then the queue isn't ready for another byte +; pop eax ; Get the byte back from the stack +; mov dx, 0x03F8 ; Serial data register +; out dx, al ; Send the byte +; pop edx +; ret + +align 16 +db '64' +align 16 + + +; ============================================================================= +; 64-bit mode +USE64 + +start64: +; Debug + mov al, '4' ; Now in 64-bit mode + mov [0x000B809C], al + mov al, '0' + mov [0x000B809E], al +; mov al, '0' +; call serial_send_64 + + mov al, 2 + mov ah, 22 + call os_move_cursor + + xor rax, rax ; aka r0 + xor rbx, rbx ; aka r3 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor rbp, rbp ; aka r5 + mov rsp, 0x8000 ; aka r4 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + mov ds, ax ; Clear the legacy segment registers + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + mov rax, clearcs64 ; Do a proper 64-bit jump. Should not be needed as the ... + jmp rax ; ... jmp SYS64_CODE_SEL:start64 would have sent us ... + nop ; .. out of compatibilty mode and into 64-bit mode +clearcs64: + xor rax, rax + + lgdt [GDTR64] ; Reload the GDT + +; Debug + mov al, '2' + mov [0x000B809E], al +; mov al, '2' +; call serial_send_64 + +; Patch Pure64 AP code ; The AP's will be told to start execution at 0x8000 + mov edi, 0x00008030 ; We need to remove the BSP Jump call to get the AP's + mov eax, 0x90909090 ; to fall through to the AP Init code + stosd + +; Build the rest of the page tables (4GiB+) + mov rcx, 0x0000000000000000 + mov rax, 0x000000010000008F + mov rdi, 0x0000000000014000 +buildem: + stosq + add rax, 0x0000000000200000 + add rcx, 1 + cmp rcx, 30720 ; Another 60 GiB (We already mapped 4 GiB) + jne buildem + ; We have 64 GiB mapped now + +; Build a temporary IDT + xor rdi, rdi ; create the 64-bit IDT (at linear address 0x0000000000000000) + + mov rcx, 32 +make_exception_gates: ; make gates for exception handlers + mov rax, exception_gate + push rax ; save the exception gate to the stack for later use + stosw ; store the low word (15..0) of the address + mov ax, SYS64_CODE_SEL + stosw ; store the segment selector + mov ax, 0x8E00 + stosw ; store exception gate marker + pop rax ; get the exception gate back + shr rax, 16 + stosw ; store the high word (31..16) of the address + shr rax, 16 + stosd ; store the extra high dword (63..32) of the address. + xor rax, rax + stosd ; reserved + dec rcx + jnz make_exception_gates + + mov rcx, 256-32 +make_interrupt_gates: ; make gates for the other interrupts + mov rax, interrupt_gate + push rax ; save the interrupt gate to the stack for later use + stosw ; store the low word (15..0) of the address + mov ax, SYS64_CODE_SEL + stosw ; store the segment selector + mov ax, 0x8F00 + stosw ; store interrupt gate marker + pop rax ; get the interrupt gate back + shr rax, 16 + stosw ; store the high word (31..16) of the address + shr rax, 16 + stosd ; store the extra high dword (63..32) of the address. + xor rax, rax + stosd ; reserved + dec rcx + jnz make_interrupt_gates + + ; Set up the exception gates for all of the CPU exceptions + ; The following code will be seriously busted if the exception gates are moved above 16MB + mov word [0x00*16], exception_gate_00 + mov word [0x01*16], exception_gate_01 + mov word [0x02*16], exception_gate_02 + mov word [0x03*16], exception_gate_03 + mov word [0x04*16], exception_gate_04 + mov word [0x05*16], exception_gate_05 + mov word [0x06*16], exception_gate_06 + mov word [0x07*16], exception_gate_07 + mov word [0x08*16], exception_gate_08 + mov word [0x09*16], exception_gate_09 + mov word [0x0A*16], exception_gate_10 + mov word [0x0B*16], exception_gate_11 + mov word [0x0C*16], exception_gate_12 + mov word [0x0D*16], exception_gate_13 + mov word [0x0E*16], exception_gate_14 + mov word [0x0F*16], exception_gate_15 + mov word [0x10*16], exception_gate_16 + mov word [0x11*16], exception_gate_17 + mov word [0x12*16], exception_gate_18 + mov word [0x13*16], exception_gate_19 + + mov rdi, 0x21 ; Set up Keyboard IRQ handler + mov rax, keyboard + call create_gate + mov rdi, 0x28 ; Set up RTC IRQ handler + mov rax, rtc + call create_gate + mov rdi, 0xF8 ; Set up Spurious handler + mov rax, spurious + call create_gate + + lidt [IDTR64] ; load IDT register + +; Debug + mov al, '4' + mov [0x000B809E], al +; mov al, '5' +; call serial_send_64 + +; Clear memory 0xf000 - 0xf7ff for the infomap (2048 bytes) + xor rax, rax + mov rcx, 256 + mov rdi, 0x000000000000F000 +clearmapnext: + stosq + dec rcx + cmp rcx, 0 + jne clearmapnext + + call init_acpi ; Find and process the ACPI tables + + call init_cpu ; Setup CPU + + call init_ioapic ; Setup the IO-APIC(s), also activate interrupts + +; Debug + mov al, '6' ; CPU Init complete + mov [0x000B809E], al +; mov al, '6' +; call serial_send_64 + +; Make sure exceptions are working. +; xor rax, rax +; xor rbx, rbx +; xor rcx, rcx +; xor rdx, rdx +; div rax + + call hdd_setup ; Gather Hard Drive information + +; Debug + mov al, '8' ; HDD Init complete + mov [0x000B809E], al +; mov al, '8' +; call serial_send_64 + +; Find init64.cfg +; mov rbx, configname +; call findfile +; cmp rbx, 0 +; je near noconfig ; If the config file was not found we just use the default settings. + mov al, 1 + mov byte [cfg_default], al ; We have a config file + +; Read in the first cluster of init64.cfg +; mov rdi, 0x0000000000100000 +; call readcluster + +; Parse init64.cfg +; Get Kernel name +; get SMP setting + +; noconfig: + +; Init of SMP + call smp_setup + +; Reset the stack to the proper location (was set to 0x8000 previously) + mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ... + add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. + lodsd ; Load a 32-bit value. We only want the high 8 bits + shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID + shl rax, 10 ; shift left 10 bits for a 1024byte stack + add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in + mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that + +; Debug + mov al, '6' ; SMP Init complete + mov [0x000B809C], al + mov al, '0' + mov [0x000B809E], al +; mov al, 'E' +; call serial_send_64 + +; Calculate amount of usable RAM from Memory Map + xor rcx, rcx + mov rsi, 0x0000000000004000 ; E820 Map location +readnextrecord: + lodsq + lodsq + lodsd + cmp eax, 0 ; Are we at the end? + je endmemcalc + cmp eax, 1 ; Usuable RAM + je goodmem + cmp eax, 3 ; ACPI Reclaimable + je goodmem + cmp eax, 6 ; BIOS Reclaimable + je goodmem + lodsd + lodsq + jmp readnextrecord +goodmem: + sub rsi, 12 + lodsq + add rcx, rax + lodsq + lodsq + jmp readnextrecord + +endmemcalc: + shr rcx, 20 ; Value is in bytes so do a quick divide by 1048576 to get MiB's + add cx, 1 ; The BIOS will usually report actual memory minus 1 + and cx, 0xFFFE ; Make sure it is an even number (in case we added 1 to an even number) + mov word [mem_amount], cx + +; Debug + mov al, '2' + mov [0x000B809E], al + +; Convert CPU speed value to string + xor rax, rax + mov ax, [cpu_speed] + mov rdi, speedtempstring + call os_int_to_string + +; Convert CPU amount value to string + xor rax, rax + mov ax, [cpu_activated] + mov rdi, cpu_amount_string + call os_int_to_string + +; Convert RAM amount value to string + xor rax, rax + mov ax, [mem_amount] + mov rdi, memtempstring + call os_int_to_string + +; Build the infomap + xor rdi, rdi + mov di, 0x5000 + mov rax, [os_ACPITableAddress] + stosq + mov eax, [os_BSP] + stosd + + mov di, 0x5010 + mov ax, [cpu_speed] + stosw + mov ax, [cpu_activated] + stosw + mov ax, [cpu_detected] + stosw + + mov di, 0x5020 + mov ax, [mem_amount] + stosw + + mov di, 0x5030 + mov al, [cfg_mbr] + stosb + mov al, [os_IOAPICCount] + stosb + + mov di, 0x5040 + mov eax, [VBEModeInfoBlock.PhysBasePtr] + stosd + mov ax, [VBEModeInfoBlock.XResolution] + stosw + mov ax, [VBEModeInfoBlock.YResolution] + stosw + + mov di, 0x5060 + mov rax, [os_LocalAPICAddress] + stosq + xor ecx, ecx + mov cl, [os_IOAPICCount] + mov rsi, os_IOAPICAddress +nextIOAPIC: + lodsq + stosq + sub cl, 1 + cmp cl, 0 + jne nextIOAPIC + +; Initialization is now complete... write a message to the screen + mov rsi, msg_done + call os_print_string + +; Write an extra message if we are using the default config + cmp byte [cfg_default], 1 + je nodefaultconfig + mov al, 2 + mov ah, 28 + call os_move_cursor + mov rsi, msg_noconfig + call os_print_string +nodefaultconfig: + +; Debug + mov al, '4' + mov [0x000B809E], al + +; Print info on CPU, MEM, and HD + mov ax, 0x0004 + call os_move_cursor + mov rsi, msg_CPU + call os_print_string + mov rsi, speedtempstring + call os_print_string + mov rsi, msg_mhz + call os_print_string + mov rsi, cpu_amount_string + call os_print_string + + mov rsi, msg_MEM + call os_print_string + mov rsi, memtempstring + call os_print_string + mov rsi, msg_mb + call os_print_string + + mov rsi, msg_HDD + call os_print_string + mov rsi, hdtempstring + call os_print_string + mov rsi, msg_mb + call os_print_string + +; ============================================================================= +%ifdef PURE64_CHAIN_LOADING + mov rsi, 0x8000+7168 ; Memory offset to end of pure64.sys + mov rdi, 0x100000 ; Destination address at the 1MiB mark + mov rcx, 0x1000 ; For up to 32KiB kernel (4096 x 8) + rep movsq ; Copy 8 bytes at a time + jmp fini ; Print starting message and jump to kernel +%endif +; ============================================================================= + +; Print a message that the kernel is being loaded + mov ax, 0x0006 + call os_move_cursor + mov rsi, msg_loadingkernel + call os_print_string + +; Find the kernel file + mov rsi, kernelname + call findfile + cmp ax, 0x0000 + je near nokernel + +; Debug + push rax + mov al, '6' + mov [0x000B809E], al + pop rax + +; Load 64-bit kernel from drive to 0x0000000000010000 + mov rdi, 0x0000000000100000 +readfile_getdata: + push rax + mov al, '.' ; Show loading progress + call os_print_char + pop rax + call readcluster ; store in memory + cmp ax, 0xFFFF ; Value for end of cluster chain. + jne readfile_getdata ; Are there more clusters? If so then read again.. if not fall through. + +; Print a message that the kernel has been loaded + mov rsi, msg_done + call os_print_string + +fini: ; For chainloading + +; Print a message that the kernel is being started + mov ax, 0x0008 + call os_move_cursor + mov rsi, msg_startingkernel + call os_print_string + +; Debug +; mov al, ' ' ; Clear the debug messages +; mov [0x000B809A], al +; mov [0x000B809C], al +; mov [0x000B809E], al + +; mov al, '-' +; call serial_send_64 + +; Clear all registers (skip the stack pointer) + xor rax, rax ; aka r0 + xor rbx, rbx ; aka r3 + xor rcx, rcx ; aka r1 + xor rdx, rdx ; aka r2 + xor rsi, rsi ; aka r6 + xor rdi, rdi ; aka r7 + xor rbp, rbp ; aka r5 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + jmp 0x0000000000100000 ; Jump to the kernel + +nokernel: + mov al, 6 + mov ah, 0 + call os_move_cursor + mov rsi, kernelerror + call os_print_string +nokernelhalt: + hlt + jmp nokernelhalt + +; 64-bit function to send a char our via serial +;serial_send_64: +; push rdx +; push rax ; Save RAX since the serial line status check clobbers AL +; mov dx, 0x03FD ; Serial Line Status register +;serial_send_wait_64: +; in al, dx +; bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag +; jnc serial_send_wait_64 ; If the bit is not set then the queue isn't ready for another byte +; pop rax ; Get the byte back from the stack +; mov dx, 0x03F8 ; Serial data register +; out dx, al ; Send the byte +; pop rdx +; ret + +%include "init_cpu.asm" +%include "init_acpi.asm" +%include "init_ioapic.asm" +%include "init_hdd.asm" +%include "init_smp.asm" +%include "syscalls.asm" +%include "interrupt.asm" +%include "pci.asm" +%include "fat16.asm" +%include "sysvar.asm" + +; Pad to an even KB file (6 KiB) +times 7168-($-$$) db 0x90 + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/syscalls.asm b/amd64/pure64-0.5.0/src/syscalls.asm index 6585556c..25db578b 100644 --- a/amd64/pure64-0.5.0/src/syscalls.asm +++ b/amd64/pure64-0.5.0/src/syscalls.asm @@ -1,515 +1,515 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; System Calls -; ================================================================= - - -; ----------------------------------------------------------------------------- -; os_move_cursor -- Moves the virtual cursor in text mode -; IN: AH, AL = row, column -; OUT: Nothing. All registers preserved -os_move_cursor: - push rcx - push rbx - push rax - - mov [screen_cursor_x], ah - mov [screen_cursor_y], al - - and rax, 0x000000000000FFFF ; only keep the low 16 bits - ;calculate the new offset - mov cl, 80 - mul cl ; AX = AL * CL - xor rbx, rbx - mov bl, [screen_cursor_x] - add ax, bx - shl ax, 1 ; multiply by 2 - - add rax, 0x00000000000B8000 - mov [screen_cursor_offset], rax - - pop rax - pop rbx - pop rcx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_newline -- Reset cursor to start of next line and scroll if needed -; IN: Nothing -; OUT: Nothing, all registers perserved -os_print_newline: - push rax - - mov ah, 0 ; Set the cursor x value to 0 - mov al, [screen_cursor_y] ; Grab the cursor y value - cmp al, 24 ; Compare to see if we are on the last line - je os_print_newline_scroll ; If so then we need to scroll the sreen - - inc al ; If not then we can go ahead an increment the y value - jmp os_print_newline_done - -os_print_newline_scroll: - mov ax, 0x0000 ; If we have reached the end then wrap back to the front - -os_print_newline_done: - call os_move_cursor ; update the cursor - - pop rax - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_string -- Displays text -; IN: RSI = message location (zero-terminated string) -; OUT: Nothing, all registers perserved -os_print_string: - push rsi - push rax - - cld ; Clear the direction flag.. we want to increment through the string - -os_print_string_nextchar: - lodsb ; Get char from string and store in AL - cmp al, 0 ; Strings are Zero terminated. - je os_print_string_done ; If char is Zero then it is the end of the string - - cmp al, 13 ; Check if there was a newline character in the string - je os_print_string_newline ; If so then we print a new line - - call os_print_char - - jmp os_print_string_nextchar - -os_print_string_newline: - call os_print_newline - jmp os_print_string_nextchar - -os_print_string_done: - pop rax - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char -- Displays a char -; IN: AL = char to display -; OUT: Nothing. All registers preserved -os_print_char: - push rdi - - mov rdi, [screen_cursor_offset] - stosb - add qword [screen_cursor_offset], 2 ; Add 2 (1 byte for char and 1 byte for attribute) - - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_print_char_hex -- Displays a char in hex mode -; IN: AL = char to display -; OUT: Nothing. All registers preserved -os_print_char_hex: - push rbx - push rax - - mov rbx, hextable - - push rax ; save rax for the next part - shr al, 4 ; we want to work on the high part so shift right by 4 bits - xlatb - call os_print_char - - pop rax - and al, 0x0f ; we want to work on the low part so clear the high part - xlatb - call os_print_char - - pop rax - pop rbx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_debug_dump_(rax|eax|ax|al) -- Dump content of RAX, EAX, AX, or AL to the screen in hex format -; IN: RAX = content to dump -; OUT: Nothing, all registers preserved -os_debug_dump_rax: - ror rax, 56 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 32 -os_debug_dump_eax: - ror rax, 24 - call os_print_char_hex - rol rax, 8 - call os_print_char_hex - rol rax, 16 -os_debug_dump_ax: - ror rax, 8 - call os_print_char_hex - rol rax, 8 -os_debug_dump_al: - call os_print_char_hex - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_copy -- Copy the contents of one string into another -; IN: RSI = source -; RDI = destination -; OUT: Nothing. All registers preserved -; Note: It is up to the programmer to ensure that there is sufficient space in the destination -os_string_copy: - push rsi - push rdi - push rax - -os_string_copy_more: - lodsb ; Load a character from the source string - stosb - cmp al, 0 ; If source string is empty, quit out - jne os_string_copy_more - - pop rax - pop rdi - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_compare -- See if two strings match -; IN: RSI = string one -; RDI = string two -; OUT: Carry flag set if same -os_string_compare: - push rsi - push rdi - push rbx - push rax - -os_string_compare_more: - mov al, [rsi] ; Store string contents - mov bl, [rdi] - - cmp al, 0 ; End of first string? - je os_string_compare_terminated - - cmp al, bl - jne os_string_compare_not_same - - inc rsi - inc rdi - jmp os_string_compare_more - -os_string_compare_not_same: - pop rax - pop rbx - pop rdi - pop rsi - clc - ret - -os_string_compare_terminated: - cmp bl, 0 ; End of second string? - jne os_string_compare_not_same - - pop rax - pop rbx - pop rdi - pop rsi - stc - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_string_uppercase -- Convert zero-terminated string to uppercase -; IN: RSI = string location -; OUT: Nothing. All registers preserved -os_string_uppercase: - push rsi - -os_string_uppercase_more: - cmp byte [rsi], 0x00 ; Zero-termination of string? - je os_string_uppercase_done ; If so, quit - - cmp byte [rsi], 97 ; In the uppercase A to Z range? - jl os_string_uppercase_noatoz - cmp byte [rsi], 122 - jg os_string_uppercase_noatoz - - sub byte [rsi], 0x20 ; If so, convert input char to uppercase - - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_noatoz: - inc rsi - jmp os_string_uppercase_more - -os_string_uppercase_done: - pop rsi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_dump_regs -- Dump the values on the registers to the screen (For debug purposes) -; IN/OUT: Nothing -os_dump_regs: - push r15 - push r14 - push r13 - push r12 - push r11 - push r10 - push r9 - push r8 - push rsp - push rbp - push rdi - push rsi - push rdx - push rcx - push rbx - push rax - - mov byte [os_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting - mov rcx, rsp - call os_print_newline - -os_dump_regs_again: - mov rsi, os_dump_reg_string00 - xor rax, rax - xor rbx, rbx - mov al, [os_dump_reg_stage] - mov bl, 5 ; each string is 5 bytes - mul bl ; ax = bl x al - add rsi, rax - call os_print_string ; Print the register name - - mov rdi, os_dump_reg_tstring - mov rsi, rdi - mov rax, [rcx] - add rcx, 8 - call os_int_to_hex_string ; Convert the register value to a hex string - call os_print_string ; Print the hex string - - add byte [os_dump_reg_stage], 1 - cmp byte [os_dump_reg_stage], 0x10 - jne os_dump_regs_again - - pop rax - pop rbx - pop rcx - pop rdx - pop rsi - pop rdi - pop rbp - pop rsp - pop r8 - pop r9 - pop r10 - pop r11 - pop r12 - pop r13 - pop r14 - pop r15 - -ret - -os_dump_reg_string00: db ' A:', 0 -os_dump_reg_string01: db ' B:', 0 -os_dump_reg_string02: db ' C:', 0 -os_dump_reg_string03: db ' D:', 0 -os_dump_reg_string04: db ' SI:', 0 -os_dump_reg_string05: db ' DI:', 0 -os_dump_reg_string06: db ' BP:', 0 -os_dump_reg_string07: db ' SP:', 0 -os_dump_reg_string08: db ' 8:', 0 -os_dump_reg_string09: db ' 9:', 0 -os_dump_reg_string0A: db ' 10:', 0 -os_dump_reg_string0B: db ' 11:', 0 -os_dump_reg_string0C: db ' 12:', 0 -os_dump_reg_string0D: db ' 13:', 0 -os_dump_reg_string0E: db ' 14:', 0 -os_dump_reg_string0F: db ' 15:', 0 - -os_dump_reg_tstring: times 17 db 0 -os_dump_reg_stage: db 0x00 -; ----------------------------------------------------------------------------- - - - -; ----------------------------------------------------------------------------- -; os_dump_mem -- Dump some memory content to the screen (For debug purposes) -; IN: RSI = memory to dump (512bytes) -;OUT: -os_dump_mem: - push rdx - push rcx - push rbx - push rax - - push rsi - - mov rcx, 512 -dumpit: - lodsb - call os_print_char_hex - dec rcx - cmp rcx, 0 - jne dumpit - - pop rsi - -; call os_print_newline - - pop rax - pop rbx - pop rcx - pop rdx -ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_int_to_string -- Convert a binary interger into an string string -; IN: RAX = binary integer -; RDI = location to store string -; OUT: RDI = pointer to end of string -; All other registers preserved -; Min return value is 0 and max return value is 18446744073709551615 so your -; string needs to be able to store at least 21 characters (20 for the number -; and 1 for the string terminator). -; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s -os_int_to_string: - push rdx - push rcx - push rbx - push rax - - mov rbx, 10 ; base of the decimal system - xor rcx, rcx ; number of digits generated -os_int_to_string_next_divide: - xor rdx, rdx ; RAX extended to (RDX,RAX) - div rbx ; divide by the number-base - push rdx ; save remainder on the stack - inc rcx ; and count this remainder - cmp rax, 0x0 ; was the quotient zero? - jne os_int_to_string_next_divide ; no, do another division -os_int_to_string_next_digit: - pop rdx ; else pop recent remainder - add dl, '0' ; and convert to a numeral - mov [rdi], dl ; store to memory-buffer - inc rdi - loop os_int_to_string_next_digit ; again for other remainders - mov al, 0x00 - stosb ; Store the null terminator at the end of the string - - pop rax - pop rbx - pop rcx - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_int_to_hex_string -- Convert an integer to a hex string -; IN: RAX = Integer value -; RDI = location to store string -; OUT: Nothing. All registers preserved -os_int_to_hex_string: - push rdi - push rdx - push rcx - push rbx - push rax - - mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes -os_int_to_hex_string_next_nibble: - rol rax, 4 ; next nibble into AL - mov bl, al ; copy nibble into BL - and rbx, 0x0F ; and convert to word - mov dl, [hextable + rbx] ; lookup ascii numeral - push rax - mov al, dl - stosb - pop rax - loop os_int_to_hex_string_next_nibble ; again for next nibble - xor rax, rax ; clear RAX to 0 - stosb ; Store AL to terminate string - - pop rax - pop rbx - pop rcx - pop rdx - pop rdi - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; os_serial_write -- Send a byte over the primary serial port -; IN: AL = Byte to send over serial port -; OUT: Nothing, all registers preserved -os_serial_send: - push rdx - push rax ; Save RAX since the serial line status check clobbers AL - - mov dx, 0x03FD ; Serial Line Status register -os_serial_send_wait: - in al, dx - bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag - jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte - - pop rax ; Get the byte back from the stack - mov dx, 0x03F8 ; Serial data register - out dx, al ; Send the byte - - pop rdx - ret -; ----------------------------------------------------------------------------- - - -; ----------------------------------------------------------------------------- -; create_gate -; rax = address of handler -; rdi = gate # to configure -create_gate: - push rdi - push rax - - shl rdi, 4 ; quickly multiply rdi by 16 - stosw ; store the low word (15..0) - shr rax, 16 - add rdi, 4 ; skip the gate marker - stosw ; store the high word (31..16) - shr rax, 16 - stosd ; store the high dword (63..32) - - pop rax - pop rdi -ret -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; System Calls +; ================================================================= + + +; ----------------------------------------------------------------------------- +; os_move_cursor -- Moves the virtual cursor in text mode +; IN: AH, AL = row, column +; OUT: Nothing. All registers preserved +os_move_cursor: + push rcx + push rbx + push rax + + mov [screen_cursor_x], ah + mov [screen_cursor_y], al + + and rax, 0x000000000000FFFF ; only keep the low 16 bits + ;calculate the new offset + mov cl, 80 + mul cl ; AX = AL * CL + xor rbx, rbx + mov bl, [screen_cursor_x] + add ax, bx + shl ax, 1 ; multiply by 2 + + add rax, 0x00000000000B8000 + mov [screen_cursor_offset], rax + + pop rax + pop rbx + pop rcx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_newline -- Reset cursor to start of next line and scroll if needed +; IN: Nothing +; OUT: Nothing, all registers perserved +os_print_newline: + push rax + + mov ah, 0 ; Set the cursor x value to 0 + mov al, [screen_cursor_y] ; Grab the cursor y value + cmp al, 24 ; Compare to see if we are on the last line + je os_print_newline_scroll ; If so then we need to scroll the sreen + + inc al ; If not then we can go ahead an increment the y value + jmp os_print_newline_done + +os_print_newline_scroll: + mov ax, 0x0000 ; If we have reached the end then wrap back to the front + +os_print_newline_done: + call os_move_cursor ; update the cursor + + pop rax + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_string -- Displays text +; IN: RSI = message location (zero-terminated string) +; OUT: Nothing, all registers perserved +os_print_string: + push rsi + push rax + + cld ; Clear the direction flag.. we want to increment through the string + +os_print_string_nextchar: + lodsb ; Get char from string and store in AL + cmp al, 0 ; Strings are Zero terminated. + je os_print_string_done ; If char is Zero then it is the end of the string + + cmp al, 13 ; Check if there was a newline character in the string + je os_print_string_newline ; If so then we print a new line + + call os_print_char + + jmp os_print_string_nextchar + +os_print_string_newline: + call os_print_newline + jmp os_print_string_nextchar + +os_print_string_done: + pop rax + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char -- Displays a char +; IN: AL = char to display +; OUT: Nothing. All registers preserved +os_print_char: + push rdi + + mov rdi, [screen_cursor_offset] + stosb + add qword [screen_cursor_offset], 2 ; Add 2 (1 byte for char and 1 byte for attribute) + + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_print_char_hex -- Displays a char in hex mode +; IN: AL = char to display +; OUT: Nothing. All registers preserved +os_print_char_hex: + push rbx + push rax + + mov rbx, hextable + + push rax ; save rax for the next part + shr al, 4 ; we want to work on the high part so shift right by 4 bits + xlatb + call os_print_char + + pop rax + and al, 0x0f ; we want to work on the low part so clear the high part + xlatb + call os_print_char + + pop rax + pop rbx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_debug_dump_(rax|eax|ax|al) -- Dump content of RAX, EAX, AX, or AL to the screen in hex format +; IN: RAX = content to dump +; OUT: Nothing, all registers preserved +os_debug_dump_rax: + ror rax, 56 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 32 +os_debug_dump_eax: + ror rax, 24 + call os_print_char_hex + rol rax, 8 + call os_print_char_hex + rol rax, 16 +os_debug_dump_ax: + ror rax, 8 + call os_print_char_hex + rol rax, 8 +os_debug_dump_al: + call os_print_char_hex + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_copy -- Copy the contents of one string into another +; IN: RSI = source +; RDI = destination +; OUT: Nothing. All registers preserved +; Note: It is up to the programmer to ensure that there is sufficient space in the destination +os_string_copy: + push rsi + push rdi + push rax + +os_string_copy_more: + lodsb ; Load a character from the source string + stosb + cmp al, 0 ; If source string is empty, quit out + jne os_string_copy_more + + pop rax + pop rdi + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_compare -- See if two strings match +; IN: RSI = string one +; RDI = string two +; OUT: Carry flag set if same +os_string_compare: + push rsi + push rdi + push rbx + push rax + +os_string_compare_more: + mov al, [rsi] ; Store string contents + mov bl, [rdi] + + cmp al, 0 ; End of first string? + je os_string_compare_terminated + + cmp al, bl + jne os_string_compare_not_same + + inc rsi + inc rdi + jmp os_string_compare_more + +os_string_compare_not_same: + pop rax + pop rbx + pop rdi + pop rsi + clc + ret + +os_string_compare_terminated: + cmp bl, 0 ; End of second string? + jne os_string_compare_not_same + + pop rax + pop rbx + pop rdi + pop rsi + stc + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_string_uppercase -- Convert zero-terminated string to uppercase +; IN: RSI = string location +; OUT: Nothing. All registers preserved +os_string_uppercase: + push rsi + +os_string_uppercase_more: + cmp byte [rsi], 0x00 ; Zero-termination of string? + je os_string_uppercase_done ; If so, quit + + cmp byte [rsi], 97 ; In the uppercase A to Z range? + jl os_string_uppercase_noatoz + cmp byte [rsi], 122 + jg os_string_uppercase_noatoz + + sub byte [rsi], 0x20 ; If so, convert input char to uppercase + + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_noatoz: + inc rsi + jmp os_string_uppercase_more + +os_string_uppercase_done: + pop rsi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_dump_regs -- Dump the values on the registers to the screen (For debug purposes) +; IN/OUT: Nothing +os_dump_regs: + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rsp + push rbp + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + + mov byte [os_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting + mov rcx, rsp + call os_print_newline + +os_dump_regs_again: + mov rsi, os_dump_reg_string00 + xor rax, rax + xor rbx, rbx + mov al, [os_dump_reg_stage] + mov bl, 5 ; each string is 5 bytes + mul bl ; ax = bl x al + add rsi, rax + call os_print_string ; Print the register name + + mov rdi, os_dump_reg_tstring + mov rsi, rdi + mov rax, [rcx] + add rcx, 8 + call os_int_to_hex_string ; Convert the register value to a hex string + call os_print_string ; Print the hex string + + add byte [os_dump_reg_stage], 1 + cmp byte [os_dump_reg_stage], 0x10 + jne os_dump_regs_again + + pop rax + pop rbx + pop rcx + pop rdx + pop rsi + pop rdi + pop rbp + pop rsp + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + +ret + +os_dump_reg_string00: db ' A:', 0 +os_dump_reg_string01: db ' B:', 0 +os_dump_reg_string02: db ' C:', 0 +os_dump_reg_string03: db ' D:', 0 +os_dump_reg_string04: db ' SI:', 0 +os_dump_reg_string05: db ' DI:', 0 +os_dump_reg_string06: db ' BP:', 0 +os_dump_reg_string07: db ' SP:', 0 +os_dump_reg_string08: db ' 8:', 0 +os_dump_reg_string09: db ' 9:', 0 +os_dump_reg_string0A: db ' 10:', 0 +os_dump_reg_string0B: db ' 11:', 0 +os_dump_reg_string0C: db ' 12:', 0 +os_dump_reg_string0D: db ' 13:', 0 +os_dump_reg_string0E: db ' 14:', 0 +os_dump_reg_string0F: db ' 15:', 0 + +os_dump_reg_tstring: times 17 db 0 +os_dump_reg_stage: db 0x00 +; ----------------------------------------------------------------------------- + + + +; ----------------------------------------------------------------------------- +; os_dump_mem -- Dump some memory content to the screen (For debug purposes) +; IN: RSI = memory to dump (512bytes) +;OUT: +os_dump_mem: + push rdx + push rcx + push rbx + push rax + + push rsi + + mov rcx, 512 +dumpit: + lodsb + call os_print_char_hex + dec rcx + cmp rcx, 0 + jne dumpit + + pop rsi + +; call os_print_newline + + pop rax + pop rbx + pop rcx + pop rdx +ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_int_to_string -- Convert a binary interger into an string string +; IN: RAX = binary integer +; RDI = location to store string +; OUT: RDI = pointer to end of string +; All other registers preserved +; Min return value is 0 and max return value is 18446744073709551615 so your +; string needs to be able to store at least 21 characters (20 for the number +; and 1 for the string terminator). +; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s +os_int_to_string: + push rdx + push rcx + push rbx + push rax + + mov rbx, 10 ; base of the decimal system + xor rcx, rcx ; number of digits generated +os_int_to_string_next_divide: + xor rdx, rdx ; RAX extended to (RDX,RAX) + div rbx ; divide by the number-base + push rdx ; save remainder on the stack + inc rcx ; and count this remainder + cmp rax, 0x0 ; was the quotient zero? + jne os_int_to_string_next_divide ; no, do another division +os_int_to_string_next_digit: + pop rdx ; else pop recent remainder + add dl, '0' ; and convert to a numeral + mov [rdi], dl ; store to memory-buffer + inc rdi + loop os_int_to_string_next_digit ; again for other remainders + mov al, 0x00 + stosb ; Store the null terminator at the end of the string + + pop rax + pop rbx + pop rcx + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_int_to_hex_string -- Convert an integer to a hex string +; IN: RAX = Integer value +; RDI = location to store string +; OUT: Nothing. All registers preserved +os_int_to_hex_string: + push rdi + push rdx + push rcx + push rbx + push rax + + mov rcx, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes +os_int_to_hex_string_next_nibble: + rol rax, 4 ; next nibble into AL + mov bl, al ; copy nibble into BL + and rbx, 0x0F ; and convert to word + mov dl, [hextable + rbx] ; lookup ascii numeral + push rax + mov al, dl + stosb + pop rax + loop os_int_to_hex_string_next_nibble ; again for next nibble + xor rax, rax ; clear RAX to 0 + stosb ; Store AL to terminate string + + pop rax + pop rbx + pop rcx + pop rdx + pop rdi + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; os_serial_write -- Send a byte over the primary serial port +; IN: AL = Byte to send over serial port +; OUT: Nothing, all registers preserved +os_serial_send: + push rdx + push rax ; Save RAX since the serial line status check clobbers AL + + mov dx, 0x03FD ; Serial Line Status register +os_serial_send_wait: + in al, dx + bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag + jnc os_serial_send_wait ; If the bit is not set then the queue isn't ready for another byte + + pop rax ; Get the byte back from the stack + mov dx, 0x03F8 ; Serial data register + out dx, al ; Send the byte + + pop rdx + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; create_gate +; rax = address of handler +; rdi = gate # to configure +create_gate: + push rdi + push rax + + shl rdi, 4 ; quickly multiply rdi by 16 + stosw ; store the low word (15..0) + shr rax, 16 + add rdi, 4 ; skip the gate marker + stosw ; store the high word (31..16) + shr rax, 16 + stosd ; store the high dword (63..32) + + pop rax + pop rdi +ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF diff --git a/amd64/pure64-0.5.0/src/sysvar.asm b/amd64/pure64-0.5.0/src/sysvar.asm index cca3a871..7544603c 100644 --- a/amd64/pure64-0.5.0/src/sysvar.asm +++ b/amd64/pure64-0.5.0/src/sysvar.asm @@ -1,166 +1,166 @@ -; ============================================================================= -; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT -; -; System Variables -; ============================================================================= - - -;CONFIG -cfg_smpinit: db 1 ; By default SMP is enabled. Set to 0 to disable. -cfg_vesa: db 0 ; By default VESA is disabled. Set to 1 to enable. -cfg_default: db 0 ; By default we don't need a config file so set to 0. If a config file is found set to 1. -cfg_e820: db 1 ; By default E820 should be present. Pure64 will set this to 0 if not found/usable. -cfg_mbr: db 0 ; Did we boot off of a disk with a proper MBR - -; Memory locations -E820Map: equ 0x0000000000004000 -InfoMap: equ 0x0000000000005000 -SystemVariables: equ 0x0000000000005A00 -VBEModeInfoBlock equ 0x0000000000005C00 -hdbuffer: equ 0x0000000000070000 ; 32768 bytes = 0x6000 -> 0xDFFF VERIFY THIS!!! -hdbuffer1: equ 0x000000000007E000 ; 512 bytes = 0xE000 -> 0xE1FF VERIFY THIS!!! - -; DQ - Starting at offset 0, increments by 0x8 -os_ACPITableAddress: equ SystemVariables + 0x00 -screen_cursor_offset: equ SystemVariables + 0x08 -hd1_maxlba: equ SystemVariables + 0x10 -os_Counter_Timer: equ SystemVariables + 0x18 -os_Counter_RTC: equ SystemVariables + 0x20 -os_LocalAPICAddress: equ SystemVariables + 0x28 -os_IOAPICAddress: equ SystemVariables + 0x30 - -; DD - Starting at offset 128, increments by 4 -hd1_size: equ SystemVariables + 128 -fat16_FatStart: equ SystemVariables + 132 -fat16_TotalSectors: equ SystemVariables + 136 -fat16_DataStart: equ SystemVariables + 140 -fat16_RootStart: equ SystemVariables + 144 -fat16_PartitionOffset: equ SystemVariables + 148 -sata_base: equ SystemVariables + 152 -os_BSP: equ SystemVariables + 156 - -; DW - Starting at offset 256, increments by 2 -cpu_speed: equ SystemVariables + 256 -cpu_activated: equ SystemVariables + 258 -cpu_detected: equ SystemVariables + 260 -mem_amount: equ SystemVariables + 262 -fat16_BytesPerSector: equ SystemVariables + 264 -fat16_ReservedSectors: equ SystemVariables + 266 -fat16_SectorsPerFat: equ SystemVariables + 268 -fat16_RootDirEnts: equ SystemVariables + 270 -ata_base: equ SystemVariables + 272 - -; DB - Starting at offset 384, increments by 1 -hd1_enable: equ SystemVariables + 384 -hd1_lba48: equ SystemVariables + 385 -screen_cursor_x: equ SystemVariables + 386 -screen_cursor_y: equ SystemVariables + 387 -fat16_SectorsPerCluster: equ SystemVariables + 388 -fat16_Fats: equ SystemVariables + 389 -memtempstring: equ SystemVariables + 390 -speedtempstring: equ SystemVariables + 400 -cpu_amount_string: equ SystemVariables + 410 -hdtempstring: equ SystemVariables + 420 -os_key: equ SystemVariables + 421 -os_IOAPICCount: equ SystemVariables + 424 - -;MISC -screen_cols: db 80 -screen_rows: db 25 -hextable: db '0123456789ABCDEF' - -;STRINGS -pure64: db 'Pure64 - ', 0 -kernelerror: db 'ERROR: Software not found.', 0 -kernelname: db 'KERNEL64SYS', 0 -configname: db 'PURE64 CFG', 0 -msg_done: db ' Done', 0 -msg_CPU: db '[CPU: ', 0 -msg_mhz: db 'MHz x', 0 -msg_MEM: db '] [MEM: ', 0 -msg_mb: db ' MiB]', 0 -msg_HDD: db ' [HDD: ', 0 -msg_loadingkernel: db 'Loading software', 0;...', 0 -msg_startingkernel: db 'Starting software.', 0 -msg_noconfig: db '(default config)', 0 -no64msg: db 'ERROR: This computer does not support 64-Bit mode. Press any key to reboot.', 0 -initStartupMsg: db 'Pure64 v0.5.0 - http://www.returninfinity.com', 13, 10, 13, 10, 'Initializing system... ', 0 -msg_date: db '2011/12/19', 0 -hdd_setup_no_drive: db 'No HDD detected', 0 -hdd_setup_read_error: db 'Error reading HDD', 0 - -; Mandatory information for all VBE revisions -VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes -VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes -VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes -VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB -VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB -VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment -VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment -VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function -VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line -; Mandatory information for VBE 1.2 and above -VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters -VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters -VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels -VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels -VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes -VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel -VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks -VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type -VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB -VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages -VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) -; Direct Color fields (required for direct/6 and YUV/7 memory models) -VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits -VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask -VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits -VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask -VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits -VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask -VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits -VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask -VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes -; Mandatory information for VBE 2.0 and above -VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer -VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 -VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 -; Mandatory information for VBE 3.0 and above -;VBEModeInfoBlock.LinBytesPerScanLine dw 0 ; bytes per scan line for linear modes -;VBEModeInfoBlock.BnkNumberOfImagePages db 0 ; number of images for banked modes -;VBEModeInfoBlock.LinNumberOfImagePages db 0 ; number of images for linear modes -;VBEModeInfoBlock.LinRedMaskSize db 0 ; size of direct color red mask (linear modes) -;VBEModeInfoBlock.LinRedFieldPosition db 0 ; bit position of lsb of red mask (linear modes) -;VBEModeInfoBlock.LinGreenMaskSize db 0 ; size of direct color green mask (linear modes) -;VBEModeInfoBlock.LinGreenFieldPosition db 0 ; bit position of lsb of green mask (linear modes) -;VBEModeInfoBlock.LinBlueMaskSize db 0 ; size of direct color blue mask (linear modes) -;VBEModeInfoBlock.LinBlueFieldPosition db 0 ; bit position of lsb of blue mask (linear modes) -;VBEModeInfoBlock.LinRsvdMaskSize db 0 ; size of direct color reserved mask (linear modes) -;VBEModeInfoBlock.LinRsvdFieldPosition db 0 ; bit position of lsb of reserved mask (linear modes) -;VBEModeInfoBlock.MaxPixelClock dd 0 ; maximum pixel clock (in Hz) for graphics mode - - -; ----------------------------------------------------------------------------- -align 16 -GDTR64: ; Global Descriptors Table Register - dw gdt64_end - gdt64 - 1 ; limit of GDT (size minus one) - dq 0x0000000000001000 ; linear address of GDT - -gdt64: ; This structure is copied to 0x0000000000001000 -SYS64_NULL_SEL equ $-gdt64 ; Null Segment - dq 0x0000000000000000 -SYS64_CODE_SEL equ $-gdt64 ; Code segment, read/execute, nonconforming - dq 0x0020980000000000 ; 0x00209A0000000000 -SYS64_DATA_SEL equ $-gdt64 ; Data segment, read/write, expand down - dq 0x0000900000000000 ; 0x0020920000000000 -gdt64_end: - -IDTR64: ; Interrupt Descriptor Table Register - dw 256*16-1 ; limit of IDT (size minus one) (4096 bytes - 1) - dq 0x0000000000000000 ; linear address of IDT -; ----------------------------------------------------------------------------- - - -; ============================================================================= -; EOF +; ============================================================================= +; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT +; +; System Variables +; ============================================================================= + + +;CONFIG +cfg_smpinit: db 1 ; By default SMP is enabled. Set to 0 to disable. +cfg_vesa: db 0 ; By default VESA is disabled. Set to 1 to enable. +cfg_default: db 0 ; By default we don't need a config file so set to 0. If a config file is found set to 1. +cfg_e820: db 1 ; By default E820 should be present. Pure64 will set this to 0 if not found/usable. +cfg_mbr: db 0 ; Did we boot off of a disk with a proper MBR + +; Memory locations +E820Map: equ 0x0000000000004000 +InfoMap: equ 0x0000000000005000 +SystemVariables: equ 0x0000000000005A00 +VBEModeInfoBlock equ 0x0000000000005C00 +hdbuffer: equ 0x0000000000070000 ; 32768 bytes = 0x6000 -> 0xDFFF VERIFY THIS!!! +hdbuffer1: equ 0x000000000007E000 ; 512 bytes = 0xE000 -> 0xE1FF VERIFY THIS!!! + +; DQ - Starting at offset 0, increments by 0x8 +os_ACPITableAddress: equ SystemVariables + 0x00 +screen_cursor_offset: equ SystemVariables + 0x08 +hd1_maxlba: equ SystemVariables + 0x10 +os_Counter_Timer: equ SystemVariables + 0x18 +os_Counter_RTC: equ SystemVariables + 0x20 +os_LocalAPICAddress: equ SystemVariables + 0x28 +os_IOAPICAddress: equ SystemVariables + 0x30 + +; DD - Starting at offset 128, increments by 4 +hd1_size: equ SystemVariables + 128 +fat16_FatStart: equ SystemVariables + 132 +fat16_TotalSectors: equ SystemVariables + 136 +fat16_DataStart: equ SystemVariables + 140 +fat16_RootStart: equ SystemVariables + 144 +fat16_PartitionOffset: equ SystemVariables + 148 +sata_base: equ SystemVariables + 152 +os_BSP: equ SystemVariables + 156 + +; DW - Starting at offset 256, increments by 2 +cpu_speed: equ SystemVariables + 256 +cpu_activated: equ SystemVariables + 258 +cpu_detected: equ SystemVariables + 260 +mem_amount: equ SystemVariables + 262 +fat16_BytesPerSector: equ SystemVariables + 264 +fat16_ReservedSectors: equ SystemVariables + 266 +fat16_SectorsPerFat: equ SystemVariables + 268 +fat16_RootDirEnts: equ SystemVariables + 270 +ata_base: equ SystemVariables + 272 + +; DB - Starting at offset 384, increments by 1 +hd1_enable: equ SystemVariables + 384 +hd1_lba48: equ SystemVariables + 385 +screen_cursor_x: equ SystemVariables + 386 +screen_cursor_y: equ SystemVariables + 387 +fat16_SectorsPerCluster: equ SystemVariables + 388 +fat16_Fats: equ SystemVariables + 389 +memtempstring: equ SystemVariables + 390 +speedtempstring: equ SystemVariables + 400 +cpu_amount_string: equ SystemVariables + 410 +hdtempstring: equ SystemVariables + 420 +os_key: equ SystemVariables + 421 +os_IOAPICCount: equ SystemVariables + 424 + +;MISC +screen_cols: db 80 +screen_rows: db 25 +hextable: db '0123456789ABCDEF' + +;STRINGS +pure64: db 'Pure64 - ', 0 +kernelerror: db 'ERROR: Software not found.', 0 +kernelname: db 'KERNEL64SYS', 0 +configname: db 'PURE64 CFG', 0 +msg_done: db ' Done', 0 +msg_CPU: db '[CPU: ', 0 +msg_mhz: db 'MHz x', 0 +msg_MEM: db '] [MEM: ', 0 +msg_mb: db ' MiB]', 0 +msg_HDD: db ' [HDD: ', 0 +msg_loadingkernel: db 'Loading software', 0;...', 0 +msg_startingkernel: db 'Starting software.', 0 +msg_noconfig: db '(default config)', 0 +no64msg: db 'ERROR: This computer does not support 64-Bit mode. Press any key to reboot.', 0 +initStartupMsg: db 'Pure64 v0.5.0 - http://www.returninfinity.com', 13, 10, 13, 10, 'Initializing system... ', 0 +msg_date: db '2011/12/19', 0 +hdd_setup_no_drive: db 'No HDD detected', 0 +hdd_setup_read_error: db 'Error reading HDD', 0 + +; Mandatory information for all VBE revisions +VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes +VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes +VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes +VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB +VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB +VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment +VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment +VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function +VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line +; Mandatory information for VBE 1.2 and above +VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters +VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters +VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels +VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels +VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes +VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel +VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks +VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type +VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB +VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages +VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) +; Direct Color fields (required for direct/6 and YUV/7 memory models) +VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits +VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask +VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits +VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask +VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits +VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask +VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits +VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask +VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes +; Mandatory information for VBE 2.0 and above +VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer +VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 +VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 +; Mandatory information for VBE 3.0 and above +;VBEModeInfoBlock.LinBytesPerScanLine dw 0 ; bytes per scan line for linear modes +;VBEModeInfoBlock.BnkNumberOfImagePages db 0 ; number of images for banked modes +;VBEModeInfoBlock.LinNumberOfImagePages db 0 ; number of images for linear modes +;VBEModeInfoBlock.LinRedMaskSize db 0 ; size of direct color red mask (linear modes) +;VBEModeInfoBlock.LinRedFieldPosition db 0 ; bit position of lsb of red mask (linear modes) +;VBEModeInfoBlock.LinGreenMaskSize db 0 ; size of direct color green mask (linear modes) +;VBEModeInfoBlock.LinGreenFieldPosition db 0 ; bit position of lsb of green mask (linear modes) +;VBEModeInfoBlock.LinBlueMaskSize db 0 ; size of direct color blue mask (linear modes) +;VBEModeInfoBlock.LinBlueFieldPosition db 0 ; bit position of lsb of blue mask (linear modes) +;VBEModeInfoBlock.LinRsvdMaskSize db 0 ; size of direct color reserved mask (linear modes) +;VBEModeInfoBlock.LinRsvdFieldPosition db 0 ; bit position of lsb of reserved mask (linear modes) +;VBEModeInfoBlock.MaxPixelClock dd 0 ; maximum pixel clock (in Hz) for graphics mode + + +; ----------------------------------------------------------------------------- +align 16 +GDTR64: ; Global Descriptors Table Register + dw gdt64_end - gdt64 - 1 ; limit of GDT (size minus one) + dq 0x0000000000001000 ; linear address of GDT + +gdt64: ; This structure is copied to 0x0000000000001000 +SYS64_NULL_SEL equ $-gdt64 ; Null Segment + dq 0x0000000000000000 +SYS64_CODE_SEL equ $-gdt64 ; Code segment, read/execute, nonconforming + dq 0x0020980000000000 ; 0x00209A0000000000 +SYS64_DATA_SEL equ $-gdt64 ; Data segment, read/write, expand down + dq 0x0000900000000000 ; 0x0020920000000000 +gdt64_end: + +IDTR64: ; Interrupt Descriptor Table Register + dw 256*16-1 ; limit of IDT (size minus one) (4096 bytes - 1) + dq 0x0000000000000000 ; linear address of IDT +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF -- 2.11.4.GIT