* mikeOS 16 bit and amd64 baremetal
[mascara-docs.git] / amd64 / bareMetalOS-0.5.3 / os / interrupt.asm
blob1e89cd6ff4f513087d9ca7eb26da75ea1ce32da5
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 ; Interrupts
6 ; =============================================================================
8 align 16
9 db 'DEBUG: INTERRUPT'
10 align 16
13 ; -----------------------------------------------------------------------------
14 ; Default exception handler
15 exception_gate:
16 mov rsi, int_string00
17 call os_print_string
18 mov rsi, exc_string
19 call os_print_string
20 jmp $ ; Hang
21 ; -----------------------------------------------------------------------------
24 ; -----------------------------------------------------------------------------
25 ; Default interrupt handler
26 align 16
27 interrupt_gate: ; handler for all other interrupts
28 iretq ; It was an undefined interrupt so return to caller
29 ; -----------------------------------------------------------------------------
32 ; -----------------------------------------------------------------------------
33 ; Keyboard interrupt. IRQ 0x01, INT 0x21
34 ; This IRQ runs whenever there is input on the keyboard
35 align 16
36 keyboard:
37 push rdi
38 push rbx
39 push rax
41 xor eax, eax
43 in al, 0x60 ; Get the scancode from the keyboard
44 cmp al, 0x01
45 je keyboard_escape
46 cmp al, 0x2A ; Left Shift Make
47 je keyboard_shift
48 cmp al, 0x36 ; Right Shift Make
49 je keyboard_shift
50 cmp al, 0xAA ; Left Shift Break
51 je keyboard_noshift
52 cmp al, 0xB6 ; Right Shift Break
53 je keyboard_noshift
54 test al, 0x80
55 jz keydown
56 jmp keyup
58 keydown:
59 cmp byte [key_shift], 0x00
60 jne keyboard_lowercase
61 jmp keyboard_uppercase
63 keyboard_lowercase:
64 mov rbx, keylayoutupper
65 jmp keyboard_processkey
67 keyboard_uppercase:
68 mov rbx, keylayoutlower
70 keyboard_processkey: ; Convert the scancode
71 add rbx, rax
72 mov bl, [rbx]
73 mov [key], bl
74 mov al, [key]
75 jmp keyboard_done
77 keyboard_escape:
78 jmp reboot
80 keyup:
81 jmp keyboard_done
83 keyboard_shift:
84 mov byte [key_shift], 0x01
85 jmp keyboard_done
87 keyboard_noshift:
88 mov byte [key_shift], 0x00
89 jmp keyboard_done
91 keyboard_done:
92 mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC
93 add rdi, 0xB0
94 xor eax, eax
95 stosd
96 call os_smp_wakeup_all ; A terrible hack
98 pop rax
99 pop rbx
100 pop rdi
101 iretq
102 ; -----------------------------------------------------------------------------
105 ; -----------------------------------------------------------------------------
106 ; Real-time clock interrupt. IRQ 0x08, INT 0x28
107 ; Currently this IRQ runs 8 times per second (As defined in init_64.asm)
108 ; The supervisor lives here
109 align 16
110 rtc:
111 push rsi
112 push rcx
113 push rax
115 cld ; Clear direction flag
116 add qword [os_ClockCounter], 1 ; 64-bit counter started at bootup
118 cmp byte [os_show_sysstatus], 0
119 je rtc_no_sysstatus
120 call system_status ; Show System Status information on screen
121 rtc_no_sysstatus:
123 ; Check to make sure that at least one core is running something
124 cmp word [os_QueueLen], 0 ; Check the length of the Queue
125 jne rtc_end ; If it is greater than 0 then skip to the end
126 mov rcx, 256
127 mov rsi, cpustatus
128 nextcpu:
129 lodsb
130 dec rcx
131 bt ax, 1 ; Is bit 1 set? If so then the CPU is running a job
132 jc rtc_end
133 cmp rcx, 0
134 jne nextcpu
135 mov rax, os_command_line ; If nothing is running then restart the CLI
136 call os_smp_enqueue
138 rtc_end:
139 mov al, 0x0C ; Select RTC register C
140 out 0x70, al ; Port 0x70 is the RTC index, and 0x71 is the RTC data
141 in al, 0x71 ; Read the value in register C
142 mov rsi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC
143 xor eax, eax
144 mov dword [rsi+0xB0], eax
146 pop rax
147 pop rcx
148 pop rsi
149 iretq
150 ; -----------------------------------------------------------------------------
153 ; -----------------------------------------------------------------------------
154 ; Network interrupt.
155 align 16
156 network:
157 push rdi
158 push rsi
159 push rcx
160 push rax
161 pushfq
163 cld ; Clear direction flag
164 call os_ethernet_ack_int ; Call the driver function to acknowledge the interrupt internally
166 bt ax, 0 ; TX bit set (caused the IRQ?)
167 jc network_tx ; If so then jump past RX section
168 bt ax, 7 ; RX bit set
169 jnc network_end
170 network_rx_as_well:
171 mov byte [os_NetActivity_RX], 1
173 ; Max size of Ethernet packet: 1518
174 ; + size: 2 = 1520 = 0x5F0
175 ; Set each element size to 0x800 (2048). 262144 byte buffer / 2048 = room for 128 packets
176 ; Deal with the received packet
177 ; Get current offset in the ring buffer
178 mov rdi, os_EthernetBuffer
179 xor rax, rax
180 mov al, byte [os_EthernetBuffer_C2]
181 push rax ; Save the ring element value
182 shl rax, 11 ; Quickly multiply RAX by 2048
183 add rdi, rax
184 push rdi
185 add rdi, 2
186 call os_ethernet_rx_from_interrupt
187 pop rdi
188 mov rax, rcx
189 stosw ; Store the size of the packet
190 ; increment the offset in the ring buffer
191 pop rax ; Restore the ring element value
192 add al, 1
193 cmp al, 128 ; Max element number is 127
194 jne network_rx_buffer_nowrap
195 xor al, al
196 network_rx_buffer_nowrap:
197 mov byte [os_EthernetBuffer_C2], al
199 ; Check the packet type
200 mov ax, [rdi+12] ; Grab the EtherType/Length
201 xchg al, ah ; Convert big endian to little endian
202 cmp ax, 0x0800 ; IPv4
203 je network_IPv4_handler
204 cmp ax, 0x0806 ; ARP
205 je network_ARP_handler
206 cmp ax, 0x86DD ; IPv6
207 je network_IPv6_handler
209 jmp network_end
211 network_tx:
212 mov byte [os_NetActivity_TX], 1
213 bt ax, 7
214 jc network_rx_as_well
216 network_end:
217 mov rdi, [os_LocalAPICAddress] ; Acknowledge the IRQ on APIC
218 add rdi, 0xB0
219 xor eax, eax
220 stosd
222 popfq
223 pop rax
224 pop rcx
225 pop rsi
226 pop rdi
227 iretq
229 network_ARP_handler: ; Copy the packet and call the handler
230 mov rsi, rdi ; Copy the packet location
231 mov rdi, os_eth_temp_buffer ; and copy it here
232 push rsi
233 push rcx
234 rep movsb
235 pop rcx
236 pop rsi
238 ; Remove the ARP packet from the ring buffer
239 ; mov al, byte [os_EthernetBuffer_C2]
241 call os_arp_handler ; Handle the packet
242 jmp network_end
244 network_IPv4_handler:
245 mov rsi, rdi ; Copy the packet location
246 mov rdi, os_eth_temp_buffer ; and copy it here
247 push rsi
248 push rcx
249 rep movsb
250 pop rcx
251 pop rsi
253 mov al, [rsi+0x17]
254 cmp al, 0x01 ; ICMP
255 je network_IPv4_ICMP_handler
256 cmp al, 0x06 ; TCP
257 je network_IPv4_TCP_handler
258 cmp al, 0x11 ; UDP
259 je network_end
260 jmp network_end
262 network_IPv4_ICMP_handler:
263 call os_icmp_handler
264 jmp network_end
266 network_IPv4_TCP_handler:
267 call os_tcp_handler
268 jmp network_end
270 network_IPv6_handler:
271 jmp network_end
273 network_string01 db 'ARP!', 0
274 network_string02 db 'ICMP!', 0
275 network_string03 db 'TCP!', 0
276 network_string04 db 'UDP!', 0
277 ; -----------------------------------------------------------------------------
280 ; -----------------------------------------------------------------------------
281 ; A simple interrupt that just acknowledges an IPI. Useful for getting an AP past a 'hlt' in the code.
282 align 16
283 ap_wakeup:
284 push rdi
285 push rax
287 cld ; Clear direction flag
288 mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI
289 add rdi, 0xB0
290 xor rax, rax
291 stosd
293 pop rax
294 pop rdi
295 iretq ; Return from the IPI.
296 ; -----------------------------------------------------------------------------
299 ; -----------------------------------------------------------------------------
300 ; Resets a CPU to execute ap_clear
301 align 16
302 ap_reset:
303 cld ; Clear direction flag
304 mov rax, ap_clear ; Set RAX to the address of ap_clear
305 mov [rsp], rax ; Overwrite the return address on the CPU's stack
306 mov rdi, [os_LocalAPICAddress] ; Acknowledge the IPI
307 add rdi, 0xB0
308 xor rax, rax
309 stosd
310 iretq ; Return from the IPI. CPU will execute code at ap_clear
311 ; -----------------------------------------------------------------------------
314 ; -----------------------------------------------------------------------------
315 ; CPU Exception Gates
316 align 16
317 exception_gate_00:
318 push rax
319 mov al, 0x00
320 jmp exception_gate_main
322 align 16
323 exception_gate_01:
324 push rax
325 mov al, 0x01
326 jmp exception_gate_main
328 align 16
329 exception_gate_02:
330 push rax
331 mov al, 0x02
332 jmp exception_gate_main
334 align 16
335 exception_gate_03:
336 push rax
337 mov al, 0x03
338 jmp exception_gate_main
340 align 16
341 exception_gate_04:
342 push rax
343 mov al, 0x04
344 jmp exception_gate_main
346 align 16
347 exception_gate_05:
348 push rax
349 mov al, 0x05
350 jmp exception_gate_main
352 align 16
353 exception_gate_06:
354 push rax
355 mov al, 0x06
356 jmp exception_gate_main
358 align 16
359 exception_gate_07:
360 push rax
361 mov al, 0x07
362 jmp exception_gate_main
364 align 16
365 exception_gate_08:
366 push rax
367 mov al, 0x08
368 jmp exception_gate_main
370 align 16
371 exception_gate_09:
372 push rax
373 mov al, 0x09
374 jmp exception_gate_main
376 align 16
377 exception_gate_10:
378 push rax
379 mov al, 0x0A
380 jmp exception_gate_main
382 align 16
383 exception_gate_11:
384 push rax
385 mov al, 0x0B
386 jmp exception_gate_main
388 align 16
389 exception_gate_12:
390 push rax
391 mov al, 0x0C
392 jmp exception_gate_main
394 align 16
395 exception_gate_13:
396 push rax
397 mov al, 0x0D
398 jmp exception_gate_main
400 align 16
401 exception_gate_14:
402 push rax
403 mov al, 0x0E
404 jmp exception_gate_main
406 align 16
407 exception_gate_15:
408 push rax
409 mov al, 0x0F
410 jmp exception_gate_main
412 align 16
413 exception_gate_16:
414 push rax
415 mov al, 0x10
416 jmp exception_gate_main
418 align 16
419 exception_gate_17:
420 push rax
421 mov al, 0x11
422 jmp exception_gate_main
424 align 16
425 exception_gate_18:
426 push rax
427 mov al, 0x12
428 jmp exception_gate_main
430 align 16
431 exception_gate_19:
432 push rax
433 mov al, 0x13
434 jmp exception_gate_main
436 align 16
437 exception_gate_main:
438 push rbx
439 push rdi
440 push rsi
441 push rax ; Save RAX since os_smp_get_id clobers it
442 call os_print_newline
443 mov bl, 0x0F
444 mov rsi, int_string00
445 call os_print_string_with_color
446 call os_smp_get_id ; Get the local CPU ID and print it
447 mov rdi, os_temp_string
448 mov rsi, rdi
449 call os_int_to_string
450 call os_print_string_with_color
451 mov rsi, int_string01
452 call os_print_string
453 mov rsi, exc_string00
454 pop rax
455 and rax, 0x00000000000000FF ; Clear out everything in RAX except for AL
456 push rax
457 mov bl, 52
458 mul bl ; AX = AL x BL
459 add rsi, rax ; Use the value in RAX as an offset to get to the right message
460 pop rax
461 mov bl, 0x0F
462 call os_print_string_with_color
463 call os_print_newline
464 pop rsi
465 pop rdi
466 pop rbx
467 pop rax
468 call os_print_newline
469 call os_debug_dump_reg
470 mov rsi, rip_string
471 call os_print_string
472 push rax
473 mov rax, [rsp+0x08] ; RIP of caller
474 call os_debug_dump_rax
475 pop rax
476 call os_print_newline
477 push rax
478 push rcx
479 push rsi
480 mov rsi, stack_string
481 call os_print_string
482 mov rsi, rsp
483 add rsi, 0x18
484 mov rcx, 4
485 next_stack:
486 lodsq
487 call os_debug_dump_rax
488 mov al, ' '
489 call os_print_char
490 ; call os_print_char
491 ; call os_print_char
492 ; call os_print_char
493 loop next_stack
494 call os_print_newline
495 pop rsi
496 pop rcx
497 pop rax
498 ; jmp $ ; For debugging
499 call init_memory_map
500 jmp ap_clear ; jump to AP clear code
503 int_string00 db 'BareMetal OS - CPU ', 0
504 int_string01 db ' - ', 0
505 ; Strings for the error messages
506 exc_string db 'Unknown Fatal Exception!', 0
507 exc_string00 db 'Interrupt 00 - Divide Error Exception (#DE) ', 0
508 exc_string01 db 'Interrupt 01 - Debug Exception (#DB) ', 0
509 exc_string02 db 'Interrupt 02 - NMI Interrupt ', 0
510 exc_string03 db 'Interrupt 03 - Breakpoint Exception (#BP) ', 0
511 exc_string04 db 'Interrupt 04 - Overflow Exception (#OF) ', 0
512 exc_string05 db 'Interrupt 05 - BOUND Range Exceeded Exception (#BR)', 0
513 exc_string06 db 'Interrupt 06 - Invalid Opcode Exception (#UD) ', 0
514 exc_string07 db 'Interrupt 07 - Device Not Available Exception (#NM)', 0
515 exc_string08 db 'Interrupt 08 - Double Fault Exception (#DF) ', 0
516 exc_string09 db 'Interrupt 09 - Coprocessor Segment Overrun ', 0 ; No longer generated on new CPU's
517 exc_string10 db 'Interrupt 10 - Invalid TSS Exception (#TS) ', 0
518 exc_string11 db 'Interrupt 11 - Segment Not Present (#NP) ', 0
519 exc_string12 db 'Interrupt 12 - Stack Fault Exception (#SS) ', 0
520 exc_string13 db 'Interrupt 13 - General Protection Exception (#GP) ', 0
521 exc_string14 db 'Interrupt 14 - Page-Fault Exception (#PF) ', 0
522 exc_string15 db 'Interrupt 15 - Undefined ', 0
523 exc_string16 db 'Interrupt 16 - x87 FPU Floating-Point Error (#MF) ', 0
524 exc_string17 db 'Interrupt 17 - Alignment Check Exception (#AC) ', 0
525 exc_string18 db 'Interrupt 18 - Machine-Check Exception (#MC) ', 0
526 exc_string19 db 'Interrupt 19 - SIMD Floating-Point Exception (#XM) ', 0
527 rip_string db ' IP:', 0
528 stack_string db ' ST:', 0
532 ; =============================================================================
533 ; EOF