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
|
CC = i686-elf-gcc # cross-compiler
|
||||||
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
|
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
***************************************/
|
***************************************/
|
||||||
#ifndef _GDT_H_
|
#ifndef _GDT_H_
|
||||||
#define _GDT_H_
|
#define _GDT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
/*
|
/*
|
||||||
* First a bit of theory:
|
* First a bit of theory:
|
||||||
* GDT(Global Descriptor Table) is a complex data structure used in x86 systems
|
* GDT(Global Descriptor Table) is a complex data structure used in x86 systems
|
||||||
@ -29,8 +31,6 @@
|
|||||||
* a new GDT ourself.
|
* a new GDT ourself.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/* Those values were taken from Intel's developer manual */
|
/* Those values were taken from Intel's developer manual */
|
||||||
|
|
||||||
// GDT fields
|
// GDT fields
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
***************************************/
|
***************************************/
|
||||||
#ifndef _IDT_H_
|
#ifndef _IDT_H_
|
||||||
#define _IDT_H_
|
#define _IDT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
/*
|
/*
|
||||||
* First a bit of theory:
|
* First a bit of theory:
|
||||||
* Sometimes you want to interrupt the processor from what it is currently doing
|
* Sometimes you want to interrupt the processor from what it is currently doing
|
||||||
@ -18,8 +20,6 @@
|
|||||||
* of interrupts handlers(ISRs) to the CPU.
|
* of interrupts handlers(ISRs) to the CPU.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
// Reserved bits in IDT entries
|
// Reserved bits in IDT entries
|
||||||
#define IDT_FLAG_RESERVED 0x0E
|
#define IDT_FLAG_RESERVED 0x0E
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
***************************************/
|
***************************************/
|
||||||
#ifndef _ISR_H_
|
#ifndef _ISR_H_
|
||||||
#define _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
|
* 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,
|
* first 32 ISRs) are reserved by the CPU to signal the kernel about critical actions,
|
||||||
@ -36,8 +39,6 @@
|
|||||||
* 18 - Machine check exception
|
* 18 - Machine check exception
|
||||||
* 19-31 - Reserved */
|
* 19-31 - Reserved */
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define IRQ0 32
|
#define IRQ0 32
|
||||||
#define IRQ1 33
|
#define IRQ1 33
|
||||||
#define IRQ2 34
|
#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>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// TODO: write something about Frame Buffer
|
||||||
|
|
||||||
// VGA colors
|
// VGA colors
|
||||||
enum TTY_COLORS {
|
enum TTY_COLORS {
|
||||||
BLACK, // 0
|
BLACK, // 0
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "drivers/tty.h"
|
#include "drivers/tty.h"
|
||||||
#include "drivers/gdt.h"
|
#include "drivers/gdt.h"
|
||||||
#include "drivers/idt.h"
|
#include "drivers/idt.h"
|
||||||
|
#include "drivers/timer.h"
|
||||||
#include "libc/stdio.h"
|
#include "libc/stdio.h"
|
||||||
|
|
||||||
void kernel_main() {
|
void kernel_main() {
|
||||||
@ -9,7 +10,8 @@ void kernel_main() {
|
|||||||
|
|
||||||
clear_prompt();
|
clear_prompt();
|
||||||
init_prompt(); // Initialize frame buffer
|
init_prompt(); // Initialize frame buffer
|
||||||
puts("Hello World!");
|
//puts("Hello World!");
|
||||||
|
init_timer(1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Testing some interrupts
|
// Testing some interrupts
|
||||||
|
Loading…
Reference in New Issue
Block a user