1 ; =============================================================================
2 ; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT
6 ; =================================================================
9 ; -----------------------------------------------------------------------------
10 ; os_move_cursor -- Moves the virtual cursor in text mode
11 ; IN: AH, AL = row, column
12 ; OUT: Nothing. All registers preserved
18 mov [screen_cursor_x
], ah
19 mov [screen_cursor_y
], al
21 and rax
, 0x000000000000FFFF ; only keep the low 16 bits
22 ;calculate the new offset
26 mov bl, [screen_cursor_x
]
28 shl ax, 1 ; multiply by 2
30 add rax
, 0x00000000000B8000
31 mov [screen_cursor_offset
], rax
37 ; -----------------------------------------------------------------------------
40 ; -----------------------------------------------------------------------------
41 ; os_print_newline -- Reset cursor to start of next line and scroll if needed
43 ; OUT: Nothing, all registers perserved
47 mov ah, 0 ; Set the cursor x value to 0
48 mov al, [screen_cursor_y
] ; Grab the cursor y value
49 cmp al, 24 ; Compare to see if we are on the last line
50 je os_print_newline_scroll
; If so then we need to scroll the sreen
52 inc al ; If not then we can go ahead an increment the y value
53 jmp os_print_newline_done
55 os_print_newline_scroll:
56 mov ax, 0x0000 ; If we have reached the end then wrap back to the front
58 os_print_newline_done:
59 call os_move_cursor
; update the cursor
63 ; -----------------------------------------------------------------------------
66 ; -----------------------------------------------------------------------------
67 ; os_print_string -- Displays text
68 ; IN: RSI = message location (zero-terminated string)
69 ; OUT: Nothing, all registers perserved
74 cld ; Clear the direction flag.. we want to increment through the string
76 os_print_string_nextchar:
77 lodsb ; Get char from string and store in AL
78 cmp al, 0 ; Strings are Zero terminated.
79 je os_print_string_done
; If char is Zero then it is the end of the string
81 cmp al, 13 ; Check if there was a newline character in the string
82 je os_print_string_newline
; If so then we print a new line
86 jmp os_print_string_nextchar
88 os_print_string_newline:
90 jmp os_print_string_nextchar
96 ; -----------------------------------------------------------------------------
99 ; -----------------------------------------------------------------------------
100 ; os_print_char -- Displays a char
101 ; IN: AL = char to display
102 ; OUT: Nothing. All registers preserved
106 mov rdi
, [screen_cursor_offset
]
108 add qword [screen_cursor_offset
], 2 ; Add 2 (1 byte for char and 1 byte for attribute)
112 ; -----------------------------------------------------------------------------
115 ; -----------------------------------------------------------------------------
116 ; os_print_char_hex -- Displays a char in hex mode
117 ; IN: AL = char to display
118 ; OUT: Nothing. All registers preserved
125 push rax
; save rax for the next part
126 shr al, 4 ; we want to work on the high part so shift right by 4 bits
131 and al, 0x0f ; we want to work on the low part so clear the high part
138 ; -----------------------------------------------------------------------------
141 ; -----------------------------------------------------------------------------
142 ; os_string_copy -- Copy the contents of one string into another
145 ; OUT: Nothing. All registers preserved
146 ; Note: It is up to the programmer to ensure that there is sufficient space in the destination
153 lodsb ; Load a character from the source string
155 cmp al, 0 ; If source string is empty, quit out
156 jne os_string_copy_more
162 ; -----------------------------------------------------------------------------
165 ; -----------------------------------------------------------------------------
166 ; os_string_compare -- See if two strings match
167 ; IN: RSI = string one
169 ; OUT: Carry flag set if same
176 os_string_compare_more:
177 mov al, [rsi
] ; Store string contents
180 cmp al, 0 ; End of first string?
181 je os_string_compare_terminated
184 jne os_string_compare_not_same
188 jmp os_string_compare_more
190 os_string_compare_not_same:
198 os_string_compare_terminated:
199 cmp bl, 0 ; End of second string?
200 jne os_string_compare_not_same
208 ; -----------------------------------------------------------------------------
211 ; -----------------------------------------------------------------------------
212 ; os_string_uppercase -- Convert zero-terminated string to uppercase
213 ; IN: RSI = string location
214 ; OUT: Nothing. All registers preserved
218 os_string_uppercase_more:
219 cmp byte [rsi
], 0x00 ; Zero-termination of string?
220 je os_string_uppercase_done
; If so, quit
222 cmp byte [rsi
], 97 ; In the uppercase A to Z range?
223 jl os_string_uppercase_noatoz
225 jg os_string_uppercase_noatoz
227 sub byte [rsi
], 0x20 ; If so, convert input char to uppercase
230 jmp os_string_uppercase_more
232 os_string_uppercase_noatoz:
234 jmp os_string_uppercase_more
236 os_string_uppercase_done:
239 ; -----------------------------------------------------------------------------
242 ; -----------------------------------------------------------------------------
243 ; os_dump_regs -- Dump the values on the registers to the screen (For debug purposes)
245 ; FIX: Clean this up.. it could be shorter with loops.
264 mov byte [os_dump_reg_stage
], 0x00 ; Reset the stage to 0 since we are starting
267 mov rsi
, os_dump_reg_string00
270 mov al, [os_dump_reg_stage
]
271 mov bl, 5 ; each string is 5 bytes
272 mul bl ; ax = bl x al
274 call os_print_string
; Print the register name
276 mov rdi
, os_dump_reg_tstring
278 call os_int_to_hex_string
; Convert the register value to a hex string
279 mov rsi
, os_dump_reg_tstring
280 call os_print_string
; Print the hex string
282 inc byte [os_dump_reg_stage
]
283 cmp byte [os_dump_reg_stage
], 0x10
284 jne os_dump_regs_again
286 ; call os_print_newline
290 os_dump_reg_string00: db ' A:', 0
291 os_dump_reg_string01: db ' B:', 0
292 os_dump_reg_string02: db ' C:', 0
293 os_dump_reg_string03: db ' D:', 0
294 os_dump_reg_string04: db ' SI:', 0
295 os_dump_reg_string05: db ' DI:', 0
296 os_dump_reg_string06: db ' BP:', 0
297 os_dump_reg_string07: db ' SP:', 0
298 os_dump_reg_string08: db ' 8:', 0
299 os_dump_reg_string09: db ' 9:', 0
300 os_dump_reg_string0A: db ' 10:', 0
301 os_dump_reg_string0B: db ' 11:', 0
302 os_dump_reg_string0C: db ' 12:', 0
303 os_dump_reg_string0D: db ' 13:', 0
304 os_dump_reg_string0E: db ' 14:', 0
305 os_dump_reg_string0F: db ' 15:', 0
307 os_dump_reg_tstring: times
17 db 0
308 os_dump_reg_stage: db 0x00
309 ; -----------------------------------------------------------------------------
313 ; -----------------------------------------------------------------------------
314 ; os_dump_mem -- Dump some memory content to the screen (For debug purposes)
315 ; IN: RSI = memory to dump (512bytes)
328 call os_print_char_hex
335 ; call os_print_newline
342 ; -----------------------------------------------------------------------------
345 ; -----------------------------------------------------------------------------
346 ; os_int_to_string -- Convert a binary interger into an string string
347 ; IN: RAX = binary integer
348 ; RDI = location to store string
349 ; OUT: RDI = pointer to end of string
350 ; All other registers preserved
351 ; Min return value is 0 and max return value is 18446744073709551615 so your
352 ; string needs to be able to store at least 21 characters (20 for the number
353 ; and 1 for the string terminator).
354 ; Adapted from http://www.cs.usfca.edu/~cruse/cs210s09/rax2uint.s
361 mov rbx
, 10 ; base of the decimal system
362 xor rcx
, rcx
; number of digits generated
363 os_int_to_string_next_divide:
364 xor rdx
, rdx
; RAX extended to (RDX,RAX)
365 div rbx
; divide by the number-base
366 push rdx
; save remainder on the stack
367 inc rcx
; and count this remainder
368 cmp rax
, 0x0 ; was the quotient zero?
369 jne os_int_to_string_next_divide
; no, do another division
370 os_int_to_string_next_digit:
371 pop rdx
; else pop recent remainder
372 add dl, '0' ; and convert to a numeral
373 mov [rdi
], dl ; store to memory-buffer
375 loop os_int_to_string_next_digit
; again for other remainders
377 stosb ; Store the null terminator at the end of the string
384 ; -----------------------------------------------------------------------------
387 ; -----------------------------------------------------------------------------
388 ; os_int_to_hex_string -- Convert an integer to a hex string
389 ; IN: RAX = Integer value
390 ; RDI = location to store string
391 ; OUT: Nothing. All registers preserved
392 os_int_to_hex_string:
399 mov rcx
, 16 ; number of nibbles. 64 bit = 16 nibbles = 8 bytes
400 os_int_to_hex_string_next_nibble:
401 rol rax
, 4 ; next nibble into AL
402 mov bl, al ; copy nibble into BL
403 and rbx
, 0x0F ; and convert to word
404 mov dl, [hextable
+ rbx
] ; lookup ascii numeral
409 loop os_int_to_hex_string_next_nibble
; again for next nibble
410 xor rax
, rax
; clear RAX to 0
411 stosb ; Store AL to terminate string
419 ; -----------------------------------------------------------------------------
422 ; -----------------------------------------------------------------------------
423 ; os_serial_write -- Send a byte over the primary serial port
424 ; IN: AL = Byte to send over serial port
425 ; OUT: Nothing, all registers preserved
428 push rax
; Save RAX since the serial line status check clobbers AL
430 mov dx, 0x03FD ; Serial Line Status register
433 bt ax, 5 ; Copy bit 5 (THR is empty) to the Carry Flag
434 jnc os_serial_send_wait
; If the bit is not set then the queue isn't ready for another byte
436 pop rax
; Get the byte back from the stack
437 mov dx, 0x03F8 ; Serial data register
438 out dx, al ; Send the byte
442 ; -----------------------------------------------------------------------------
445 ; -----------------------------------------------------------------------------
447 ; rax = address of handler
448 ; rdi = gate # to configure
453 shl rdi
, 4 ; quickly multiply rdi by 16
454 stosw ; store the low word (15..0)
456 add rdi
, 4 ; skip the gate marker
457 stosw ; store the high word (31..16)
459 stosd ; store the high dword (63..32)
464 ; -----------------------------------------------------------------------------
467 ; =============================================================================