* better
[mascara-docs.git] / amd64 / bareMetalOS-0.5.2 / pure64.boot0 / src / syscalls.asm
blob6456b62a986f122bf8130d7141c6db28411b6e2b
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
5 ; System Calls
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
13 os_move_cursor:
14 push rcx
15 push rbx
16 push rax
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
23 mov cl, 80
24 mul cl ; AX = AL * CL
25 xor rbx, rbx
26 mov bl, [screen_cursor_x]
27 add ax, bx
28 shl ax, 1 ; multiply by 2
30 add rax, 0x00000000000B8000
31 mov [screen_cursor_offset], rax
33 pop rax
34 pop rbx
35 pop rcx
36 ret
37 ; -----------------------------------------------------------------------------
40 ; -----------------------------------------------------------------------------
41 ; os_print_newline -- Reset cursor to start of next line and scroll if needed
42 ; IN: Nothing
43 ; OUT: Nothing, all registers perserved
44 os_print_newline:
45 push rax
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
61 pop rax
62 ret
63 ; -----------------------------------------------------------------------------
66 ; -----------------------------------------------------------------------------
67 ; os_print_string -- Displays text
68 ; IN: RSI = message location (zero-terminated string)
69 ; OUT: Nothing, all registers perserved
70 os_print_string:
71 push rsi
72 push rax
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
84 call os_print_char
86 jmp os_print_string_nextchar
88 os_print_string_newline:
89 call os_print_newline
90 jmp os_print_string_nextchar
92 os_print_string_done:
93 pop rax
94 pop rsi
95 ret
96 ; -----------------------------------------------------------------------------
99 ; -----------------------------------------------------------------------------
100 ; os_print_char -- Displays a char
101 ; IN: AL = char to display
102 ; OUT: Nothing. All registers preserved
103 os_print_char:
104 push rdi
106 mov rdi, [screen_cursor_offset]
107 stosb
108 add qword [screen_cursor_offset], 2 ; Add 2 (1 byte for char and 1 byte for attribute)
110 pop rdi
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
119 os_print_char_hex:
120 push rbx
121 push rax
123 mov rbx, hextable
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
127 xlatb
128 call os_print_char
130 pop rax
131 and al, 0x0f ; we want to work on the low part so clear the high part
132 xlatb
133 call os_print_char
135 pop rax
136 pop rbx
138 ; -----------------------------------------------------------------------------
141 ; -----------------------------------------------------------------------------
142 ; os_string_copy -- Copy the contents of one string into another
143 ; IN: RSI = source
144 ; RDI = destination
145 ; OUT: Nothing. All registers preserved
146 ; Note: It is up to the programmer to ensure that there is sufficient space in the destination
147 os_string_copy:
148 push rsi
149 push rdi
150 push rax
152 os_string_copy_more:
153 lodsb ; Load a character from the source string
154 stosb
155 cmp al, 0 ; If source string is empty, quit out
156 jne os_string_copy_more
158 pop rax
159 pop rdi
160 pop rsi
162 ; -----------------------------------------------------------------------------
165 ; -----------------------------------------------------------------------------
166 ; os_string_compare -- See if two strings match
167 ; IN: RSI = string one
168 ; RDI = string two
169 ; OUT: Carry flag set if same
170 os_string_compare:
171 push rsi
172 push rdi
173 push rbx
174 push rax
176 os_string_compare_more:
177 mov al, [rsi] ; Store string contents
178 mov bl, [rdi]
180 cmp al, 0 ; End of first string?
181 je os_string_compare_terminated
183 cmp al, bl
184 jne os_string_compare_not_same
186 inc rsi
187 inc rdi
188 jmp os_string_compare_more
190 os_string_compare_not_same:
191 pop rax
192 pop rbx
193 pop rdi
194 pop rsi
198 os_string_compare_terminated:
199 cmp bl, 0 ; End of second string?
200 jne os_string_compare_not_same
202 pop rax
203 pop rbx
204 pop rdi
205 pop rsi
208 ; -----------------------------------------------------------------------------
211 ; -----------------------------------------------------------------------------
212 ; os_string_uppercase -- Convert zero-terminated string to uppercase
213 ; IN: RSI = string location
214 ; OUT: Nothing. All registers preserved
215 os_string_uppercase:
216 push rsi
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
224 cmp byte [rsi], 122
225 jg os_string_uppercase_noatoz
227 sub byte [rsi], 0x20 ; If so, convert input char to uppercase
229 inc rsi
230 jmp os_string_uppercase_more
232 os_string_uppercase_noatoz:
233 inc rsi
234 jmp os_string_uppercase_more
236 os_string_uppercase_done:
237 pop rsi
239 ; -----------------------------------------------------------------------------
242 ; -----------------------------------------------------------------------------
243 ; os_dump_regs -- Dump the values on the registers to the screen (For debug purposes)
244 ; IN/OUT: Nothing
245 ; FIX: Clean this up.. it could be shorter with loops.
246 os_dump_regs:
247 push r15
248 push r14
249 push r13
250 push r12
251 push r11
252 push r10
253 push r9
254 push r8
255 push rsp
256 push rbp
257 push rdi
258 push rsi
259 push rdx
260 push rcx
261 push rbx
262 push rax
264 mov byte [os_dump_reg_stage], 0x00 ; Reset the stage to 0 since we are starting
266 os_dump_regs_again:
267 mov rsi, os_dump_reg_string00
268 xor rax, rax
269 xor rbx, rbx
270 mov al, [os_dump_reg_stage]
271 mov bl, 5 ; each string is 5 bytes
272 mul bl ; ax = bl x al
273 add rsi, rax
274 call os_print_string ; Print the register name
276 mov rdi, os_dump_reg_tstring
277 pop rax
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)
316 ;OUT:
317 os_dump_mem:
318 push rdx
319 push rcx
320 push rbx
321 push rax
323 push rsi
325 mov rcx, 512
326 dumpit:
327 lodsb
328 call os_print_char_hex
329 dec rcx
330 cmp rcx, 0
331 jne dumpit
333 pop rsi
335 ; call os_print_newline
337 pop rax
338 pop rbx
339 pop rcx
340 pop rdx
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
355 os_int_to_string:
356 push rdx
357 push rcx
358 push rbx
359 push rax
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
374 inc rdi
375 loop os_int_to_string_next_digit ; again for other remainders
376 mov al, 0x00
377 stosb ; Store the null terminator at the end of the string
379 pop rax
380 pop rbx
381 pop rcx
382 pop rdx
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:
393 push rdi
394 push rdx
395 push rcx
396 push rbx
397 push rax
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
405 push rax
406 mov al, dl
407 stosb
408 pop rax
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
413 pop rax
414 pop rbx
415 pop rcx
416 pop rdx
417 pop rdi
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
426 os_serial_send:
427 push rdx
428 push rax ; Save RAX since the serial line status check clobbers AL
430 mov dx, 0x03FD ; Serial Line Status register
431 os_serial_send_wait:
432 in al, dx
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
440 pop rdx
442 ; -----------------------------------------------------------------------------
445 ; -----------------------------------------------------------------------------
446 ; create_gate
447 ; rax = address of handler
448 ; rdi = gate # to configure
449 create_gate:
450 push rdi
451 push rax
453 shl rdi, 4 ; quickly multiply rdi by 16
454 stosw ; store the low word (15..0)
455 shr rax, 16
456 add rdi, 4 ; skip the gate marker
457 stosw ; store the high word (31..16)
458 shr rax, 16
459 stosd ; store the high dword (63..32)
461 pop rax
462 pop rdi
464 ; -----------------------------------------------------------------------------
467 ; =============================================================================
468 ; EOF