System calls


The MikeOS Assembly App Developer Handbook

For version 4.5, 21 December 2014 - (C) MikeOS Developers

This documentation file explains how write software for MikeOS in assembly language. It shows you the tools you need, how MikeOS programs work, and how to use the system calls included in the kernel. If you have any questions, see the MikeOS website for contact details.

Click the links on the left to navigate around this guide.



Many MikeOS programs are written in 16-bit, real mode assembly language. (The OS also includes a BASIC interpreter.) Because MikeOS and its programs live in a single 64K memory segment, you do not need to concern yourself with segment registers.

MikeOS programs are loaded at the 32K point (32768) in the segment, and have a maximum size of 32K. Consequently, your programs will need to begin with these directives:

ORG 32768

There are many system calls available in MikeOS for controlling the screen, getting input, manipulating strings, loading/saving files, and more. All parameters to MikeOS system calls are passed in registers, and not on the stack. To use them in your programs, you need this line:


This doesn't include any code, but a list of equ directives that point to system call vectors in the kernel. So, by including this file you can call, for instance, the MikeOS os_print_string routine without having to know exactly where it is in the kernel. is included in the programs/ directory of the MikeOS download -- it also provides a quick reference to the system calls.

If a MikeOS program is run from the command line, and one or more parameters was provided with the command, they are passed to the program via the SI register as a zero-terminated string.

Tools needed

To write MikeOS programs you need:

  • NASM -- A powerful, free and open source assembler
  • -- The system call vectors described above
  • A way to add programs to the floppy disk

Let's clarify this: MikeOS uses NASM for its programs and kernel source code, hence why we recommend it here. You can, of course, use any other assembler that can output plain binary files (ie with no header) and accept 16-bit code. NASM is available in most Linux distro repositories, or you can download the Windows version from here (get the 'win32' file).

For the second point, copy programs/ so that it's alongside your program's source code for inclusion.

For the third point, if you've written MikeOS to a real floppy disk, you can just copy your .BIN programs onto that disk (root directory only!), boot MikeOS and test them out. If you're working with the virtual mikeos.flp disk image, see the Copying files section of the User Handbook.


Source code

Here is an example MikeOS program, in NASM format, which prints a string to the screen and waits for the user to press a key before finishing:

	BITS 16
	ORG 32768

	mov si, mystring
	call os_print_string

	call os_wait_for_key


	mystring db 'My first MikeOS program!', 0


Save the above code as testapp.asm, and enter this command to assemble it (works on both Linux and Windows):

nasm -f bin -o testapp.bin testapp.asm

Using the '-f bin' option we tell NASM that we just want a plain binary file: no header or sections. The resulting executable file is testapp.bin that we can copy to our floppy disk or add to the virtual disk image as described in Copying files in the User Handbook. Then we can boot MikeOS and run the program.


This is a very short program, but we'll explain exactly how it works for complete clarity. The first three lines will not be assembled to machine code instructions, but are just directives to tell NASM that we want to operate in 16 bit mode, our code is written to be executed from the 32K mark, and we want to use system calls from the MikeOS API.

Next we have the 'start:' label, which is not essential but good practice to make things clear. We put the location of a zero-terminated string into the SI register, then call the MikeOS os_print_string routine which we can access via the vectors listed in After that we pause program until a the user presses a key.

All MikeOS programs must end with a ret instruction, which passes control back to the OS. After that instruction we have the data for our string. And that's it!

System calls


The MikeOS 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, 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 source/features/ directory in MikeOS. Each aspect of the API below is contained within an assembly source file, so you can enhance the system calls as per the MikeOS System Developer Handbook.



Generate comma-separated string of files on floppy

  • IN/OUT: AX = location to store zero-terminated filename string


	mov ax, .filestring
	call os_get_file_list

	; Now .filestring will contain something like

	.filestring	times 256 db 0


Load file into RAM

  • IN: AX = location of zero-terminated filename string, CX = location in RAM to load file
  • OUT: BX = file size (in bytes), carry set if file not found


	mov ax, filename
	mov cx, 36960		; 4K after where external program loads
	call os_load_file


	filename db 'README.TXT', 0


Save (max 64K) file to disk

  • IN: AX = filename, BX = data location, CX = bytes to write
  • OUT: Carry clear if OK, set if failure


	; For this example, there's some text stored in .data

	mov ax, .filename
	mov bx, .data
	mov cx, 4192
	call os_write_file

	.filename	db 'HELLO.TXT', 0
	.data		times 4192 db 0


Check for presence of file on the floppy

  • IN: AX = filename location
  • OUT: carry clear if found, set if not


	mov ax, .filename
	call os_file_exists
	jc .not_found


	; Print error message here

	.filename	db 'HELLO.TXT', 0


Creates a new 0-byte file on the floppy disk

  • IN: AX = location of filename
  • OUT: Nothing


	mov ax, .filename
	call os_create_file


	.filename	db 'HELLO.TXT', 0


Deletes the specified file from the filesystem

  • IN: AX = location of filename to remove
  • OUT: Nothing


Change the name of a file on the disk

  • IN: AX = filename to change, BX = new filename (zero-terminated strings)
  • OUT: carry set on error


	mov ax, .filename1
	mov bx, .filename2
	call os_rename_file

	jc .error


	; File couldn't be renamed (may already exist)

	.filename1	db 'ORIG.TXT', 0
	.filename2	db 'NEW.TXT', 0


Get file size information for specified file

  • IN: AX = filename
  • OUT: BX = file size in bytes (up to 64K) or carry set if file not found



Waits for keypress and returns key

  • IN: Nothing
  • OUT: AX = key pressed, other regs preserved


	call os_wait_for_key
	cmp al, 'y'
	je .yes
	cmp al, 'n'
	je .no
	jmp .loop


Scans keyboard for input, but doesn't wait

  • IN: Nothing
  • OUT: AX = 0 if no key pressed, otherwise scan code

Example: see code above



Converts binary coded decimal number to an integer

  • IN: AL = BCD number
  • OUT: AX = integer value


	mov al, 00010110b	; 0001 0110 = 16 (decimal) or 10h in BCD
	call os_bcd_to_int 
	; AX now contains the 16 bit-integer 00000000 00010000b


Multiply value in DX:AX by -1

  • IN: DX:AX = long integer
  • OUT: DX:AX = -(initial DX:AX)


	mov dx, 01h
	mov ax, 45h
	call os_long_int_negate

	; DX now contains 0xFFFF
	; and AX 0xFEBB


Get a random integer between high and low values (inclusive)

  • IN: AX = low integer, BX = high
  • OUT: CX = random number between AX and BX



Return current version of MikeOS API

  • IN: Nothing
  • OUT: AL = API version number


	call os_get_api_version
	; AL now contains version number (eg 8)


Delay execution for specified 10ths of second

  • IN: AX = number of 10ths of second to wait
  • OUT: nothing


	; Halt execution for 3 secs

	mov ax, 30
	call os_pause


Display error message and halt execution

  • IN: AX = error message string location
  • OUT: nothing


	mov ax, .error_msg
	call os_fatal_error

	.error_msg	db 'Massive error!', 0



Sends a byte to the specified port

  • IN: DX = port address, AL = byte
  • OUT: Nothing


Retrieves a byte from the specified port

  • IN: DX = port address
  • OUT: AL = byte


Turn on the first serial port

  • IN: AX = 0 for normal mode (9600 baud), or 1 for slow mode (1200 baud)
  • OUT: AH = bit 7 clear on success


Send a byte via the serial port

  • IN: AL = byte to send via serial
  • OUT: AH = bit 7 clear on success


	mov al, 'a'			; Place char to transmit in AL
	call os_send_via_serial
	cmp ah, 128			; If bit 7 is set, there's an error
	jnz all_ok			; Otherwise it's all OK
	jmp oops_error			; Deal with the error


Get a byte from the serial port

  • IN: nothing
  • OUT: AL = byte that was received; OUT: AH = bit 7 clear on success


	call os_get_via_serial
	cmp ah, 128		; If bit 7 is set, there's an error.
	jnz all_ok		; Otherwise it's all OK
	jmp oops_error		; Deal with the error

	mov [rx_byte], al	; Store byte we retrieved



Displays text

  • IN: SI = message location (zero-terminated string)
  • OUT: Nothing (registers preserved)


	mov si, .message
	call os_print_string


	.message	db 'Hello, world', 0


Clears the screen to background

  • IN/OUT: Nothing (registers preserved)


Moves cursor in text mode

  • IN: DH, DL = row, column
  • OUT: Nothing (registers preserved)


	; Move to middle of screen

	mov dh, 12
	mov dl, 40
	call os_move_cursor


Return position of text cursor

  • OUT: DH, DL = row, column


Draw a horizontal line on the screen

  • IN: AX = line type (1 for double, otherwise single)
  • OUT: Nothing (registers preserved)


Turns on cursor in text mode

  • IN/OUT: Nothing


Turns off cursor in text mode

  • IN/OUT: Nothing


Render block of specified colour

  • IN: BL/DL/DH/SI/DI = colour/start X pos/start Y pos/width/finish Y pos
  • OUT: Nothing


	mov bl, 0100111b	; White on red
	mov dl, 20		; Start X position
	mov dh, 2		; Start Y position
	mov si, 40		; Width
	mov di, 23		; Finish Y position
	call os_draw_block


Show a file selection dialog

  • IN: Nothing
  • OUT: AX = location of filename string (or carry set if Esc pressed)


	call os_file_selector
	jc .esc_pressed

	; Now AX points to the chosen filename



Show a dialog with a list of options

  • IN: AX = comma-separated list of strings to show (zero-terminated),
  •  BX = first help string, CX = second help string
  • OUT: AX = number (starts from 1) of entry selected carry set if Esc pressed


	mov ax, .list
	mov bx, .msg1
	mov cx, .msg2
	call os_list_dialog
	jc .esc_pressed

	; Now AX = number (from 1) of option chosen


	.list	db 'Open,Close,Reboot', 0
	.msg1	db 'Choose an option', 0
	.msg2	db 'Or press Esc to quit', 0


Clear screen with white top and bottom bars, containing text, and a coloured middle section

  • IN: AX/BX = top/bottom string locations, CX = colour
  • OUT: Nothing


	mov ax, .title_msg
	mov bx, .footer_msg
	mov cx, 00100000b	; Colour
	call os_draw_background


	.title_msg	db 'File manager', 0
	.footer_msg	db 'Choose an option...', 0


Reset cursor to start of next line

  • IN/OUT: Nothing (registers preserved)


Displays register contents in hex on the screen

  • IN/OUT: AX/BX/CX/DX = registers to show


Get text string from user via a dialog box

  • IN: AX = string location, BX = message to show
  • OUT: AX = string location


	mov bx, .filename_msg
	mov ax, .filename_input
	call os_input_dialog


	.filename_msg	'Please enter a filename:', 0
	.filename_input	times 12 db 0


Print dialog box in middle of screen, with button(s)

  • IN: AX, BX, CX = string locations (set registers to 0 for no display),
  •  DX = 0 for single 'OK' dialog, 1 for two-button 'OK' and 'Cancel'
  • OUT: If two-button mode, AX = 0 for OK and 1 for cancel
  • NOTE: Each string is limited to 40 characters


	mov ax, .string1
	mov bx, .string2
	mov cx, .string3
	mov dx, 1
	call os_dialog_box

	cmp ax, 1
	je .first_option_chosen

	; Otherwise second was chosen


	.string1	db 'Welcome to my program!', 0
	.string2	db 'Please choose to destroy the world,', 0
	.string3	db 'or play with fluffy kittens.', 0


Print a space to the screen

  • IN/OUT: nothing


Dump string as hex bytes and printable characters

  • IN: SI = points to string to dump
  • OUT: Nothing


Displays contents of AX as a single digit (works up to base 37, ie digits 0-Z)

  • IN: AX = "digit" to format and print
  • OUT: Nothing


Displays low nibble of AL in hex format

  • IN: AL = number to format and print
  • OUT: Nothing


Displays AL in hex format

  • IN: AL = number to format and print
  • OUT: Nothing


Displays AX in hex format

  • IN: AX = number to format and print
  • OUT: Nothing


Take string from keyboard entry

  • IN/OUT: AX = location of string, other regs preserved
  • (Location will contain up to 255 characters, zero-terminated)


	mov ax, .string
	call os_input_string


	.string		times 256 db 0



Return length of a string

  • IN: AX = string location
  • OUT AX = length (other regs preserved)


	jmp Get_Len

	Test_String db 'This string has 46 characters including spaces', 0

	mov ax, Test_String
	call os_string_length
	; AX now contains the number 46


Get the position of a character in a string

  • IN: SI = string location, AL = character to find
  • OUT: AX = location in string, or 0 if char not present


jmp Search_Str

     Test_String db 'This is the test string', 0
     message_1   db 'Character not found', 0
     message_2   db 'Character found at position', 0
     message_3   db '  ', 0
     str_len     dw  0


     mov ax, Test_String           ; string to search
     mov si, ax
     xor ax, ax                    ; clear ax

     mov al, 'x'                   ; x is the character to find
     call os_find_char_in_string

     mov [str_len], ax             ; store result
     cmp ax, 0                  
     jz Char_Not_Found 
     jmp Char_Found


     mov si, message_1
     call os_print_string     
     jmp Main_Pgm


     mov ax, [str_len]             ; convert result into string first
     mov bx, message_3
     call os_int_to_string

     mov si, message_2
     call os_print_string          ; print message_2
     call os_print_space           ; print a space

     mov si, message_3
     call os_print_string          ; print the position at which x was found     


Swar order of characters in a string

  • IN: SI = location of zero-terminated string


	mov si, mystring
	call os_string_reverse

	; Now mystring contains 'olleH'

	mystring db 'Hello', 0


Change instances of character in a string

  • IN: SI = string location, AL = char to find, BL = char to replace with


Convert zero-terminated string to upper case

  • IN/OUT: AX = string location


Convert zero-terminated string to lower case

  • IN/OUT: AX = string location


Copy one string into another

  • IN/OUT: SI = source, DI = destination (programmer ensure sufficient room)


	mov si, .old_string
	mov di, .new_string
	call os_string_copy


	.old_string	db 'Hello', 0
	.new_string	times 16 db 0


Chop string down to specified number of characters

  • IN: SI = string location, AX = number of characters
  • OUT: string modified, registers preserved


	mov si, .string
	mov ax, 3
	call os_string_truncate

	; .string now contains 'HEL', 0

	.string		db 'HELLO', 0


Join two strings into a third string

  • IN/OUT: AX = string one, BX = string two, CX = destination string


	mov ax, .string1
	mov bx, .string2
	mov cx, .string3
	call os_string_join

	; CX now points to 'HELLOYOU', 0

	.string1	db 'HELLO', 0
	.string2	db 'YOU', 0
	.string3	times 50 db 0


Strip leading and trailing spaces from a string

  • IN: AX = string location
  • OUT: nothing


	mov ax, .string
	call os_string_chomp

	; AX now points to 'KITTEN', 0

	.string		db '  KITTEN  ', 0


Removes specified character from a string

  • IN: SI = string location, AL = character to remove
  • OUT: nothing


	mov si, .string
	mov al, 'U'
	call os_string_strip

	; .string now contains 'MOSE', 0

	.string		db 'MOUSE', 0


See if two strings match

  • IN: SI = string one, DI = string two
  • OUT: carry set if same, clear if different


	mov si, .string1
	mov di, .string2
	call os_string_compare
	jc .same

	; Strings are different


	; Strings are the same

	.string1	db 'ONE', 0
	.string2	db 'TWO', 0


See if two strings match up to set number of chars

  • IN: SI = string one, DI = string two, CL = chars to check
  • OUT: carry set if same, clear if different

Example: like above, but with CL = number of characters to check


Take string (eg "run foo bar baz") and return pointers to zero-terminated strings (eg AX = "run", BX = "foo" etc.)

  • IN: SI = string
  • OUT: AX, BX, CX, DX = individual strings


	mov si, .string
	call os_string_parse

	; Now AX points to 'This',
	; BX to 'is',
	; CX to 'a',
	; and DX to 'test'

	.string		db 'This is a test', 0


Convert decimal string to integer value

  • IN: SI = string location (max 5 chars, up to '65536')
  • OUT: AX = number


	mov si, .string
	call os_string_to_int

	; Now AX contains the number 1234

	.string		db '1234', 0


Convert unsigned value in AX to string

  • IN: AX = unsigned integer
  • OUT: AX = location of internal string buffer with result


	mov ax, 1234
	call os_int_to_string

	; Now AX points to '1234', 0


Convert signed value in AX to string

  • IN: AX = signed integer
  • OUT: AX = location of internal string buffer with result


	mov ax, -1234
	call os_int_to_string

	; Now AX points to '-1234', 0


Convert value in DX:AX to string

  • IN: DX:AX = long unsigned integer, BX = number base, DI = string location
  • OUT: DI = location of converted string


Set time reporting format (eg '10:25 AM' or '2300 hours')

  • IN: AL = format flag, 0 = 12-hr format
  • OUT: nothing


Get current time in a string (eg '10:25')

  • IN/OUT: BX = string location


Set date reporting format (M/D/Y, D/M/Y or Y/M/D - 0, 1, 2)

  • IN: AX = format flag, 0-2
  •  If AX bit 7 = 1 = use name for months
  •  If AX bit 7 = 0, high byte = separator character
  • OUT: nothing


Get current date in a string (eg '12/31/2007')

  • IN/OUT: BX = string location



Generate PC speaker tone (call os_speaker_off to turn off)

  • IN: AX = note frequency
  • OUT: Nothing (registers preserved)

Example: see code below


Turn off PC speaker

  • IN/OUT: Nothing (registers preserved)


; Generate "middle C" 261.626 Hz (263 Hz close enough) for 2 secs
; 2 secs = 2,000,000 uS which is 1E8480h

	jmp Play_It

	music_note  dw  263

	mov ax, [music_note]
	call os_speaker_tone

	mov cx, 1Eh
	mov dx, 8480h
	call os_pause

	call os_speaker_off         



Runs kernel BASIC interpreter at the specified point

  • IN: AX = location of BASIC code, BX = size of code (in bytes)



If you have any questions about MikeOS, or you're developing a similar OS and want to share code and ideas, go to the MikeOS website.


MikeOS is open source and released under a BSD-like license (see doc/LICENSE.TXT in the MikeOS .zip file). 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 MikeOS developers for their work.