|
[ source navigation ] [ diff markup ] [ identifier search ] [ general search ] |
|||
|
001 /* Copyright (C) 2004 David Decotigny 002 Copyright (C) 1999 Free Software Foundation, Inc. 003 004 This program is free software; you can redistribute it and/or 005 modify it under the terms of the GNU General Public License 006 as published by the Free Software Foundation; either version 2 007 of the License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU General Public License for more details. 013 014 You should have received a copy of the GNU General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 017 USA. 018 */ 019 #include "segment.h" 020 021 #include "idt.h" 022 023 /** 024 * An entry in the IDT, or "IDTE" in the following, ie a reference to 025 * a interrupt/trap routine or a task gate to handle the sw/hw 026 * interrupts and exceptions. 027 * 028 * @see figure 5-2, intel x86 doc, vol 3 029 */ 030 struct x86_idt_entry 031 { 032 /* Low dword */ 033 sos_ui16_t offset_low; /* 15..0, offset of the routine in the segment */ 034 sos_ui16_t seg_sel; /* 31..16, the ID of the segment */ 035 036 /* High dword */ 037 sos_ui8_t reserved:5; /* 4..0 */ 038 sos_ui8_t flags:3; /* 7..5 */ 039 sos_ui8_t type:3; /* 10..8 (interrupt gate, trap gate...) */ 040 sos_ui8_t op_size:1; /* 11 (0=16bits instructions, 1=32bits instr.) */ 041 sos_ui8_t zero:1; /* 12 */ 042 sos_ui8_t dpl:2; /* 14..13 */ 043 sos_ui8_t present:1; /* 15 */ 044 sos_ui16_t offset_high; /* 31..16 */ 045 } __attribute__((packed)); 046 047 048 /** 049 * The IDT register, which stores the address and size of the 050 * IDT. 051 * 052 * @see Intel x86 doc vol 3, section 2.4, figure 2-4 053 */ 054 struct x86_idt_register 055 { 056 /* The maximum GDT offset allowed to access an entry in the GDT */ 057 sos_ui16_t limit; 058 059 /* This is not exactly a "virtual" address, ie an adddress such as 060 those of instructions and data; this is a "linear" address, ie an 061 address in the paged memory. However, in SOS we configure the 062 segmented memory as a "flat" space: the 0-4GB segment-based (ie 063 "virtual") addresses directly map to the 0-4GB paged memory (ie 064 "linear"), so that the "linear" addresses are numerically equal 065 to the "virtual" addresses: this base_addr will thus be the same 066 as the address of the gdt array */ 067 sos_ui32_t base_addr; 068 } __attribute__((packed, aligned (8))); 069 070 071 static struct x86_idt_entry idt[SOS_IDTE_NUM]; 072 073 sos_ret_t sos_idt_setup() 074 { 075 struct x86_idt_register idtr; 076 int i; 077 078 for (i = 0 ; 079 i < SOS_IDTE_NUM ; 080 i++) 081 { 082 struct x86_idt_entry *idte = idt + i; 083 084 /* Setup an empty IDTE interrupt gate, see figure 5-2 in Intel 085 x86 doc, vol 3 */ 086 idte->seg_sel = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE); 087 idte->reserved = 0; 088 idte->flags = 0; 089 idte->type = 0x6; /* Interrupt gate (110b) */ 090 idte->op_size = 1; /* 32bits instructions */ 091 idte->zero = 0; 092 093 /* Disable this IDT entry for the moment */ 094 sos_idt_set_handler(i, (sos_vaddr_t)NULL, 0/* Don't care */); 095 } 096 097 /* 098 * Setup the IDT register, see Intel x86 doc vol 3, section 5.8. 099 */ 100 101 /* Address of the IDT */ 102 idtr.base_addr = (sos_ui32_t) idt; 103 104 /* The limit is the maximum offset in bytes from the base address of 105 the IDT */ 106 idtr.limit = sizeof(idt) - 1; 107 108 /* Commit the IDT into the CPU */ 109 asm volatile ("lidt %0\n"::"m"(idtr):"memory"); 110 111 return SOS_OK; 112 } 113 114 115 sos_ret_t sos_idt_set_handler(int index, 116 sos_vaddr_t handler_address, 117 int lowest_priviledge /* 0..3 */) 118 { 119 struct x86_idt_entry *idte; 120 121 if ((index < 0) || (index >= SOS_IDTE_NUM)) 122 return -SOS_EINVAL; 123 if ((lowest_priviledge < 0) || (lowest_priviledge > 3)) 124 return -SOS_EINVAL; 125 126 idte = idt + index; 127 if (handler_address != (sos_vaddr_t)NULL) 128 { 129 idte->offset_low = handler_address & 0xffff; 130 idte->offset_high = (handler_address >> 16) & 0xffff; 131 idte->dpl = lowest_priviledge; 132 idte->present = 1; /* Yes, there is a handler */ 133 } 134 else /* Disable this IDT entry */ 135 { 136 idte->offset_low = 0; 137 idte->offset_high = 0; 138 idte->dpl = 0; 139 idte->present = 0; /* No, there is no handler */ 140 } 141 142 return SOS_OK; 143 } 144 145 146 sos_ret_t sos_idt_get_handler(int index, 147 sos_vaddr_t *handler_address, 148 int *lowest_priviledge) 149 { 150 if ((index < 0) || (index >= SOS_IDTE_NUM)) 151 return -SOS_EINVAL; 152 153 if (handler_address != NULL) 154 *handler_address = idt[index].offset_low 155 | (idt[index].offset_high << 16); 156 if (lowest_priviledge != NULL) 157 *lowest_priviledge = idt[index].dpl; 158 159 return SOS_OK; 160 }
[ source navigation ] | [ diff markup ] | [ identifier search ] | [ general search ] |