diff --git a/.gitignore b/.gitignore index da271bff..8ff138b1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ *.sym *.pcap *.img +*.log +*.a +*.DS_Store diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index d5f21089..d791ba46 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -33,6 +33,7 @@ extern "C" { #define APIC_TPR 0x0080 // Task Priority Regster #define APIC_EOI 0x00B0 // EOI Register #define APIC_SVR 0x00F0 // Spurious Interrupt Vector Register +#define APIC_ESR 0x0280 // Error Status Regsiter #define APIC_ICR1 0x0300 // Interrupt Command Register [0-31] #define APIC_ICR2 0x0310 // Interrupt Command Register [32-63] #define APIC_LVT_T 0x0320 // LVT Timer Register diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index 4a79d9ec..f8289b10 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -31,7 +31,9 @@ inline static void irq_disable(void) { inline static uint32_t irq_nested_disable(void) { uint32_t flags; asm volatile("pushf; cli; popl %0": "=r"(flags) : : "memory"); - return flags; + if (flags & (1 << 9)) + return 1; + return 0; } inline static void irq_enable(void) { @@ -39,7 +41,8 @@ inline static void irq_enable(void) { } inline static void irq_nested_enable(uint32_t flags) { - asm volatile("pushl %0; popf" : : "r"(flags) : "memory"); + if (flags) + irq_enable(); } #ifdef __cplusplus diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 9e44bf1d..d8e3d698 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -71,14 +71,6 @@ inline static void cpuid(uint32_t code, uint32_t* a, uint32_t* b, uint32_t* c, u asm volatile ("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "0"(code)); } -inline static void flush_pipeline(void) { - uint32_t low = 0; - uint32_t high = 0; - uint32_t code = 0; - - asm volatile ("cpuid" : "=a"(low), "=d"(high) : "0"(code) : "%ebx", "%ecx"); -} - inline static uint64_t rdmsr(uint32_t msr) { uint32_t low, high; diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c index f7eee024..151b9143 100644 --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c @@ -76,8 +76,7 @@ static inline void lapic_write(uint32_t addr, uint32_t value) * to avoid a pentium bug, we have to read a apic register * before we write a value to this register */ - asm volatile ("cmpl (%0), %%eax; movl %1, (%0)" :: "r"(lapic+addr), "r"(value)); - //asm volatile ("movl (%%eax), %%edx; movl %%ebx, (%%eax)" :: "a"(lapic+addr), "b"(value) : "%edx"); + asm volatile ("movl (%%eax), %%edx; movl %%ebx, (%%eax)" :: "a"(lapic+addr), "b"(value) : "%edx"); //*((volatile uint32_t*) (lapic+addr)) = value; } @@ -255,6 +254,25 @@ int smp_init(void) } #endif +static int lapic_reset(void) +{ + uint32_t max_lvt = apic_lvt_entries(); + + lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127 + lapic_write(APIC_TPR, 0x00); // allow all interrupts + lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt + if (max_lvt >= 4) + lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt + if (max_lvt >= 5) + lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt + lapic_write(APIC_LINT0, 0x7C); // connect LINT0 to idt entry 124 + lapic_write(APIC_LINT1, 0x7D); // connect LINT1 to idt entry 125 + lapic_write(APIC_LVT_ER, 0x7E); // connect error to idt entry 126 + lapic_write(APIC_ID, 0x00); // reset boot processor id + + return 0; +} + /* * detects the timer frequency of the APIC and restart * the APIC timer with the correct period @@ -263,10 +281,13 @@ int apic_calibration(void) { uint8_t i; uint32_t flags; - #ifndef CONFIG_ROCKCREEK uint64_t ticks, old; uint32_t diff; +#else + uint64_t start, end, ticks; + uint32_t diff; +#endif if (!has_apic()) return -ENXIO; @@ -274,30 +295,47 @@ int apic_calibration(void) lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE); if (BUILTIN_EXPECT(!lapic, 0)) return -ENXIO; + kprintf("Mapped LAPIC at 0x%x\n", lapic); + + if (ioapic) { + size_t old = 0; - if (ioapic) ioapic = (ioapic_t*) map_region(0 /*(size_t)ioapic*/, (size_t) ioapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE); + kprintf("Mapped IOAPIC at 0x%x\n", ioapic); + // map all processor entries + for(i=0; i Therefore, we disable the PIC outportb(0xA1, 0xFF); @@ -308,27 +346,17 @@ int apic_calibration(void) * and possess no PIC timer. Therfore, we use the rdtsc to * to calibrate the APIC timer. */ - uint64_t start, end, ticks; - uint32_t diff; - - if (!has_apic()) - return -ENXIO; - - lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE); - if (BUILTIN_EXPECT(!lapic, 0)) - return -ENXIO; - - if (ioapic) - ioapic = (ioapic_t*) map_region(0 /*(size_t)ioapic*/, (size_t)ioapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE); + flags = irq_nested_disable(); lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it lapic_write(APIC_ICR, 0xFFFFFFFFUL); /* wait 3 time slices to determine a ICR */ + rmb(); start = rdtsc(); do { - flush_pipeline(); + rmb(); end = rdtsc(); ticks = end > start ? end - start : start - end; } while(ticks*TIMER_FREQ < 3*RC_REFCLOCKMHZ*1000000UL); @@ -336,9 +364,12 @@ int apic_calibration(void) diff = 0xFFFFFFFFUL - lapic_read(APIC_CCR); diff = diff / 3; + lapic_reset(); lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it lapic_write(APIC_ICR, diff); + + irq_nested_enable(flags); #endif kprintf("APIC calibration determines an ICR of 0x%x\n", diff); @@ -520,31 +551,28 @@ no_mp: goto check_lapic; } +static void apic_err_handler(struct state *s) +{ + kprintf("Got APIC error 0x%x\n", lapic_read(APIC_ESR)); +} + int apic_init(void) { int ret; uint8_t i; - uint32_t v; - uint32_t max_lvt; ret = apic_probe(); if (!ret) return ret; - max_lvt = apic_lvt_entries(); + // set APIC error handler + irq_install_handler(126, apic_err_handler); - lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127 - lapic_write(APIC_TPR, 0x00); // allow all interrupts - lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt - if (max_lvt >= 4) - lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt - if (max_lvt >= 5) - lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt - lapic_write(APIC_LINT0, 0x7C); // connect LINT0 to idt entry 124 - lapic_write(APIC_LINT1, 0x7D); // connect LINT1 to idt entry 125 - lapic_write(APIC_LVT_ER, 0x7E); // connect error to idt entry 126 + ret = lapic_reset(); + if (!ret) + return ret; - if (0) { //ioapic) { + if (ioapic) { // enable timer interrupt ioapic_inton(0, apic_processors[boot_processor]->id); // now lets turn everything else off diff --git a/arch/x86/kernel/gdt.c b/arch/x86/kernel/gdt.c index 084f071c..b4fd61ae 100644 --- a/arch/x86/kernel/gdt.c +++ b/arch/x86/kernel/gdt.c @@ -69,6 +69,8 @@ int arch_fork(task_t* task) memcpy(kstacks[id], kstacks[curr_task->id], KERNEL_STACK_SIZE); task_state_segments[id].cr3 = (uint32_t) (virt_to_phys((size_t)task->pgd)); task_state_segments[id].eflags = read_eflags(); + // the parent task will enable the IF flag + task_state_segments[id].eflags |= (1 << 9); task_state_segments[id].esp0 = (uint32_t) kstacks[id] + KERNEL_STACK_SIZE - sizeof(size_t); asm volatile("mov %%esp, %0" : "=r"(task_state_segments[id].esp)); @@ -76,18 +78,18 @@ int arch_fork(task_t* task) task_state_segments[id].esp += (uint32_t) kstacks[id]; asm volatile ("pusha"); - asm volatile ("pop %%eax" : "=a"(task_state_segments[id].edi)); - asm volatile ("pop %%eax" : "=a"(task_state_segments[id].esi)); - asm volatile ("pop %%eax" : "=a"(task_state_segments[id].ebp)); + asm volatile ("pop %0" : "=r"(task_state_segments[id].edi)); + asm volatile ("pop %0" : "=r"(task_state_segments[id].esi)); + asm volatile ("pop %0" : "=r"(task_state_segments[id].ebp)); #ifdef WITH_FRAME_POINTER task_state_segments[id].ebp -= (uint32_t) kstacks[curr_task->id]; task_state_segments[id].ebp += (uint32_t) kstacks[id]; #endif asm volatile ("add $4, %%esp" ::: "%esp"); - asm volatile ("pop %%eax" : "=a"(task_state_segments[id].ebx)); - asm volatile ("pop %%eax" : "=a"(task_state_segments[id].edx)); - asm volatile ("pop %%eax" : "=a"(task_state_segments[id].ecx)); - asm volatile ("pop %%eax" : "=a"(task_state_segments[id].eax)); + asm volatile ("pop %0" : "=r"(task_state_segments[id].ebx)); + asm volatile ("pop %0" : "=r"(task_state_segments[id].edx)); + asm volatile ("pop %0" : "=r"(task_state_segments[id].ecx)); + asm volatile ("pop %0" : "=r"(task_state_segments[id].eax)); // This will be the entry point for the new task. task_state_segments[id].eip = read_eip(); diff --git a/arch/x86/kernel/processor.c b/arch/x86/kernel/processor.c index f2237f17..2b1c84bf 100644 --- a/arch/x86/kernel/processor.c +++ b/arch/x86/kernel/processor.c @@ -23,16 +23,10 @@ #include #ifdef CONFIG_ROCKCREEK #include -#else -/* disable optimization for the following functions */ -uint32_t detect_cpu_frequency(void) __attribute__((optimize(0))); #endif static uint32_t cpu_freq = 0; -/* disable optimization for the following functions */ -void udelay(uint32_t usecs) __attribute__((optimize(0))); - uint32_t detect_cpu_frequency(void) { #ifdef CONFIG_ROCKCREEK @@ -53,12 +47,14 @@ uint32_t detect_cpu_frequency(void) /* wait for the next time slice */ while((ticks = get_clock_tick()) - old == 0) - ; + HALT; + rmb(); start = rdtsc(); /* wait a second to determine the frequency */ while(get_clock_tick() - ticks < TIMER_FREQ) - ; + HALT; + rmb(); end = rdtsc(); diff = end > start ? end - start : start - end; @@ -82,6 +78,7 @@ void udelay(uint32_t usecs) uint64_t deadline = get_cpu_frequency() * usecs; do { + rmb(); end = rdtsc(); diff = end > start ? end - start : start - end; } while(diff < deadline); diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index 993ccc3d..533f4a5c 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -87,6 +87,12 @@ inline static size_t copy_page_table(task_t* task, uint32_t pgd_index, page_tabl for(i=0; i<1024; i++) { if (pgt->entries[i] & 0xFFFFF000) { + if (!(pgt->entries[i] & PG_USER)) { + // Kernel page => copy only page entries + new_pgt->entries[i] = pgt->entries[i]; + continue; + } + phyaddr = get_page(); if (!phyaddr) continue; @@ -140,9 +146,10 @@ int create_pgd(task_t* task, int copy) spinlock_lock(&kslock); - for(i=0; ientries[i] = boot_pgd.entries[i]; - if (pgd->entries[i]) + // only kernel entries will be copied + if (pgd->entries[i] && !(pgd->entries[i] & PG_USER)) pgt->entries[i] = pgt_container->entries[i]; } @@ -165,6 +172,8 @@ int create_pgd(task_t* task, int copy) for (i=KERNEL_SPACE/(1024*PAGE_SIZE); i<1024; i++) { if (!(curr_task->pgd->entries[i])) continue; + if (!(curr_task->pgd->entries[i] & PG_USER)) + continue; phyaddr = copy_page_table(task, i, (page_table_t*) ((KERNEL_SPACE - 1024*PAGE_SIZE + i*PAGE_SIZE) & 0xFFFFF000), &counter); if (phyaddr) { @@ -194,8 +203,8 @@ int drop_pgd(void) spinlock_lock(&task->pgd_lock); - for(i=KERNEL_SPACE/(1024*PAGE_SIZE); i<1024; i++) { - if (pgd->entries[i] & 0xFFFFF000) { + for(i=0; i<1024; i++) { + if (pgd->entries[i] & PG_USER) { put_page(pgd->entries[i] & 0xFFFFF000); pgd->entries[i] = 0; } @@ -328,7 +337,7 @@ size_t map_region(size_t viraddr, size_t phyaddr, uint32_t npages, uint32_t flag index = (viraddr >> 12) & 0x3FF; if (BUILTIN_EXPECT(pgt->entries[index], 0)) { spinlock_unlock(pgd_lock); - kprintf("0x%x is already maped\n"); + kprintf("0x%x is already maped\n", viraddr); return 0; } @@ -646,8 +655,9 @@ int arch_paging_init(void) * of course, mb_info has to map into the kernel space */ if (mb_info) - map_region((size_t) mb_info, (size_t) mb_info, 1, MAP_KERNEL_SPACE); + map_region((size_t) mb_info & 0xFFFFF000, (size_t) mb_info & 0xFFFFF000, 1, MAP_KERNEL_SPACE); +#if 0 /* * Map reserved memory regions into the kernel space */ @@ -665,6 +675,7 @@ int arch_paging_init(void) mmap++; } } +#endif /* * Modules like the init ram disk are already loaded. diff --git a/kernel/main.c b/kernel/main.c index 3cf4aa07..8be29f22 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -114,7 +114,7 @@ int main(void) reschedule(); while(1) { - NOP8; + HALT; } return 0; diff --git a/kernel/tasks.c b/kernel/tasks.c index 144026fc..3f7a1b7a 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -104,7 +104,7 @@ static void NORETURN do_exit(int arg) { kputs("Kernel panic: scheduler found no valid task\n"); while(1) { - NOP8; + HALT; } }