CFLAGS = -std=gnu99 -g -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
-KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/kernel.o
+KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/arch/x86/time/i8254.o kernel/kernel.o
BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN
default: kernel/kernel.elf bootloader
--- /dev/null
+#ifndef X86_I8254_H
+#define X86_I8254_H
+
+#include <stdint.h>
+#include <io.h>
+#include <irq/i8259a.h>
+
+/* for setting reload value and reading current count */
+#define PORT_CHANNEL_0_DATA 0x40
+#define PORT_CHANNEL_1_DATA 0x41
+#define PORT_CHANNEL_2_DATA 0x42
+
+/* for configuring the channels */
+#define PORT_MODE_CMD_REG 0x43
+
+/* operating modes */
+#define INT_ON_TERM_CNT 0x0
+#define HW_RETRIGGER_ONESHOT 0x1
+#define RATE_GENERATOR 0x2
+#define SQUARE_WAVE_GENERATOR 0x3
+#define SW_TRIGGERED_STROBE 0x4
+#define HW_TRIGGERED_STROBE 0x5
+
+/* access modes */
+#define ACMODE_COUNTER_LATCH_CMD 0x0
+#define ACMODE_LSB_ONLY 0x1
+#define ACMODE_MSB_ONLY 0x2
+#define ACMODE_LSB_MSB 0x3
+
+union mode_command {
+ struct {
+ unsigned bcd: 1, /* if set, uses BCD for reload value */
+ opmode: 3, /* operating mode */
+ acmode: 2, /* access mode */
+ channel: 2; /* channel to configure */
+ } fields;
+ uint8_t command;
+};
+
+extern unsigned int ticks;
+extern uint16_t reload;
+
+extern void i8254_configure_channel(char channel, char opmode, uint16_t new_reload);
+extern void i8254_irq_enable();
+
+#endif
extern void screen_clear(void);
extern void kprint(const char *string, uint8_t color);
+extern void kprints(const char *string, uint8_t color);
extern void kprintb(const uint8_t byte);
extern void kprintw(const uint16_t word);
extern void kprintd(const uint32_t dword);
+extern void kprintc(const char character, uint8_t color);
extern int kprintdec(uint32_t num);
#endif
#include <irq/i8259a.h>
#include <io.h>
#include <stdint.h>
+#include <time/i8254.h>
+
+unsigned int ticks = 0;
typedef uint32_t uword_t;
goto halt;
}
+
+__attribute__((interrupt))
+void timer_tick(struct interrupt_frame *frame)
+{
+ pic_send_eoi(0);
+ ticks++;
+}
--- /dev/null
+#include <time/i8254.h>
+
+uint16_t reload;
+
+void i8254_configure_channel(char channel, char opmode, uint16_t new_reload)
+{
+ union mode_command command;
+
+ command.fields.bcd = 0;
+ command.fields.channel = channel;
+ command.fields.acmode = ACMODE_LSB_MSB;
+ command.fields.opmode = opmode;
+
+ outb(PORT_MODE_CMD_REG, command.command);
+
+ switch (channel) {
+ case 0:
+ outb(PORT_CHANNEL_0_DATA, new_reload & 0xff);
+ outb(PORT_CHANNEL_0_DATA, new_reload >> 8);
+ break;
+ case 1:
+ outb(PORT_CHANNEL_1_DATA, new_reload & 0xff);
+ outb(PORT_CHANNEL_1_DATA, new_reload >> 8);
+ break;
+ case 2:
+ outb(PORT_CHANNEL_2_DATA, new_reload & 0xff);
+ outb(PORT_CHANNEL_2_DATA, new_reload >> 8);
+ break;
+ }
+
+ reload = new_reload;
+}
+
+void i8254_irq_enable()
+{
+ pic_unmask(0);
+}
#include <io.h>
#include <tty.h>
#include <stdint.h>
+#include <time/i8254.h>
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
}
void kprint(const char *string, uint8_t color)
+{
+ kprintc('[', 0);
+ kprintdec(ticks / (1193182 / 65536));
+ kprints("] ", 0);
+ kprints(string, color);
+}
+
+void kprints(const char *string, uint8_t color)
{
char next_char;
uint8_t vga_misc_output;
{
char buffer[11];
int digits = 10;
+
/* TODO: make an actual memset function to use instead of this */
for (int i=0; i<11; i++) {
buffer[i] = 0;
}
+ /* handle edge case */
+ if (num==0) {
+ *buffer = '0';
+ goto print;
+ }
+
/* put the numbers in the buffer */
for (int i=9; i>0 && num>0; i--) {
uint8_t currdigit = num%10;
}
}
- kprint(buffer, 0);
+print:
+ kprints(buffer, 0);
return digits;
}
#include <io.h>
#include <irq/idt.h>
#include <irq/i8259a.h>
+#include <time/i8254.h>
#include <stdint.h>
extern void double_fault(struct abort_frame *frame);
extern void keyb_handler(struct interrupt_frame *frame);
+extern void timer_tick(struct interrupt_frame *frame);
struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
struct idtr idtr __attribute__((aligned(0x10)));
void kmain(void)
{
+ ticks = 0;
screen_clear();
kprint("Welcome to Nameless OS!\nRunning revision: ", 0);
kprint(GIT_COMMIT, 0);
kprint("\n", 0);
kprint("Preparing IDT...\n", 0);
idt_set_descriptor(idt, 0x8, 0x8, (uint32_t) double_fault, IDT_TRAP_GATE, 0x0);
+ idt_set_descriptor(idt, 0x20, 0x8, (uint32_t) timer_tick, IDT_INTERRUPT_GATE, 0x0);
idt_set_descriptor(idt, 0x21, 0x8, (uint32_t) keyb_handler, IDT_INTERRUPT_GATE, 0x0);
kprint("IDT prepared, loading...\n", 0);
populate_idtr(&idtr, idt);
pic_mask_all();
pic_unmask(1);
asm volatile ("sti");
+ kprint("Setting up timer...\n", 0);
+ i8254_configure_channel(0, SQUARE_WAVE_GENERATOR, 0);
+ i8254_irq_enable();
kprint("All done\n", 0);
- kprintdec(12345);
- kprintc('\n');
- kprintdec(6789);
- kprintc('\n');
while(1);
}