Browse Source

APIC Timer (@wrong freq)

master
Mathieu Sérandour 1 year ago
parent
commit
a8b8e1cbbc
  1. 2
      Makefile
  2. 9
      disk_root/boot/limine.cfg
  3. 14
      kernel/acpi/acpi.c
  4. 23
      kernel/acpi/acpitables.h
  5. 5
      kernel/cpuid.s
  6. 9
      kernel/entry.c
  7. 143
      kernel/int/apic.c
  8. 65
      kernel/int/apic.h
  9. 7
      kernel/int/isr.c
  10. 2
      kernel/klib/sprintf.c
  11. 50
      kernel/regs.s
  12. 22
      kernel/video/terminal.c
  13. 27
      kernel/video/video.c

2
Makefile

@ -9,7 +9,7 @@ USED_LOOPBACK := /dev/loop6
LIMINE_INSTALL := ./limine-bootloader/limine-install-linux-x86_64
QEMU_PATH := "/mnt/d/Program Files/qemu/qemu-system-x86_64.exe"
QEMU_ARGS := -monitor stdio -bios "d:/Program Files/qemu/bios/OVMF.fd" -m 256 -vga std -no-reboot
QEMU_ARGS := -monitor stdio -bios "d:/Program Files/qemu/bios/OVMF.fd" -m 256 -vga std -no-reboot
# -bios "d:/Program Files/qemu/bios/OVMF.fd"
run: all

9
disk_root/boot/limine.cfg

@ -4,18 +4,19 @@ DEFAULT_ENTRY=1
#VERBOSE=yes
TIMEOUT=10
GRAPHICS=no
VERBOSE=no
VERBOSE=yes
THEME_MARGIN=64
RESOLUTION=800x600
MENU_RESOLUTION=800x600
#BACKGROUND_PATH=boot:///boot/bg.bmp
#THEME_BACKGROUND=8f000000
BACKGROUND_STYLE=centered
:Bincows
:Bincows
PROTOCOL=stivale2
#RESOLUTION=960x540
#RESOLUTION=960x540x32
COMMENT=The best Cows-related OS in the market!
#BACKGROUND_PATH=boot:///boot/bg.bmp
KERNEL_PATH=boot:///boot/kernel.elf
BACKGROUND_STYLE=centered

14
kernel/acpi/acpi.c

@ -25,11 +25,13 @@ static bool __ATTR_PURE__ checksum(const void* table, size_t size) {
}
static void parse_madt(const struct MADT* table);
static void parse_hpet(const struct HPET* table);
static void parse_fadt(const struct ACPISDTHeader* table);
#define MADT_SIGNATURE 0x43495041
#define FACP_SIGNATURE 0x50434146
#define HPET_SIGNATURE 0x54455048
void read_acpi_tables(const void* rsdp_location) {
const struct RSDPDescriptor20* rsdpd = rsdp_location;
@ -50,6 +52,7 @@ void read_acpi_tables(const void* rsdp_location) {
bool madt_parsed = false,
hpet_parsed = false,
fadt_parsed = false;
for(size_t i = 0; i < n_entries; i++) {
@ -65,17 +68,26 @@ void read_acpi_tables(const void* rsdp_location) {
parse_fadt(table);
fadt_parsed = true;
break;
case HPET_SIGNATURE:
parse_hpet(table);
hpet_parsed = true;
break;
default:
break;
}
kprintf("%3u: %4s\n", i, table->signature.arg);
}
asm volatile("hlt");
assert(madt_parsed);
//assert(hpet_parsed);
assert(fadt_parsed);
}
static void parse_hpet(const struct HPET* table) {
}
static void parse_madt(const struct MADT* table) {
// checksum is already done

23
kernel/acpi/acpitables.h

@ -139,3 +139,26 @@ struct MADT {
#define APIC_TYPE_LOCAL_NMI 4
#define APIC_TYPE_LAPIC_ADDRESS_OVERRIDE 5
#define APIC_TYPE_LAPICX2 9
struct HPET
{
struct ACPISDTHeader header;
uint8_t hardware_rev_id;
uint8_t comparator_count:5;
uint8_t counter_size:1;
uint8_t reserved:1;
uint8_t legacy_replacement:1;
uint16_t pci_vendor_id;
uint8_t address_space_id; // 0 - system memory, 1 - system I/O
uint8_t register_bit_width;
uint8_t register_bit_offset;
uint8_t reserved2;
uint64_t address;
uint8_t hpet_number;
uint16_t minimum_tick;
uint8_t page_protection;
} __attribute__((packed));

5
kernel/cpuid.s

@ -8,8 +8,7 @@
; void cpuid(uint32_t eax, struct cpuid_regs* out_regs);
cpuid:
push ebp
mov ebp, esp
push rbp; no stack alloc
push rbx
mov eax, edi
@ -22,5 +21,5 @@ cpuid:
pop rbx
leave
pop rbp
ret

9
kernel/entry.c

@ -45,8 +45,8 @@ static struct stivale2_header_tag_framebuffer framebuffer_hdr_tag = {
},
// We set all the framebuffer specifics to 0 as we want the bootloader
// to pick the best it can.
.framebuffer_width = 1152,
.framebuffer_height = 864,
.framebuffer_width = 800,
.framebuffer_height = 600,
.framebuffer_bpp = 32
};
@ -127,6 +127,8 @@ static void print_fb_infos(struct stivale2_struct_tag_framebuffer* fbtag) {
// Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling functio
// The following will be our kernel's entry point.
void _start(struct stivale2_struct *stivale2_struct) {
// Let's get the terminal structure tag from the bootloader.
struct stivale2_struct_tag_terminal *term_str_tag;
term_str_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_TERMINAL_ID);
@ -181,7 +183,6 @@ void _start(struct stivale2_struct *stivale2_struct) {
kputs("DONE\n");
apic_setup_clock();
@ -190,7 +191,7 @@ void _start(struct stivale2_struct *stivale2_struct) {
for(;;) {
asm volatile("hlt");
kprintf("%lu\t", clock());
kprintf("%lu\r", clock());
}

143
kernel/int/apic.c

@ -5,28 +5,18 @@
#include "apic.h"
#include "../klib/sprintf.h"
#define LAPIC_TIMER_IRQ 0xff
volatile struct APICConfig* apic_config = NULL;
struct APICConfig* apic_config = NULL;
void outb(uint16_t dx, uint16_t al);
static inline void outb(uint16_t port, uint8_t val)
{
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
}
uint8_t inb(uint16_t dx);
void set_rflags(uint64_t rf);
uint64_t get_rflags(void);
static void pit_wait(size_t ms) {
outb(0x43, 0x30);
uint16_t val = 0x4a9 * ms;
outb(0x40, (uint8_t)val);
outb(0x40, (uint8_t)(val >> 8));
for(;;) {
outb(0x43, 0xe2);
uint8_t status = inb(0x40);
if ((status & (1 << 7)) != 0) {
break;
}
}
}
static unsigned read_pit_count(void) {
unsigned count = 0;
@ -34,9 +24,7 @@ static unsigned read_pit_count(void) {
// Disable interrupts
uint64_t rf = get_rflags();
_cli();
// al = channel in bits 6 and 7, remaining bits clear
outb(0x43,0b0000000);
count = inb(0x40); // Low byte
count |= inb(0x40)<<8; // High byte
@ -48,48 +36,129 @@ static unsigned read_pit_count(void) {
}
#define ABS(X) (X<0 ? -X : X)
static void pit_init() {
// al = channel in bits 6 and 7, remaining bits clear
outb(0x43,0b0000000);
outb(0x40, 0xff);
outb(0x40, 0xff);
}
static void pit_wait(size_t ms) {
uint32_t delta = ms * 0x04a9;
// no overflow
//assert(delta > 0xffff == 0);
uint32_t cur = read_pit_count();
uint16_t end = (cur + delta) % 0x10000;
// 16 bit counter
uint16_t dif = delta, ndif;
while(1) {
uint16_t pit = read_pit_count();
uint16_t ndif = ABS(end - pit);
if(ndif > dif)
break;
dif = ndif;
}
//asm volatile("pause");
return;
/*
uint16_t val = 0x4a9 * ms;
outb(0x40, (uint8_t)val);
outb(0x40, (uint8_t)(val >> 8));
outb(0x43, 0x30);
for(;;) {
outb(0x43, 0xe2);
uint8_t status = inb(0x40);
if ((status & (1 << 7)) != 0) {
break;
}
}
*/
}
uint64_t apic_timer_clock_count = 0;
char buffer[128] = {0};
__attribute__((interrupt)) void lapic_timer_handler(struct IFrame* frame) {
(void) frame;
++apic_timer_clock_count;
kprintf("%x\n", apic_timer_clock_count);
apic_config->end_of_interrupt.reg = 0;
}
uint64_t clock(void) {
return apic_timer_clock_count;
}
extern uint64_t read_msr(uint32_t address);
extern void write_msr(uint32_t address, uint64_t value);
inline uint64_t read(uint32_t m_address) {
uint32_t low, high;
asm("rdmsr" : "=a"(low), "=d"(high) : "c"(m_address));
return ((uint64_t) high << 32) | low;
}
#define PRINT(X) kprintf("%s = %lx\n", #X, X)
void apic_setup_clock(void) {
// enable apic msr
uint64_t IA32_APIC_BASE = read_msr(0x1b);
IA32_APIC_BASE |= (1 << 11);
write_msr(0x1b, IA32_APIC_BASE);
assert(apic_config != NULL);
set_irq_handler(32, lapic_timer_handler);
pit_init();
set_irq_handler(LAPIC_TIMER_IRQ, lapic_timer_handler);
// disable apic and set spurious int to 32
apic_config->spurious_interrupt_vector.reg = 0 | LAPIC_TIMER_IRQ;
// enable apic and set spurious int to 0xff
apic_config->spurious_interrupt_vector.reg = 1 | LAPIC_SPURIOUS_IRQ;
// masks the irq, one shot mode
apic_config->LVT_timer.reg = 0x10000;
apic_config->timer_divide_configuration.reg = 2; // divide by 8
apic_config->timer_divide_configuration.reg = 3; // divide by 16
apic_config->timer_initial_count.reg = UINT32_MAX;
pit_wait(1); /// wait for 1 ms
for(int i = 0; i < 10; i++)
pit_wait(1); /// wait for 1 ms
//apic_config->timer_initial_count.reg = UINT32_MAX - apic_config->timer_current_count.reg;
uint32_t t = (UINT32_MAX - apic_config->timer_current_count.reg);
apic_config->timer_initial_count.reg = t;
// irq on
for(int i = 0; i < 1000000000; i++) {
kprintf("%x\t%x\n", apic_config->timer_current_count.reg, read_pit_count());
// asm volatile("hlt");
}
// count
// enable apic and set spurious int to 0xff
apic_config->spurious_interrupt_vector.reg = 0x100 | LAPIC_SPURIOUS_IRQ;
// unmask the IRQ, periodic mode, timer on irq 32
apic_config->LVT_timer.reg = 0x20020;
// enable the clock irqs
apic_config->spurious_interrupt_vector.reg = 0x100 | LAPIC_TIMER_IRQ;
}

65
kernel/int/apic.h

@ -4,47 +4,48 @@
#include <stdint.h>
#include "../debug/assert.h"
#define LAPIC_SPURIOUS_IRQ 0xff
struct APICRegister
{
uint32_t reg;
volatile uint32_t reg;
uint32_t reserved[3];
};
static_assert(sizeof(struct APICRegister) == 16);
struct APICConfig
{
struct APICRegister reserved1[2]; //
struct APICRegister LAPIC_ID; // RW
struct APICRegister LAPIC_version; // R
struct APICRegister reserved2[4]; //
struct APICRegister task_priority; // RW
struct APICRegister arbitration_priority; // R
struct APICRegister processor_priority; // R
struct APICRegister end_of_interrupt; // W
struct APICRegister remote_read; // R
struct APICRegister logical_destination; // RW
struct APICRegister destination_format; // RW
struct APICRegister spurious_interrupt_vector; // RW
struct APICRegister in_service[8]; // R
struct APICRegister trigger_mode[8]; // R
struct APICRegister interrupt_request[8]; // R
struct APICRegister error_status; // R
struct APICRegister reserved3[6]; //
struct APICRegister LVT_corrected_machine_check_interrupt;// RW
struct APICRegister interrupt_command[2]; // RW
struct APICRegister LVT_timer; // RW
struct APICRegister LVT_thermal_sensor; // RW
struct APICRegister LVT_performance_monitoring_counters; // RW
struct APICRegister LVT_LINT0; // RW
struct APICRegister LVT_LINT1; // RW
struct APICRegister LVT_error; // RW
struct APICRegister timer_initial_count; // RW
struct APICRegister timer_current_count; // R
struct APICRegister reserved4[4]; //
struct APICRegister timer_divide_configuration; // RW
struct APICRegister reserved5; //
volatile struct APICRegister reserved1[2]; //
volatile struct APICRegister LAPIC_ID; // RW
volatile struct APICRegister LAPIC_version; // R
volatile struct APICRegister reserved2[4]; //
volatile struct APICRegister task_priority; // RW
volatile struct APICRegister arbitration_priority; // R
volatile struct APICRegister processor_priority; // R
volatile struct APICRegister end_of_interrupt; // W
volatile struct APICRegister remote_read; // R
volatile struct APICRegister logical_destination; // RW
volatile struct APICRegister destination_format; // RW
volatile struct APICRegister spurious_interrupt_vector; // RW
volatile struct APICRegister in_service[8]; // R
volatile struct APICRegister trigger_mode[8]; // R
volatile struct APICRegister interrupt_request[8]; // R
volatile struct APICRegister error_status; // R
volatile struct APICRegister reserved3[6]; //
volatile struct APICRegister LVT_corrected_machine_check_interrupt;// RW
volatile struct APICRegister interrupt_command[2]; // RW
volatile struct APICRegister LVT_timer; // RW
volatile struct APICRegister LVT_thermal_sensor; // RW
volatile struct APICRegister LVT_performance_monitoring_counters; // RW
volatile struct APICRegister LVT_LINT0; // RW
volatile struct APICRegister LVT_LINT1; // RW
volatile struct APICRegister LVT_error; // RW
volatile struct APICRegister timer_initial_count; // RW
volatile struct APICRegister timer_current_count; // R
volatile struct APICRegister reserved4[4]; //
volatile struct APICRegister timer_divide_configuration; // RW
volatile struct APICRegister reserved5; //
};
static_assert(sizeof(struct APICConfig) == 0x400);

7
kernel/int/isr.c

@ -117,10 +117,15 @@ void setup_isr(void) {
set_irs_handler(12, (void *) ISR_stack_segment_fault_handler);
set_irs_handler(13, (void *) ISR_general_protection_fault_handler);
set_irs_handler(14, (void *) ISR_page_fault_handler);
// >= 32 && < 38
for(int i = 15; i <= 255; i++)
for(int i = 15; i <= 0xff; i++)
set_irs_handler(i, ISR_spurious);
set_irs_handler(32, ISR_coproc_segment_overrun_handler);
//for(int i = d; i <= 0xff; i++)
// set_irs_handler(i, ISR_coproc_segment_overrun_handler);
setup_idt();
_sti();
}

2
kernel/klib/sprintf.c

@ -137,7 +137,7 @@ int vsprintf(char *str, const char *format, va_list ap) {
const char* arg = ARG(const char*);
if(digits >= 0) {
strncpy(str, arg, digits);
if((int) strlen(arg) > digits)
if((int) strlen(arg) < digits)
str += strlen(arg);
else
str += digits;

50
kernel/regs.s

@ -8,8 +8,10 @@
[global outb]
[global get_rflags]
[global set_rflags]
[global read_msr]
[global write_msr]
section .text
[section .text]
_ds:
xor rax,rax
@ -65,11 +67,47 @@ inb:
pop rdx
ret
outb:
push rdx
mov al, dil
; read_msr(uint32_t addr)
read_msr:
push rbp
mov rbp, rsp
out dx, al
push rcx
push rdx
mov ecx, edi
rdmsr
shl rdx, 32
or rax, rdx
pop rcx
pop rdx
pop rdx
mov rsp, rbp
pop rbp
ret
; read_msr(uint32_t addr, uint64_t value)
write_msr:
push rbp
mov rbp, rsp
push rcx
push rdx
mov ecx, edi
mov eax, esi
mov rdx, rsi
shr rdx, 32
wrmsr
pop rcx
pop rdx
mov rsp, rbp
pop rbp
ret

22
kernel/video/terminal.c

@ -19,6 +19,7 @@ struct Char {
static void write_string(const char *string, size_t length);
static struct Char make_Char(char c);
static void print_char(const struct Char* restrict c, int line, int col);
static void flush_screen(void);
static terminal_handler_t terminal_handler = NULL;
@ -62,7 +63,7 @@ void setup_terminal(void) {
// with right size
ncols = screenImage->w / FONTWIDTH;
term_nlines = (screenImage->h / LINE_HEIGHT);
term_nlines = (screenImage->h / LINE_HEIGHT) - 3;
nlines = N_PAGES * term_nlines;
@ -86,6 +87,8 @@ void terminal_clear(void) {
struct Char* ptr = buffer;
for(;buffer_len > 0; --buffer_len)
*(ptr++) = make_Char(0);
flush_screen();
}
@ -122,7 +125,7 @@ static void next_line(void) {
move_buffer(1);
}
else if(cur_line > first_line + term_nlines) {
else if(cur_line >= first_line + term_nlines) {
first_line++;
need_refresh = true;
}
@ -149,8 +152,8 @@ static void emplace_char(char c) {
const struct Char* ch = &buffer[ncols * cur_line + cur_col];
cur_col += 1;
print_char(ch, cur_line, cur_col);
if(!need_refresh)
print_char(ch, cur_line - first_line, cur_col);
if(cur_col >= ncols)
next_line();
@ -162,7 +165,7 @@ static void emplace_char(char c) {
break;
case '\t':
cur_col = ((cur_col + TAB_SPACE - 1) / TAB_SPACE) * TAB_SPACE;
cur_col = ((cur_col + TAB_SPACE) / TAB_SPACE) * TAB_SPACE;
if(cur_col >= ncols)
next_line();
@ -206,10 +209,15 @@ static void print_char(const struct Char* restrict c, int line, int col) {
.h = INTERLINE,
};
*/
/*
blitcharX2(charmap, c->c, c->fg_color, c->bg_color,
col * FONTWIDTH, line * LINE_HEIGHT);
col * FONTWIDTH * 2, 2 *line * LINE_HEIGHT);
*/
blitchar(charmap, c->c, c->fg_color, c->bg_color,
col * FONTWIDTH, line * LINE_HEIGHT);
//imageDraw(charmap, NULL, NULL);

27
kernel/video/video.c

@ -431,7 +431,7 @@ void blitchar(const struct Image* charset,
// 4 2-byte lines = 8*8 = 64 (1 access every 4 lines)
// 1st line address for the selected char
uint64_t* lines_ptr = (uint64_t*)charset->pix + c;
uint64_t* lines_ptr = (uint64_t*)charset->pix + srcy / sizeof(uint64_t);
@ -476,30 +476,33 @@ void blitcharX2(const struct Image* charset,
uint16_t srcy = c * FONTHEIGHT;
uint64_t* dst_ptr = (uint64_t *)(screen.pix + screen.pitch * dsty + 4 * dstx);
uint16_t dst_skip = screen.pitch - FONTWIDTH * 4;
uint16_t dst_skip = 2 * screen.pitch - 2 * FONTWIDTH * 4;
/// second line to modify
uint64_t* dst_ptr2 = dst_ptr + dst_skip / 8;
uint64_t* dst_ptr2 = dst_ptr + screen.pitch / 8;
uint64_t* lines_ptr = (uint64_t*)charset->pix + c;
uint64_t* lines_ptr = (uint64_t*)charset->pix + srcy / sizeof(uint64_t);
uint64_t lines = *lines_ptr;
#pragma GCC unroll 8
for(size_t n_line = 8; n_line > 0; n_line--) {
#pragma GCC unroll 3
uint64_t lines0 = lines;
#pragma GCC unroll 3
for(size_t n_col2 = FONTWIDTH / 2 ; n_col2 > 0 ; n_col2--) {
uint16_t index = lines0 & 0b11;
uint16_t index = lines & 0b11;
register uint64_t pixs_val = colormap[index];
register uint64_t pixs_val_low = pixs_val | (pixs_val << 32);
register uint64_t pixs_val_high = pixs_val | (pixs_val >> 32);
*(dst_ptr++) = pixs_val;
*(dst_ptr2++) = pixs_val;
*(dst_ptr++) = pixs_val_low;
*(dst_ptr++) = pixs_val_high;
*(dst_ptr2++) = pixs_val_low;
*(dst_ptr2++) = pixs_val_high;
// x2
lines0 >>= 2;
lines >>= 2;
}
dst_ptr += dst_skip / 8;
dst_ptr += dst_skip / 8;
dst_ptr2 += dst_skip / 8;
@ -544,7 +547,6 @@ Image* loadBMP_24b_1b(const void* rawFile) {
assert(w == 6);
assert(h == 2048);
size_t bpitch = ret->pitch;
uint8_t* pix = ret->pix;
@ -552,7 +554,6 @@ Image* loadBMP_24b_1b(const void* rawFile) {
uint8_t byte = 0;
uint16_t _x = 0;
for(size_t x = 0; x < w; x++) {
const uint8_t* src_ptr = (srcpix + 20 * (h-1 - y) + 3 * (w-1-x));

Loading…
Cancel
Save