From c77d9395cd9cc53f9f06a018183ff6d6b3a47458 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Thu, 20 Jun 2013 00:01:04 +0200 Subject: [PATCH] Refactor kernel interrupt handling. --- sortix/Makefile | 1 - sortix/include/sortix/kernel/interrupt.h | 38 ++--- sortix/interrupt.cpp | 180 +++++++++++------------ sortix/x64/idt.s | 33 ----- sortix/x86-family/idt.cpp | 88 ++++++----- sortix/x86-family/idt.h | 55 +------ sortix/x86/idt.s | 34 ----- 7 files changed, 168 insertions(+), 261 deletions(-) delete mode 100644 sortix/x64/idt.s delete mode 100644 sortix/x86/idt.s diff --git a/sortix/Makefile b/sortix/Makefile index 2b7bfcdc..0fbf63da 100644 --- a/sortix/Makefile +++ b/sortix/Makefile @@ -48,7 +48,6 @@ ifdef X86FAMILY $(CPU)/interrupt.o \ $(CPU)/gdt.o \ x86-family/gdt.o \ - $(CPU)/idt.o \ x86-family/idt.o \ $(CPU)/syscall.o \ $(CPU)/thread.o \ diff --git a/sortix/include/sortix/kernel/interrupt.h b/sortix/include/sortix/kernel/interrupt.h index 0d58e337..8ac6a323 100644 --- a/sortix/include/sortix/kernel/interrupt.h +++ b/sortix/include/sortix/kernel/interrupt.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -35,22 +35,22 @@ struct InterruptRegisters; namespace Interrupt { -const unsigned IRQ0 = 32; -const unsigned IRQ1 = 33; -const unsigned IRQ2 = 34; -const unsigned IRQ3 = 35; -const unsigned IRQ4 = 36; -const unsigned IRQ5 = 37; -const unsigned IRQ6 = 38; -const unsigned IRQ7 = 39; -const unsigned IRQ8 = 40; -const unsigned IRQ9 = 41; -const unsigned IRQ10 = 42; -const unsigned IRQ11 = 43; -const unsigned IRQ12 = 44; -const unsigned IRQ13 = 45; -const unsigned IRQ14 = 46; -const unsigned IRQ15 = 47; +const unsigned int IRQ0 = 32; +const unsigned int IRQ1 = 33; +const unsigned int IRQ2 = 34; +const unsigned int IRQ3 = 35; +const unsigned int IRQ4 = 36; +const unsigned int IRQ5 = 37; +const unsigned int IRQ6 = 38; +const unsigned int IRQ7 = 39; +const unsigned int IRQ8 = 40; +const unsigned int IRQ9 = 41; +const unsigned int IRQ10 = 42; +const unsigned int IRQ11 = 43; +const unsigned int IRQ12 = 44; +const unsigned int IRQ13 = 45; +const unsigned int IRQ14 = 46; +const unsigned int IRQ15 = 47; extern "C" unsigned long asm_interrupts_are_enabled(); extern "C" unsigned long asm_is_cpu_interrupted; @@ -67,10 +67,10 @@ inline bool SetEnabled(bool isenabled) } typedef void (*Handler)(CPU::InterruptRegisters* regs, void* user); -void RegisterHandler(unsigned index, Handler handler, void* user); +void RegisterHandler(unsigned int index, Handler handler, void* user); typedef void (*RawHandler)(void); -void RegisterRawHandler(unsigned index, RawHandler handler, bool userspace); +void RegisterRawHandler(unsigned int index, RawHandler handler, bool userspace); void Init(); void InitWorker(); diff --git a/sortix/interrupt.cpp b/sortix/interrupt.cpp index e009a745..e11967eb 100644 --- a/sortix/interrupt.cpp +++ b/sortix/interrupt.cpp @@ -22,9 +22,14 @@ *******************************************************************************/ +#include +#include +#include + #include #include #include +#include #include #include #include @@ -32,10 +37,6 @@ #include #include -#include -#include -#include - #include "x86-family/idt.h" #include "sound.h" // Hack for SIGSEGV @@ -67,42 +68,40 @@ const bool DEBUG_ISR = false; const bool CALLTRACE_KERNEL = false; const bool CALLTRACE_USER = false; const bool RUN_DEBUGGER_ON_CRASH = false; -bool initialized; const size_t NUM_KNOWN_EXCEPTIONS = 20; const char* exceptions[] = { - "Divide by zero", - "Debug", - "Non maskable interrupt", - "Breakpoint", - "Into detected overflow", - "Out of bounds", - "Invalid opcode", - "No coprocessor", - "Double fault", - "Coprocessor segment overrun", - "Bad TSS", - "Segment not present", - "Stack fault", - "General protection fault", - "Page fault", - "Unknown interrupt", - "Coprocessor fault", - "Alignment check", - "Machine check", - "SIMD Floating-Point", + "Divide by zero", /* 0, 0x0 */ + "Debug", /* 1, 0x1 */ + "Non maskable interrupt", /* 2, 0x2 */ + "Breakpoint", /* 3, 0x3 */ + "Into detected overflow", /* 4, 0x4 */ + "Out of bounds", /* 5, 0x5 */ + "Invalid opcode", /* 6, 0x6 */ + "No coprocessor", /* 7, 0x7 */ + "Double fault", /* 8, 0x8 */ + "Coprocessor segment overrun", /* 9, 0x9 */ + "Bad TSS", /* 10, 0xA */ + "Segment not present", /* 11, 0xB */ + "Stack fault", /* 12, 0xC */ + "General protection fault", /* 13, 0xD */ + "Page fault", /* 14, 0xE */ + "Unknown interrupt", /* 15, 0xF */ + "Coprocessor fault", /* 16, 0x10 */ + "Alignment check", /* 17, 0x11 */ + "Machine check", /* 18, 0x12 */ + "SIMD Floating-Point", /* 19, 0x13 */ }; -const unsigned NUM_INTERRUPTS = 256UL; - -Handler interrupthandlers[NUM_INTERRUPTS]; -void* interrupthandlerptr[NUM_INTERRUPTS]; +const unsigned int NUM_INTERRUPTS = 256UL; +static Handler interrupt_handlers[NUM_INTERRUPTS]; +static void* interrupt_handler_params[NUM_INTERRUPTS]; extern "C" void ReprogramPIC() { - uint8_t mastermask = 0; - uint8_t slavemask = 0; + uint8_t master_mask = 0; + uint8_t slave_mask = 0; CPU::OutPortB(PIC_MASTER + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4); CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4); CPU::OutPortB(PIC_MASTER + PIC_DATA, IRQ0); @@ -111,14 +110,14 @@ extern "C" void ReprogramPIC() CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x02); // Cascade Identity CPU::OutPortB(PIC_MASTER + PIC_DATA, PIC_MODE_8086); CPU::OutPortB(PIC_SLAVE + PIC_DATA, PIC_MODE_8086); - CPU::OutPortB(PIC_MASTER + PIC_DATA, mastermask); - CPU::OutPortB(PIC_SLAVE + PIC_DATA, slavemask); + CPU::OutPortB(PIC_MASTER + PIC_DATA, master_mask); + CPU::OutPortB(PIC_SLAVE + PIC_DATA, slave_mask); } extern "C" void DeprogramPIC() { - uint8_t mastermask = 0; - uint8_t slavemask = 0; + uint8_t master_mask = 0; + uint8_t slave_mask = 0; CPU::OutPortB(PIC_MASTER + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4); CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4); CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x08); @@ -127,19 +126,18 @@ extern "C" void DeprogramPIC() CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x02); // Cascade Identity CPU::OutPortB(PIC_MASTER + PIC_DATA, PIC_MODE_8086); CPU::OutPortB(PIC_SLAVE + PIC_DATA, PIC_MODE_8086); - CPU::OutPortB(PIC_MASTER + PIC_DATA, mastermask); - CPU::OutPortB(PIC_SLAVE + PIC_DATA, slavemask); + CPU::OutPortB(PIC_MASTER + PIC_DATA, master_mask); + CPU::OutPortB(PIC_SLAVE + PIC_DATA, slave_mask); } void Init() { - initialized = false; IDT::Init(); - for ( unsigned i = 0; i < NUM_INTERRUPTS; i++ ) + for ( unsigned int i = 0; i < NUM_INTERRUPTS; i++ ) { - interrupthandlers[i] = NULL; - interrupthandlerptr[i] = NULL; + interrupt_handlers[i] = NULL; + interrupt_handler_params[i] = NULL; RegisterRawHandler(i, interrupt_handler_null, false); } @@ -198,37 +196,38 @@ void Init() // TODO: Let the syscall.cpp code register this. RegisterRawHandler(128, syscall_handler, true); - IDT::Flush(); - initialized = true; - Interrupt::Enable(); } -void RegisterHandler(unsigned n, Interrupt::Handler handler, void* user) +void RegisterHandler(unsigned int index, Interrupt::Handler handler, void* user) { - interrupthandlers[n] = handler; - interrupthandlerptr[n] = user; + interrupt_handlers[index] = handler; + interrupt_handler_params[index] = user; } // TODO: This function contains magic IDT-related values! -void RegisterRawHandler(unsigned index, RawHandler handler, bool userspace) +void RegisterRawHandler(unsigned int index, RawHandler handler, bool userspace) { - addr_t handlerentry = (addr_t) handler; - uint16_t sel = 0x08; + addr_t handler_entry = (addr_t) handler; + uint16_t sel = KCS; uint8_t flags = 0x8E; - if ( userspace ) { flags |= 0x60; } - IDT::SetGate(index, handlerentry, sel, flags); - if ( initialized ) { IDT::Flush(); } + if ( userspace ) + flags |= 0x60; + IDT::SetEntry(index, handler_entry, sel, flags); } void CrashHandler(CPU::InterruptRegisters* regs) { CurrentThread()->SaveRegisters(regs); - const char* message = ( regs->int_no < NUM_KNOWN_EXCEPTIONS ) + const char* message = regs->int_no < NUM_KNOWN_EXCEPTIONS ? exceptions[regs->int_no] : "Unknown"; - if ( DEBUG_EXCEPTION ) { regs->LogRegisters(); Log::Print("\n"); } + if ( DEBUG_EXCEPTION ) + { + regs->LogRegisters(); + Log::Print("\n"); + } #ifdef PLATFORM_X64 addr_t ip = regs->rip; @@ -237,8 +236,8 @@ void CrashHandler(CPU::InterruptRegisters* regs) #endif // Halt and catch fire if we are the kernel. - unsigned codemode = regs->cs & 0x3U; - bool is_in_kernel = !codemode; + unsigned code_mode = regs->cs & 0x3; + bool is_in_kernel = !code_mode; bool is_in_user = !is_in_kernel; if ( (is_in_kernel && CALLTRACE_KERNEL) || (is_in_user && CALLTRACE_USER) ) @@ -267,9 +266,6 @@ void CrashHandler(CPU::InterruptRegisters* regs) Log::PrintF("%s exception at ip=0x%zx (cr2=0x%p, err_code=0x%p)\n", message, ip, regs->cr2, regs->err_code); - //addr_t topofstack = ((size_t*) regs->useresp)[0]; - //Log::PrintF("Top of stack is 0x%zx\n", topofstack); - Sound::Mute(); // Exit the process with the right error code. @@ -280,33 +276,30 @@ void CrashHandler(CPU::InterruptRegisters* regs) Signal::Dispatch(regs); } -void ISRHandler(Sortix::CPU::InterruptRegisters* regs) +void ISRHandler(CPU::InterruptRegisters* regs) { + unsigned int int_no = regs->int_no; + if ( DEBUG_ISR ) { - Log::PrintF("ISR%u ", regs->int_no); + Log::PrintF("ISR%u ", int_no); regs->LogRegisters(); Log::Print("\n"); } - if ( regs->int_no < 32 && regs->int_no != 7 ) - { + // Run the desired interrupt handler. + if ( int_no < 32 && int_no != 7 ) CrashHandler(regs); - return; - } - - if ( interrupthandlers[regs->int_no] != NULL ) - { - void* user = interrupthandlerptr[regs->int_no]; - interrupthandlers[regs->int_no](regs, user); - } + else if ( interrupt_handlers[regs->int_no] != NULL ) + interrupt_handlers[int_no](regs, interrupt_handler_params[int_no]); } -void IRQHandler(Sortix::CPU::InterruptRegisters* regs) +void IRQHandler(CPU::InterruptRegisters* regs) { // TODO: IRQ 7 and 15 might be spurious and might need to be ignored. // See http://wiki.osdev.org/PIC for details (section Spurious IRQs). - if ( regs->int_no == 32 + 7 || regs->int_no == 32 + 15 ) { return; } + if ( regs->int_no == 32 + 7 || regs->int_no == 32 + 15 ) + return; if ( DEBUG_IRQ ) { @@ -315,24 +308,23 @@ void IRQHandler(Sortix::CPU::InterruptRegisters* regs) Log::Print("\n"); } - unsigned int_no = regs->int_no; + unsigned int int_no = regs->int_no; // Send an EOI (end of interrupt) signal to the PICs. - if ( IRQ8 <= int_no ) { CPU::OutPortB(PIC_SLAVE, PIC_CMD_ENDINTR); } + if ( IRQ8 <= int_no ) + CPU::OutPortB(PIC_SLAVE, PIC_CMD_ENDINTR); CPU::OutPortB(PIC_MASTER, PIC_CMD_ENDINTR); - if ( interrupthandlers[int_no] ) - { - void* user = interrupthandlerptr[int_no]; - interrupthandlers[int_no](regs, user); - } + if ( interrupt_handlers[int_no] ) + interrupt_handlers[int_no](regs, interrupt_handler_params[int_no]); } -extern "C" void interrupt_handler(Sortix::CPU::InterruptRegisters* regs) +extern "C" void interrupt_handler(CPU::InterruptRegisters* regs) { - size_t int_no = regs->int_no; - if ( 32 <= int_no && int_no < 48 ) { IRQHandler(regs); } - else { ISRHandler(regs); } + if ( 32 <= regs->int_no && regs->int_no < 48 ) + IRQHandler(regs); + else + ISRHandler(regs); } // TODO: This implementation is a bit hacky and can be optimized. @@ -357,9 +349,11 @@ void InitWorker() const size_t QUEUE_SIZE = 4UL*1024UL; STATIC_ASSERT(QUEUE_SIZE % sizeof(Package) == 0); queue = new uint8_t[QUEUE_SIZE]; - if ( !queue ) { Panic("Can't allocate interrupt worker queue"); } + if ( !queue ) + Panic("Can't allocate interrupt worker queue"); storage = new uint8_t[QUEUE_SIZE]; - if ( !storage ) { Panic("Can't allocate interrupt worker storage"); } + if ( !storage ) + Panic("Can't allocate interrupt worker storage"); queuesize = QUEUE_SIZE; queueoffset = 0; queueused = 0; @@ -373,7 +367,8 @@ static void WriteToQueue(const void* src, size_t size) size_t count = available < size ? available : size; memcpy(queue + writeat, buf, count); queueused += count; - if ( count < size ) { WriteToQueue(buf + count, size - count); } + if ( count < size ) + WriteToQueue(buf + count, size - count); } static void ReadFromQueue(void* dest, size_t size) @@ -384,7 +379,8 @@ static void ReadFromQueue(void* dest, size_t size) memcpy(buf, queue + queueoffset, count); queueused -= count; queueoffset = (queueoffset + count) % queuesize; - if ( count < size ) { ReadFromQueue(buf + count, size - count); } + if ( count < size ) + ReadFromQueue(buf + count, size - count); } static Package* PopPackage(uint8_t** payloadp, Package* /*prev*/) @@ -393,7 +389,8 @@ static Package* PopPackage(uint8_t** payloadp, Package* /*prev*/) uint8_t* payload = NULL; Interrupt::Disable(); - if ( !queueused ) { goto out; } + if ( !queueused ) + goto out; package = (Package*) storage; ReadFromQueue(package, sizeof(*package)); @@ -431,7 +428,8 @@ bool ScheduleWork(WorkHandler handler, void* payload, size_t payloadsize) package.handler = handler; size_t queuefreespace = queuesize - queueused; - if ( queuefreespace < package.size ) { return false; } + if ( queuefreespace < package.size ) + return false; WriteToQueue(&package, sizeof(package)); WriteToQueue(payload, payloadsize); diff --git a/sortix/x64/idt.s b/sortix/x64/idt.s deleted file mode 100644 index 0611e33b..00000000 --- a/sortix/x64/idt.s +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. - - This file is part of Sortix. - - Sortix is free software: you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation, either version 3 of the License, or (at your option) any later - version. - - Sortix is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - You should have received a copy of the GNU General Public License along with - Sortix. If not, see . - - x64/idt.s - Handles initialization of the 64-bit IDT. - -*******************************************************************************/ - -.section .text - -.global idt_flush -.type idt_flush, @function -idt_flush: - # Load the IDT pointer. - lidt (%rdi) - ret -.size idt_flush, . - idt_flush diff --git a/sortix/x86-family/idt.cpp b/sortix/x86-family/idt.cpp index 9b90ff91..d986e018 100644 --- a/sortix/x86-family/idt.cpp +++ b/sortix/x86-family/idt.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -18,48 +18,64 @@ Sortix. If not, see . x86-family/idt.cpp - Initializes and handles the IDT. + Initializes and handles the interrupt descriptor table. *******************************************************************************/ -#include +#include #include + #include "idt.h" -namespace Sortix +namespace Sortix { +namespace IDT { + +struct idt_entry { - namespace IDT - { - extern "C" void idt_flush(addr_t); - - idt_entry_t idt_entries[256]; - idt_ptr_t idt_ptr; - - void Init() - { - idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; - idt_ptr.base = (addr_t) &idt_entries; - - memset(&idt_entries, 0, sizeof(idt_entry_t)*256); - } - - void Flush() - { - idt_flush((addr_t) &idt_ptr); - } - - void SetGate(uint8_t num, addr_t base, uint16_t sel, uint8_t flags) - { - idt_entries[num].base_low = base & 0xFFFF; - idt_entries[num].base_high = (base >> 16) & 0xFFFF; -#ifdef PLATFORM_X64 - idt_entries[num].base_highest = (base >> 32 ) & 0xFFFFFFFFU; - idt_entries[num].zero1 = 0; + uint16_t handler_low; + uint16_t sel; + uint8_t reserved0; + uint8_t flags; + uint16_t handler_high; +#if defined(__x86_64__) + uint32_t handler_highest; + uint32_t reserved1; #endif +}; - idt_entries[num].sel = sel; - idt_entries[num].always0 = 0; - idt_entries[num].flags = flags; - } - } +struct idt_ptr +{ + uint16_t limit; +#if defined(__x86_64__) + uint64_t idt_ptr; +#else + uint32_t idt_ptr; +#endif +} __attribute__((packed)); + +static struct idt_entry idt_entries[256]; + +void Init() +{ + volatile struct idt_ptr ptr; + ptr.limit = sizeof(idt_entries) - 1; + ptr.idt_ptr = (unsigned long) &idt_entries; + asm volatile ("lidt (%0)" : : "r"(&ptr)); + memset(&idt_entries, 0, sizeof(idt_entries)); } + +void SetEntry(uint8_t num, uintptr_t handler, uint16_t sel, uint8_t flags) +{ + idt_entries[num].flags = flags; + idt_entries[num].reserved0 = 0; + idt_entries[num].sel = sel; + idt_entries[num].handler_low = handler >> 0 & 0xFFFF; + idt_entries[num].handler_high = handler >> 16 & 0xFFFF; +#if defined(__x86_64__) + idt_entries[num].handler_highest = handler >> 32 & 0xFFFFFFFFU; + idt_entries[num].reserved1 = 0; +#endif +} + +} // namespace IDT +} // namespace Sortix diff --git a/sortix/x86-family/idt.h b/sortix/x86-family/idt.h index 5788bd05..aa6d6981 100644 --- a/sortix/x86-family/idt.h +++ b/sortix/x86-family/idt.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -25,53 +25,14 @@ #ifndef SORTIX_X86_FAMILY_IDT_H #define SORTIX_X86_FAMILY_IDT_H -namespace Sortix -{ - namespace IDT - { - // A struct describing an interrupt gate. - struct idt_entry32_struct - { - uint16_t base_low; // The lower 16 bits of the address to jump to when this interrupt fires. - uint16_t sel; // Kernel segment selector. - uint8_t always0; // This must always be zero. - uint8_t flags; // More flags. See documentation. - uint16_t base_high; // The upper 16 bits of the address to jump to. - } __attribute__((packed)); +namespace Sortix { +namespace IDT { - struct idt_entry64_struct - { - uint16_t base_low; // The lower 16 bits of the address to jump to when this interrupt fires. - uint16_t sel; // Kernel segment selector. - uint8_t always0; // This must always be zero. - uint8_t flags; // More flags. See documentation. - uint16_t base_high; // The upper 16 bits of the address to jump to. - uint32_t base_highest; - uint32_t zero1; // Reserved - } __attribute__((packed)); +void Init(); +void SetEntry(uint8_t num, uintptr_t handler, uint16_t sel, uint8_t flags); +void Flush(); - typedef struct idt_entry32_struct idt_entry32_t; - typedef struct idt_entry64_struct idt_entry64_t; -#ifdef PLATFORM_X64 - typedef idt_entry64_t idt_entry_t; -#else - typedef idt_entry32_t idt_entry_t; -#endif - - // A struct describing a pointer to an array of interrupt handlers. - // This is in a format suitable for giving to 'lidt'. - struct idt_ptr_struct - { - uint16_t limit; - addr_t base; // The address of the first element in our idt_entry_t array. - } __attribute__((packed)); - - typedef struct idt_ptr_struct idt_ptr_t; - - void Init(); - void SetGate(uint8_t num, addr_t base, uint16_t sel, uint8_t flags); - void Flush(); - } -} +} // namespace IDT +} // namespace Sortix #endif diff --git a/sortix/x86/idt.s b/sortix/x86/idt.s deleted file mode 100644 index 73f14e2f..00000000 --- a/sortix/x86/idt.s +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. - - This file is part of Sortix. - - Sortix is free software: you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation, either version 3 of the License, or (at your option) any later - version. - - Sortix is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - You should have received a copy of the GNU General Public License along with - Sortix. If not, see . - - x86/idt.s - Handles initialization of the 32-bit IDT. - -*******************************************************************************/ - -.section .text - -.global idt_flush -.type idt_flush, @function -idt_flush: - # Load the IDT pointer. - mov 4(%esp), %eax - lidt (%eax) - ret -.size idt_flush, . - idt_flush