Added Programmable Interval Timer(PIT) driver

This commit is contained in:
ice-bit 2019-07-06 01:09:10 +02:00
parent ba9feaba18
commit bb1df4da6b
8 changed files with 94 additions and 8 deletions

View File

@ -1,4 +1,4 @@
OBJS = tty.o gdt.o idt.o isr.o
OBJS = tty.o gdt.o idt.o isr.o timer.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c

View File

@ -7,6 +7,8 @@
***************************************/
#ifndef _GDT_H_
#define _GDT_H_
#include <stdint.h>
/*
* First a bit of theory:
* GDT(Global Descriptor Table) is a complex data structure used in x86 systems
@ -29,8 +31,6 @@
* a new GDT ourself.
*/
#include <stdint.h>
/* Those values were taken from Intel's developer manual */
// GDT fields

View File

@ -7,6 +7,8 @@
***************************************/
#ifndef _IDT_H_
#define _IDT_H_
#include <stdint.h>
/*
* First a bit of theory:
* Sometimes you want to interrupt the processor from what it is currently doing
@ -18,8 +20,6 @@
* of interrupts handlers(ISRs) to the CPU.
*/
#include <stdint.h>
// Reserved bits in IDT entries
#define IDT_FLAG_RESERVED 0x0E

View File

@ -7,6 +7,9 @@
***************************************/
#ifndef _ISR_H_
#define _ISR_H_
#include <stdint.h>
/*
* When we implement ISRs we have to keep in mind that the first 32 interrupts(and so the
* first 32 ISRs) are reserved by the CPU to signal the kernel about critical actions,
@ -36,8 +39,6 @@
* 18 - Machine check exception
* 19-31 - Reserved */
#include <stdint.h>
#define IRQ0 32
#define IRQ1 33
#define IRQ2 34

40
kernel/drivers/timer.c Normal file
View File

@ -0,0 +1,40 @@
#include "timer.h"
#include "isr.h"
#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
// Start tick at zero
uint32_t tick = 0;
static void timer_callback(registers_t regs) {
tick++;
uint8_t buf[8];
itoa(tick, buf, 10);
kprint((uint8_t*)"Time: ");
kprint((uint8_t*)buf);
kprint((uint8_t*)"\n");
// Cast to void unused parameter
UNUSED_PAR(regs);
}
void init_timer(uint32_t frequency) {
// Register a new ISR for IRQ0
register_interrupt_handler(IRQ0, &timer_callback);
/* As mentioned before, we'll send to PIT a value to divide for
* his system clock(1.1931 MHz). We have to keep in mind that
* this value must fit into a 16 bits variable */
uint32_t divisor = 1193180 / frequency;
// Send command to the right port
outb(0x43, 0x36);
// The two divisor has to be sent byte-wise, to do this we split them in two parts
uint8_t low = (uint8_t)(divisor & 0xFF);
uint8_t high = (uint8_t)((divisor >> 8) & 0xFF);
// Send the frequency divisor
outb(0x40, low);
outb(0x40, high);
}

41
kernel/drivers/timer.h Normal file
View File

@ -0,0 +1,41 @@
/**************************************
* iceOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _TIMER_H_
#define _TIMER_H_
#include <stdint.h>
/*
* The PIT(Programmable Interval Timer) is a chip that consist of an oscillator
* It's connected to IRQ0 and it can be configure at a user-defined rate
* between 10.Hz to 1.1931 MHz. The PIT is the primary method used to implement
* a system clock and for implement multitasking.
* The PIT's internal clock(~1.1931 MHz) is fed through a frequency divider that
* modulate the final signal. This chip has 3 channel, each with his own
* frequency divider:
* Channel 0: The most useful, it's output is connected to IRQ0
* Channel 1: It were used to control refresh rates on DRAM(RAMs with capacitors)
* Channel 2: Controls the PC speakers.
*
* In our case, we will use only channel 0.
* So we have to set up PIT at a frequency 'f', so it interrupts us at regular
* intervals. We'll set the frequency to 100Hz(once every 10 ms); to do this
* we'll send the PIT a divisor that will be divided for it's input frequency.
* E.g. -> divisor = 1193180 Hz(1.1931MHz) / 100 Hz
*
* Apart of that, the PIT has 4 registers: 0x40-0x42(data ports) and 0x43(command port)
*/
void init_timer(uint32_t frequency);
/* Since regs parameter(from timer_callback) will be unused
* GCC(with -Werror flag) will dump an error, so we avoid this
* using the following macro
*/
#define UNUSED_PAR(x) (void)(x)
#endif

View File

@ -11,6 +11,8 @@
#include <stdint.h>
// TODO: write something about Frame Buffer
// VGA colors
enum TTY_COLORS {
BLACK, // 0

View File

@ -1,6 +1,7 @@
#include "drivers/tty.h"
#include "drivers/gdt.h"
#include "drivers/idt.h"
#include "drivers/timer.h"
#include "libc/stdio.h"
void kernel_main() {
@ -9,7 +10,8 @@ void kernel_main() {
clear_prompt();
init_prompt(); // Initialize frame buffer
puts("Hello World!");
//puts("Hello World!");
init_timer(1);
/*
// Testing some interrupts