From f356cc8f9587d328521b8ccd4d6068599ae08b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Sun, 20 Nov 2016 00:23:47 +0100 Subject: [PATCH] [SMP] Cpu initialization cleanup --- kernel/arch/acpi.c | 3 +++ kernel/arch/gdt.c | 8 +++---- kernel/boot/kmain.c | 19 +++------------ kernel/cpu/cpu.c | 52 ++++++++++++++++++++++++++++++++++++++++ kernel/cpu/get_cpu.S | 6 +++++ kernel/include/cpu.h | 37 ++++++++++++++++++++++++++++ kernel/include/process.h | 6 ++--- kernel/include/thread.h | 6 ++--- kernel/interrupts/apic.c | 9 ++----- kernel/proc/scheduler.c | 21 +++++++++------- kernel/proc/thread.c | 2 -- 11 files changed, 126 insertions(+), 43 deletions(-) create mode 100644 kernel/cpu/cpu.c create mode 100644 kernel/cpu/get_cpu.S create mode 100644 kernel/include/cpu.h diff --git a/kernel/arch/acpi.c b/kernel/arch/acpi.c index ed6bf3b..d81d728 100644 --- a/kernel/arch/acpi.c +++ b/kernel/arch/acpi.c @@ -5,6 +5,7 @@ #include #include #include +#include RSDP_st *find_rsdp() { @@ -80,6 +81,8 @@ void parse_MADT(SDT_header *header) if(f->proc.flags & 0x1) { debug(" enabled"); + // Add processor and LAPIC to list + cpu_add(f->proc.proc_ID, f->proc.APIC_ID); } debug("\n"); break; diff --git a/kernel/arch/gdt.c b/kernel/arch/gdt.c index aaf0a43..c7729a4 100644 --- a/kernel/arch/gdt.c +++ b/kernel/arch/gdt.c @@ -1,15 +1,15 @@ #include #include #include +#include -uint64_t gdt[5]; -struct gdtp_st gdt_p; -#define GDT gdt -#define GDTP gdt_p +#define GDT cpu->gdt +#define GDTP cpu->gdt_p void gdt_init() { + cpu_t *cpu = get_cpu(); GDT[0] = 0; GDT[SEG_KCODE/8] = (uint64_t)(GDT_PRESENT | GDT_CODEDATA | GDT_WRITE | GDT_EXECUTE | GDT_64BIT); diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index 7898299..15c7253 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -1,23 +1,17 @@ #include -#include #include #include -#include #include #include #include -#include -#include -#include -#include +#include #include -#include void thread_function() { while(1) { - debug((char *)0x10000); + ; } } @@ -32,16 +26,9 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) multiboot_init(multiboot_magic, P2V(multiboot_data)); vmm_init(); pmm_init(); - gdt_init(); - scheduler_init(); - pic_init(); - acpi_init(); - apic_init(); - ioapic_init(); - sse_init(); + cpu_init(); pit_init(); - process_t *p1 = process_spawn(0); process_t *p2 = process_spawn(p1); diff --git a/kernel/cpu/cpu.c b/kernel/cpu/cpu.c new file mode 100644 index 0000000..89b9369 --- /dev/null +++ b/kernel/cpu/cpu.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +cpu_t cpus[MAX_NUMCPU]; +unsigned int num_cpu = 0; + +void cpu_add(uint64_t id, uint64_t apic) +{ + if(num_cpu >= MAX_NUMCPU) + return; + + cpu_t *cpu = &cpus[num_cpu]; + memset(cpu, 0, sizeof(cpu_t)); + cpu->cpu = (uint64_t)cpu; + cpu->id = id; + cpu->apic_id = apic; + cpu->is_bsp = (num_cpu)?0:1; + num_cpu++; +} + +void init_cpu() +{ + cpu_t *cpu = get_cpu(); + debug_info("CPU - Initializing CPU %x\n", cpu->id); + + interrupt_init(); + apic_init(); + gdt_init(); + sse_init(); + scheduler_init(); +} + +void cpu_init() +{ + acpi_init(); + pic_init(); + ioapic_init(); + + msr_write(MSR_REG_KERNEL_GS, cpus[0].cpu); + asm("swapgs"); + init_cpu(); + + debug_info("CPU - Status\n"); + for(unsigned int i = 0; i < num_cpu; i++) + { + debug(" CPU id:%x lapic:%x\n", cpus[i].id, cpus[i].apic_id); + } +} diff --git a/kernel/cpu/get_cpu.S b/kernel/cpu/get_cpu.S new file mode 100644 index 0000000..55ea01f --- /dev/null +++ b/kernel/cpu/get_cpu.S @@ -0,0 +1,6 @@ +#include +.intel_syntax noprefix +.global get_cpu +get_cpu: + mov rax, gs:GS_OFFSET_CPU + ret diff --git a/kernel/include/cpu.h b/kernel/include/cpu.h new file mode 100644 index 0000000..c1935cb --- /dev/null +++ b/kernel/include/cpu.h @@ -0,0 +1,37 @@ +#pragma once + +#define MAX_NUMCPU 64 + +#define GS_OFFSET_CPU 0 + +#ifndef __ASSEMBLER__ +#include +#include +#include +#include + +typedef struct cpu_t +{ + uint64_t cpu; + uint64_t id; + uint64_t apic_id; + uint64_t apic_ticks_per_us; + uint64_t is_bsp; + thread_t *current_thread; + thread_t *last_thread; + process_t *current_process; + uint64_t gdt[5]; + struct gdtp_st gdt_p; + thread_t *scheduler; +}__attribute__((packed)) cpu_t; + +extern cpu_t cpus[]; +extern unsigned int num_cpu; + +void acpi_init(); +void cpu_add(uint64_t id, uint64_t apic); +void cpu_init(); +cpu_t *get_cpu(); +#endif + + diff --git a/kernel/include/process.h b/kernel/include/process.h index ccfad96..8e4d5c0 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -3,6 +3,7 @@ typedef struct process_st process_t; #include #include #include +#include typedef struct process_st { @@ -23,9 +24,8 @@ typedef struct process_st #define process_alive(proc) ((proc)->state == PROC_STATE_READY || (proc)->state == PROC_STATE_RUNNING) -process_t *current_process; -#define get_current_process() (current_process) -#define set_current_process(proc) (current_process = (proc)) +#define get_current_process() (get_cpu()->current_process) +#define set_current_process(proc) (get_cpu()->current_process = (proc)) process_t *process_spawn(process_t *parent); void process_attach(process_t *proc, thread_t *th); diff --git a/kernel/include/thread.h b/kernel/include/thread.h index 8405d68..db8f593 100644 --- a/kernel/include/thread.h +++ b/kernel/include/thread.h @@ -4,6 +4,7 @@ typedef struct thread_st thread_t; #include #include #include +#include #define THREAD_STACK_SIZE 0x1000-sizeof(thread_t) @@ -40,9 +41,8 @@ typedef struct thread_stack_st thread_t tcb; } thread_stack_t; -thread_t *current_thread; -#define get_current_thread() (current_thread) -#define set_current_thread(new) (current_thread = (new)) +#define get_current_thread() (get_cpu()->current_thread) +#define set_current_thread(new) (get_cpu()->current_thread = (new)) thread_t *new_thread(void (*func)(void)); void switch_thread(thread_t *old, thread_t *new); diff --git a/kernel/interrupts/apic.c b/kernel/interrupts/apic.c index 6fab6b7..699a34c 100644 --- a/kernel/interrupts/apic.c +++ b/kernel/interrupts/apic.c @@ -46,8 +46,6 @@ #define APIC(reg) apic[reg/4] uint32_t volatile *apic = P2V(APIC_BASE); -uint32_t apic_ticks_per_us; - void apic_interrupt(uint8_t destination, uint8_t level, uint8_t type, uint8_t vector) { uint64_t data = ((level & 0x1)<<14) | ((type & 0x7)<<8) | vector; @@ -69,7 +67,7 @@ registers_t *apic_timer_handler(registers_t *r) void apic_timer(uint64_t us) { APIC(R_TIMER_DIV) = TIMER_DIV1; - APIC(R_TIMER_INIT) = us*apic_ticks_per_us; + APIC(R_TIMER_INIT) = us*get_cpu()->apic_ticks_per_us; APIC(R_TIMER_LVT) = TIMER_LVT_ONESHOT | INT_APIC_TIMER; } void apic_timer_stop() @@ -91,7 +89,6 @@ uint32_t calibrate_apic_timer(uint32_t resolution) void apic_init() { - debug_info("APIC - APIC_BASE MSR: %x\n", msr_read(MSR_APIC_BASE)); // Enable APIC by setting the enable bit in the APIC MSR msr_write(MSR_APIC_BASE, msr_read(MSR_APIC_BASE) | APIC_MSR_ENABLE); @@ -106,9 +103,7 @@ void apic_init() APIC(R_EOI) = 0; // Calibrate timer - apic_ticks_per_us = calibrate_apic_timer(100); - debug_info("APIC - ticks per us:%d\n", apic_ticks_per_us); - debug(" corresponds to processor frequency: %d MHz\n", apic_ticks_per_us); + get_cpu()->apic_ticks_per_us = calibrate_apic_timer(100); // Register temporary timer handler to go off every 10 ms register_int_handler(INT_APIC_TIMER, apic_timer_handler); diff --git a/kernel/proc/scheduler.c b/kernel/proc/scheduler.c index 7a6312c..0dcf8c0 100644 --- a/kernel/proc/scheduler.c +++ b/kernel/proc/scheduler.c @@ -7,9 +7,10 @@ LIST(thread_t, ready_queue); thread_t *scheduler_th; -thread_t *last_thread = 0; -#define get_last_thread() (last_thread) -#define set_last_thread(new) (last_thread = (new)) +#define get_last_thread() (get_cpu()->last_thread) +#define set_last_thread(new) (get_cpu()->last_thread = (new)) + +int scheduler_started = 0; void scheduler_insert(thread_t *th) { @@ -66,7 +67,7 @@ void scheduler() switch_process(new->process); sse_restore(new->sse_registers); apic_timer(1000000); - switch_thread(scheduler_th, new); + switch_thread(get_cpu()->scheduler, new); } } @@ -75,7 +76,7 @@ void schedule() // This function handles swithing to the next thread in the ready queue thread_t *old = get_current_thread(); - if(old == scheduler_th) + if(old == get_cpu()->scheduler) return; if(old) @@ -84,11 +85,15 @@ void schedule() } switch_process(0); - switch_thread(old, scheduler_th); + switch_thread(old, get_cpu()->scheduler); } void scheduler_init() { - LIST_HEAD_INIT(ready_queue); - scheduler_th = new_thread(scheduler); + if(!scheduler_started) + { + LIST_HEAD_INIT(ready_queue); + scheduler_started = 1; + } + get_cpu()->scheduler = new_thread(scheduler); } diff --git a/kernel/proc/thread.c b/kernel/proc/thread.c index 16a6665..3c92103 100644 --- a/kernel/proc/thread.c +++ b/kernel/proc/thread.c @@ -6,8 +6,6 @@ #include #include -thread_t *current_thread = 0; - uint64_t tid = 1;