#include "kernel.h" // http://www.intel.com/content/dam/doc/specification-update/64-architecture-x2apic-specification.pdf // http://download.intel.com/design/chipsets/datashts/29056601.pdf // http://www.scs.stanford.edu/05au-cs240c/lab/ia32/IA32-3.pdf // https://wiki.osdev.org/Symmetric_Multiprocessing // https://wiki.osdev.org/APIC_timer #include #include "smp.h" #include "mem.h" #include "spinlock.h" #include "asm_x86.h" #define FOOLOS_APIC_SPUR_INT 0x00f0 #define FOOLOS_APIC_INT_COMMAND_LOW 0x0300 #define FOOLOS_APIC_INT_COMMAND_HIGH 0x0310 #define FOOLOS_APIC_ID 0x020 #define APIC_APICID 0x20 #define APIC_APICVER 0x30 #define APIC_TASKPRIOR 0x80 #define APIC_EOI 0x0B0 #define APIC_LDR 0x0D0 #define APIC_DFR 0x0E0 #define APIC_SPURIOUS 0x0F0 #define APIC_ESR 0x280 #define APIC_ICRL 0x300 #define APIC_ICRH 0x310 #define APIC_LVT_TMR 0x320 #define APIC_LVT_PERF 0x340 #define APIC_LVT_LINT0 0x350 #define APIC_LVT_LINT1 0x360 #define APIC_LVT_ERR 0x370 #define APIC_TMRINITCNT 0x380 #define APIC_TMRCURRCNT 0x390 #define APIC_TMRDIV 0x3E0 #define APIC_LAST 0x38F #define APIC_DISABLE 0x10000 #define APIC_SW_ENABLE 0x100 #define APIC_CPUFOCUS 0x200 #define APIC_NMI (4<<8) #define TMR_PERIODIC 0x20000 #define TMR_BASEDIV (1<<20) // some multiprocessor shit that should move away TODO uint32_t c1,c2,c3; volatile uint8_t proc; uint32_t cpu_counter[SMP_MAX_PROC]; uint32_t local_apic_addr; extern uint32_t LLOCK; void smp_main() { // setup stack uint32_t ebp=kballoc(1); asm volatile("mov %0, %%ebp"::"r"(ebp)); asm volatile("mov %ebp, %esp"); asm volatile("jmp kernel_ap"); } void writeAPIC(uint32_t offset, uint32_t value) { uint32_t *reg; reg=local_apic_addr+offset; *reg=value; } uint32_t readAPIC(uint32_t offset) { uint32_t *reg; reg=local_apic_addr+offset; uint32_t value=*reg; return value; } void kernel_ap() { uint32_t *reg; reg=local_apic_addr+FOOLOS_APIC_ID; klog("smp local apic id: 0x%08X",(*reg)); reg=local_apic_addr+FOOLOS_APIC_SPUR_INT; klog("svr value: 0x%08X",(*reg)); *reg|=0x100; // enable APIC int_install(); gdt_init(); uint32_t countdown=0x0fffffff; writeAPIC(APIC_TMRDIV, 0x3); writeAPIC(APIC_LVT_TMR, 200 | TMR_PERIODIC); writeAPIC(APIC_TMRINITCNT, countdown); x86_sti(); LLOCK=0; // release lock, so next ap can continue... while(1) { asm("hlt"); klog("tack: 0x%08X: 0x%08X",readAPIC(FOOLOS_APIC_ID), readAPIC(APIC_TMRCURRCNT)); } // switch_to_user_mode(); /* while(1); uint32_t ebp=pmmngr_alloc_block()+4095; asm volatile("mov %0, %%ebp"::"r"(ebp)); asm volatile("mov %ebp, %esp"); asm volatile("jmp kernel_ap"); proc=c1=c2=c3=0; for(int i=0;iprocessors;i++) { klog("cpu %d, apic_id: 0x%X, bps: %s, apic_addr:0x%08X",i,procdata->local_apic_id[i],i==procdata->boot?"yes":"no",procdata->local_apic_address); } } // this will start all our application processors! void smp_start_aps(smp_processors *pros) { // TODO: check if local APIC is present via CPUID (P6 (i686) and above) local_apic_addr=pros->local_apic_address; //bsp (boot processor) enables its local apic // uint32_t *reg=local_apic_addr+FOOLOS_APIC_SPUR_INT; // *reg=0xffffffff; // all bits 1 and interrupt 255 (is this not set anyway?) // *reg=0; uint32_t *reg=local_apic_addr+FOOLOS_APIC_ID; klog("bsp local apic id: 0x%08X",(*reg)); for(int i=0;iprocessors;i++) { if(pros->boot==i)continue; uint8_t dest=pros->local_apic_id[i]; klog("starting cpu %d (dest: %d) ",i,dest); reg=local_apic_addr+FOOLOS_APIC_INT_COMMAND_HIGH; *reg=dest<<24; // destination apic. reg=local_apic_addr+FOOLOS_APIC_INT_COMMAND_LOW; *reg=(5<<8)|(1<<14); // 101 INIT // do we really neet this? // TODO!! // todo: use some real sleep (not implemented yet :( ) //sleep(30); // start proc 0x7 = at addr 0x7000; *reg=(6<<8)|(1<<14)|0x7; // 110 SIPI } }