ウォンツテック

そでやまのーと

タイマーが動かない原因はディスクリプタテーブルを登録する時(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