00001
00002
00003
00004
00005
00006
00007
00008 #ifndef __ia32_h
00009 #define __ia32_h
00010
00011 #include <cpu.h>
00012 #include <utility/debug.h>
00013
00014 __BEGIN_SYS
00015
00016 class IA32: public CPU_Common {
00017 private:
00018 typedef Traits<IA32> _Traits;
00019 static const Type_Id _TYPE = Type<IA32>::TYPE;
00020
00021 public:
00022
00023 typedef Reg16 IO_Port;
00024 typedef Reg16 IO_Irq;
00025
00026
00027 typedef Reg32 Flags;
00028 enum {
00029 FLAG_CF = 0x00000001,
00030 FLAG_PF = 0x00000004,
00031 FLAG_AF = 0x00000010,
00032 FLAG_ZF = 0x00000040,
00033 FLAG_SF = 0x00000080,
00034 FLAG_TF = 0x00000100,
00035 FLAG_IF = 0x00000200,
00036 FLAG_DF = 0x00000400,
00037 FLAG_OF = 0x00000800,
00038 FLAG_IOPL1 = 0x00001000,
00039 FLAG_IOPL2 = 0x00002000,
00040 FLAG_NT = 0x00004000,
00041 FLAG_RF = 0x00010000,
00042 FLAG_VM = 0x00020000,
00043 FLAG_AC = 0x00040000,
00044 FLAG_VIF = 0x00080000,
00045 FLAG_VIP = 0x00100000,
00046 FLAG_ID = 0x00200000,
00047 FLAG_DEFAULTS = FLAG_IF,
00048
00049 FLAG_CLEAR = ~(FLAG_TF | FLAG_IOPL1 | FLAG_IOPL2 | FLAG_NT |
00050 FLAG_RF | FLAG_VM | FLAG_AC)
00051 };
00052
00053
00054 enum Exceptions {
00055 EXC_DIV0 = 0x00,
00056 EXC_DEBUG = 0x01,
00057 EXC_NMI = 0x02,
00058 EXC_BP = 0x03,
00059 EXC_OVFLOW = 0x04,
00060 EXC_BOUND = 0x05,
00061 EXC_INVOP = 0x06,
00062 EXC_NODEV = 0x07,
00063 EXC_DOUBLE = 0x08,
00064 EXC_FPU_OR = 0x09,
00065 EXC_INVTSS = 0x0a,
00066 EXC_NOTPRE = 0x0b,
00067 EXC_STACK = 0x0c,
00068 EXC_GPF = 0x0d,
00069 EXC_PF = 0x0e,
00070 EXC_RESERV = 0x0f,
00071 EXC_FPU = 0x10,
00072 EXC_ALIGN = 0x11,
00073 EXC_BUS = 0x12,
00074 EXC_LAST = 0x1f
00075 };
00076
00077
00078 enum {
00079 CR0_PE = 0x00000001,
00080 CR0_MP = 0x00000002,
00081 CR0_EM = 0x00000004,
00082 CR0_TS = 0x00000008,
00083 CR0_ET = 0x00000010,
00084 CR0_NE = 0x00000020,
00085 CR0_WP = 0x00010000,
00086 CR0_AM = 0x00040000,
00087 CR0_NW = 0x20000000,
00088 CR0_CD = 0x40000000,
00089 CR0_PG = 0x80000000,
00090
00091 CR0_CLEAR = (CR0_PE | CR0_EM | CR0_TS | CR0_NE | CR0_AM |
00092 CR0_NW | CR0_CD),
00093
00094 CR0_SET = (CR0_PE | CR0_MP | CR0_ET | CR0_PG)
00095 };
00096
00097
00098 enum {
00099 SEG_ACC = 0x01,
00100 SEG_RW = 0x02,
00101 SEG_CONF = 0x04,
00102 SEG_CODE = 0x08,
00103 SEG_NOSYS = 0x10,
00104 SEG_DPL1 = 0x20,
00105 SEG_DPL2 = 0x40,
00106 SEG_PRE = 0x80,
00107 SEG_TSS = 0x09,
00108 SEG_INT = 0x0e,
00109 SEG_TRAP = 0x0f,
00110 SEG_32 = 0x40,
00111 SEG_4K = 0x80,
00112 SEG_FLT_CODE = (SEG_PRE | SEG_NOSYS | SEG_CODE | SEG_ACC),
00113 SEG_FLT_DATA = (SEG_PRE | SEG_NOSYS | SEG_RW | SEG_ACC),
00114 SEG_APP_CODE = (SEG_PRE | SEG_NOSYS | SEG_DPL2 | SEG_DPL1 |
00115 SEG_CODE | SEG_ACC),
00116 SEG_APP_DATA = (SEG_PRE | SEG_NOSYS | SEG_DPL2 | SEG_DPL1 |
00117 SEG_RW | SEG_ACC),
00118 SEG_SYS_CODE = (SEG_PRE | SEG_NOSYS | SEG_CODE | SEG_ACC),
00119 SEG_SYS_DATA = (SEG_PRE | SEG_NOSYS | SEG_RW | SEG_ACC),
00120 SEG_IDT_ENTRY = (SEG_PRE | SEG_INT | SEG_DPL1 | SEG_DPL2)
00121 };
00122
00123
00124 enum {
00125 PL_APP = 3,
00126 PL_SYS = 0
00127 };
00128
00129
00130 enum GDT_Layout {
00131 GDT_NULL = 0,
00132 GDT_FLT_CODE = 1,
00133 GDT_FLT_DATA = 2,
00134 GDT_APP_CODE = 3,
00135 GDT_APP_DATA = 4,
00136 GDT_APP_STACK = 5,
00137 GDT_SYS_CODE = 6,
00138 GDT_SYS_DATA = 7,
00139 GDT_SYS_STACK = 8,
00140 GDT_LAST = 8
00141 };
00142
00143
00144 enum {
00145 SEL_FLT_CODE = (GDT_FLT_CODE << 3) | PL_SYS,
00146 SEL_FLT_DATA = (GDT_FLT_DATA << 3) | PL_SYS,
00147 SEL_APP_CODE = (GDT_APP_CODE << 3) | PL_APP,
00148 SEL_APP_DATA = (GDT_APP_DATA << 3) | PL_APP,
00149 SEL_APP_STACK = (GDT_APP_STACK << 3) | PL_APP,
00150 SEL_SYS_CODE = (GDT_SYS_CODE << 3) | PL_SYS,
00151 SEL_SYS_DATA = (GDT_SYS_DATA << 3) | PL_SYS,
00152 SEL_SYS_STACK = (GDT_SYS_STACK << 3) | PL_SYS
00153 };
00154
00155
00156 class GDT_Entry {
00157 public:
00158 GDT_Entry() {}
00159 GDT_Entry(Reg32 b, Reg32 l, Reg8 f)
00160 : limit_15_00((Reg16)l),
00161 base_15_00((Reg16)b),
00162 base_23_16((Reg8)(b >> 16)),
00163 p_dpl_s_type(f),
00164 g_d_0_a_limit_19_16(((f & SEG_NOSYS)?SEG_4K | SEG_32 : 0) |
00165 ((Reg8)(l >> 16))),
00166 base_31_24((Reg8)(b >> 24)) {}
00167
00168 friend Debug & operator << (Debug & db, const GDT_Entry & g) {
00169 db << "{bas=" << (void *)((g.base_31_24 << 24) |
00170 (g.base_23_16 << 16) |
00171 g.base_15_00)
00172 << ",lim=" << (void *)(((g.g_d_0_a_limit_19_16 & 0xf) << 16) |
00173 g.limit_15_00)
00174 << ",p=" << (g.p_dpl_s_type >> 7)
00175 << ",dpl=" << ((g.p_dpl_s_type >> 5) & 0x3)
00176 << ",s=" << ((g.p_dpl_s_type >> 4) & 0x1)
00177 << ",typ=" << (g.p_dpl_s_type & 0xf)
00178 << ",g=" << (g.g_d_0_a_limit_19_16 >> 7)
00179 << ",d=" << ((g.g_d_0_a_limit_19_16 >> 6) & 0x1)
00180 << ",a=" << ((g.g_d_0_a_limit_19_16 >> 4) & 0x1) << "}";
00181 return db;
00182 }
00183
00184 private:
00185 Reg16 limit_15_00;
00186 Reg16 base_15_00;
00187 Reg8 base_23_16;
00188 Reg8 p_dpl_s_type;
00189 Reg8 g_d_0_a_limit_19_16;
00190 Reg8 base_31_24;
00191 };
00192
00193
00194 class IDT_Entry {
00195 public:
00196 IDT_Entry() {}
00197 IDT_Entry(Reg16 s, Reg32 o, Reg16 f)
00198 : offset_15_00((Reg16)o),
00199 selector(s << 3),
00200 zero(0),
00201 p_dpl_0_d_1_1_0(f),
00202 offset_31_16((Reg16)(o >> 16)) {}
00203
00204 Reg32 offset() const {return (offset_31_16 << 16) | offset_15_00;}
00205
00206 friend Debug & operator << (Debug & db, const IDT_Entry & i) {
00207 db << "{sel=" << (i.selector >> 3)
00208 << ",off=" << (void *)i.offset()
00209 << ",p=" << (i.p_dpl_0_d_1_1_0 >> 7)
00210 << ",dpl=" << ((i.p_dpl_0_d_1_1_0 >> 5) & 0x3)
00211 << ",d=" << ((i.p_dpl_0_d_1_1_0 >> 4) & 0x1) << "}";
00212 return db;
00213 }
00214
00215 private:
00216 Reg16 offset_15_00;
00217 Reg16 selector;
00218 Reg8 zero;
00219 Reg8 p_dpl_0_d_1_1_0;
00220 Reg16 offset_31_16;
00221 };
00222 static const int IDT_ENTRIES = 256;
00223
00224
00225
00226 struct TSS {
00227 Reg16 back_link;
00228 Reg16 zero1;
00229 Reg32 esp0;
00230 Reg16 ss0;
00231 Reg16 zero2;
00232 Reg32 esp1;
00233 Reg16 ss1;
00234 Reg16 zero3;
00235 Reg32 esp2;
00236 Reg16 ss2;
00237 Reg16 zero4;
00238 Reg32 pdbr;
00239 Reg32 eip;
00240 Reg32 eflags;
00241 Reg32 eax;
00242 Reg32 ecx;
00243 Reg32 edx;
00244 Reg32 ebx;
00245 Reg32 esp;
00246 Reg32 ebp;
00247 Reg32 esi;
00248 Reg32 edi;
00249 Reg16 es;
00250 Reg16 zero5;
00251 Reg16 cs;
00252 Reg16 zero6;
00253 Reg16 ss;
00254 Reg16 zero7;
00255 Reg16 ds;
00256 Reg16 zero8;
00257 Reg16 fs;
00258 Reg16 zero9;
00259 Reg16 gs;
00260 Reg16 zero10;
00261 Reg16 ldt;
00262 Reg16 zero11;
00263 Reg16 zero12;
00264 Reg16 io_bmp;
00265 };
00266
00267
00268 class Context {
00269 public:
00270 Context(Log_Addr entry)
00271 : _edi(6), _esi(5), _ebp(7), _esp((Reg32)this), _ebx(2), _edx(4),
00272 _ecx(3), _eax(1), _eflags(FLAG_DEFAULTS), _eip(entry) {}
00273 Context(Reg32 eflags, Reg32 eax, Reg32 ebx, Reg32 ecx, Reg32 edx,
00274 Reg32 esi, Reg32 edi, Reg32 ebp, Reg32 esp, Reg32 eip)
00275 : _edi(edi), _esi(esi), _ebp(ebp), _esp(esp), _ebx(ebx),
00276 _edx(edx), _ecx(ecx), _eax(eax), _eflags(eflags), _eip(eip) {}
00277
00278 void save() volatile;
00279 void load() const volatile;
00280
00281 friend Debug & operator << (Debug & db, const Context & c) {
00282 db << "{eflags=" << (void *)c._eflags
00283 << ",eax=" << c._eax
00284 << ",ebx=" << c._ebx
00285 << ",ecx=" << c._ecx
00286 << ",edx=" << c._edx
00287 << ",esi=" << c._esi
00288 << ",edi=" << c._edi
00289 << ",ebp=" << (void *)c._ebp
00290 << ",esp=" << (void *)c._esp
00291 << ",eip=" << (void *)c._eip
00292 << ",cs=" << cs()
00293 << ",ds=" << ds()
00294 << ",es=" << es()
00295 << ",fs=" << fs()
00296 << ",gs=" << gs()
00297 << ",ss=" << ss()
00298 << ",pdp=" << (void *)pdp()
00299 << "}";
00300 return db;
00301 }
00302
00303 private:
00304 Reg32 _edi;
00305 Reg32 _esi;
00306 Reg32 _ebp;
00307 Reg32 _esp;
00308 Reg32 _ebx;
00309 Reg32 _edx;
00310 Reg32 _ecx;
00311 Reg32 _eax;
00312 Reg32 _eflags;
00313 Reg32 _eip;
00314 };
00315
00316 public:
00317 IA32() {}
00318 ~IA32() {}
00319
00320 static Hertz clock() {return _Traits::CLOCK;}
00321
00322 static void int_enable() {ASMV("sti");}
00323 static void int_disable() {ASMV("cli");}
00324 static void halt() {ASMV("hlt");}
00325
00326 static void switch_context(Context * volatile * o, Context * volatile n);
00327
00328 static Flags flags() {return eflags();}
00329 static void flags(Flags flags) {eflags(flags);}
00330
00331 static Reg32 sp() {return esp();}
00332 static void sp(Reg32 sp) {esp(sp);}
00333
00334 static Reg32 fr() {return eax();}
00335 static void fr(Reg32 sp) {eax(sp);}
00336
00337 static Reg32 pdp() {return cr3();}
00338 static void pdp(Reg32 pdp) {cr3(pdp);}
00339
00340 static Log_Addr ip() {return eip();}
00341
00342 static bool tsl(volatile bool & lock) {
00343 register bool old = 1;
00344 ASMV("xchg %0, %2" : "=a"(old) : "a"(old), "m"(lock)); return old;
00345 }
00346 static int finc(volatile int & number) {
00347 register int old = 1;
00348 ASMV("lock\n"
00349 "xadd %0, %2" : "=a"(old) : "a"(old), "m"(number)); return old;
00350 }
00351 static int fdec(volatile int & number) {
00352 register int old = -1;
00353 ASMV("lock\n"
00354 "xadd %0, %2" : "=a"(old) : "a"(old), "m"(number)); return old;
00355 }
00356
00357 static Reg32 htonl(Reg32 v) {
00358 ASMV("bswap %0" : "=r" (v) : "0" (v), "r" (v)); return v;
00359 }
00360 static Reg16 htons(Reg16 v) {
00361 return htons_lsb(v);
00362 }
00363 static Reg32 ntohl(Reg32 v) {
00364 return htonl(v);
00365 }
00366 static Reg16 ntohs(Reg16 v) {
00367 return htons(v);
00368 }
00369
00370 static Flags eflags() {
00371 Reg32 value; ASMV("pushfl");
00372 ASMV("popl %0" : "=r"(value) :); return value;
00373 }
00374 static void eflags(Flags value) {
00375 ASMV("pushl %0" : : "r"(value)); ASMV("popfl");
00376 }
00377
00378 static Reg32 esp() {
00379 Reg32 value; ASMV("movl %%esp,%0" : "=r"(value) :); return value;
00380 }
00381 static void esp(Reg32 value) {
00382 ASMV("movl %0,%%esp" : : "r"(value));
00383 }
00384
00385 static Reg32 eax() {
00386 Reg32 value; ASMV("movl %%eax,%0" : "=r"(value) :); return value;
00387 }
00388 static void eax(Reg32 value) {
00389 ASMV("movl %0,%%eax" : : "r"(value));
00390 }
00391
00392 static Log_Addr eip() {
00393 Log_Addr value;
00394 ASMV(" call 1f \n"
00395 "1: movl (%%esp), %0 \n"
00396 " addl $4, %%esp" : "=r"(value) : );
00397 return value;
00398 }
00399
00400 static Reg32 cr0() {
00401 Reg32 value; ASMV("movl %%cr0,%0" : "=r"(value) :); return value;
00402 }
00403 static void cr0(Reg32 value) {
00404 ASMV("movl %0,%%cr0" : : "r"(value));
00405 }
00406
00407 static Reg32 cr2() {
00408 Reg32 value; ASMV("movl %%cr2,%0" : "=r"(value) :); return value;
00409 }
00410
00411 static Reg32 cr3() {
00412 Reg32 value; ASMV("movl %%cr3,%0" : "=r"(value) :); return value;
00413 }
00414
00415 static void cr3(Reg32 value) {
00416 ASMV("movl %0,%%cr3" : : "r"(value));
00417 }
00418
00419 static void gdtr(Reg16 * limit, Reg32 * base) {
00420 char aux[6];
00421 ASMV("sgdt %0" : "=m"(aux[0]) :);
00422 *limit = *((Reg16 *)&aux[0]);
00423 *base = *((Reg32 *)&aux[2]);
00424 }
00425 static void gdtr(Reg16 limit, Reg32 base) {
00426 char aux[6];
00427 *((Reg16 *)&aux[0]) = limit;
00428 *((Reg32 *)&aux[2]) = base;
00429 ASMV("lgdt %0" : : "m" (aux[0]));
00430 }
00431
00432 static void idtr(Reg16 * limit, Reg32 * base) {
00433 char aux[6];
00434 ASMV("sidt %0" : "=m"(aux[0]) :);
00435 *limit = *((Reg16 *)&aux[0]);
00436 *base = *((Reg32 *)&aux[2]);
00437 }
00438 static void idtr(Reg16 limit, Reg32 base) {
00439 char aux[6];
00440 *((Reg16 *)&aux[0]) = limit;
00441 *((Reg32 *)&aux[2]) = base;
00442 ASMV("lidt %0" : : "m" (aux[0]));
00443 }
00444
00445 static Reg16 cs() {
00446 Reg16 value; ASMV("mov %%cs,%0" : "=r"(value) :); return value;
00447 }
00448
00449 static Reg16 ds() {
00450 Reg16 value; ASMV("mov %%ds,%0" : "=r"(value) :); return value;
00451 }
00452
00453 static Reg16 es() {
00454 Reg16 value; ASMV("mov %%es,%0" : "=r"(value) :); return value;
00455 }
00456
00457 static Reg16 ss() {
00458 Reg16 value; ASMV("mov %%ss,%0" : "=r"(value) :); return value;
00459 }
00460
00461 static Reg16 fs() {
00462 Reg16 value; ASMV("mov %%fs,%0" : "=r"(value) :); return value;
00463 }
00464
00465 static Reg16 gs() {
00466 Reg16 value; ASMV("mov %%gs,%0" : "=r"(value) :); return value;
00467 }
00468
00469 static Reg64 time_stamp() {
00470 Reg64 ts; ASMV("rdtsc" : "=A" (ts) : ); return ts;
00471 }
00472
00473 static void init_fpu() {
00474 ASM("fninit");
00475 }
00476
00477 static void shutdown() {
00478 while(true);
00479 }
00480
00481 static Reg8 in8(IO_Port port) {
00482 Reg8 value;
00483 ASMV("inb %1,%0" : "=a"(value) : "d"(port));
00484 return value;
00485 }
00486
00487 static Reg16 in16(IO_Port port) {
00488 Reg16 value;
00489 ASMV("inw %1,%0" : "=a"(value) : "d"(port));
00490 return value;
00491 }
00492
00493 static Reg32 in32(IO_Port port) {
00494 Reg32 value;
00495 ASMV("inl %1,%0" : "=a"(value) : "d"(port));
00496 return value;
00497 }
00498
00499 static void out8(IO_Port port, Reg8 value) {
00500 ASMV("outb %1,%0" : : "d"(port), "a"(value));
00501 }
00502
00503 static void out16(IO_Port port, Reg16 value) {
00504 ASMV("outw %1,%0" : : "d"(port), "a"(value));
00505 }
00506
00507 static void out32(IO_Port port, Reg32 value) {
00508 ASMV("outl %1,%0" : : "d"(port), "a"(value));
00509 }
00510
00511 static void switch_tss(Reg32 tss_selector) {
00512 struct {
00513 Reg32 offset;
00514 Reg32 selector;
00515 }address;
00516
00517 address.offset = 0;
00518 address.selector = tss_selector;
00519
00520 ASM("ljmp *%0" : "=o" (address));
00521 }
00522
00523 static int init(System_Info *si);
00524 };
00525
00526 typedef IA32 CPU;
00527
00528 __END_SYS
00529
00530 #endif