Added Programmable Interval Timer(PIT) driver
This commit is contained in:
parent
ba9feaba18
commit
bb1df4da6b
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
40
kernel/drivers/timer.c
Normal 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
41
kernel/drivers/timer.h
Normal 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
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// TODO: write something about Frame Buffer
|
||||
|
||||
// VGA colors
|
||||
enum TTY_COLORS {
|
||||
BLACK, // 0
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user