.section .text .global idt_load .type idt_load, @function idt_load: mov 4(%esp), %eax lidt (%eax) ret /* Common ISR stub */ isr_common_stub: pusha /* Save segment registers */ mov %ds, %ax push %eax /* Load kernel data segment */ mov $0x10, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs /* Push pointer to stack structure as argument for C handler */ push %esp call isr_handler add $4, %esp /* Clean up pushed pointer */ /* Restore segment registers */ pop %eax mov %eax, %ds mov %eax, %es mov %eax, %fs mov %eax, %gs popa add $8, %esp /* Cleans up error code and ISR number */ iret /* Macro for exceptions with NO Error Code */ .macro ISR_NOERRCODE num .global isr\num .type isr\num, @function isr\num: cli push $0 push $\num jmp isr_common_stub .endm /* Macro for exceptions WITH Error Code */ .macro ISR_ERRCODE num .global isr\num .type isr\num, @function isr\num: cli push $\num jmp isr_common_stub .endm ISR_NOERRCODE 0 ISR_NOERRCODE 1 ISR_NOERRCODE 2 ISR_NOERRCODE 3 ISR_NOERRCODE 4 ISR_NOERRCODE 5 ISR_NOERRCODE 6 ISR_NOERRCODE 7 ISR_ERRCODE 8 ISR_NOERRCODE 9 ISR_ERRCODE 10 ISR_ERRCODE 11 ISR_ERRCODE 12 ISR_ERRCODE 13 ISR_ERRCODE 14 ISR_NOERRCODE 15 ISR_NOERRCODE 16 ISR_ERRCODE 17 ISR_NOERRCODE 18 ISR_NOERRCODE 19 ISR_NOERRCODE 20 ISR_NOERRCODE 21 ISR_NOERRCODE 22 ISR_NOERRCODE 23 ISR_NOERRCODE 24 ISR_NOERRCODE 25 ISR_NOERRCODE 26 ISR_NOERRCODE 27 ISR_NOERRCODE 28 ISR_NOERRCODE 29 ISR_ERRCODE 30 ISR_NOERRCODE 31 /* Macro for IRQs (Hardware Interrupts) */ .macro ISR_IRQ num, idt_index .global irq\num .type irq\num, @function irq\num: cli push $0 push $\idt_index jmp isr_common_stub .endm /* Hardware Interrupts */ ISR_IRQ 0, 32 ISR_IRQ 1, 33 ISR_IRQ 2, 34 ISR_IRQ 3, 35 ISR_IRQ 4, 36 ISR_IRQ 5, 37 ISR_IRQ 6, 38 ISR_IRQ 7, 39 ISR_IRQ 8, 40 ISR_IRQ 9, 41 ISR_IRQ 10, 42 ISR_IRQ 11, 43 ISR_IRQ 12, 44 ISR_IRQ 13, 45 ISR_IRQ 14, 46 ISR_IRQ 15, 47 /* * INT 0x80 - System call entry point. * Uses the same isr_common_stub so the register layout matches registers_t. */ .global isr128 .type isr128, @function isr128: cli push $0 /* Fake error code */ push $0x80 /* Interrupt number 128 */ jmp isr_common_stub /* * tss_flush - Load the Task Register with the TSS selector. * TSS is GDT entry 5, selector = 5*8 = 0x28. With RPL=0: 0x28. */ .global tss_flush .type tss_flush, @function tss_flush: mov $0x28, %ax ltr %ax ret /* * enter_usermode - Switch to Ring 3 user mode via iret. * void enter_usermode(uint32_t eip, uint32_t esp); * * Builds an iret frame on the stack: * SS = 0x23 (user data) * ESP = user stack pointer * EFLAGS = IF=1 * CS = 0x1B (user code) * EIP = user entry point */ .global enter_usermode .type enter_usermode, @function enter_usermode: mov 4(%esp), %ecx /* user EIP */ mov 8(%esp), %edx /* user ESP */ /* Set data segment registers to user data segment */ mov $0x23, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs /* Build iret frame */ push $0x23 /* SS (user data) */ push %edx /* ESP (user stack) */ pushf /* EFLAGS */ orl $0x200, (%esp) /* Ensure IF (Interrupt Flag) is set */ push $0x1B /* CS (user code) */ push %ecx /* EIP (entry point) */ iret /* * process_switch_to_user - Restore full register state and iret to user mode. * void process_switch_to_user(registers_t *regs); * * Used by process_exit to context-switch to the next process when the normal * interrupt-return path isn't available (because we're not returning through * an ISR stub). Loads all registers from the registers_t struct and performs * iret to enter user mode. */ .global process_switch_to_user .type process_switch_to_user, @function process_switch_to_user: movl 4(%esp), %esp /* Point ESP to the registers_t struct */ /* Restore segment register (ds → all data segments) */ pop %eax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs popa /* Restore EAX-EDI */ addl $8, %esp /* Skip int_no and err_code */ iret /* Pops EIP, CS, EFLAGS, UserESP, SS */