1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT
5 ; The BareMetal OS kernel. Assemble with NASM
6 ; =============================================================================
10 ORG 0x0000000000100000
12 %DEFINE BAREMETALOS_VER
'v0.5.2 (June 29, 2011)', 13, 'Copyright (C) 2008-2011 Return Infinity', 13, 0
13 %DEFINE BAREMETALOS_API_VER
1
16 jmp start
; Skip over the function call index
21 jmp os_print_string
; Jump to function
23 dq os_print_string
; Memory address of function
41 jmp os_input_key_check
86 jmp os_string_find_char
88 dq os_string_find_char
96 jmp os_string_truncate
116 jmp os_string_compare
121 jmp os_string_uppercase
123 dq os_string_uppercase
126 jmp os_string_lowercase
128 dq os_string_lowercase
141 jmp os_debug_dump_reg
146 jmp os_debug_dump_mem
151 jmp os_debug_dump_rax
156 jmp os_debug_dump_eax
226 jmp os_get_timecounter
228 dq os_get_timecounter
236 jmp os_int_to_hex_string
238 dq os_int_to_hex_string
241 jmp os_hex_string_to_int
243 dq os_hex_string_to_int
246 jmp os_string_change_char
248 dq os_string_change_char
296 jmp os_print_string_with_color
298 dq os_print_string_with_color
301 jmp os_print_char_with_color
303 dq os_print_char_with_color
341 jmp os_ethernet_avail
346 jmp os_print_char_hex_with_color
348 dq os_print_char_hex_with_color
351 jmp os_ethernet_tx_raw
353 dq os_ethernet_tx_raw
371 jmp os_show_statusbar
376 jmp os_hide_statusbar
391 jmp os_print_chars_with_color
393 dq os_print_chars_with_color
399 call init_64
; After this point we are in a working 64-bit enviroment
403 call init_net
; Initialize the network
405 call hdd_setup
; Gather information about the harddrive and set it up
407 call os_screen_clear
; Clear screen and display cursor
409 cmp byte [os_NetEnabled
], 1 ; Print network details (if a supported NIC was initialized)
415 call os_debug_dump_MAC
418 mov ax, 0x0016 ; Print the "ready" message
423 mov ax, 0x0018 ; Set the hardware cursor to the bottom left-hand corner
427 mov rsi
, startupapp
; Look for a file called startup.app
428 mov rdi
, programlocation
; We load the program to this location in memory (currently 0x00200000 : at the 2MB mark)
429 call os_file_read
; Read the file into memory
430 jc ap_clear
; If carry is set then the file was not found
433 mov rax
, programlocation
; 0x00200000 : at the 2MB mark
434 xor rbx
, rbx
; No arguements required (The app can get them with os_get_argc and os_get_argv)
435 call os_smp_enqueue
; Queue the application to run on the next available core
437 ; Fall through to ap_clear as align fills the space with No-Ops
438 ; At this point the BSP is just like one of the AP's
443 ap_clear: ; All cores start here on first startup and after an exception
445 cli ; Disable interrupts on this core
447 ; Get local ID of the core
448 mov rsi
, [os_LocalAPICAddress
]
449 xor eax, eax ; Clear Task Priority (bits 7:4) and Task Priority Sub-Class (bits 3:0)
450 mov dword [rsi
+0x80], eax ; APIC Task Priority Register (TPR)
451 mov eax, dword [rsi
+0x20] ; APIC ID
452 shr rax
, 24 ; Shift to the right and AL now holds the CPU's APIC ID
454 ; Calculate offset into CPU status table
456 add rdi
, rax
; RDI points to this cores status byte (we will clear it later)
459 shl rax
, 21 ; Shift left 21 bits for a 2 MiB stack
460 add rax
, [os_StackBase
] ; The stack decrements when you "push", start at 2 MiB in
463 ; Set the CPU status to "Present" and "Ready"
464 mov al, 00000001b ; Bit 0 set for "Present", Bit 1 clear for "Ready"
465 stosb ; Set status to Ready for this CPU
467 sti ; Re-enable interrupts on this core
469 ; Clear registers. Gives us a clean slate to work with
470 xor rax
, rax
; aka r0
471 xor rcx
, rcx
; aka r1
472 xor rdx
, rdx
; aka r2
473 xor rbx
, rbx
; aka r3
474 xor rbp
, rbp
; aka r5, We skip RSP (aka r4) as it was previously set
475 xor rsi
, rsi
; aka r6
476 xor rdi
, rdi
; aka r7
486 ap_spin: ; Spin until there is a workload in the queue
487 cmp word [os_QueueLen
], 0 ; Check the length of the queue
488 je ap_halt
; If the queue was empty then jump to the HLT
489 call os_smp_dequeue
; Try to pull a workload out of the queue
490 jnc ap_process
; Carry clear if successful, jump to ap_process
492 ap_halt: ; Halt until a wakup call is received
493 hlt ; If carry was set we fall through to the HLT
494 jmp ap_spin
; Try again
496 ap_process: ; Set the status byte to "Busy" and run the code
500 mov rsi
, [os_LocalAPICAddress
]
503 mov dword [rsi
+0x80], eax ; APIC Task Priority Register (TPR)
508 push rdi
; Push RDI since it is used temporarily
509 push rax
; Push RAX since os_smp_get_id uses it
511 call os_smp_get_id
; Set RAX to the APIC ID
513 mov al, 00000011b ; Bit 0 set for "Present", Bit 1 set for "Busy"
515 pop rax
; Pop RAX (holds the workload code address)
516 pop rdi
; Pop RDI (holds the variable/variable address)
543 mov rsi
, os_args
; ARGV[0]
548 call rax
; Run the code
550 jmp ap_clear
; Reset the stack, clear the registers, and wait for something else to work on
554 %include "init_64.asm"
555 %include "init_pci.asm"
556 %include "init_net.asm"
557 %include "init_hdd.asm"
558 %include "syscalls.asm"
559 %include "drivers.asm"
560 %include "interrupt.asm"
563 %include "sysvar.asm" ; Include this last to keep the read/write variables away from the code
565 ;times 16384-($-$$) db 0 ; Set the compiled kernel binary to at least this size in bytes
567 ; =============================================================================