summaryrefslogtreecommitdiff
path: root/kernel/hal
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/hal')
-rw-r--r--kernel/hal/Makefile20
-rw-r--r--kernel/hal/counters.c17
-rw-r--r--kernel/hal/interrupts.c230
-rw-r--r--kernel/hal/interrupts.h92
-rw-r--r--kernel/hal/intsupport.asm326
-rw-r--r--kernel/hal/io.c40
-rw-r--r--kernel/hal/timer.c43
-rw-r--r--kernel/hal/timestamp.asm19
-rw-r--r--kernel/hal/video.h15
9 files changed, 802 insertions, 0 deletions
diff --git a/kernel/hal/Makefile b/kernel/hal/Makefile
new file mode 100644
index 0000000..3725f18
--- /dev/null
+++ b/kernel/hal/Makefile
@@ -0,0 +1,20 @@
+CC= gcc
+CFLAGS= -Wall -imacros ../defines -I../inc
+OBJS= video.o io.o interrupts.o intsupport.o keyboard.o timer.o \
+ timestamp.o counters.o
+RM= /bin/rm
+NASM= nasm
+NASMFLAGS= -f elf
+
+.SUFFIXES: .c .o .asm
+
+all: $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+.asm.o:
+ $(NASM) $(NASMFLAGS) -o $*.o $<
+
+clean:
+ $(RM) -f $(OBJS) *~ #*# .#*
diff --git a/kernel/hal/counters.c b/kernel/hal/counters.c
new file mode 100644
index 0000000..9bd9466
--- /dev/null
+++ b/kernel/hal/counters.c
@@ -0,0 +1,17 @@
+//+----------------------------------------------------------------------------
+//
+// File: counters.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Copyright (C) 2003 Scott Gasch
+//
+// Created: sgasch 24 Oct 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+
+UINT64 g_ullTimeStampCounter = 0;
diff --git a/kernel/hal/interrupts.c b/kernel/hal/interrupts.c
new file mode 100644
index 0000000..94f2528
--- /dev/null
+++ b/kernel/hal/interrupts.c
@@ -0,0 +1,230 @@
+//+----------------------------------------------------------------------------
+//
+// File: interrupts.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 6 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+#include "hal.h"
+#include "rtl.h"
+#include "interrupts.h"
+
+IDT_ENTRY g_IDT[NUM_IDT_ENTRIES];
+INTERRUPT_HANDLER g_InterruptHandlerTable[NUM_IDT_ENTRIES];
+ULONG g_uInterruptsEnabled = 0;
+
+void
+HalEnableInterrupts(void)
+{
+ g_uInterruptsEnabled++;
+ ASSERT(g_uInterruptsEnabled == 1);
+
+ __asm__ __volatile__ (
+ "sti"
+ );
+}
+
+void
+HalDisableInterrupts(void)
+{
+ g_uInterruptsEnabled--;
+ ASSERT(g_uInterruptsEnabled == 0);
+
+ __asm__ __volatile__ (
+ "cli"
+ );
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Function: DoNothing
+//
+// Synopsis: The default interrupt handler, do nothing
+//
+// Arguments: INTERRUPT_STATE *p
+//
+// Returns: void
+//
+//+----------------------------------------------------------------------------
+void HalDoNothing(INTERRUPT_STATE *p)
+{
+ ;
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Function: InterruptSendIrqEoi
+//
+// Synopsis: Send Interrupt ReQuest End Of Interrupt to the PIC.
+//
+// Arguments: INTERRUPT_STATE *is
+//
+// Returns: void
+//
+//+----------------------------------------------------------------------------
+void
+HalInterruptSendIrqEoi(INTERRUPT_STATE *is)
+{
+ ULONG uIrq;
+ BYTE bCommand;
+ BYTE *p = (BYTE *)0x000B8000;
+
+ *p = '3';
+ *(p + 1) = ' ';
+
+ if ((is->uIntNum >= FIRST_EXTERNAL_INT) &&
+ (is->uIntNum <= LAST_EXTERNAL_INT))
+ {
+ uIrq = (is->uIntNum - FIRST_EXTERNAL_INT);
+ ASSERT(uIrq >= 0);
+ ASSERT(uIrq <= 15);
+ bCommand = 0x60 | (uIrq & 0x7);
+
+ if (uIrq < 8)
+ {
+ // EOI to master PIC
+ out(0x20, bCommand);
+ HalIoDelay();
+ }
+ else
+ {
+ // EOI to slave PIC and cascade line EOI to master PIC
+ out(0xA0, bCommand);
+ out(0x20, 0x62);
+ HalIoDelay();
+ }
+ }
+
+ *p = '4';
+ *(p + 1) = ' ';
+}
+
+//+----------------------------------------------------------------------------
+//
+// Function: InterruptInitializeGate
+//
+// Synopsis: Initializes an interrupt gate with given handler address
+// and descriptor privilege level.
+//
+// Arguments: IDT_ENTRY *pEntry,
+// void *pPreamble,
+// ULONG uDpl
+//
+// Returns: void
+//
+//+----------------------------------------------------------------------------
+void
+HalInterruptInitializeGate(IDT_ENTRY *pEntry,
+ void *pPreamble,
+ ULONG uDpl)
+{
+ ULONG u = (ULONG)pPreamble;
+
+ pEntry->i.offsetLow = u & 0xffff;
+ pEntry->i.segmentSelector = (1<<3);
+ pEntry->i.reserved = 0;
+ pEntry->i.signature = 0x70; // == 01110000b
+ pEntry->i.dpl = uDpl;
+ pEntry->i.present = 1;
+ pEntry->i.offsetHigh = u >> 16;
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Function: InterruptInstallHandler
+//
+// Synopsis: Installs an interrupt handler routine for a given IRQ number
+//
+// Arguments: ULONG uInterruptNumber,
+// INTERRUPT_HANDLER pHandler
+//
+// Returns: void
+//
+//+----------------------------------------------------------------------------
+void
+HalInterruptInstallHandler(ULONG uInterruptNumber,
+ INTERRUPT_HANDLER pHandler)
+{
+ ASSERT(uInterruptNumber < ARRAY_LENGTH(g_InterruptHandlerTable));
+
+ g_InterruptHandlerTable[uInterruptNumber] = pHandler;
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Function: InterruptInitialize
+//
+// Synopsis: Initialize the interrupt system
+//
+// Arguments: void
+//
+// Returns: void
+//
+//+----------------------------------------------------------------------------
+void
+HalInitializeInterrupts(void)
+{
+ ULONG uPreambleEntrySize = (ULONG)&HalInterruptHandlerPreambleAfter;
+ ULONG u;
+ ULONG uDpl;
+ USHORT uLimitAndBase[3];
+ BYTE *p;
+
+ //
+ // Determine the size of an interrupt preamble table entry.
+ //
+ uPreambleEntrySize -= (ULONG)&HalInterruptHandlerPreambleBefore;
+
+ //
+ // Set the base interrupt number for each PIC. See comments in
+ // intsupport.asm.
+ //
+ HalInterruptInitializePICs();
+
+ //
+ // Build interrupt descriptor table
+ //
+ for (u = 0, p = &HalInterruptHandlerPreamble;
+ u < ARRAY_LENGTH(g_IDT);
+ u++, p += uPreambleEntrySize)
+ {
+ uDpl = (u == 0x2E) ? USER_PRIVILEGE : KERNEL_PRIVILEGE;
+
+ HalInterruptInitializeGate(&(g_IDT[u]), p, uDpl);
+ HalInterruptInstallHandler(u, HalDoNothing);
+ }
+
+ //
+ // Install the IDT
+ //
+ u = (ULONG)&(g_IDT);
+ uLimitAndBase[0] = 8 * NUM_IDT_ENTRIES;
+ uLimitAndBase[1] = (USHORT)(u & 0xffff);
+ uLimitAndBase[2] = (USHORT)(u >> 16);
+
+ HalInterruptLoadIDTR((void *)uLimitAndBase);
+
+ //
+ // Install interrupt handlers
+ //
+ HalInterruptInstallHandler(IRQ0, HalTimerInt);
+ HalInterruptInstallHandler(IRQ1, HalKeyboardInt);
+
+ out(0x21, 0xFC); // turn on keyboard and timer
+
+ //
+ // Enable interrupts
+ //
+ HalEnableInterrupts();
+}
+
diff --git a/kernel/hal/interrupts.h b/kernel/hal/interrupts.h
new file mode 100644
index 0000000..673b13b
--- /dev/null
+++ b/kernel/hal/interrupts.h
@@ -0,0 +1,92 @@
+//+----------------------------------------------------------------------------
+//
+// File: interrupts.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 6 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#ifndef _INTERRUPTS_H_
+#define _INTERRUPTS_H_
+
+#define NUM_IDT_ENTRIES (256)
+
+// Exceptions range from 0x00..0x11
+#define FIRST_EXCEPTION 0x00
+#define LAST_EXCEPTION 0x11
+#define NUM_EXCEPTIONS 18
+
+// External IRQs range from 0x30..0x3F
+#define FIRST_EXTERNAL_INT 0x30
+#define LAST_EXTERNAL_INT 0x3F
+#define IRQ0 0x30
+#define IRQ1 0x31
+#define IRQ2 0x39
+#define IRQ3 0x33
+#define IRQ4 0x34
+#define IRQ5 0x35
+#define IRQ6 0x36
+#define IRQ7 0x37
+#define IRQ8 0x38
+#define IRQ9 0x39
+#define IRQ10 0x3A
+#define IRQ11 0x3B
+#define IRQ12 0x3C
+#define IRQ13 0x3D
+#define IRQ14 0x3E
+#define IRQ15 0x3F
+#define NUM_EXTERNAL_INTS 16
+
+typedef struct _INTERRUPT_GATE
+{
+ USHORT offsetLow;
+ USHORT segmentSelector;
+ USHORT reserved : 5;
+ USHORT signature : 8;
+ USHORT dpl : 2;
+ USHORT present : 1;
+ USHORT offsetHigh;
+}
+INTERRUPT_GATE;
+
+typedef union _IDT_ENTRY
+{
+ INTERRUPT_GATE i;
+ // In theory we could have members for trap gates
+ // and task gates if we wanted.
+}
+IDT_ENTRY;
+
+//
+// Defined in intsupport.asm
+//
+extern void HalInterruptInitializePICs(void);
+extern void HalInterruptLoadIDTR(void *uLimitAndBase);
+extern void HalIoDelay(void);
+extern BYTE HalInterruptHandlerPreamble;
+extern BYTE HalInterruptHandlerPreambleBefore;
+extern BYTE HalInterruptHandlerPreambleAfter;
+
+//
+// Defined in interrupts.c
+//
+extern void HalDisableInterrupts(void);
+extern void HalEnableInterrupts(void);
+
+
+//
+// Defined in keyboard.c
+//
+extern void HalKeyboardInt(INTERRUPT_STATE *is);
+
+//
+// Defined in timer.c
+//
+extern void HalTimerInt(INTERRUPT_STATE *is);
+
+#endif
+
diff --git a/kernel/hal/intsupport.asm b/kernel/hal/intsupport.asm
new file mode 100644
index 0000000..3d1fcc8
--- /dev/null
+++ b/kernel/hal/intsupport.asm
@@ -0,0 +1,326 @@
+[BITS 32]
+
+FIRST_EXTERNAL_INT equ 0x30
+LAST_EXTERNAL_INT equ 0x30+15
+
+GLOBAL HalInterruptLoadIDTR
+GLOBAL HalInterruptGenericHandler
+GLOBAL HalInterruptHandlerPreamble
+GLOBAL HalInterruptHandlerPreambleBefore
+GLOBAL HalInterruptHandlerPreambleAfter
+GLOBAL HalInterruptInitializePICs
+GLOBAL HalIoDelay
+
+EXTERN g_InterruptHandlerTable
+EXTERN HalVideoPrint
+EXTERN HalInterruptSendIrqEoi
+
+;; Save registers prior to calling a handler function.
+;; This must be kept up to date with:
+;; - Interrupt_State struct in int.h
+;; - Setup_Initial_Thread_Context() in kthread.c
+%macro SAVE_REGISTERS 0
+ push eax
+ push ebx
+ push ecx
+ push edx
+ push esi
+ push edi
+ push ebp
+ push ds
+ push es
+ push fs
+ push gs
+%endmacro
+
+;; Restore registers and clean up the stack after calling a handler function
+;; (i.e., just before we return from the interrupt via an iret instruction).
+%macro RESTORE_REGISTERS 0
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop ebp
+ pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ add esp, 8
+%endmacro
+
+%macro INT_NO_ERROR 1
+align 8
+ push 0xffffffff ; fake the error code
+ push %1 ; push the int number
+ jmp HalInterruptGenericHandler;
+%endmacro
+
+%macro INT_WITH_ERROR 1
+align 8
+ push %1 ; error code already pushed, just push int num
+ jmp HalInterruptGenericHandler
+%endmacro
+
+[SECTION .text]
+;;;
+;;; void
+;;; InterruptLoadIDTR(IDT *p)
+;;;
+;;; Function to load the interrupt descriptor table register (IDTR)
+;;; callable from C.
+;;;
+HalInterruptLoadIDTR:
+ mov eax, [esp+4] ; p
+ lidt [eax]
+ ret
+
+;;;
+;;; The following is code to initialize the master and slave 8259
+;;; programmable interrupt controllers (PICs).
+;;;
+;;; For ISA machines there are two 8259's, a master and a slave. Each has
+;;; eight interrupt request (IR) pins and one interrupt (INT) pin. The
+;;; master's INT pin is tied to the INT line of the microprocessor. The
+;;; slave's INT pin is tied to the master's IR2 line. Thus the master's
+;;; IR0, IR1, and IR3..7 are real devices. But the master's IR2 means
+;;; that some IR pin on the slave is asserted. So the system IRQs are:
+;;;
+;;; (highest default priority)
+;;; IRQ0 = master IR0 [IRQ0 = system timer]
+;;; IRQ1 = master IR1 [IRQ1 = keyboard]
+;;; IRQ2 = master IR2 --> IRQ8..IRQ15 = slave IR0..7
+;;; [IRQ8 = rt. timer][IRQ13 = coproc.]
+;;; IRQ3 = master IR3
+;;; IRQ4 = master IR4
+;;; IRQ5 = master IR5
+;;; IRQ6 = master IR6
+;;; IRQ7 = master IR7
+;;; (lowest default priority)
+;;;
+;;; By default these IRQs raise the following interrupt numbers:
+;;;
+;;; IRQ0 = int 0x8 [collides with double exception]
+;;; IRQ1 = int 0x9 [collides with coprocessor exception]
+;;; IRQ2/9 = int 0x71
+;;; IRQ3 = int 0xb [collides with segment not present exception]
+;;; IRQ4 = int 0xc [collides with stack fault exception]
+;;; IRQ5 = int 0xd [collides with general protection exception]
+;;; IRQ6 = int 0xe [collides with page fault]
+;;; IRQ7 = int 0xf
+;;; IRQ8 = int 0x70
+;;; IRQ10 = int 0x72
+;;; IRQ11 = int 0x73
+;;; IRQ12 = int 0x74
+;;; IRQ13 = int 0x75
+;;; IRQ14 = int 0x76
+;;; IRQ15 = int 0x77
+;;;
+;;; So the problem is that IRQ0, IRQ1, IRQ3..6 all, by default, map to
+;;; interrupt numbers that collide with interrupts raised by the cpu
+;;; as a result of a software exception. The solution to this problem
+;;; is to remap what interrupts are raised by these IRQs by reprogramming
+;;; the 8259 PICs to raise new interrupt numbers.
+;;;
+;;; This is accomplished by sending initialization command words (ICWs)
+;;; to I/O ports 0x20-0x21 (master PIC) and 0xA0-0xA1 (slave PIC). By doing
+;;; so we can remap the interrupt numbers raised by IRQs so that:
+;;;
+;;; IRQ0 = 0x30 IRQ8 = 0x38
+;;; IRQ1 = 0x31 IRQ10 = 0x3A
+;;; IRQ2/9 = 0x39 IRQ11 = 0x3B
+;;; IRQ3 = 0x33 IRQ12 = 0x3C
+;;; IRQ4 = 0x34 IRQ13 = 0x3D
+;;; IRQ5 = 0x35 IRQ14 = 0x3E
+;;; IRQ6 = 0x36 IRQ15 = 0x3F
+;;; IRQ7 = 0x37
+;;;
+;;; ICW1 is the same for both the master and slave PIC. Here's the meaning
+;;; of the individual bits in the word:
+;;;
+;;; F E D C B A 9 8 | 7 6 5 4 3 2 1 0
+;;; (not used) | | | | |__ 1=expect ICW4
+;;; | | | |_____ 0=cascade 1=single
+;;; | | |________ 0=interval-4, 1=8
+;;; | |___________ 0=edge triggered
+;;; | 1=level triggered
+;;; |______________ must be 1
+;;;
+;;;
+BOTH_ICW1 equ 0x11 ; expect ICW4, cascade mode, call address
+ ; interval=8, edge triggered mode
+
+;;;
+;;; ICW2 tells the PICs their base interrupt number. For example, the
+;;; default base interrupt for the master PIC is 0x8. Thus IRQ0=0x8,
+;;; IRQ1=0x9 ... IRQ7=0xF. As stated, we want to relocate these.
+;;;
+MASTER_ICW2 equ 0x30 ; use ints 0x30..0x37
+SLAVE_ICW2 equ 0x38 ; use ints 0x38..0x3F
+
+;;;
+;;; ICW3 to the master tells it which of its IR pins is connected to the
+;;; slave PIC. ICW3 to the slave tells its id number.
+;;;
+MASTER_ICW3 equ 0x04 ; slave on IR pin 2
+SLAVE_ICW3 equ 0x02 ; slave id=2
+
+;;;
+;;; ICW4 to both PICs is another bitvector to set some features:
+;;;
+;;;
+;;; F E D C B A 9 8 | 7 6 5 4 3 2 1 0
+;;; (not used) | ---- | |__ 0=MCS80/85 1=8086/88
+;;; | | |_____ 0=normal 1=auto EOI
+;;; | |_________ 00=non-buf mode
+;;; | 10=buf mode, slave
+;;; | 11=buf mode, master
+;;; |______________ 0=!nested 1=nested
+;;;
+BOTH_ICW4 equ 0x01
+
+HalInterruptInitializePICs:
+ mov al, BOTH_ICW1
+ out 0x20, al ; ICW1 to master PIC
+ call HalIoDelay
+ out 0xA0, al ; ICW1 to slave PIC
+ call HalIoDelay
+
+ mov al, MASTER_ICW2
+ out 0x21, al ; ICW2 to master PIC
+ call HalIoDelay
+ mov al, SLAVE_ICW2
+ out 0xA1, al ; ICW2 to slave PIC
+ call HalIoDelay
+
+ mov al, MASTER_ICW3
+ out 0x21, al ; ICW3 to master PIC
+ call HalIoDelay
+ mov al, SLAVE_ICW3
+ out 0xA1, al ; ICW3 to slave PIC
+ call HalIoDelay
+
+ mov al, BOTH_ICW4
+ out 0x21, al ; ICW4 to master PIC
+ call HalIoDelay
+ out 0xA1, al ; ICW4 to slave PIC
+ call HalIoDelay
+
+;;;
+;;; After the four ICW sequence has been completed any subsequent writes
+;;; to port 0x21 or 0xA1 set the IRQ mask for the master/slave PIC. If
+;;; this mask is 0xFF all IRQs are disabled. If this mask is 0x00
+;;; all IRQs are enabled.
+;;;
+ mov al, 0xff ; slave PIC cannot interrupt
+ out 0xA1, al
+ call HalIoDelay
+ mov al, 0xfb ; mask all IRQs but 2 (the slave PIC) in master
+ out 0x21, al
+ call HalIoDelay
+ ret
+
+;;;
+;;; When doing I/O operations this routine can be used to "delay" long
+;;; enough to let the external controller keep up with the cpu.
+;;;
+HalIoDelay:
+ jmp .done
+.done: ret
+
+;;;
+;;; This is the start of the main interrupt handler code. The first section
+;;; of this code is called the InterruptHandlerPreamble. It consists of
+;;; 256 entry points in a table (one per possible interrupt number). These
+;;; preamble entry points push the interrupt number and (when needed for
+;;; interrupt numbers that the processor doesn't automatically push an error
+;;; code for) a fake error code. Then they jump to the main generic interrupt
+;;; handling routing: InterruptGenericHandler. Thus the stack is always layed
+;;; out in the same way when control passes to the generic handler:
+;;;
+;;; saved ss (pushed by cpu for system calls)
+;;; saved esp (pushed by cpu for system calls)
+;;; ------------
+;;; saved eflags (pushed by cpu)
+;;; saved CS (pushed by cpu)
+;;; saved IP (pushed by cpu)
+;;; error code (pushed by preamble or cpu)
+;;; interrupt number (pushed by preamble)
+;;; esp --> return address (pushed by jmp InteruptGenericHandler)
+;;;
+;;; The first thing InterruptGenericHandler does is push the rest of the
+;;; registers onto the stack.
+;;;
+align 8
+HalInterruptHandlerPreamble:
+HalInterruptHandlerPreambleBefore:
+ INT_NO_ERROR 0
+ align 8
+HalInterruptHandlerPreambleAfter:
+ INT_NO_ERROR 1
+ INT_NO_ERROR 2
+ INT_NO_ERROR 3
+ INT_NO_ERROR 4
+ INT_NO_ERROR 5
+ INT_NO_ERROR 6
+ INT_NO_ERROR 7
+ INT_WITH_ERROR 8
+ INT_NO_ERROR 9
+ INT_WITH_ERROR 10
+ INT_WITH_ERROR 11
+ INT_WITH_ERROR 12
+ INT_WITH_ERROR 13
+ INT_WITH_ERROR 14
+ INT_NO_ERROR 15
+ INT_NO_ERROR 16
+ INT_WITH_ERROR 17
+
+;;;
+;;; The rest of the interrupt numbers are INT_NO_ERRORs. Use nasm's
+;;; %rep command to do them all at once.
+;;;
+%assign intNum 18
+%rep (256 - 18)
+ INT_NO_ERROR intNum
+%assign intNum intNum + 1
+%endrep
+
+;;;
+;;; This is the generic interrupt handler which is called by the preambles
+;;; above. It's job is to save the registers on the stack and then transfer
+;;; control to a specific per-interrupt handler. It finds the address of
+;;; the per-interrupt handler to call by indexing into g_InterruptHandlerTable
+;;;
+align 8
+HalInterruptGenericHandler:
+ SAVE_REGISTERS
+
+ ;; Ensure that we're using the kernel data segment
+ mov ax, (2<<3)
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ ;; Get interrupt number the preamble pushed for us
+ mov esi, [esp+44]
+
+ ;; Get the address of the handler function from the
+ ;; table of handler functions.
+ mov eax, g_InterruptHandlerTable
+ mov ebx, [eax+esi*4]
+
+ ;; Call the handler. The argument passed is a pointer to
+ ;; INTERRUPT_STATE. Interrupts are enabled at this point
+ ;; so if the handler is non-reentrant it must disable them.
+ push esp
+ call ebx
+ add esp, 4
+
+ push esp
+ call HalInterruptSendIrqEoi
+ add esp, 4
+
+ RESTORE_REGISTERS
+ iret
diff --git a/kernel/hal/io.c b/kernel/hal/io.c
new file mode 100644
index 0000000..d97a211
--- /dev/null
+++ b/kernel/hal/io.c
@@ -0,0 +1,40 @@
+#include "kernel.h"
+
+// Write a byte to an I/O port.
+void
+out(WORD port, BYTE value )
+{
+ __asm__ __volatile__ (
+ "outb %b0, %w1"
+ :
+ : "a" (value), "Nd" (port)
+ );
+}
+
+// Read a byte from an I/O port.
+BYTE
+in(WORD port)
+{
+ BYTE value;
+
+ __asm__ __volatile__ (
+ "inb %w1, %b0"
+ : "=a" (value)
+ : "Nd" (port)
+ );
+
+ return value;
+}
+
+// Short delay. May be needed when talking to some
+// (slow) I/O devices.
+void
+iodelay(void)
+{
+ BYTE value = 0;
+ __asm__ __volatile__ (
+ "outb %0, $0x80"
+ :
+ : "a" (value)
+ );
+}
diff --git a/kernel/hal/timer.c b/kernel/hal/timer.c
new file mode 100644
index 0000000..3c82691
--- /dev/null
+++ b/kernel/hal/timer.c
@@ -0,0 +1,43 @@
+//+----------------------------------------------------------------------------
+//
+// File: timer.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 21 Oct 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+#include "hal.h"
+#include "rtl.h"
+#include "interrupts.h"
+
+void
+HalTimerInt(INTERRUPT_STATE *is)
+{
+ static CHAR whee[] = "|/-\\\0";
+ static ULONG u = 0;
+ static BYTE b = 0;
+ static unsigned int foo;
+ BYTE *p = (BYTE *)0x000B8000;
+
+ out(0x61, 0x80);
+ u++;
+
+ CURRENT_STAMP(&foo);
+
+ if ((u % 500) == 0)
+ {
+ b++;
+ if (whee[b] == '\0')
+ {
+ b = 0;
+ }
+ *(p + 158) = whee[b];
+ *(p + 159) = ' ';
+ }
+}
+
diff --git a/kernel/hal/timestamp.asm b/kernel/hal/timestamp.asm
new file mode 100644
index 0000000..b56bedb
--- /dev/null
+++ b/kernel/hal/timestamp.asm
@@ -0,0 +1,19 @@
+
+ [BITS 32]
+
+GLOBAL HalReadTimestampCounter
+EXTERN g_ullTimeStampCounter
+
+[SECTION .text]
+;;;
+;;; ULONGLONG
+;;; HalReadTimestampCounter(void)
+;;;
+;;; Function to read the processor's timestamp counter
+;;;
+HalReadTimestampCounter:
+ ALIGN 4
+ rdtsc
+ mov [g_ullTimeStampCounter], edx
+ mov [g_ullTimeStampCounter+4], eax
+ ret
diff --git a/kernel/hal/video.h b/kernel/hal/video.h
new file mode 100644
index 0000000..dcd7b01
--- /dev/null
+++ b/kernel/hal/video.h
@@ -0,0 +1,15 @@
+//+----------------------------------------------------------------------------
+//
+// File: video.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+#ifndef VIDEO_H
+#define VIDEO_H
+
+#endif // VIDEO_H