Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion includes/interrupt/idt.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ struct idtr {
void idt_set_gate(uint8_t vector, uint32_t handler, uint16_t selector, uint8_t type_attr);

void idt_init_descriptor(void);
static void idt_load(void);
void idt_init(void);

void idt_clear(void);
Expand Down
File renamed without changes.
40 changes: 40 additions & 0 deletions includes/interrupt/pit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef PIT_H
#define PIT_H

#define PIT_CHANNEL0 0x40
#define PIT_CHANNEL1 0x41
#define PIT_CHANNEL2 0x42
#define PIT_COMMAND 0x43
#define PIT_BASE_FREQ 1193182

#include <stdint.h>

/* Channels */
#define PIT_CHANNEL_0 0
#define PIT_CHANNEL_1 1
#define PIT_CHANNEL_2 2

/* Access modes */
#define PIT_ACCESS_LATCH 0x00
#define PIT_ACCESS_LOBYTE 0x10
#define PIT_ACCESS_HIBYTE 0x20
#define PIT_ACCESS_LOHI 0x30

/* Operating modes */
#define PIT_MODE_0 0x00
#define PIT_MODE_1 0x02
#define PIT_MODE_2 0x04
#define PIT_MODE_3 0x06
#define PIT_MODE_4 0x08
#define PIT_MODE_5 0x0A

/* Binary mode */
#define PIT_BINARY 0x00

void pit_init(uint32_t frequency);
void pit_set_frequency(uint32_t frequency);
uint16_t pit_calculate_divisor(uint32_t frequency);
uint16_t get_divisor();
uint32_t get_frequency();

#endif
20 changes: 20 additions & 0 deletions includes/timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef TIMER_H
#define TIMER_H

#include <stdint.h>

void timer_init(uint32_t frequency);

void timer_irq_handler(void);

uint32_t timer_get_ticks(void);

uint32_t timer_get_seconds(void);

uint32_t timer_get_frequency(void);

void timer_sleep_m(uint32_t milliseconds);
void timer_sleep_s(uint32_t seconds);
void timer_sleep(float seconds);

#endif
2 changes: 1 addition & 1 deletion src/driver/vga.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ void vga_print(const char *str) {
return;
}

for (uint64_t i = 0; str[i] != '\0'; i++) {
for (uint32_t i = 0; str[i] != '\0'; i++) {
if (str[i] == '\n') {
uint8_t y = vga_get_cursor_y() + 1;
vga_set_cursor(0, y);
Expand Down
9 changes: 0 additions & 9 deletions src/interrupt/irq.c

This file was deleted.

77 changes: 38 additions & 39 deletions src/interrupt/irq.asm → src/interrupt/irq/irq.asm
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
; ============================================================
; IRQ handlers 0-15
;
; PIC IRQs:
; IRQ 0 -> IDT vector 32
; IRQ 1 -> IDT vector 33
; ...
; IRQ 15 -> IDT vector 47
;
; The IDT uses vectors 32-47, but we pass IRQ numbers
; 0-15 to the C IRQ handler.
; ============================================================

[BITS 32]


; ============================================================
; Export IRQ handlers and IRQ table
; ============================================================

global irq0
global irq1
global irq2
Expand All @@ -37,39 +19,41 @@ global irq15

global irq_table


extern irq_handler


; ============================================================
; IRQ macro
;
; IRQs do NOT automatically push an error code.
; Hardware IRQs do NOT automatically push an error code.
;
; We push:
; We push only the IRQ number ourselves.
;
; 1. dummy error code
; 2. IRQ number
; Stack when entering irq_common_stub:
;
; This gives us a predictable stack layout.
; [ESP] = IRQ number
; [ESP + 4] = EIP
; [ESP + 8] = CS
; [ESP + 12] = EFLAGS
; ============================================================

%macro IRQ 1

irq%1:

; Interrupt gates already clear IF automatically.
; This CLI is therefore optional.
cli

push dword 0 ; dummy error code
push dword %1 ; IRQ number: 0-15
; Push IRQ number
push dword %1

jmp irq_common_stub

%endmacro


; ============================================================
; IRQ entry points
; IRQ handlers
; ============================================================

IRQ 0
Expand Down Expand Up @@ -121,29 +105,44 @@ irq_table:


; ============================================================
; Common IRQ stub
; Common IRQ handler
; ============================================================

section .text

irq_common_stub:

; Save general-purpose registers
; Save all general-purpose registers
pusha

; Pass pointer to interrupt frame
push esp
; After PUSHA:
;
; [ESP + 0] = EDI
; [ESP + 4] = ESI
; [ESP + 8] = EBP
; [ESP + 12] = original ESP
; [ESP + 16] = EBX
; [ESP + 20] = EDX
; [ESP + 24] = ECX
; [ESP + 28] = EAX
; [ESP + 32] = IRQ number
; [ESP + 36] = EIP
; [ESP + 40] = CS
; [ESP + 44] = EFLAGS

; Pass IRQ number to C
push dword [esp + 32]

call irq_handler

; Remove argument passed to C
add esp, 4

; Restore general-purpose registers
; Restore registers
popa

; Remove:
;
; 4 bytes = IRQ number
; 4 bytes = dummy error code
;
add esp, 8
; Remove IRQ number
add esp, 4

; Return from interrupt
iretd
22 changes: 22 additions & 0 deletions src/interrupt/irq/irq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "irq.h"
#include "pic.h"
#include "timer.h"
#include "vga.h"
#include "vga_lib.h"

void irq_handler(uint32_t vector) {

switch (vector) {
case 0:
timer_irq_handler();
pic_send_eoi((uint8_t)vector);
break;

default:
vga_print("IRQ: ");
vga_print_hex(vector);
vga_print("\n");

pic_send_eoi((uint8_t)vector);
}
}
File renamed without changes.
File renamed without changes.
39 changes: 39 additions & 0 deletions src/interrupt/pit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "pit.h"
#include "utils.h"
#include <stdint.h>

uint16_t div;
uint32_t freq;

void pit_init(uint32_t frequency) { pit_set_frequency(frequency); }

void pit_set_frequency(uint32_t frequency) {
uint16_t divisor = pit_calculate_divisor(frequency);

div = divisor;
freq = frequency;

outb(PIT_COMMAND, 0x34); // ch 0, mode 2, binary

outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF)); // Low byte
outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF)); // High byte
}

uint16_t pit_calculate_divisor(uint32_t frequency) {
if (frequency == 0)
return 0;

uint32_t divisor = PIT_BASE_FREQ / frequency;

if (divisor < 1)
divisor = 1;

if (divisor > 65535) // overflow check
divisor = 65535;

return (uint16_t)divisor;
}

uint16_t get_divisor() { return div; }

uint32_t get_frequency() { return freq; }
25 changes: 20 additions & 5 deletions src/kernel/kernel.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
#include "kernel.h"

#include "idt.h"
#include "panic.h"

#include "pic.h"
#include "utils.h"
#include "pit.h"
#include "timer.h"

#include "vga.h"
#include "vga_lib.h"

#include "panic.h"

#include "utils.h"

void kernel_main() {

vga_init();
Expand All @@ -20,12 +27,20 @@ void kernel_main() {
idt_init();
vga_print_at_end_c("... Ok\n", GREEN);

asm volatile("int $0x22");
vga_log_info("[", "init", "] pit and timer");
pic_clear_mask(0);
timer_init(1000); // 1000 Hz

sti();

panic("testing panics");
for (int i = 0; i < 53; i++) {
vga_print(".");
timer_sleep(0.02);
}
vga_print_at_end_c("... Ok\n", GREEN); // timer

for (;;) {
asm volatile("cli");
asm volatile("hlt");
}

return;
Expand Down
31 changes: 31 additions & 0 deletions src/kernel/timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "timer.h"
#include "pit.h"
#include "vga.h"

static uint32_t ticks = 0;
static uint32_t timer_frequency = 0;

void timer_init(uint32_t frequency) {
timer_frequency = frequency;
pit_init(frequency);
}

void timer_irq_handler(void) { ticks++; }

uint32_t timer_get_ticks(void) { return ticks; }

uint32_t timer_get_seconds(void) { return ticks / timer_frequency; }

uint32_t timer_get_frequency(void) { return timer_frequency; }

void timer_sleep_m(uint32_t milliseconds) {
uint32_t start = timer_get_ticks();
uint32_t wait_ticks = ((uint32_t)milliseconds * timer_frequency) / 1000;

while (timer_get_ticks() - start < wait_ticks) {
}
}

void timer_sleep_s(uint32_t seconds) { timer_sleep_m(seconds * 1000); }

void timer_sleep(float seconds) { timer_sleep_m((uint32_t)(seconds * 1000)); }
Loading