--- /dev/null
+SUBDIR += boot0
+SUBDIR += boot1
+SUBDIR += kernel
+
+.include <bsd.port.subdir.mk>
--- /dev/null
+RM = /bin/rm
+TARGET = boot0.bin
+SOURCES = boot0.asm
+
+all: $(SOURCES)
+ nasm -f bin -o $(TARGET) $(SOURCES) ; \
+ mformat -f 1440 -B boot0.bin Q:
+clean:
+ $(RM) -f *.log *.core *~ *.gmon \#*\# $(TARGET)
--- /dev/null
+;
+; This boot sector was based on VnutZ's example available online
+; at http://www.geocities.com/mvea/bootstrap.htm. It also made use
+; of info at http://support.microsoft.com/support/kb/articles/Q140/4/18.asp
+; and the source code for geekos.
+;
+; It searches the root directory of a floppy for two files: boot.com and
+; kernel.bin. If either is missing the boot fails. If they are found, they
+; are loaded into memory at BOOT1SEG:BOOT1OFF and KERNSEG:KERNOFF. Then
+; control is passed to the next stage bootloader, boot.com.
+;
+%include "../inc/defs.asm"
+
+[BITS 16]
+[ORG 0]
+
+START:
+ jmp AROUND_DATA
+
+szOEM_ID db "SCOTTOS", 0 ; 8 bytes, null not required
+wBytesPerSector dw 0x0200 ; bytes per sector
+bSectorsPerCluster db 0x01 ; sectors per cluster
+wReservedSectors dw 0x0001 ; reserved sectors (boot sector)
+bTotalFATs db 0x02 ; num copies of the FAT
+wMaxRootEntries dw 0x00E0 ; max num entries in root directory
+wTotalSectorsSmall dw 0x0B40 ;
+bMediaDescriptor db 0xF0 ;
+wSectorsPerFAT dw 0x0009 ; length of single FAT copy in sectors
+wSectorsPerTrack dw 0x0012 ; sectors per track
+wNumHeads dw 0x0002 ; num heads
+dwHiddenSectors dd 0x00000000 ; num hidden sectors
+dwTotalSectorsLarge dd 0x00000000 ;
+bDriveNumber db 0x00 ; 0x00=A: 0x01=B: 0x80=C: ...
+bFlags db 0x00 ;
+bSignature db 0x29 ;
+dwVolumeID dd 0xFFFFFFFF ;
+szVolumeLabel db "SCOTT BOOT", 0 ; 11 bytes, null not required
+szSystemID db "FAT12 " ;
+
+AROUND_DATA:
+;;; setup segment registers, this code is located at 7C00:0000
+ mov dx, BOOT0SEG ; 7C00
+ mov ds, dx
+ mov es, dx
+
+;;; create a temporary stack at the top of segment 7C00
+ mov ss, dx
+ mov sp, 0xFFFF ; top of this segment
+
+LOAD_ROOT_DIRECTORY:
+;;;
+;;; Compute the length (in number of disk sectors) of the floppy's
+;;; root directory information:
+;;;
+;;; wNumRootDirectorySectors = sizeof(directory_entry) *
+;;; wMaxRootEntries / wBytesPerSector
+;;;
+;;; Store this in cx and in the wNumRootDirectorySectors identifier.
+;;;
+ mov ax, 0x0020 ; sizeof(directory_entry)
+ mul WORD [wMaxRootEntries]
+ div WORD [wBytesPerSector]
+ mov cx, ax ; count of num sectors to read for dir
+
+;;;
+;;; Compute the starting location of the root directory (sector number):
+;;;
+;;; wRootDirectoryStartSector = wReservedSectors +
+;;; (bTotalFATs * wSectorsPerFAT)
+;;;
+ mov al, BYTE [bTotalFATs]
+ mul WORD [wSectorsPerFAT]
+ add ax, WORD [wReservedSectors]
+
+;;;
+;;; Compute the first sector after the root directory -- this is the
+;;; sector where real data starts on the floppy.
+;;;
+ mov WORD [wDriveDataStartSector], ax
+ add WORD [wDriveDataStartSector], cx
+
+;;;
+;;; Read the floppy's root directory into memory at BOOT0SEG:0200 by
+;;; calling ReadSectors. This function reads cx count (wNumRootDirSectors)
+;;; starting at sector ax (wRootDirStartSector) into memory at es:bx
+;;;
+ mov bx, 0x0200
+ call ReadSectors
+
+SEARCH_ROOT_DIRECTORY:
+;;;
+;;; Search the root directory for the stage two loader and the kernel.
+;;;
+ mov cx, WORD [wMaxRootEntries]
+ mov di, 0x0200 ; offset of first directory entry
+.LOOP:
+ push cx ; save current entry count
+ mov cx, 0x000B ; 11 char name
+ mov si, szStage2Image ; name we are seeking
+ push di ; save current entry ptr
+ rep cmpsb ; test for match
+ pop di ; restore entry ptr
+ jne .TRY_KERN ; match? if not see if it matches the kernel
+ mov dx, WORD [di+1Ah] ; match. save the starting cluster
+ mov WORD [wStage2Cluster], dx
+.TRY_KERN:
+ mov cx, 0x000B ; 11 char name
+ mov si, szKernelImage ; name we are seeking
+ push di ; save current entry ptr
+ rep cmpsb ; test for match
+ pop di ; restore entry ptr
+ jne .NEXT ; match? if not next entry
+ mov dx, WORD [di+1Ah] ; match. save the starting cluster
+ mov WORD [wKernelCluster], dx
+.NEXT:
+ pop cx ; cx = entry count again
+ add di, 0x0020 ; next directory entry (+32 bytes later)
+ loop .LOOP ; cx -= 1, jmp .LOOP if cx != 0
+
+.DONE:
+;;;
+;;; Did we find both the kernel and the second stage boot loader? If not
+;;; give them a "missing operating system" message.
+;;;
+ mov ax, [wStage2Cluster]
+ test ax, 0xFFFF
+ jz .NOOS
+ mov ax, [wKernelCluster]
+ test ax, 0xFFFF
+ jnz LOAD_FAT
+.NOOS:
+ mov si, szNoOperatingSystem
+ call Write
+FAIL: mov ah, 0x00 ; wait for a keystroke and reboot
+ int 0x16
+ int 0x19
+
+LOAD_FAT:
+;;;
+;;; Prepare the load the FAT into memory. Compute the size of the FAT (in
+;;; number of sectors) and store in cx for a call to ReadSectors.
+;;;
+ xor ax, ax
+ mov al, BYTE [bTotalFATs]
+ mul WORD [wSectorsPerFAT]
+ mov cx, ax
+
+;;;
+;;; Compute location of FAT and store in ax
+;;;
+ mov ax, WORD [wReservedSectors]
+
+;;;
+;;; Read the FAT into memory at BOOT0SEG:0200. This overwrites the root
+;;; directory information but we already have the cluster number for the
+;;; stage two boot loader and the kernel.
+;;;
+ mov bx, 0x0200
+ call ReadSectors
+
+;;;
+;;; Prepare to read the stage two boot loader into memory at
+;;; BOOT1SEG:BOOT1OFF
+;;;
+ ;; point es:bx at where we want the stage two loader read into memory
+ mov ax, BOOT1SEG
+ mov es, ax ; destination for image
+ mov bx, BOOT1OFF ; destination for image
+
+ ;; use the starting cluster we found by reading the directory
+ mov ax, WORD [wStage2Cluster]
+ mov WORD [wCluster], ax
+
+ ;; call LOAD_IMAGE to read in the file
+ call LOAD_IMAGE
+
+;;;
+;;; Prepare to read the kernel into memory at KERNSEG:KERNOFF
+;;;
+ ;; point es:bx at where we want the kernel read into memory
+ mov ax, KERNSEG
+ mov es, ax
+ mov bx, KERNOFF
+
+ ;; use the starting cluster we found by reading the directory
+ mov ax, WORD [wKernelCluster]
+ mov WORD [wCluster], ax
+
+ ;; call LOAD_IMAGE to read in the file
+ call LOAD_IMAGE
+
+DONE:
+;;;
+;;; We're done, transfer control to the second stage loader which we
+;;; put at BOOT1SEG:BOOT1OFF.
+;;;
+ push WORD BOOT1SEG
+ push WORD BOOT1OFF
+ retf
+
+;; *************************************************************************
+;; PROCEDURE ClusterLBA
+;; convert FAT cluster into LBA addressing scheme
+;; LBA = (cluster - 2) * sectors per cluster
+;; *************************************************************************
+ClusterLBA:
+ sub ax, 0x0002 ; cluster number is zero-based
+ xor cx, cx
+ mov cl, BYTE [bSectorsPerCluster]; convert byte to word
+ mul cx
+ add ax, WORD [wDriveDataStartSector]; base data sector
+ ret
+
+;;; *************************************************************************
+;;; PROCEDURE LBACHS
+;;;
+;;; convert ax LBA addressing scheme to CHS addressing scheme using these
+;;; formulas:
+;;;
+;;; absolute sector = (logical sector / sectors per track) + 1
+;;; absolute head = (logical sector / sectors per track) MOD number of heads
+;;; absolute track = logical sector / (sectors per track * number of heads)
+;;; *************************************************************************
+LBACHS:
+ xor dx, dx
+ div WORD [wSectorsPerTrack]
+ inc dl ; adjust for sector 0
+ mov BYTE [bAbsoluteSector], dl
+ xor dx, dx ; prepare dx:ax for operation
+ div WORD [wNumHeads]
+ mov BYTE [bAbsoluteHead], dl
+ mov BYTE [bAbsoluteTrack], al
+ ret
+
+;;; *************************************************************************
+;;; PROCEDURE ReadSectors
+;;;
+;;; reads disk sectors ax..ax+cx from the disk into memory at es:bx
+;;;
+;;; *************************************************************************
+ReadSectors:
+.MAIN
+ mov di, 5 ; five retries for disk errors
+.SECTORLOOP
+ push ax
+ push bx
+ push cx
+ call LBACHS ; convert LBA sector in ax into absolute CHT
+ mov ah, 0x02 ; BIOS read sector
+ mov al, 0x01 ; read one sector
+ mov ch, BYTE [bAbsoluteTrack]
+ mov cl, BYTE [bAbsoluteSector]
+ mov dh, BYTE [bAbsoluteHead]
+ mov dl, BYTE [bDriveNumber]
+ int 0x13
+ jnc .SUCCESS ; CF=1 on read error
+
+ ;; read error, reset the disk and try again
+ xor ax, ax ; BIOS reset disk
+ int 0x13
+ dec di ; error counter -= 1
+ pop cx ; restore registers
+ pop bx
+ pop ax
+ jnz .SECTORLOOP ; if error counter != 0, try to read again
+
+ ;; give up
+ mov si, szReadError
+ call Write
+ jmp FAIL
+
+ ;; sector read succeeded
+.SUCCESS
+ pop cx ; restore registers
+ pop bx
+ pop ax
+ inc ax ; next sector
+
+ ;;; bx += wBytesPerSector
+ add bx, WORD [wBytesPerSector]
+ loop .MAIN ; cx -= 1, jmp .MAIN if cx != 0
+ ret
+
+;;; *************************************************************************
+;;; PROCEDURE Write
+;;;
+;;; display ASCIIZ string at ds:si via BIOS
+;;; *************************************************************************
+Write:
+ cld ; make sure direction flag is correct
+ lodsb ; load char to al, increment si
+ or al, al ; see if it's null
+ jz .DONE ; if so, we're finished
+ mov ah, 0x0E ; service 0x0E: output one char
+ mov bh, 0x00 ; display page 0
+ mov bl, 0x07 ; char text attrib (white on black)
+ int 0x10 ; invoke bios
+ jmp Write ; next char
+.DONE:
+ ret
+
+LOAD_IMAGE:
+ mov ax, WORD [wCluster] ; cluster to read
+ call ClusterLBA ; convert cluster to LBA
+ xor cx, cx
+ mov cl, BYTE [bSectorsPerCluster]
+ call ReadSectors ; this increments bx
+
+ ;; compute next cluster
+ mov ax, WORD [wCluster] ; identify current cluster
+ mov cx, ax ; copy current cluster
+ mov dx, ax ; copy current cluster
+ shr dx, 0x0001 ; dx = wCluster / 2
+ add cx, dx ; cx = wCluster + (wCluster / 2)
+ push bx
+ mov bx, 0x0200 ; location of FAT in memory
+ add bx, cx ; index into FAT
+ mov dx, WORD [bx] ; read two bytes from FAT
+ pop bx
+ test ax, 0x0001 ; is the cluster even or odd?
+ jnz .ODD
+.EVEN:
+ and dx, 0x0FFF ; take low twelve bits
+ jmp .DONE
+.ODD:
+ shr dx, 0x0004 ; take high twelve bits
+.DONE:
+ mov WORD [wCluster], dx ; store new cluster
+ cmp dx, 0x0FF0 ; test for end of file
+ jb LOAD_IMAGE ; if not, go get the next one
+ ret
+
+wDriveDataStartSector dw 0x0000
+szStage2Image db "BOOT COM", 0
+wStage2Cluster dw 0x0000
+szKernelImage db "KERNEL BIN", 0
+wKernelCluster dw 0x0000
+szNoOperatingSystem db "Missing OS File", 13, 10, 0
+szReadError db "Disk read error", 13, 10, 0
+wCluster dw 0x0000
+bAbsoluteSector db 0x00
+bAbsoluteHead db 0x00
+bAbsoluteTrack db 0x00
+szProgress db ".", 0
+
+ TIMES 510-($-$$) DB 0 ; 0 padding
+ DW 0xAA55 ; bootsector signature
--- /dev/null
+NASM= nasm
+NASMFLAGS= -f bin -i../inc
+RM= /bin/rm
+TARGET= boot.com
+SOURCES= boot1.asm
+SUPPORT= video.asm hardware.asm
+
+all: $(SOURCES) $(SUPPORT)
+ $(NASM) $(NASMFLAGS) $(SOURCES) -o $(TARGET) ; \
+ mcopy -o $(TARGET) Q:\
+
+clean:
+ $(RM) -f *.log *.core *~ *.gmon \#*\# $(TARGET) ; \
+ mdel Q:\$(TARGET)
--- /dev/null
+[BITS 16]
+[ORG 0]
+
+START:
+ ;; initialize segments
+ mov ax, BOOT1SEG
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ ;; make sure we are running on a 386+
+
+ ;; while we're still in real mode, detect system hardware via BIOS
+ call PROBE_VIDEO
+ call GET_EQUIPMENT_LIST
+ call GET_MEMORY_SIZE
+ call GET_TIME
+
+ ;; switch the processor into protected mode, keep ints disabled
+ cli
+ lidt [IDT_Pointer]
+ lgdt [GDT_Pointer]
+ call ENABLE_A20
+ mov ax, 0x01
+ lmsw ax
+
+ ;; Jump to 32 bit code, this completes the transition to protected mode
+ db 0x66 ; operand size override prefix
+ db 0xea ; jmp opcode
+ dd (BOOT1SEG<<4) + setup_32 ; want to jump here
+ dw (1<<3) ; ...in the kernel code segment
+
+[BITS 32]
+setup_32:
+ ;; set up data segment registers
+ mov ax, (2<<3)
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ ;; create an initial stack
+ mov esp, KERN_STACK + 4096
+ mov ebp, esp
+
+ ;; create a stack frame, pass ptr to hardware block as param
+ mov eax, (BOOT1SEG<<4)+BIOS_HARDWARE_BLOCK
+ push eax
+ push (BOOT1SEG<<4)+.HANG
+ jmp (1<<3):0x00010000 ; entry point of kernel
+
+.HANG:
+ nop
+ jmp .HANG
+
+
+; Setup data
+; ----------------------------------------------------------------------
+
+BIOS_HARDWARE_BLOCK:
+bDisplayType db 0x00
+bFontSize db 0x00
+wEquipmentBitvector dw 0x0000
+wMemorySize dw 0x0000
+wSystemClock dw 0x0000
+
+NUM_GDT_ENTRIES equ 3 ; number of entries in GDT
+GDT_ENTRY_SZ equ 8 ; size of a single GDT entry
+
+align 8, db 0
+GDT:
+ ; Descriptor 0 is not used
+ dw 0
+ dw 0
+ dw 0
+ dw 0
+
+ ; Descriptor 1: kernel code segment
+ dw 0xFFFF ; bytes 0 and 1 of segment size
+ dw 0x0000 ; bytes 0 and 1 of segment base address
+ db 0x00 ; byte 2 of segment base address
+ db 0x9A ; present, DPL=0, non-system, code, non-conforming,
+ ; readable, not accessed
+ db 0xCF ; granularity=page, 32 bit code, upper nibble of size
+ db 0x00 ; byte 3 of segment base address
+
+ ; Descriptor 2: kernel data and stack segment
+ ; NOTE: what Intel calls an "expand-up" segment
+ ; actually means that the stack will grow DOWN,
+ ; towards lower memory. So, we can use this descriptor
+ ; for both data and stack references.
+ dw 0xFFFF ; bytes 0 and 1 of segment size
+ dw 0x0000 ; bytes 0 and 1 of segment base address
+ db 0x00 ; byte 2 of segment base address
+ db 0x92 ; present, DPL=0, non-system, data, expand-up,
+ ; writable, not accessed
+ db 0xCF ; granularity=page, big, upper nibble of size
+ db 0x00 ; byte 3 of segment base address
+
+GDT_Pointer:
+ dw NUM_GDT_ENTRIES*GDT_ENTRY_SZ ; limit
+ dd (BOOT1SEG<<4) + GDT ; base address
+
+IDT_Pointer:
+ dw 0
+ dd 00
+
+%include "defs.asm"
+%include "hardware.asm"
+%include "video.asm"
+
+
\ No newline at end of file
--- /dev/null
+[BITS 16]
+;;; Call BIOS to populate equipment bitv in the HARDWARE buffer.
+GET_EQUIPMENT_LIST:
+ xor ax, ax
+ int 0x11
+ mov [wEquipmentBitvector], ax
+ ret
+
+;;; Call BIOS to get the system memory size.
+GET_MEMORY_SIZE:
+ xor ax, ax
+ mov ah, 0x88
+ int 0x15
+ add ax, 1024
+ mov [wMemorySize], ax
+ ret
+
+GET_TIME:
+ xor ax, ax
+ int 0x1a
+ push es
+ push si
+ mov es, cx
+ mov si, dx
+ mov cx, WORD [es:si]
+ mov [wSystemClock], cx
+ pop si
+ pop es
+ ret
+
+; Enable the A20 address line, so we can correctly address
+; memory above 1MB.
+ENABLE_A20:
+ mov al, 0xD1
+ out 0x64, al
+ nop
+ jmp .here
+.here: mov al, 0xDF
+ out 0x60, al
+ nop
+ jmp .there
+.there: ret
--- /dev/null
+;;;
+SIZE_MEMORY:
+
\ No newline at end of file
--- /dev/null
+;;; Display the ASCIIZ string at ds:si via BIOS VIDEO call (real mode only)
+Write:
+ lodsb ; load char to al, increment si
+ or al, al ; see if it's null
+ jz .DONE ; if so, we're finished
+ mov ah, 0x0E ; service 0x0E: output one char
+ mov bh, 0x00 ; display page 0
+ mov bl, 0x07 ; char text attrib (white on black)
+ int 0x10 ; invoke bios
+ jmp Write ; next char
+.DONE:
+ ret
+
+;;; Probe the video system of the machine via BIOS VIDEO calls, populate
+;;; the HARDWARE_INFO buffer (real mode only).
+PROBE_VIDEO:
+ ;; identify the display type
+ call DISP_ID
+ mov [bDisplayType], al
+
+ ;; determine the font size
+ call FONT_SIZE
+ mov [bFontSize], al
+ ret
+
+;;; Determine the font size (width in pixels) of the current display.
+FONT_SIZE:
+ cmp al, 0x0a
+ jl .TRY_OLD
+ mov al, BYTE 16
+ ret
+.TRY_OLD:
+ cmp al, BYTE 1
+ jne .TRY_CGA
+ mov al, BYTE 14
+ ret
+.TRY_CGA:
+ cmp al, BYTE 2
+ jne .TRY_VGA
+ mov al, BYTE 8
+ ret
+.TRY_VGA:
+ mov ah, 0x11
+ mov al, 0x30
+ mov bh, 0
+ int 0x10
+ mov al, cl
+ ret
+
+;;; Determine the video type via BIOS VIDEO call
+DISP_ID:
+ xor ax, ax
+ mov ah, 0x1a
+ int 0x10
+ cmp al, 0x1a
+ jne .TRY_EGA
+ mov al, bl
+ ret
+.TRY_EGA:
+ mov ah, 0x12
+ mov bx, 0x10
+ int 0x10
+ cmp bx, 0x10
+ je .OLD_BOARDS
+ cmp bh, 0
+ je .EGA_COLOR
+ mov al, 5
+ ret
+.EGA_COLOR:
+ mov al, 4
+ ret
+.OLD_BOARDS:
+ int 0x11
+ and al, 0x30
+ cmp al, 0x30
+ jne .CGA
+ mov al, 1
+ ret
+.CGA:
+ mov al, 2
+ ret
--- /dev/null
+BOOT0SEG equ 0x07C0
+BOOT0OFF equ 0x0000
+
+BOOT1SEG equ 0x0100
+BOOT1OFF equ 0x0000
+
+KERNSEG equ 0x1000
+KERNOFF equ 0x0000
+
+VIDEOSEG equ 0xB800
+
+; 8259A PIC initialization codes.
+; Source: Linux bootsect.S, and Intel 8259A datasheet
+
+; The most important reason why we reprogram the PICs is to
+; route the hardware interrupts through vectors *above*
+; those reserved by Intel. The BIOS (for historical reasons :-)
+; routes them such that they conflict with internal processor-generated
+; interrupts.
+
+ICW1 equ 0x11 ; ICW1 - ICW4 needed, cascade mode, interval=8,
+ ; edge triggered. (I think interval is irrelevant
+ ; for x86.)
+ICW2_MASTER equ 0x20 ; put IRQs 0-7 at 0x20 (above Intel reserved ints)
+ICW2_SLAVE equ 0x28 ; put IRQs 8-15 at 0x28
+ICW3_MASTER equ 0x04 ; IR2 connected to slave
+ICW3_SLAVE equ 0x02 ; slave has id 2
+ICW4 equ 0x01 ; 8086 mode, no auto-EOI, non-buffered mode,
+ ; not special fully nested mode
+
+KERN_THREAD_OBJ equ (1024*1024)
+KERN_STACK equ KERN_THREAD_OBJ + 4096
+
--- /dev/null
+DEBUGFLAGS=-DDEBUG
+
+SUBDIR += init
+SUBDIR += hal
+SUBDIR += rtl
+
+.include <bsd.port.subdir.mk>
+
+OBJCOPY= objcopy
+OBJCOPY_FLAGS= -R .dynamic -R .note -R .comment
+OBJS= init/entry.o init/main.o hal/video.o hal/io.o \
+ rtl/string.o rtl/memory.o hal/intsupport.o hal/interrupts.o \
+ hal/timer.o hal/keyboard.o hal/timestamp.o hal/counters.o
+RM= /bin/rm
+
+all: kernel.bin
+
+kernel.bin: kernel.tmp
+ $(OBJCOPY) $(OBJCOPY_FLAGS) -S -O binary ./kernel.tmp kernel.bin ; \
+ mcopy -o ./kernel.bin Q: ; \
+ mcopy -o ./kernel.map Q: ; \
+ $(RM) -f kernel.tmp
+
+kernel.tmp: $(OBJS)
+ $(LD) -M -o kernel.tmp -Ttext 0x00010000 -e StartOfKernelImage $(OBJS) \
+ > kernel.map
+
+clean:
+ $(RM) -f $(TARGET) $(OBJS) *~ #*# .#* ; \
+ mdel Q:\$(TARGET)
--- /dev/null
+//
+// Symbols defined here are globally defined in all Makefiles below
+// here.
+//
+#define KERNEL
+#define DEBUG
\ No newline at end of file
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: keyboard.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 21 Oct 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+#include "hal.h"
+#include "rtl.h"
+#include "interrupts.h"
+
+void
+HalKeyboardInt(INTERRUPT_STATE *is)
+{
+ BYTE c;
+ BYTE k;
+
+ HalDisableInterrupts();
+
+ c = in(0x64);
+ HalIoDelay();
+ if (c & 1)
+ {
+ k = in(0x60);
+ HalIoDelay();
+ HalVideoPrint("Testing %x.\n\0", 1);
+ }
+
+ HalEnableInterrupts();
+}
+
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: video.c
+//
+// Module: Video driver
+//
+// Synopsis: low-level interface to video memory
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#include <stdarg.h>
+
+#include "kernel.h"
+#include "hal.h"
+#include "rtl.h"
+#include "video.h"
+
+extern BIOS_HARDWARE_BLOCK g_BiosHardwareBlock;
+
+//
+// Local #defines
+//
+#define FG_BG_TO_ATTRIB_BYTE(fg,bg) ((fg&0x0F)|((bg&0x0F)<<4))
+#define LINES (0)
+#define COLS (1)
+#define CRT_ADDR_REG (0x3D4)
+#define CRT_DATA_REG (0x3D5)
+#define CRT_CURSOR_LOC_HIGH_REG (0x0E)
+#define CRT_CURSOR_LOC_LOW_REG (0x0F)
+#define ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(L,C)\
+ (((g_bScreenResolution[COLS] << 1) * (L)) + ((C) << 1))
+#define ZERO_BASED_LINE_COL_TO_ULONG_OFFSET(L,C)\
+ (ZERO_BASED_LINE_COL_TO_BYTE_OFFSET((L),(C)) >> 2)
+
+//
+// Global identifiers
+//
+BYTE *g_pVideoMemory = NULL;
+BYTE g_bScreenResolution[2] = { 0, 0 };
+BYTE g_bSoftCursor[2] = { 0, 0 };
+BYTE g_bColorAttribute = FG_BG_TO_ATTRIB_BYTE(BLACK, WHITE);
+
+typedef struct _VIDEO_LOOKUP_ENTRY
+{
+ CHAR *szBoardName;
+ BYTE *pStartOfVideoMemory;
+ BYTE uScreenLines[3];
+}
+VIDEO_LOOKUP_ENTRY;
+
+static VIDEO_LOOKUP_ENTRY g_VideoLookupTable[] =
+{
+ { "No video adapter",
+ (BYTE *)0x000B0000,
+ { 25, 25, 25 } },
+ { "Monochrome display adapter",
+ (BYTE *)0x000B0000,
+ { 25, 25, 25 } },
+ { "CGA",
+ (BYTE *)0x000B8000,
+ { 25, 25, 25 } },
+ { "Code 3: Undefined",
+ (BYTE *)0x000B0000,
+ { 25, 25, 25 } },
+ { "EGA with color display",
+ (BYTE *)0x000B8000,
+ { 43, 25, 25 } },
+ { "EGA with mono display",
+ (BYTE *)0x000B0000,
+ { 43, 25, 25 } },
+ { "Code 6: Undefined",
+ (BYTE *)0x000B0000,
+ { 25, 25, 25 } },
+ { "VGA with mono display",
+ (BYTE *)0x000B0000,
+ { 50, 27, 25 } },
+ { "VGA with color display",
+ (BYTE *)0x000B8000,
+ { 50, 27, 25 } },
+ { "Code 9: Undefined",
+ (BYTE *)0x000B0000,
+ { 25, 25, 25 } },
+ { "MCGA with digital color",
+ (BYTE *)0x000B8000,
+ { 25, 25, 25 } },
+ { "MCGA with monochrome",
+ (BYTE *)0x000B0000,
+ { 25, 25, 25 } },
+ { "MCGA with analog color",
+ (BYTE *)0x000B8000,
+ { 25, 25, 25 } }
+};
+
+
+//+----------------------------------------------------------------------------
+//
+// Function: VideopInitialize
+//
+// Synopsis:
+//
+// Arguments: void
+//
+// Returns: STATUS
+//
+//+----------------------------------------------------------------------------
+STATUS
+VideopInitialize(void)
+{
+ BYTE uType = g_BiosHardwareBlock.bDisplayType;
+ BYTE uIndex = 2;
+
+ //
+ // Based on the font size (width in pixels), set the index into the
+ // screen lines lookup table
+ //
+ switch(g_BiosHardwareBlock.bFontSize)
+ {
+ case 8:
+ uIndex = 0;
+ break;
+ case 14:
+ uIndex = 1;
+ break;
+ case 16:
+ uIndex = 2;
+ break;
+ }
+
+ //
+ // If the display type returned by BIOS is known to us, use the
+ // lookup table to populate some globals here.
+ //
+ if (uType <= ARRAY_LENGTH(g_VideoLookupTable))
+ {
+ g_pVideoMemory = g_VideoLookupTable[uType].pStartOfVideoMemory;
+ g_bScreenResolution[LINES] =
+ g_VideoLookupTable[uType].uScreenLines[uIndex];
+ }
+
+ //
+ // Otherwise make some guesses
+ //
+ else
+ {
+ g_pVideoMemory = (BYTE *)0x000B8000;
+ g_bScreenResolution[LINES] = 25;
+ }
+ g_bScreenResolution[COLS] = 80;
+
+ //
+ // Set color to WHITE on BLACK
+ //
+ VideoSetCurrentColorAttribute(WHITE, BLACK);
+
+ //
+ // Clear the screen and thus synchronize the hardware and soft cursor
+ // position.
+ //
+ VideoClearScreen();
+ return(STATUS_SUCCESS);
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Function: VideoDriverMain
+//
+// Synopsis:
+//
+// Arguments: UINT uEvent
+//
+// Returns: STATUS
+//
+//+----------------------------------------------------------------------------
+STATUS
+VideoDriverMain(UINT uEvent)
+{
+ switch(uEvent)
+ {
+ case DEVICE_DRIVER_INITIALIZATION:
+ return(VideopInitialize());
+
+ case DEVICE_DETATCH:
+ ASSERT(FALSE);
+ return(STATUS_NOT_SUPPORTED);
+
+ case DEVICE_DRIVER_SHUTDOWN:
+ g_fVideoEnabled = FALSE;
+ return(STATUS_SUCCESS);
+
+ default:
+ }
+ return(TRUE);
+}
+
+STATUS
+VideoDriverRead(UINT uAddress,
+ void *pBuffer,
+ UINT uBufferLength);
+
+STATUS
+VideoDriverWrite(UINT uAddress,
+ void *pBuffer,
+ UINT uBufferLength);
+
+STATUS
+VideoDriverIoctl(UINT uIoctlCode,
+ void *pBuffer,
+ UINT uBufferLength);
+
+
+//
+// Move the hardware cursor on the screen to sync up with the software
+// cursor position in g_bSoftwareCursor
+//
+void
+VideoSetHardwareCursor(void)
+{
+ WORD wOffset; // byte offset into video mem
+ BYTE bOrig; // original port contents holder
+
+ //
+ // Cursor is zero-based (e.g. line 24 is the last one)
+ //
+ ASSERT(g_bSoftCursor[LINES] < g_bScreenResolution[LINES]);
+ ASSERT(g_bSoftCursor[COLS] < g_bScreenResolution[COLS]);
+
+ wOffset = ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bSoftCursor[LINES],
+ g_bSoftCursor[COLS]);
+ ASSERT(wOffset <= (g_bScreenResolution[LINES] *
+ g_bScreenResolution[COLS]) * 2 - 2);
+
+ //
+ // Save original contents of CRT address register.
+ //
+ bOrig = in(CRT_ADDR_REG);
+
+ //
+ // Set the high cursor location byte
+ //
+ out(CRT_ADDR_REG, CRT_CURSOR_LOC_HIGH_REG);
+ out(CRT_DATA_REG, (wOffset >> 8) & 0xFF);
+ IoDelay();
+
+ //
+ // Set the low cursor location byte
+ //
+ out(CRT_ADDR_REG, CRT_CURSOR_LOC_LOW_REG);
+ IoDelay();
+ out(CRT_DATA_REG, (wOffset & 0xFF));
+ IoDelay();
+
+ //
+ // Restore contents of the CRT address register
+ //
+ out(CRT_ADDR_REG, bOrig);
+ IoDelay();
+}
+
+void
+VideoSetCurrentColorAttribute(BYTE bFg, BYTE bBg)
+{
+ bFg &= 0x0F; // restrict these guys to colors
+ bBg &= 0x0F; // and the high intense bit
+
+ g_bColorAttribute = FG_BG_TO_ATTRIB_BYTE(bFg, bBg);
+}
+
+void
+VideoClearScreen(void)
+{
+ ULONG *p = (ULONG *)g_pVideoMemory;
+ ULONG uFill;
+ ULONG uCount;
+
+ //
+ // Start uCount at the number of ULONGs in visible video memory
+ //
+ uCount = ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bScreenResolution[LINES] - 1,
+ g_bScreenResolution[COLS] - 1);
+ uCount += 2;
+ uCount >>= 2;
+
+ //
+ // Construct a fill ULONG: blank attrib blank attrib
+ //
+ uFill = 0;
+ uFill |= (ULONG)g_bColorAttribute;
+ uFill |= ((ULONG)g_bColorAttribute) << 16;
+
+ //
+ // Blast uFills into video memory
+ //
+ while(uCount)
+ {
+ *p++ = uFill;
+ uCount--;
+ }
+
+ //
+ // Set cursor position to 0,0
+ //
+ g_bSoftCursor[LINES] = g_bSoftCursor[COLS] = 0;
+ VideoSetHardwareCursor();
+}
+
+
+void
+VideoScroll(void)
+{
+ ULONG *p = (ULONG *)g_pVideoMemory;
+ ULONG uUlongsPerLine = (g_bScreenResolution[COLS] >> 1); // 2X/4
+ ULONG i, j;
+ ULONG uFill;
+
+ ASSERT(sizeof(ULONG) == 4);
+ ASSERT(sizeof(BYTE) == 1);
+
+ for (i = 0;
+ i < (g_bScreenResolution[LINES] - 2);
+ i++)
+ {
+ //
+ // Start at i, 0. Copy a ULONG up from i+1, 0. Do the whole line i.
+ //
+ for (j = 0;
+ j < uUlongsPerLine;
+ j++)
+ {
+ *p = *(p + uUlongsPerLine);
+ p++;
+ }
+ }
+
+ //
+ // Construct a fill ULONG: blank attrib blank attrib
+ //
+ uFill = 0;
+ uFill |= (ULONG)g_bColorAttribute;
+ uFill |= ((ULONG)g_bColorAttribute) << 16;
+
+ //
+ // Blank the last line
+ //
+ p = (ULONG *)(g_pVideoMemory +
+ ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bScreenResolution[LINES] - 1, 0));
+ for (i = 0;
+ i < uUlongsPerLine;
+ i++)
+ {
+ *p = uFill;
+ p++;
+ }
+}
+
+void
+VideoPutChar(BYTE c)
+{
+ BYTE *p = (g_pVideoMemory +
+ ZERO_BASED_LINE_COL_TO_BYTE_OFFSET(g_bSoftCursor[LINES],
+ g_bSoftCursor[COLS]));
+ switch(c)
+ {
+ case '\n':
+ g_bSoftCursor[LINES]++;
+ if (g_bSoftCursor[LINES] >= g_bScreenResolution[LINES])
+ {
+ VideoScroll();
+ g_bSoftCursor[LINES] = g_bScreenResolution[LINES] - 1;
+ }
+ g_bSoftCursor[COLS] = 0;
+ return;
+ default:
+ *p = c;
+ p++;
+ *p = g_bColorAttribute;
+ p++;
+ g_bSoftCursor[COLS]++;
+ if (g_bSoftCursor[COLS] >= g_bScreenResolution[COLS])
+ {
+ g_bSoftCursor[COLS] = 0;
+ g_bSoftCursor[LINES]++;
+ if (g_bSoftCursor[LINES] >= g_bScreenResolution[LINES])
+ {
+ VideoScroll();
+ g_bSoftCursor[LINES] = g_bScreenResolution[LINES] - 1;
+ }
+ }
+ }
+}
+
+void
+VideoPutNullTerminatedString(BYTE *s)
+{
+ ULONG uSafety = 0;
+
+ while (*s != 0)
+ {
+ VideoPutChar(*s);
+ s++;
+ uSafety++;
+
+ if (uSafety > 256)
+ {
+ VideoPutNullTerminatedString("RUNAWAYSTRING!?!\n\0");
+ break;
+ }
+ }
+ VideoSetHardwareCursor();
+}
+
+void
+VideoSetCursorPosition(BYTE bLine, BYTE bCol)
+{
+ if (bLine >= g_bScreenResolution[LINES])
+ {
+ bLine = g_bScreenResolution[LINES] - 1;
+ }
+ if (bCol >= g_bScreenResolution[COLS])
+ {
+ bCol = g_bScreenResolution[COLS] - 1;
+ }
+
+ g_bSoftCursor[LINES] = bLine;
+ g_bSoftCursor[COLS] = bCol;
+ VideoSetHardwareCursor();
+}
+
+void
+VideoGetCursorPosition(BYTE *pbLine, BYTE *pbCol)
+{
+ *pbLine = g_bSoftCursor[LINES];
+ *pbCol = g_bSoftCursor[COLS];
+}
+
+void
+VideoPrint(CHAR *szFormat, ...)
+{
+ CHAR *p = szFormat;
+ CHAR *q;
+ CHAR buf[32];
+ va_list args;
+ INT iVal;
+ UINT uVal;
+ CHAR *szVal;
+
+ va_start(args, szFormat);
+ while (*p != '\0')
+ {
+ switch (*p)
+ {
+ case '%':
+ p++;
+ switch (*p)
+ {
+ case '\0':
+ goto done;
+ case '%':
+ VideoPutChar('%');
+ break;
+ case 'd':
+ iVal = va_arg(args, int);
+ q = RtlIntToAscii(iVal, buf, ARRAY_LENGTH(buf), 10);
+ ASSERT(strlen(q) < 20);
+ VideoPutNullTerminatedString(q);
+ break;
+ case 'u':
+ uVal = va_arg(args, unsigned int);
+ q = RtlIntToAscii(uVal, buf, ARRAY_LENGTH(buf), 10);
+ ASSERT(strlen(q) < 20);
+ VideoPutNullTerminatedString(q);
+ break;
+ case 'x':
+ uVal = va_arg(args, unsigned int);
+ q = RtlIntToAscii(uVal, buf, ARRAY_LENGTH(buf), 16);
+ ASSERT(strlen(q) < 20);
+ VideoPutNullTerminatedString(q);
+ break;
+ case 's':
+ szVal = va_arg(args, char *);
+ VideoPutNullTerminatedString(szVal);
+ break;
+ case 'c':
+ iVal = va_arg(args, int);
+ VideoPutChar(iVal & 0xFF);
+ break;
+ default:
+ VideoPutChar(*p);
+ break;
+ }
+ break;
+ default:
+ VideoPutChar(*p);
+ break;
+ }
+ p++;
+ }
+ done:
+ va_end(args);
+ VideoSetHardwareCursor();
+}
--- /dev/null
+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) *~ #*# .#*
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: counters.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Copyright (C) 2003 Scott Gasch
+//
+// Created: sgasch 24 Oct 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+
+UINT64 g_ullTimeStampCounter = 0;
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// 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();
+}
+
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// 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
+
--- /dev/null
+[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
--- /dev/null
+#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)
+ );
+}
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// 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) = ' ';
+ }
+}
+
--- /dev/null
+
+ [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
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: video.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+#ifndef VIDEO_H
+#define VIDEO_H
+
+#endif // VIDEO_H
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: constants.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Copyright (C) 2003
+//
+// Created: sgasch 10 Oct 2003
+//
+//+----------------------------------------------------------------------------
+
+#ifndef _CONSTANTS_H_
+#define _CONSTANTS_H_
+
+//
+// Constants
+//
+#define YES (1)
+#define NO (0)
+#ifndef TRUE
+#define TRUE (YES)
+#endif
+#ifndef FALSE
+#define FALSE (NO)
+#endif
+
+#define NULL ((void *)0)
+
+#define ASCII_ESC (0x1B)
+#define ASCII_BS (0x08)
+
+#define USER_PRIVILEGE (3)
+#define KERNEL_PRIVILEGE (0)
+
+//
+// Device driver constants
+//
+#define DEVICE_DRIVER_INITIALIZATION (1)
+#define DEVICE_IO_CONTROL (2)
+#define DEVICE_READ (3)
+#define DEVICE_WRITE (4)
+#define DEVICE_DETATCH (6)
+#define DEVICE_DRIVER_SHUTDOWN (7)
+
+#endif /* _CONSTANTS_H_ */
+
+
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: hal.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+#ifndef HAL_H
+#define HAL_H
+
+//
+// Video/CRT driver
+//
+#define BLACK (0)
+#define BLUE (1)
+#define GREEN (2)
+#define CYAN (3)
+#define RED (4)
+#define MAGENTA (5)
+#define YELLOW (6)
+#define GRAY (7)
+#define HIGH (8)
+#define WHITE (HIGH | GRAY)
+
+void
+HalVideoSetCurrentColorAttribute(BYTE bFg, BYTE bBg);
+
+void
+HalVideoClearScreen(void);
+
+void
+HalVideoGetCursorPosition(BYTE *pbLine, BYTE *pbCol);
+
+void
+HalVideoSetCursorPosition(BYTE bLine, BYTE bCol);
+
+void
+HalVideoPutNullTerminatedString(BYTE *s);
+
+void
+HalVideoInitialize(BIOS_HARDWARE_BLOCK *phw);
+
+void
+HalVideoPrint(CHAR *szFormat, ...);
+
+//
+// Keyboard driver
+//
+#define KB_IRQ (1)
+typedef WORD KEYCODE;
+
+typedef struct _INTERRUPT_STATE
+{
+ // The register contents at the time of the exception.
+ // We save these explicitly.
+ ULONG gs;
+ ULONG fs;
+ ULONG es;
+ ULONG ds;
+ ULONG ebp;
+ ULONG edi;
+ ULONG esi;
+ ULONG edx;
+ ULONG ecx;
+ ULONG ebx;
+ ULONG eax;
+
+ // We explicitly push the interrupt number.
+ // This makes it easy for the handler function to determine
+ // which interrupt occurred.
+ ULONG uIntNum;
+
+ // This may be pushed by the processor; if not, we push
+ // a dummy error code, so the stack layout is the same
+ // for every type of interrupt.
+ ULONG uErrorCode;
+
+ // These are always pushed on the stack by the processor.
+ ULONG eip;
+ ULONG cs;
+ ULONG eflags;
+}
+INTERRUPT_STATE;
+
+typedef void (*INTERRUPT_HANDLER)(INTERRUPT_STATE *pState);
+
+void HalInitializeInterrupts(void);
+void HalInterruptInstallHandler(ULONG uIntNum, INTERRUPT_HANDLER p);
+void HalInterruptDisable();
+void HalInterruptEnable();
+
+void HalIoDelay();
+
+void HalTimerInt(INTERRUPT_STATE *p);
+void HalKeyboardInt(INTERRUPT_STATE *p);
+
+extern UINT64 g_ullTimeStampCounter;
+ULONG HalReadTimestampCounter(void);
+
+#endif // HAL_H
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: kernel.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#ifndef _KERNEL_H_
+#define _KERNEL_H_
+
+#include "types.h"
+#include "constants.h"
+#include "macros.h"
+
+//
+// Shared data structures
+//
+typedef struct _BIOS_HARDWARE_BLOCK
+{
+ BYTE bDisplayType;
+ BYTE bFontSize;
+ WORD wEquipmentBitvector;
+ WORD wMemorySize;
+ WORD wSystemClock;
+}
+BIOS_HARDWARE_BLOCK;
+
+// Write a byte to an I/O port.
+void
+out(WORD port, BYTE value);
+
+BYTE
+in(WORD port);
+
+void
+iodelay(void);
+
+#endif /* _KERNEL_H_ */
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: macros.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Copyright (C) 2003
+//
+// Created: sgasch 10 Oct 2003
+//
+//+----------------------------------------------------------------------------
+
+#ifndef _MACROS_H_
+#define _MACROS_H_
+
+//
+// Macros
+//
+#define ARRAY_LENGTH(a) (sizeof((a)) / sizeof((a)[0]))
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+#if 1
+void _assert(CHAR *, CHAR *, ULONG);
+void VideoPrint(CHAR *, ...);
+#define ASSERT(x) if (x) \
+ { ; } \
+ else \
+ { _assert(__FUNCTION__ , \
+ __FILE__ , \
+ __LINE__); }
+#define TRACE(f, ...) VideoPrint("%s:%u> " ##f , __FUNCTION__ , \
+ __LINE__ , ##__VA_ARGS__)
+#else
+#define ASSERT(x) ;
+#define TRACE(f, ...) ;
+#endif // DEBUG
+
+#define CURRENT_STAMP(a) asm volatile("rdtsc" : "=a"(((unsigned int *)(a))[0]), "=d"(((unsigned int *)a)[1]))
+
+#endif /* _MACROS_H_ */
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: rtl.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Copyright (C) 2003 Scott Gasch
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#ifndef _RTL_H_
+#define _RTL_H_
+
+void
+RtlSetMemory(void *pStart,
+ BYTE bFill,
+ ULONG uLength);
+
+CHAR *
+RtlIntToAscii(INT i,
+ CHAR *buf,
+ ULONG uBufLen,
+ ULONG uBase);
+
+#endif /* _RTL_H_ */
+
+
+
+
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: types.h
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 10 Oct 2003
+//
+//+----------------------------------------------------------------------------
+
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+//
+// Datatype wrappers
+//
+#define MIN_CHAR (0x80)
+#define MAX_CHAR (0x7f)
+typedef char CHAR;
+
+#define MIN_BYTE (0x00)
+#define MAX_BYTE (0xff)
+typedef unsigned char BYTE;
+
+#define MIN_UCHAR (0x00)
+#define MAX_UCHAR (0xff)
+typedef unsigned char UCHAR;
+
+#define MIN_SHORT (0x8000)
+#define MAX_SHORT (0x7fff)
+typedef signed short SHORT;
+
+#define MIN_USHORT (0x0000)
+#define MAX_USHORT (0xffff)
+typedef unsigned short USHORT;
+
+#define MIN_WORD (0x0000)
+#define MAX_WORD (0xffff)
+typedef unsigned short WORD;
+
+#define MIN_INT (0x80000000)
+#define MAX_INT (0x7fffffff)
+typedef signed int INT;
+
+#define MIN_UINT (0x00000000)
+#define MAX_UINT (0xffffffff)
+typedef unsigned int UINT;
+
+#define MIN_LONG (0x80000000)
+#define MAX_LONG (0x7fffffff)
+typedef signed int LONG;
+
+#define MIN_ULONG (0x00000000)
+#define MAX_ULONG (0xffffffff)
+typedef unsigned long ULONG;
+
+#define MIN_INT64 (0x8000000000000000)
+#define MAX_INT64 (0x7fffffffffffffff)
+typedef signed long long INT64;
+
+#define MIN_UINT64 (0x0000000000000000)
+#define MAX_UINT64 (0xffffffffffffffff)
+typedef unsigned long long UINT64;
+
+#define MIN_BITV MIN_UINT
+#define MAX_BITV MAX_UINT
+typedef unsigned int BITV;
+
+#define MIN_BOOL MIN_UCHAR
+#define MAX_BOOL MAX_UCHAR
+typedef unsigned char BOOL;
+
+typedef unsigned int STATUS;
+#define STATUS_SUCCESS (0)
+
+#define SIZE_T ULONG
+
+#endif /* _TYPES_H_ */
--- /dev/null
+CC= gcc
+CFLAGS= -Wall -imacros ../defines -I../inc
+OBJS= main.o entry.o
+RM= /bin/rm
+NASM= nasm
+NASMFLAGS= -f elf
+
+.SUFFIXES: .c .asm .o
+
+all: $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+.asm.o:
+ $(NASM) $(NASMFLAGS) -o $*.o $<
+
+clean:
+ $(RM) -f $(OBJS) *~ #*# .#*
+
--- /dev/null
+[BITS 32]
+
+EXTERN KernelEntry
+GLOBAL StartOfKernelImage
+GLOBAL IdleLoop
+
+;;;
+;;; I put "entry.o" first in line at the linker so I am sure this function
+;;; gets put first in the kernel image. This is good because:
+;;;
+;;; 1. We know there is valid code at 0x00010000 when we jump here
+;;; 2. We can use the address of this function as the start of image
+;;; 3. We don't have to make sure main (or KernelEntry or whatever)
+;;; is always the first function in main.c
+;;;
+StartOfKernelImage:
+ jmp KernelEntry
+ ret
+
+IdleLoop:
+ sti
+ hlt
+ jmp IdleLoop
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: main.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Created: sgasch 4 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+#include "hal.h"
+#include "rtl.h"
+
+extern char __bss_start;
+extern char end;
+
+void
+ZeroBSS(void)
+{
+ BYTE *pBssStart, *pBssEnd;
+
+ pBssStart = &__bss_start;
+ pBssEnd = &end;
+
+ // Fill .bss section with zero
+ RtlSetMemory((void *)pBssStart, '\0', (pBssEnd - pBssStart));
+}
+
+void
+_assert(CHAR *szFunction, CHAR *szFile, ULONG uLine)
+{
+ HalVideoSetCursorPosition(0, 0);
+ HalVideoPrint("ASSERTION in %s at %s line %u.\n",
+ szFunction, szFile, uLine);
+ while(1)
+ {
+ ;
+ }
+}
+
+//
+// Entry point of the kernel. Not called main because I don't care to
+// listen to gcc's warnings about argc and argv anymore.
+//
+int
+KernelEntry(BIOS_HARDWARE_BLOCK *phw)
+{
+ ZeroBSS();
+
+ HalVideoInitialize(phw);
+ HalInitializeInterrupts();
+
+ HalVideoPrint("Interrupts initialized.\n");
+
+ hang:
+ HalReadTimestampCounter();
+ HalVideoPrint("Timestamp Counter: %u%u\n",
+ ((g_ullTimeStampCounter >> 32) & 0xffffffff),
+ (g_ullTimeStampCounter & 0xffffffff));
+ goto hang;
+
+ return(-1);
+}
+
--- /dev/null
+
+Allocating common symbols
+Common symbol size file
+
+g_IDT 0x800 hal/interrupts.o
+g_InterruptHandlerTable
+ 0x400 hal/interrupts.o
+
+Memory Configuration
+
+Name Origin Length Attributes
+*default* 0x00000000 0xffffffff
+
+Linker script and memory map
+
+Address of section .text set to 0x10000
+LOAD init/entry.o
+LOAD init/main.o
+LOAD hal/video.o
+LOAD hal/io.o
+LOAD rtl/string.o
+LOAD rtl/memory.o
+LOAD hal/intsupport.o
+LOAD hal/interrupts.o
+LOAD hal/timer.o
+LOAD hal/keyboard.o
+LOAD hal/timestamp.o
+LOAD hal/counters.o
+ 0x08048074 . = (0x8048000 + SIZEOF_HEADERS )
+
+.interp
+ *(.interp)
+
+.hash
+ *(.hash)
+
+.dynsym
+ *(.dynsym)
+
+.dynstr
+ *(.dynstr)
+
+.gnu.version
+ *(.gnu.version)
+
+.gnu.version_d
+ *(.gnu.version_d)
+
+.gnu.version_r
+ *(.gnu.version_r)
+
+.rel.init
+ *(.rel.init)
+
+.rela.init
+ *(.rela.init)
+
+.rel.text 0x08048074 0x0
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+
+.rela.text
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+
+.rel.fini
+ *(.rel.fini)
+
+.rela.fini
+ *(.rela.fini)
+
+.rel.rodata
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+
+.rela.rodata
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+
+.rel.data
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+
+.rela.data
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+
+.rel.ctors
+ *(.rel.ctors)
+
+.rela.ctors
+ *(.rela.ctors)
+
+.rel.dtors
+ *(.rel.dtors)
+
+.rela.dtors
+ *(.rela.dtors)
+
+.rel.got
+ *(.rel.got)
+
+.rela.got
+ *(.rela.got)
+
+.rel.bss
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+
+.rela.bss
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+
+.rel.plt
+ *(.rel.plt)
+
+.rela.plt
+ *(.rela.plt)
+
+.init
+ *(.init)
+
+.plt
+ *(.plt)
+
+.text 0x00010000 0x20b0
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ .text 0x00010000 0xa init/entry.o
+ 0x00010000 StartOfKernelImage
+ 0x00010006 IdleLoop
+ *fill* 0x0001000a 0x2 2425393296
+ .text 0x0001000c 0x104 init/main.o
+ 0x0001003c _assert
+ 0x00010078 KernelEntry
+ 0x0001000c ZeroBSS
+ .text 0x00010110 0x814 hal/video.o
+ 0x000105cc HalVideoGetCursorPosition
+ 0x00010110 HalVideoSetHardwareCursor
+ 0x000106b0 HalVideoPrint
+ 0x00010298 HalVideoClearScreen
+ 0x0001051c HalVideoPutNullTerminatedString
+ 0x00010260 HalVideoSetCurrentColorAttribute
+ 0x0001032c HalVideoScroll
+ 0x00010578 HalVideoSetCursorPosition
+ 0x0001044c HalVideoPutChar
+ 0x000105e8 HalVideoInitialize
+ .text 0x00010924 0x58 hal/io.o
+ 0x00010944 in
+ 0x00010924 out
+ 0x00010968 iodelay
+ .text 0x0001097c 0x220 rtl/string.o
+ 0x00010a10 RtlIntToAscii
+ 0x0001097c strncpy
+ 0x000109e0 strlen
+ .text 0x00010b9c 0x34 rtl/memory.o
+ 0x00010b9c RtlSetMemory
+ .text 0x00010bd0 0x10b6 hal/intsupport.o
+ 0x00011c38 HalInterruptGenericHandler
+ 0x00010bd8 HalInterruptInitializePICs
+ 0x00010bd0 HalInterruptLoadIDTR
+ 0x00010c38 HalInterruptHandlerPreamble
+ 0x00010c2f HalIoDelay
+ 0x00010c48 HalInterruptHandlerPreambleAfter
+ 0x00010c38 HalInterruptHandlerPreambleBefore
+ *fill* 0x00011c86 0x2 2425393296
+ .text 0x00011c88 0x2f4 hal/interrupts.o
+ 0x00011cbc HalDisableInterrupts
+ 0x00011e80 HalInitializeInterrupts
+ 0x00011cf8 HalInterruptSendIrqEoi
+ 0x00011cf0 HalDoNothing
+ 0x00011dd8 HalInterruptInitializeGate
+ 0x00011c88 HalEnableInterrupts
+ 0x00011e38 HalInterruptInstallHandler
+ .text 0x00011f7c 0xbc hal/timer.o
+ 0x00011f7c HalTimerInt
+ .text 0x00012038 0x5c hal/keyboard.o
+ 0x00012038 HalKeyboardInt
+ *fill* 0x00012094 0xc 2425393296
+ .text 0x000120a0 0xe hal/timestamp.o
+ 0x000120a0 HalReadTimestampCounter
+ *fill* 0x000120ae 0x2 2425393296
+ *(.gnu.warning)
+
+.fini
+ *(.fini)
+ 0x000120b0 PROVIDE (__etext, .)
+ 0x000120b0 PROVIDE (_etext, .)
+ 0x000120b0 PROVIDE (etext, .)
+
+.rodata 0x000120c0 0x246
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ .rodata 0x000120c0 0x60 init/main.o
+ .rodata 0x00012120 0x156 hal/video.o
+ *fill* 0x00012276 0x2
+ .rodata 0x00012278 0x18 rtl/string.o
+ .rodata 0x00012290 0x68 hal/interrupts.o
+ .rodata 0x000122f8 0xe hal/keyboard.o
+
+.rodata1
+ *(.rodata1)
+
+.eh_frame_hdr
+ *(.eh_frame_hdr)
+ 0x00013306 . = ( ALIGN (0x1000) + (. & 0xfff))
+ 0x00012308 . = ALIGN (0x4)
+ 0x00012306 PROVIDE (__preinit_array_start, .)
+
+.preinit_array
+ *(.preinit_array)
+ 0x00012306 PROVIDE (__preinit_array_end, .)
+ 0x00012306 PROVIDE (__init_array_start, .)
+
+.init_array
+ *(.init_array)
+ 0x00012306 PROVIDE (__init_array_end, .)
+ 0x00012306 PROVIDE (__fini_array_start, .)
+
+.fini_array
+ *(.fini_array)
+ 0x00012306 PROVIDE (__fini_array_end, .)
+
+.data 0x00013308 0xc4
+ *(.data .data.* .gnu.linkonce.d.*)
+ .data 0x00013308 0xa8 hal/video.o
+ 0x0001330e g_bSoftCursor
+ 0x00013308 g_pVideoMemory
+ 0x0001330c g_bScreenResolution
+ 0x00013310 g_bColorAttribute
+ .data 0x000133b0 0x4 hal/interrupts.o
+ 0x000133b0 g_uInterruptsEnabled
+ .data 0x000133b4 0x10 hal/timer.o
+ .data 0x000133c4 0x8 hal/counters.o
+ 0x000133c4 g_ullTimeStampCounter
+
+.data1
+ *(.data1)
+
+.eh_frame
+ *(.eh_frame)
+
+.gcc_except_table
+ *(.gcc_except_table)
+
+.dynamic
+ *(.dynamic)
+
+.ctors
+ *crtbegin.o(.ctors)
+ *(EXCLUDE_FILE(*crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+
+.dtors
+ *crtbegin.o(.dtors)
+ *(EXCLUDE_FILE(*crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+.jcr
+ *(.jcr)
+
+.got
+ *(.got.plt)
+ *(.got)
+ 0x000133cc _edata = .
+ 0x000133cc PROVIDE (edata, .)
+ 0x000133cc __bss_start = .
+
+.bss 0x000133e0 0xc20
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ .bss 0x000133e0 0x4 hal/timer.o
+ *(COMMON)
+ *fill* 0x000133e4 0x1c
+ COMMON 0x00013400 0xc00 hal/interrupts.o
+ 0x0 (size before relaxing)
+ 0x00013400 g_IDT
+ 0x00013c00 g_InterruptHandlerTable
+ 0x00014000 . = ALIGN (0x4)
+ 0x00014000 . = ALIGN (0x4)
+ 0x00014000 _end = .
+ 0x00014000 PROVIDE (end, .)
+
+.stab
+ *(.stab)
+
+.stabstr
+ *(.stabstr)
+
+.stab.excl
+ *(.stab.excl)
+
+.stab.exclstr
+ *(.stab.exclstr)
+
+.stab.index
+ *(.stab.index)
+
+.stab.indexstr
+ *(.stab.indexstr)
+
+.comment 0x00000000 0x1c5
+ *(.comment)
+ .comment 0x00000000 0x1f init/entry.o
+ .comment 0x0000001f 0x28 init/main.o
+ .comment 0x00000047 0x28 hal/video.o
+ .comment 0x0000006f 0x28 hal/io.o
+ .comment 0x00000097 0x28 rtl/string.o
+ .comment 0x000000bf 0x28 rtl/memory.o
+ .comment 0x000000e7 0x1f hal/intsupport.o
+ .comment 0x00000106 0x28 hal/interrupts.o
+ .comment 0x0000012e 0x28 hal/timer.o
+ .comment 0x00000156 0x28 hal/keyboard.o
+ .comment 0x0000017e 0x1f hal/timestamp.o
+ .comment 0x0000019d 0x28 hal/counters.o
+
+.debug
+ *(.debug)
+
+.line
+ *(.line)
+
+.debug_srcinfo
+ *(.debug_srcinfo)
+
+.debug_sfnames
+ *(.debug_sfnames)
+
+.debug_aranges
+ *(.debug_aranges)
+
+.debug_pubnames
+ *(.debug_pubnames)
+
+.debug_info
+ *(.debug_info .gnu.linkonce.wi.*)
+
+.debug_abbrev
+ *(.debug_abbrev)
+
+.debug_line
+ *(.debug_line)
+
+.debug_frame
+ *(.debug_frame)
+
+.debug_str
+ *(.debug_str)
+
+.debug_loc
+ *(.debug_loc)
+
+.debug_macinfo
+ *(.debug_macinfo)
+
+.debug_weaknames
+ *(.debug_weaknames)
+
+.debug_funcnames
+ *(.debug_funcnames)
+
+.debug_typenames
+ *(.debug_typenames)
+
+.debug_varnames
+ *(.debug_varnames)
+OUTPUT(kernel.tmp elf32-i386)
+
+.note 0x00000000 0xb4
+ .note 0x00000000 0x14 init/main.o
+ .note 0x00000014 0x14 hal/video.o
+ .note 0x00000028 0x14 hal/io.o
+ .note 0x0000003c 0x14 rtl/string.o
+ .note 0x00000050 0x14 rtl/memory.o
+ .note 0x00000064 0x14 hal/interrupts.o
+ .note 0x00000078 0x14 hal/timer.o
+ .note 0x0000008c 0x14 hal/keyboard.o
+ .note 0x000000a0 0x14 hal/counters.o
--- /dev/null
+CC= gcc
+CFLAGS= -Wall -imacros ../defines -I../inc
+OBJS= string.o memory.o
+RM= /bin/rm
+NASM= nasm
+NASMFLAGS=
+
+.SUFFIXES: .c .o .asm
+
+all: $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+.asm.o:
+ $(NASM) $(NASMFLAGS) -o $*.o $<
+
+clean:
+ $(RM) -f $(OBJS) *~ #*# .#*
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: memory.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Copyright (C) Scott Gasch
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+
+void
+RtlSetMemory(void *pStart,
+ BYTE bFill,
+ ULONG uLength)
+{
+ BYTE *p = (BYTE *)pStart;
+
+ while(uLength > 0)
+ {
+ *p++ = bFill;
+ uLength--;
+ }
+}
--- /dev/null
+//+----------------------------------------------------------------------------
+//
+// File: string.c
+//
+// Module:
+//
+// Synopsis:
+//
+// Copyright (C) 2003 Scott Gasch
+//
+// Created: sgasch 5 Jul 2003
+//
+//+----------------------------------------------------------------------------
+
+#include "kernel.h"
+
+CHAR *
+strncpy(CHAR *pDest, CHAR *pSrc, SIZE_T u)
+{
+ char *p = pDest;
+ ULONG v = 0;
+
+ while ((v < u) && (*pSrc))
+ {
+ *pDest = *pSrc;
+ pDest++; pSrc++; v++;
+ }
+
+ //
+ // If we ran out of space, null terminate the dest buffer
+ //
+ if ((*pSrc) && (u > 0))
+ {
+ *(pDest - 1) = 0;
+ }
+
+ return(p);
+}
+
+SIZE_T
+strlen(CHAR *p)
+{
+ ULONG i = 0;
+ while(*p)
+ {
+ i++;
+ p++;
+ }
+ return(i);
+}
+
+CHAR *
+RtlIntToAscii(INT i,
+ CHAR *buf,
+ ULONG uBufLen,
+ ULONG uBase)
+{
+ CHAR *p = (buf + uBufLen);
+ ULONG uSpaceLeft = uBufLen;
+ ULONG uMagnitude;
+ BOOL fNeg = FALSE;
+
+ //
+ // null terminate the workspace buffer
+ //
+ if (uSpaceLeft == 0)
+ {
+ return(NULL);
+ }
+ *p = '\0';
+ p--;
+ uSpaceLeft--;
+
+ //
+ // Get the int's sign
+ //
+ if (i < 0)
+ {
+ fNeg = TRUE;
+ uMagnitude = -i;
+ }
+ else
+ {
+ uMagnitude = i;
+ }
+
+ //
+ // Based on base, do the conversion. Build the string backwards from
+ // less significant digits. Stop if we finish or if we run out of
+ // uSpaceLeft.
+ //
+ switch(uBase)
+ {
+ case 10:
+ do
+ {
+ *p = (uMagnitude % 10) + '0';
+ p--;
+ uSpaceLeft--;
+ uMagnitude /= 10;
+ }
+ while((uSpaceLeft > 0) && (uMagnitude != 0));
+ break;
+ case 16:
+ do
+ {
+ *p = "0123456789ABCDEF"[uMagnitude & 15];
+ p--;
+ uSpaceLeft--;
+ uMagnitude >>= 4;
+ }
+ while((uSpaceLeft > 0) && (uMagnitude != 0));
+ break;
+ case 8:
+ do
+ {
+ *p = (uMagnitude & 7) + '0';
+ p--;
+ uSpaceLeft--;
+ uMagnitude >>= 3;
+ }
+ while((uSpaceLeft > 0) && (uMagnitude != 0));
+ break;
+ }
+
+ if (TRUE == fNeg)
+ {
+ if (uSpaceLeft > 0)
+ {
+ *p = '-';
+ }
+ }
+ else
+ {
+ p++;
+ }
+ return(p);
+}