1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2012 Return Infinity -- see LICENSE.TXT
6 ; =============================================================================
13 ; -----------------------------------------------------------------------------
14 ; Default exception handler
21 ; -----------------------------------------------------------------------------
24 ; -----------------------------------------------------------------------------
25 ; Default interrupt handler
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
43 in al, 0x60 ; Get the scancode from the keyboard
46 cmp al, 0x2A ; Left Shift Make
48 cmp al, 0x36 ; Right Shift Make
50 cmp al, 0xAA ; Left Shift Break
52 cmp al, 0xB6 ; Right Shift Break
59 cmp byte [key_shift
], 0x00
60 jne keyboard_lowercase
61 jmp keyboard_uppercase
64 mov rbx
, keylayoutupper
65 jmp keyboard_processkey
68 mov rbx
, keylayoutlower
70 keyboard_processkey: ; Convert the scancode
84 mov byte [key_shift
], 0x01
88 mov byte [key_shift
], 0x00
92 mov rdi
, [os_LocalAPICAddress
] ; Acknowledge the IRQ on APIC
96 call os_smp_wakeup_all
; A terrible hack
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
115 cld ; Clear direction flag
116 add qword [os_ClockCounter
], 1 ; 64-bit counter started at bootup
118 cmp byte [os_show_sysstatus
], 0
120 call system_status
; Show System Status information on screen
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
131 bt ax, 1 ; Is bit 1 set? If so then the CPU is running a job
135 mov rax
, os_command_line
; If nothing is running then restart the CLI
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
144 mov dword [rsi
+0xB0], eax
150 ; -----------------------------------------------------------------------------
153 ; -----------------------------------------------------------------------------
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
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
180 mov al, byte [os_EthernetBuffer_C2
]
181 push rax
; Save the ring element value
182 shl rax
, 11 ; Quickly multiply RAX by 2048
186 call os_ethernet_rx_from_interrupt
189 stosw ; Store the size of the packet
190 ; increment the offset in the ring buffer
191 pop rax
; Restore the ring element value
193 cmp al, 128 ; Max element number is 127
194 jne network_rx_buffer_nowrap
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
205 je network_ARP_handler
206 cmp ax, 0x86DD ; IPv6
207 je network_IPv6_handler
212 mov byte [os_NetActivity_TX
], 1
214 jc network_rx_as_well
217 mov rdi
, [os_LocalAPICAddress
] ; Acknowledge the IRQ on APIC
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
238 ; Remove the ARP packet from the ring buffer
239 ; mov al, byte [os_EthernetBuffer_C2]
241 call os_arp_handler
; Handle the packet
244 network_IPv4_handler:
245 mov rsi
, rdi
; Copy the packet location
246 mov rdi
, os_eth_temp_buffer
; and copy it here
255 je network_IPv4_ICMP_handler
257 je network_IPv4_TCP_handler
262 network_IPv4_ICMP_handler:
266 network_IPv4_TCP_handler:
270 network_IPv6_handler:
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.
287 cld ; Clear direction flag
288 mov rdi
, [os_LocalAPICAddress
] ; Acknowledge the IPI
295 iretq
; Return from the IPI.
296 ; -----------------------------------------------------------------------------
299 ; -----------------------------------------------------------------------------
300 ; Resets a CPU to execute ap_clear
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
310 iretq
; Return from the IPI. CPU will execute code at ap_clear
311 ; -----------------------------------------------------------------------------
314 ; -----------------------------------------------------------------------------
315 ; CPU Exception Gates
320 jmp exception_gate_main
326 jmp exception_gate_main
332 jmp exception_gate_main
338 jmp exception_gate_main
344 jmp exception_gate_main
350 jmp exception_gate_main
356 jmp exception_gate_main
362 jmp exception_gate_main
368 jmp exception_gate_main
374 jmp exception_gate_main
380 jmp exception_gate_main
386 jmp exception_gate_main
392 jmp exception_gate_main
398 jmp exception_gate_main
404 jmp exception_gate_main
410 jmp exception_gate_main
416 jmp exception_gate_main
422 jmp exception_gate_main
428 jmp exception_gate_main
434 jmp exception_gate_main
441 push rax
; Save RAX since os_smp_get_id clobers it
442 call os_print_newline
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
449 call os_int_to_string
450 call os_print_string_with_color
451 mov rsi
, int_string01
453 mov rsi
, exc_string00
455 and rax
, 0x00000000000000FF ; Clear out everything in RAX except for AL
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
462 call os_print_string_with_color
463 call os_print_newline
468 call os_print_newline
469 call os_debug_dump_reg
473 mov rax
, [rsp
+0x08] ; RIP of caller
474 call os_debug_dump_rax
476 call os_print_newline
480 mov rsi
, stack_string
487 call os_debug_dump_rax
494 call os_print_newline
498 ; jmp $ ; For debugging
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 ; =============================================================================