■
タイマーが動かない原因はディスクリプタテーブルを登録する時(lgdt, lidt命令)の構造体がおかしかった。
typedef struct __gdtr { u_int16_t limit; u_int32_t base; } _gdtr; と書いていたがこれだとlimitとbaseの間に16bitの空白が出来てしまい正常なアドレスが渡せない。 typedef struct __gdtr { u_int16_t limit; u_int16_t baseL; u_int16_t baseH; } _gdtr; このようにすると正常にアドレスが渡せる。
GDTとIDTのコードは以下
gdt.c
#include "descriptor.h" static selno_t selNo = 0; static void makeGdt(u_int32_t segBase, u_int32_t limit, u_int16_t type, u_int16_t selector) { gdtno_t gdtno = selector >> 3; // selector is multiples of 8 globalDescTable[gdtno].limitL = 0xffff & limit; globalDescTable[gdtno].segBaseL = 0xffff & segBase; globalDescTable[gdtno].segBaseM = (segBase >> 16) & 0xff; globalDescTable[gdtno].typeL = 0xff & type; globalDescTable[gdtno].typeH = (type >> 8) & 0xf; globalDescTable[gdtno].limitH = (limit >> 16) & 0xf; globalDescTable[gdtno].segBaseH = (segBase >> 24) & 0xff; } static selno_t allocSel() { selno_t sel = selNo; selNo += 0x08; return sel; } void init_setupgdt() { u_int16_t type_0, type_code, type_data, type_stack; type_0 = 0; type_code = (0xC << 8) | 0x9A | (DPL0 << 5); type_data = (0xC << 8) | 0x92 | (DPL0 << 5); type_stack = (0xC << 8) | 0x96 | (DPL0 << 5); makeGdt(0x0, 0x0, type_0, 0x0); makeGdt(0x00000000, 0xfffff, type_code, 0x08); makeGdt(0x00000000, 0xfffff, type_data, 0x10); makeGdt(0x9c000, 0x00000, type_stack, 0x18); gdtr.limit = sizeof(GlobalDescTable) * GDTNUM; gdtr.baseH = (u_int16_t)(((u_int32_t)&globalDescTable >> 16) & 0xffff); gdtr.baseL = (u_int16_t)(((u_int32_t)&globalDescTable >> 0) & 0xffff); lgdt(&gdtr); selNo = 0x20; }
idt.c
#include "io.h" #include "descriptor.h" #include "vga.h" #include "key.h" static u_int16_t count = 0; static char timercount[8] = {0x7C,0x2F,0x2D,0x5C,0x7C,0x2F,0x2D,0x5C}; static void (*ihandler[IDTNUM])(); static void makeGate(InterruptDescTable* idt, u_int16_t selector, u_int32_t offset, u_int8_t copy, u_int8_t type); static void makeIdtGate(idtno_t idtno, u_int16_t selector, u_int32_t offset, int8_t dpl); static void init_setupidthandlers(); void defaultHandler(); void init_setupidt(); static void makeGate(InterruptDescTable* idt, u_int16_t selector, u_int32_t offset, u_int8_t copy, u_int8_t type) { idt->offsetL = offset & 0xffff; idt->selector = selector; idt->copy = copy; idt->type = type; idt->offsetH = (offset >> 16) & 0xffff; } static void makeIdtGate(idtno_t idtno, u_int16_t selector, u_int32_t offset, int8_t dpl) { u_int8_t copy = 0; u_int8_t type = 0xE | (dpl << 5) | (1 << 7); makeGate(&interruptDescTable[idtno], selector, offset, copy, type); } static void init_setupidthandlers() { int i; for (i = 0; i < IDTNUM; ++i) ihandler[i] = asm_defaulthandler; } static void keyhandler() { short a; out8(0x20,0x20); a = (short)in8(0x60); if (0 <= a && a <= 127) { //screenRefresh(sysGetc((char)a)); //sysPrintc(key,6,sysGetc((char)a),2); //key+=1; } asm("mov %ebp,%esp"); asm("pop %ebp"); asm("iret"); } void defaultHandler() { out8(0x20, 0x20); sysPointPrintc(0, 6, timercount[count%8]); if (count == 255) count = 0; else count++; } void init_setupidt() { u_int16_t selector = 0x08; // code selector init_setupidthandlers(); int i; for (i = 0; i < IDTNUM; ++i) makeIdtGate(i, selector, (u_int32_t)ihandler[i], DPL0); makeIdtGate(0x21, selector, (u_int32_t)keyhandler, DPL0); idtr.limit = sizeof(InterruptDescTable)*IDTNUM; idtr.baseH = (u_int16_t)(((u_int32_t)&interruptDescTable >> 16) & 0xffff); idtr.baseL = (u_int16_t)(((u_int32_t)&interruptDescTable >> 0) & 0xffff); disableInterrupt(); // 8259A master setting out8(0x20,0x11); out8(0x21,0x20+0); out8(0x21,0x04); out8(0x21,0x01); // 8259A slave setting out8(0xA0,0x11); out8(0xA1,0x20+8); out8(0xA1,0x02); out8(0xA1,0x01); // mask outport at not key & timer out8(0x21, 0xFC); out8(0xA1, 0xFF); lidt(&idtr); enableInterrupt(); }
descriptor.h
/* * This file is for following descriptor table. * GDT - Global Descriptor Table * LDT - Local Descriptor Table * IDT - Interrupt Descriptor Table * for 3 gates ... task gate, interrupt gate, trap gate */ #ifndef _DESCRIPTOR_H #define _DESCRIPTOR_H #include "types.h" #define DPL0 0 #define DPL1 1 #define DPL2 2 #define DPL3 3 #define GDTNUM 128 #define IDTNUM 256 /* for GDT */ typedef struct _GlobalDescTable { u_int16_t limitL; u_int16_t segBaseL; u_int8_t segBaseM; u_int8_t typeL; u_int8_t typeH:4; u_int8_t limitH:4; u_int8_t segBaseH; } GlobalDescTable; GlobalDescTable globalDescTable[GDTNUM]; typedef struct __gdtr { u_int16_t limit; u_int16_t baseL; u_int16_t baseH; } _gdtr; _gdtr gdtr; void lgdt(_gdtr* pgdtr); void init_setupgdt(); /* for IDT */ typedef struct _InterruptDescTable { u_int16_t offsetL; u_int16_t selector; u_int8_t copy; u_int8_t type; u_int16_t offsetH; } InterruptDescTable; InterruptDescTable interruptDescTable[IDTNUM]; typedef struct __idtr { u_int16_t limit; u_int16_t baseL; u_int16_t baseH; } _idtr; _idtr idtr; void lidt(_idtr* pidtr); void asm_defaulthandler(); void defaultHandler(); void init_setupidt(); #endif /* descriptor.h */
io.h
#ifndef _IO_H #define _IO_H #include "types.h" void out8(u_int8_t num, u_int16_t port); void out16(u_int16_t num, u_int16_t port); void out32(u_int32_t num, u_int16_t port); u_int8_t in8(u_int16_t port); u_int16_t in16(u_int16_t port); u_int32_t in32(u_int16_t port); void enableInterrupt(); void disableInterrupt(); #endif /* io.h */
sys_core.S
アセンブラで書いた部分。その他lgdt,lidt, out8〜32,in8〜32。
/* void asm_defaulthandler() * This is for default Handler when interrupt occur. */ asm_defaulthandler: pushl %ebp movl %esp, %ebp call defaultHandler movl %ebp, %esp popl %ebp iret