BareMetal OS - System Calls

Version 0.5.0 (DRAFT), 14 February 2011 - Return Infinity

This documentation details the system calls provided by BareMetal and how applications can use them.



System Calls

Introduction

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.

Table of contents

  1. Debug
  2. File I/O
  3. Input
  4. Mathematics
  5. Memory
  6. Miscellaneous
  7. Networking
  8. Output
  9. Serial
  10. SMP (Symmetric Multiprocessing)
  11. Sound
  12. String


Debug

b_debug_dump_reg

Dump the values on the registers to the screen

 IN:	Nothing
OUT:	Nothing, all registers preserved

Example:

	call b_debug_dump_reg

b_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

Example:

	mov rsi, 0x1000		; Dump starting at this memory address
	mov rcx, 100		; Display 100 bytes
	call b_debug_dump_mem

b_debug_dump_rax|eax|ax|al

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 b_debug_dump_rax		; Dump the entire 64-bit register
	call b_debug_dump_eax		; Dump only the lower 32-bits
	call b_debug_dump_ax		; Dump only the lower 16-bits
	call b_debug_dump_al		; Dump only the lower 8-bits

b_debug_get_ip

Dump content of RIP into RAX

 IN:	Nothing
OUT:	RAX = RIP

This function is useful for retreiving the Instruction Pointer at the time b_debug_get_ip was called.

Example:

	call b_debug_get_ip


File I/O - Functions for dealing with files

b_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

Example:

	mov rsi, testfile	; File name
	mov rdi, 0x1000000	; Read file to this memory address
	call b_file_read
	jnc fileok		; If carry is clear then no error occured
	
	... error handling here ...
	
fileok:
	... work with file ...

	testfile: db "test.txt", 0

b_file_write

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 b_file_write
	jnc fileok		; If carry is clear then no error occured
	
	... error handling here ...
	
fileok:
	... continue on ...

	testfile: db "test.txt", 0

b_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

Example:

	mov rsi, testfile	; Name of file to delete
	call b_file_delete

	...

	testfile: db "deleteme.txt", 0

b_file_get_list

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 b_file_get_list
	call b_print_string		; Print the directory listing

b_file_get_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

Example:

	mov rsi, temp_string		; Our temporary name string
	call b_file_get_size
	jc namenotfound


Input - Functions for dealing with input from the keyboard

b_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

Example:

	call b_input_key_check
	jnc nokeypressed		; If carry is not set than no key was pressed
	call b_print_char		; Print the character that was pressed

	...

	nokeypressed:

b_input_key_wait

Waits for keypress and returns key

 IN:	Nothing
OUT:	AL = key pressed
	All other registers preserved

Example:

	call b_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:

b_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

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 b_input_string

	...

	inputstring: times 11 db 0


Mathematics

b_oword_add

Add two 128-bit integer together

 IN:	RDX,RAX = Integer 1, RCX,RBX = Integer 2
OUT:	RDX,RAX = Result
	Carry set if overflow

Example:




Memory

b_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

Example:

	mov rcx, 4		; Try to allocate 4 pages (8 MiB)
	call b_mem_allocate
	cmp rcx, 0
	je fail
	mov [mempointer], rax	; Save the pointer

	...
	
	fail:

b_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

Example:

	mov rax, [mempointer]	; Restore the pointer
	mov rcx, 4		; Free 4 pages (8 MiB)
	call b_mem_release

b_mem_get_free

Returns the number of 2 MiB pages that are available

 IN:	Nothing
OUT:	RCX = Number of free 2 MiB pages

Example:

	call b_mem_get_free


Misc

b_delay

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 b_delay		; Pause for 2 seconds


Networking

b_ethernet_avail

Check if Ethernet is available

 IN:	Nothing.
OUT:	RAX = MAC Address if Ethernet is enabled, otherwise 0. All other registers preserved

Example:

	call b_ethernet_avail
	cmp rax, 0
	je noEthernet

b_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

Example:

	mov rsi, datalocation
	mov rdi, peeraddress
	mov rbx, 0xBAAB
	mov rcx, 63
	call b_ethernet_tx

b_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

Example:

	mov rdi, EthernetBuffer
	call b_ethernet_rx
	cmp rcx, 0
	je nopacket


Output - Functions for dealing with output to the screen

b_move_cursor

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 b_move_cursor	; Move cursor to (5,5)

	...

	mov ax, 0x0505
	call b_move_cursor	; Same as above but we set AL and AH at the same time

b_inc_cursor

Increment the hardware cursor by one

 IN:	Nothing
OUT:	All registers preserved

This function will automatically call b_scroll_screen if required.

Example:

	call b_inc_cursor

b_dec_cursor

Decrement the hardware cursor by one

 IN:	Nothing
OUT:	All registers preserved

Example:

	call b_dec_cursor

b_print_newline

Reset cursor to start of next line and scroll if needed

 IN:	Nothing
OUT:	All registers perserved

Example:

	call b_print_newline

b_print_string

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 b_print_string

	...

	teststring: db "This is a test string.", 0

b_print_string_with_color

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 b_print_string_with_color

	...

	colorteststring: db "This is a test string in color!", 0

b_print_char

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 b_print_char

b_print_char_with_color

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 b_print_char_with_color

b_print_char_hex

Displays a char in hex mode

 IN:	AL  = char to display
OUT:	All registers perserved

Example:

	mov al, 0x5f
	call b_print_char_hex		; "5F" will be printed
	mov al, 154
	call b_print_char_hex		; "9A" will be printed

b_print_char_hex_with_color

Displays a char in hex mode

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.

 IN:	AL  = char to display
	BL  = color
OUT:	All registers perserved

Example:

	mov al, 0x5f
	mov bl, 0x4F			; Red background, White text
	call b_print_char_hex		; "5F" will be printed
	mov al, 154
	mov bl, 0x4F			; Red background, White text
	call b_print_char_hex		; "9A" will be printed

b_scroll_screen

Scrolls the screen up by one line

 IN:	Nothing
OUT:	All registers perserved

Example:

	call b_scroll_screen

b_hide_cursor

Turns off cursor in text mode

 IN:	Nothing
OUT:	All registers perserved

Example:

	call b_hide_cursor

b_show_cursor

Turns on cursor in text mode

 IN:	Nothing
OUT:	All registers perserved

Example:

	call b_show_cursor


Serial

b_serial_send

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 b_serial_send

b_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

Example:

	call b_serial_recv
	jnc gotnothing


Symmetric Multiprocessing (SMP)

b_smp_reset

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 b_smp_reset		; Reset the CPU Core

b_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

Example:

	call b_smp_get_id		; APIC ID returned in AL

b_smp_enqueue

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 b_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 b_smp_enqueue
	sub rcx, 1
	cmp rcx, 0
	jne spawn

b_smp_dequeue

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 b_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 b_smp_queuelen		; Check the length of the queue
	cmp rax, 0
	jne bsp				; If it is not empty try to do another workload

b_smp_run

Call the code address stored in RAX

 IN:	RAX = Address of code to execute
OUT:	Nothing

Needed for compatibilty with C.

Example:

	call b_smp_dequeue
	call b_smp_run			; You could also use "call rax" here

b_smp_queuelen

Returns the number of items in the processing queue

 IN:	Nothing
OUT:	RAX = number of items in processing queue

b_smp_dequeue makes use of this function.

Example:

	call b_smp_queuelen		; Check the length of the queue
	cmp rax, 0
	je queue_empty

b_smp_wait

Wait until all other CPU Cores are finished processing

 IN:	Nothing
OUT:	All registers preserved

Use this function to wait until all available CPU Cores are finished processing.

Example:

	call b_smp_wait			; Wait for all other processors to finish

b_smp_lock

Attempt to lock a mutex

 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:

	mov rax, Mutex
	call b_smp_lock			; Attempt to lock the mutex

b_smp_unlock

Unlock a mutex

 IN:	RAX = Address of lock variable
OUT:	Nothing. All registers preserved.

Unlock a mutex.

Example:

	mov rax, Mutex
	call b_smp_unlock		; Unlock the mutex

b_smp_numcores

Returns the number of cores in this computer

 IN:	RAX = Address of lock variable
OUT:	Nothing. All registers preserved.

Example:

	call b_smp_numcores


Sound

b_speaker_tone

Generate a tone on the PC speaker

 IN:	RAX = note frequency
OUT:	All registers preserved

Call b_speaker_off to stop the tone

Example:

	mov rax, 4000			; A 'C' note
	call b_speaker_tone

b_speaker_off

Turn off PC speaker

 IN:	Nothing
OUT:	All registers preserved

Example:

	call b_speaker_off

b_speaker_beep

Create a standard OS beep

 IN:	Nothing
OUT:	All registers preserved

Example:

	call b_speaker_beep


String

b_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

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 b_int_to_string
	call b_print_string		; "18446744073709551615" will be printed

	...

	teststring: times 21 db 0	; Space for a 20 character string

b_string_to_int

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 b_string_to_int		; RAX will be set to the decimal value 460341242

	...

	teststring: db "460341242", 0


b_int_to_hex_string

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 b_int_to_hex_string
	call b_print_string		; "DEADBEEF" will be printed

	...

	teststring: times 21 db 0	; Space for a 20 character string

b_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

Example:

	mov rsi, teststring
	call b_hex_string_to_int	; RAX will be set to 4277006349

	...

	teststring: db "FEEDF00D", 0

b_string_length

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 b_string_length		; RCX will be set to 45

	...

	teststring: db "This is a test of the string length function!", 0

b_find_char_in_string

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

b_string_charchange

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 b_string_charchange
	call b_print_string		; "PlAasA rAplacA thA lowArcasA lAttAr E's." will be printed

	...

	teststring: db "Please replace the lowercase letter E's.", 0

b_string_copy

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 b_string_copy
	mov rsi, deststring
	call b_print_string		; "Copy this string!" will be printed

	...

	srcstring: "Copy this string!", 0
	deststring: times 21 db 0	; Space for a 20 character string

b_string_truncate

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 b_string_truncate
	call b_print_string		; "AaBbC" will be printed on screen

	...

	teststring: db "AaBbCcDd 123", 0

b_string_join

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 b_string_join
	mov rsi, deststring
	call b_print_string		; "AAAAABBBBB" will be printed

	...

	string1: "AAAAA", 0
	string2: "BBBBB", 0
	deststring: times 41 db 0	; Space for a 40 character string

b_string_chomp

Strip leading and trailing spaces from a string

 IN:	RSI = string location
OUT:	All registers preserved

Example:

	mov rsi, teststring
	call b_string_chomp
	call b_print_string		; "This is a test." will be printed

	...

	teststring: db "  This is a test.       ", 0

b_string_strip

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 b_string_strip
	call b_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

b_string_compare

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 b_string_compare
	jc string_equal
	; Falls through to here if strings are not equal

	...

	string1: "AAAAA", 0
	string2: "BBBBB", 0

b_string_uppercase

Convert zero-terminated string to uppercase

 IN:	RSI = string location
OUT:	All registers preserved

Example:

	mov rsi, teststring
	call b_string_uppercase
	call b_print_string		; "AABBCCDD 123" will be printed

	...

	teststring: db "AaBbCcDd 123", 0

b_string_lowercase

Convert zero-terminated string to lowercase

 IN:	RSI = string location
OUT:	All registers preserved

Example:

	mov rsi, teststring
	call b_string_lowercase
	call b_print_string		; "aabbccdd 123" will be printed

	...

	teststring: db "AaBbCcDd 123", 0

b_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

Example:

	mov rdi, temp_string
	call b_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

b_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

Example:

	mov rdi, temp_string
	call b_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

b_is_digit

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 b_is_digit
	je itsanumber			; Jump if it was a digit, else fall through to next instruction
	mov rbx, 2134

b_is_alpha

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 b_is_alpha
	jne notaletter			; Jump if it was not a letter, else fall through to next instruction
	mov rbx, 2134

b_string_parse

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 b_string_parse
	call b_print_string		; "This is a test." will be printed. Also RCX will be set to 4

	...

	teststring: db "This   is  a test. ", 0

b_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

Example:

	mov rsi, teststring1
	mov rdi, teststring2
	call b_string_append
	mov rsi, teststring2
	call b_print_string		; "Test2Test1" will be printed.

	...

	teststring1: db "Test1", 0
	teststring2: db "Test2", 0


Appendix

Text mode color table:

For the b_print_string_with_color and b_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).



Extra

License

BareMetal OS is open source and released under the 3-clause "New BSD License" (see docs/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 Return Infinity and the BareMetal OS developers for their work.