Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add PIT implementation for timer interrupt

 Details:
  * 8242/8254(PIT) chip programming
  * <NOTE> Although pit is supported, it is unenabled without definition of
            macro: TIMER_INT_SCHED defaultly.
           There are some bugs not solved while enabling pit.
           So it uses auto-yield policy to schedule tasks currently.
  • Loading branch information...
commit e7f42dcda5ac8d14018286755fdd9302c6e017a7 1 parent 4f96c7f
@chobits authored
View
62 include/pit.h
@@ -0,0 +1,62 @@
+/*
+ * Programmbale Interval Timer(PIT) chip (8253/8254 chip)
+ */
+#ifndef __PIT_H
+#define __PIT_H
+
+#define PIT_CH0 0x40 /* Channle 0 data port(read/write) */
+#define PIT_CH1 0x41 /* Channle 1 data port(read/write) */
+#define PIT_CH2 0x42 /* Channle 2 data port(read/write) */
+#define PIT_MODE 0x43 /* Mode/Command register(write only, a read is ignored) */
+
+/*
+ * The Mode/Command register at I/O address 0x43 contains the following:
+ * Bits Usage
+ * 6, 7 Select channel :
+ * (7 6)
+ * 0 0 = Channel 0
+ * 0 1 = Channel 1
+ * 1 0 = Channel 2
+ * 1 1 = Read-back command (8254 only)
+ * 4, 5 Access mode :
+ * (5 4)
+ * 0 0 = Latch count value command
+ * 0 1 = Access mode: lobyte only
+ * 1 0 = Access mode: hibyte only
+ * 1 1 = Access mode: lobyte/hibyte
+ * 1, 2, 3 Operating mode :
+ * (3 2 1)
+ * 0 0 0 = Mode 0 (interrupt on terminal count)
+ * 0 0 1 = Mode 1 (hardware re-triggerable one-shot)
+ * 0 1 0 = Mode 2 (rate generator)
+ * 0 1 1 = Mode 3 (square wave generator)
+ * 1 0 0 = Mode 4 (software triggered strobe)
+ * 1 0 1 = Mode 5 (hardware triggered strobe)
+ * 1 1 0 = Mode 2 (rate generator, same as 010b)
+ * 1 1 1 = Mode 3 (square wave generator, same as 011b)
+ * 0 BCD/Binary mode: 0 = 16-bit binary, 1 = four-digit BCD
+ */
+#define PIT_MODE_CH0 0x00
+#define PIT_MODE_CH1 0x40
+#define PIT_MODE_CH2 0x80
+#define PIT_MODE_RB 0xc0
+
+#define PIT_MODE_LATCH 0x00
+#define PIT_MODE_LOW 0x10
+#define PIT_MODE_HIGH 0x20
+#define PIT_MODE_LOHI 0x30
+
+#define PIT_MODE_0 0x00
+#define PIT_MODE_1 0x02
+#define PIT_MODE_2 0x04
+#define PIT_MODE_3 0x06
+#define PIT_MODE_4 0x08
+#define PIT_MODE_5 0x09
+#define PIT_MODE_6 0x0a
+#define PIT_MODE_7 0x0e
+
+#define TIMER_FREQ 1000 /* timer interrupt frequence: 100 times/sec */
+#define PIT_FREQ 1193182 /* 8253 chip frequence: 1.193181666MHz */
+#define FREQ_DIV (PIT_FREQ / TIMER_FREQ)
+
+#endif /* pit.h */
View
2  kernel/Makefile
@@ -1,7 +1,7 @@
SUBDIR = kernel
OBJS = entry.o init.o interrupt.o int.o print.o string.o task.o execute.o\
- syscall.o fork.o schedule.o exit.o wait_queue.o
+ syscall.o fork.o schedule.o exit.o wait_queue.o pit.o timer.o
kernel.o:$(OBJS)
$(Q)$(LD) -r $^ -o $@
View
4 kernel/exit.c
@@ -70,7 +70,9 @@ void sys_exit(int status)
task_exit(ctask);
/* No return */
schedule();
- panic("task exiting fails");
+ if (ctask)
+ printk("%d ", ctask->pid);
+ panic("task exiting fails: %d");
}
void task_wait_exit(struct task *parent, struct task *task)
View
2  kernel/fork.c
@@ -103,6 +103,8 @@ void clone_task_context(struct regs *preg, struct task *child)
struct regs *creg = (struct regs *)child->kstacktop - 1;
*creg = *preg;
creg->eax = 0; /* Child returns 0 out of fork(). */
+ if (!(creg->eflags & EFLAGS_IF))
+ panic("has no IF flag");
child->con.esp = (unsigned int)creg;
child->con.eip = (unsigned int)fork_child_return;
}
View
15 kernel/init.c
@@ -9,6 +9,7 @@ void int_init(void);
void block_init(void);
void task_init(void);
void fs_init(void);
+void pit_init(void);
void keyboard_init(void);
void load_first_program(char *, int, char **);
@@ -17,14 +18,19 @@ void kidle(void)
printk("Kernel is idle now\n\n");
/* Open interrupt */
sti();
- while (1)
+ while (1) {
+#ifdef TIMER_INT_SCHED
+ hlt();
+#else
schedule();
+#endif
+ }
}
void load_init(void)
{
- char *argv[] = { "hello", "world", NULL };
- load_first_program("/init", 2, argv);
+ char *argv[] = { "/init", NULL };
+ load_first_program("/init", 1, argv);
}
void init(void)
@@ -40,6 +46,9 @@ void init(void)
block_init();
fs_init();
keyboard_init();
+#ifdef TIMER_INT_SCHED
+ pit_init();
+#endif
load_init();
kidle();
}
View
18 kernel/int.c
@@ -55,6 +55,7 @@ void unmask_8259A(int irq)
extern void do_page_fault(struct regs *);
extern void do_sys_call(struct regs *);
extern void keyboard_interrupt(struct regs *);
+extern void timer_interrupt(struct regs *);
/* All traps, faults, fatals and hardware interrupt handler */
void interrupt_handler(int nr, struct regs *reg)
@@ -64,7 +65,16 @@ void interrupt_handler(int nr, struct regs *reg)
panic("Unknown interrupt %d", nr);
}
+ /*
+ * IRQs are mutually exclusive.
+ * IRQ can preempt other traps and syscalls.
+ */
switch (nr) {
+#ifdef TIMER_INT_SCHED
+ case INTNO_IRQ0:
+ timer_interrupt(reg);
+ break;
+#endif
case INTNO_IRQ1:
keyboard_interrupt(reg);
break;
@@ -82,10 +92,12 @@ void interrupt_handler(int nr, struct regs *reg)
break;
}
- /* send end of interrupt signal to PIC chip (not autoeoi mode) */
+ /*
+ * send end of interrupt signal to PIC chip (not autoeoi mode)
+ * (If no EOI is sent, other hardware irq will not be accepted!)
+ */
if (nr >= INTNO_IRQ0 && nr <= INTNO_IRQ15)
EOI_8259A(nr - INTNO_IRQ0);
-
}
static struct desc idt[IDT_SIZE];
@@ -111,7 +123,7 @@ void int_init(void)
set_trap_gate(INTNO_NP, np_entry);
set_trap_gate(INTNO_SS, ss_entry);
set_trap_gate(INTNO_GP, gp_entry);
- set_trap_gate(INTNO_PF, pf_entry);
+ set_int_gate(INTNO_PF, pf_entry); /* page fault cannot allow interrupt. */
/* Vector 15 iS reserved */
set_trap_gate(INTNO_MF, mf_entry);
set_trap_gate(INTNO_AC, ac_entry);
View
16 kernel/pit.c
@@ -0,0 +1,16 @@
+#include <print.h>
+#include <8259A.h>
+#include <pit.h>
+#include <int.h>
+#include <x86.h>
+
+void pit_init(void)
+{
+ /* channel 0, rate generator, low&high bytes */
+ outb(PIT_MODE, PIT_MODE_CH0 | PIT_MODE_2 | PIT_MODE_LOHI);
+ outb(PIT_CH0, FREQ_DIV & 255); /* low byte */
+ outb(PIT_CH0, FREQ_DIV >> 8); /* high byte */
+ unmask_8259A(IRQ_TIMER);
+ printk("pit init\n");
+}
+
View
16 kernel/schedule.c
@@ -38,18 +38,32 @@ void task_switch(struct task *next)
: "memory");
}
+void debug_task(void)
+{
+ struct task *task;
+ for_each_task(task) {
+ if (task->state == TASK_RUNNABLE)
+ printk("[%d]", task->pid);
+ }
+}
+
void schedule(void)
{
struct task *task, *next = NULL;
+
+ /* FIXME: add lock to solve race condition for task_list */
for_each_task(task) {
if (task == ctask || task->state != TASK_RUNNABLE)
continue;
if (!next || task->priority > next->priority)
next = task;
}
+
if (!next) {
- if (ctask == &init_task)
+ if (ctask == &init_task) {
+ debug_task();
return;
+ }
next = &init_task;
}
next->priority--;
View
14 kernel/timer.c
@@ -0,0 +1,14 @@
+#include <print.h>
+#include <task.h>
+#include <pit.h>
+#include <int.h>
+
+unsigned int ticks = 0;
+
+extern void task_switch(struct task *);
+void timer_interrupt(struct regs *reg)
+{
+ ticks++;
+ schedule();
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.