This documentation details the system calls provided by BareMetal and how applications can use them.
The BareMetal OS kernel includes system calls for outputting to the screen, taking keyboard input, manipulating strings, producing PC speaker sounds, math operations and disk I/O. You can get a quick reference to the registers that these calls take and pass back by looking at bmdev.asm, and see practical use of the calls in the programs/ directory.
Here we have a detailed API explanation with examples. You can see the full source code behind these system calls in the os/syscalls/ directory in BareMetal OS. Each aspect of the API below is contained within their respective assembly source files.
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
Example:
call os_input_key_check jnc nokeypressed ; If carry is not set than no key was pressed call os_print_char ; Print the character that was pressed ... nokeypressed:
Waits for keypress and returns key
IN: Nothing OUT: AL = key pressed All other registers preserved
Example:
call os_input_key_wait cmp al, 'q' ; Check if Q key was hit je gottheletterq cmp al, 'w' ; Check if W key was hit je gottheletterw ... gottheletterq:
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
Make sure that RCX is set to a sane value as it will stop memory from being corrupted.
Example:
mov rdi, inputstring mov rcx, 10 call os_input_string ... inputstring: times 11 db 0
Moves cursor in text mode
IN: AH = row AL = column OUT: All registers preserved
In normal text mode the screen is 80x25. First row and column are both 0. Max row is 24 and max column is 79.
Example:
mov al, 5 mov ah, 5 call os_move_cursor ; Move cursor to (5,5) ... mov ax, 0x0505 call os_move_cursor ; Same as above but we set AL and AH at the same time
Increment the hardware cursor by one
IN: Nothing OUT: All registers preserved
This function will automatically call os_scroll_screen if required.
Example:
call os_inc_cursor
Decrement the hardware cursor by one
IN: Nothing OUT: All registers preserved
Example:
call os_dec_cursor
Reset cursor to start of next line and scroll if needed
IN: Nothing OUT: All registers perserved
Example:
call os_print_newline
Displays text
IN: RSI = message location (zero-terminated string) OUT: All registers perserved
This function defaults to Light Gray text on a Black background
Example:
mov rsi, teststring call os_print_string ... teststring: db "This is a test string.", 0
Displays text with color
IN: RSI = message location (zero-terminated string) BL = color OUT: All registers perserved
The high 4 bits of BL is for the background color and the low 4 bits are for the text color. See the Color Chart in the Appendix.
Example:
mov rsi, colorteststring mov bl, 0x04 ; Black background, Red text call os_print_string_with_color ... colorteststring: db "This is a test string in color!", 0
Displays a char
IN: AL = char to display OUT: All registers perserved
This function defaults to Light Gray text on a Black background
Example:
mov al, 'B' call os_print_char
Displays a char with color
IN: AL = char to display BL = color OUT: All registers perserved
The high 4 bits of BL is for the background color and the low 4 bits are for the text color. See the Color Chart in the Appendix.
Example:
mov al, 'B' mov bl, 0x4F ; Red background, White text call os_print_char_with_color
Displays a char in hex mode
IN: AL = char to display OUT: All registers perserved
Example:
mov al, 0x5f call os_print_char_hex ; "5F" will be printed mov al, 154 call os_print_char_hex ; "9A" will be printed
Scrolls the screen up by one line
IN: Nothing OUT: All registers perserved
Example:
call os_scroll_screen
Turns off cursor in text mode
IN: Nothing OUT: All registers perserved
Example:
call os_hide_cursor
Turns on cursor in text mode
IN: Nothing OUT: All registers perserved
Example:
call os_show_cursor
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
Example:
mov rsi, testfile ; File name mov rdi, 0x1000000 ; Read file to this memory address call os_file_read jnc fileok ; If carry is clear then no error occured ... error handling here ... fileok: ... work with file ... testfile: db "test.txt", 0
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
Example:
mov rdi, testfile ; File name mov rsi, 0x100A000 ; Data to write is at this memory address mov rcx, 50 ; Write 50 bytes call os_file_write jnc fileok ; If carry is clear then no error occured ... error handling here ... fileok: ... continue on ... testfile: db "test.txt", 0
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
Example:
mov rsi, testfile ; Name of file to delete call os_file_delete ... testfile: db "deleteme.txt", 0
Generate a list of files on disk
IN: RDI = location to store list OUT: RDI = pointer to end of list
Example:
mov rdi, temp_string ; Our temporary string mov rsi, rdi ; Point RSI to the start of the string call os_file_get_list call os_print_string ; Print the directory listing
Delay by X
IN: RCX = Time in eights of a second OUT: All registers preserved
A value of 8 in RCX 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.
Example:
mov rcx, 16 call os_delay ; Pause for 2 seconds
Send a byte over the primary serial port
IN: AL = Byte to send over serial port OUT: All registers preserved
Example:
mov al, 'H' call os_serial_send
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
Example:
call os_serial_recv jnc gotnothing
Resets a CPU/Core
IN: AL = CPU APIC ID # OUT: Nothing. All registers preserved.
This function resets an AP to run the ap_clear kernel code.
Example:
mov al, 0x01 ; Select CPU Core with APIC ID 1 call os_smp_reset ; Reset the CPU Core
Returns the APIC ID of the CPU that ran this function
IN: Nothing OUT: RAX = CPU's APIC ID number All other registers perserved
Example:
call os_smp_get_id ; APIC ID returned in AL
Add a workload to the processing queue
IN: RAX = Code to execute OUT: Carry set on failure (Queue full) All other registers perserved
This function adds a workload to the processing queue of the system. All available CPU Cores actively poll this queue and will automatically execute os_smp_dequeue.
Example:
mov rax, ap_print_id ; Our code to run on all CPUs mov rcx, 64 ; Number of instances to spawn spawn: call os_smp_enqueue sub rcx, 1 cmp rcx, 0 jne spawn
Dequeue a workload from the processing queue
IN: Nothing OUT: RAX = Code to execute (Set to 0 if queue was empty) All other registers perserved
This function is automatically called by each CPU Core that is in the Idle Kernel loop. It is also useful for the BSP to call this function after adding the initial workloads to the queue.
Example:
bsp: call os_smp_dequeue ; Try to dequeue a workload jc emptyqueue ; If carry is set then the queue is empty call rax ; Otherwise run the workload call os_smp_queuelen ; Check the length of the queue cmp rax, 0 jne bsp ; If it is not empty try to do another workload
Call the code address stored in RAX
IN: RAX = Address of code to execute OUT: Nothing
Needed for compatibilty with C.
Example:
call os_smp_dequeue call os_smp_run ; You could also use "call rax" here
Returns the number of items in the processing queue
IN: Nothing OUT: RAX = number of items in processing queue
os_smp_dequeue makes use of this function.
Example:
call os_smp_queuelen ; Check the length of the queue cmp rax, 0 je queue_empty
IN: Nothing OUT: All registers preserved
Use this function to wait until all available CPU Cores are finished processing.
Example:
call os_smp_wait ; Wait for all other processors to finish
IN: RAX = Address of lock variable OUT: Nothing. All registers preserved.
Attempt to lock a mutex. This function will block until the mutex can be locked.
Example:
call os_smp_lock ; Attempt to lock the mutex
IN: RAX = Address of lock variable OUT: Nothing. All registers preserved.
Unlock a mutex.
Example:
call os_smp_unlock ; Unlock the mutex
Generate a tone on the PC speaker
IN: RAX = note frequency OUT: All registers preserved
Call os_speaker_off to stop the tone
Example:
mov rax, 4000 ; A 'C' note call os_speaker_tone
Turn off PC speaker
IN: Nothing OUT: All registers preserved
Example:
call os_speaker_off
Create a standard OS beep
IN: Nothing OUT: All registers preserved
Example:
call os_speaker_beep
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
The minimum return value is 0 and maximum return value is 18446744073709551615. The destination string needs to be able to store at least 21 characters (20 for the digits and 1 for the string terminator).
Example:
mov rax, 0xFFFFFFFFFFFFFFFF mov rdi, teststring mov rsi, rdi ; Set RSI for print_string call call os_int_to_string call os_print_string ; "18446744073709551615" will be printed ... teststring: times 21 db 0 ; Space for a 20 character string
Convert a string into a binary interger
IN: RSI = location of string OUT: RAX = integer value All other registers preserved
Example:
mov rsi, teststring call os_string_to_int ; RAX will be set to the decimal value 460341242 ... teststring: db "460341242", 0
Convert an integer to a hex string
IN: RAX = Integer value RDI = Location to store string OUT: All registers preserved
Example:
mov rax, 3735928559 mov rdi, teststring mov rsi, rdi ; Set RSI for print_string call call os_int_to_hex_string call os_print_string ; "DEADBEEF" will be printed ... teststring: times 21 db 0 ; Space for a 20 character string
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
Example:
mov rsi, teststring call os_hex_string_to_int ; RAX will be set to 4277006349 ... teststring: db "FEEDF00D", 0
Return length of a string
IN: RSI = string location OUT: RCX = length (not including the NULL terminator) All other registers preserved
Example:
mov rsi, teststring call os_string_length ; RCX will be set to 45 ... teststring: db "This is a test of the string length function!", 0
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
Example:
mov rsi, teststring mov al, 'a' call os_find_char_in_string ; RAX will be set to 26 (The 'a' in 'lowercase' is the first instance) ... teststring: db "Where is the first lowercase 'a'?", 0
Change all instances of a character in a string
IN: RSI = string location AL = character to replace BL = replacement character OUT: All registers preserved
Example:
mov rsi, teststring mov al, 'e' mov bl, 'A' call os_string_charchange call os_print_string ; "PlAasA rAplacA thA lowArcasA lAttAr E's." will be printed ... teststring: db "Please replace the lowercase letter E's.", 0
Copy the contents of one string into another
IN: RSI = source RDI = destination OUT: All registers preserved
It is up to the programmer to ensure that there is sufficient space in the destination!
Example:
mov rsi, srcstring mov rdi, deststring call os_string_copy mov rsi, deststring call os_print_string ; "Copy this string!" will be printed ... srcstring: "Copy this string!", 0 deststring: times 21 db 0 ; Space for a 20 character string
Chop string down to specified number of characters
IN: RSI = string location RAX = number of characters OUT: All registers preserved
Example:
mov rsi, teststring mov rax, 5 call os_string_truncate call os_print_string ; "AaBbC" will be printed on screen ... teststring: db "AaBbCcDd 123", 0
Join two strings into a third string
IN: RAX = string one RBX = string two RDI = destination string OUT: All registers preserved
Example:
mov rax, string1 mov rbx, string2 mov rdi, deststring call os_string_join mov rsi, deststring call os_print_string ; "AAAAABBBBB" will be printed ... string1: "AAAAA", 0 string2: "BBBBB", 0 deststring: times 41 db 0 ; Space for a 40 character string
Strip leading and trailing spaces from a string
IN: RSI = string location OUT: All registers preserved
Example:
mov rsi, teststring call os_string_chomp call os_print_string ; "This is a test." will be printed ... teststring: db " This is a test. ", 0
Removes specified character from a string
IN: RSI = string location AL = character to remove OUT: All registers preserved
Example:
mov rsi, teststring mov al, 'i' call os_string_strip call os_print_string ; "Ths s a test of the strng_strp functon." will be printed ... teststring: db "This is a test of the string_strip function.", 0
See if two strings match
IN: RSI = string one RDI = string two OUT: Carry flag set if same
Example:
mov rsi, string1 mov rdi, string2 call os_string_compare jc string_equal ; Falls through to here if strings are not equal ... string1: "AAAAA", 0 string2: "BBBBB", 0
Convert zero-terminated string to uppercase
IN: RSI = string location OUT: All registers preserved
Example:
mov rsi, teststring call os_string_uppercase call os_print_string ; "AABBCCDD 123" will be printed ... teststring: db "AaBbCcDd 123", 0
Convert zero-terminated string to lowercase
IN: RSI = string location OUT: All registers preserved
Example:
mov rsi, teststring call os_string_lowercase call os_print_string ; "aabbccdd 123" will be printed ... teststring: db "AaBbCcDd 123", 0
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
Example:
mov rdi, temp_string call os_get_time_string ; temp_string will be set to "16:45:20" if that was the current time ... temp_string: times 41 db 0 ; Space for a 40 character 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
Example:
mov rdi, temp_string call os_get_date_string ; temp_string will be set to "2010/04/27" if that was the current date ... temp_string: times 41 db 0 ; Space for a 40 character string
Check if character is a digit
IN: AL = ASCII char OUT: EQ flag set if numeric
JE (Jump if Equal) or JNE (Jump if Not Equal) can be used after this function is called.
Example:
mov al, '6' call os_is_digit je itsanumber ; Jump if it was a digit, else fall through to next instruction mov rbx, 2134
Check if character is a letter
IN: AL = ASCII char OUT: EQ flag set if alpha
JE (Jump if Equal) or JNE (Jump if Not Equal) can be used after this function is called.
Example:
mov al, 'j' call os_is_alpha jne notaletter ; Jump if it was not a letter, else fall through to next instruction mov rbx, 2134
Parse a string into individual words
IN: RSI = Address of string OUT: RCX = word count
This function will remove extra whitespace in the source string and also return the word count. "This is a test. " will update to "This is a test."
Example:
mov rsi, teststring call os_string_parse call os_print_string ; "This is a test." will be printed. Also RCX will be set to 4 ... teststring: db "This is a test. ", 0
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
Example:
mov rsi, teststring1 mov rdi, teststring2 call os_string_append mov rsi, teststring2 call os_print_string ; "Test2Test1" will be printed. ... teststring1: db "Test1", 0 teststring2: db "Test2", 0
Dump the values on the registers to the screen
IN: Nothing OUT: Nothing, all registers preserved
Example:
call os_debug_dump_reg
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
Example:
mov rsi, 0x1000 ; Dump starting at this memory address mov rcx, 100 ; Display 100 bytes call os_debug_dump_mem
Dump content of RAX, EAX, AX, or AL to the screen in hex format
IN: RAX|EAX|AX|AL = content to dump OUT: Nothing, all registers preserved
Example:
call os_debug_dump_rax ; Dump the entire 64-bit register call os_debug_dump_eax ; Dump only the lower 32-bits call os_debug_dump_ax ; Dump only the lower 16-bits call os_debug_dump_al ; Dump only the lower 8-bits
Dump content of RIP into RAX
IN: Nothing OUT: RAX = RIP
This function is useful for retreiving the Instruction Pointer at the time os_debug_get_ip was called.
Example:
call os_debug_get_ip
Add two 128-bit integer together
IN: RDX,RAX = Integer 1, RCX,RBX = Integer 2 OUT: RDX,RAX = Result Carry set if overflow
Example:
For the os_print_string_with_color and os_print_char_with_color the color for the foreground (text) and background is selected with BL. A value of 0x09 in BL would give bright blue text on a black background. A value of 0xA4 would give you red text on a bright green background (yuck).
BareMetal OS is open source and released under a MIT license (see doc/LICENSE.TXT in the BareMetal OS distribution). Essentially, it means you can do anything you like with the code, including basing your own project on it, providing you retain the license file and give credit to the BareMetal OS developers for their work.