diff options
author | Alexis211 <alexis211@gmail.com> | 2009-10-17 18:20:46 +0200 |
---|---|---|
committer | Alexis211 <alexis211@gmail.com> | 2009-10-17 18:20:46 +0200 |
commit | ae49f59cc96e4ff3709c857b848132e82e6e0b14 (patch) | |
tree | 46c53db51b25c2deea0786d043e53ab09b647ee0 /Source | |
parent | 9520a1a101b264abe700c3f7753f5f55bba4c681 (diff) | |
download | Melon-ae49f59cc96e4ff3709c857b848132e82e6e0b14.tar.gz Melon-ae49f59cc96e4ff3709c857b848132e82e6e0b14.zip |
User mode code can now run !
We have a sample process (hardcoded in ASM in Task.wtf.asm) that
displays a's and sleeps 20ms, but it's on a hidden virtual terminal so
it's useless :D
Diffstat (limited to 'Source')
-rw-r--r-- | Source/Kernel/Core/Sys.ns.cpp | 9 | ||||
-rw-r--r-- | Source/Kernel/Core/kmain.wtf.cpp | 11 | ||||
-rw-r--r-- | Source/Kernel/MemoryManager/GDT.ns.cpp | 22 | ||||
-rw-r--r-- | Source/Kernel/MemoryManager/GDT.ns.h | 32 | ||||
-rw-r--r-- | Source/Kernel/MemoryManager/GDT.wtf.asm | 6 | ||||
-rw-r--r-- | Source/Kernel/MemoryManager/PhysMem.ns.cpp | 1 | ||||
-rw-r--r-- | Source/Kernel/SyscallManager/IDT.ns.cpp | 11 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Task.ns.cpp | 5 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Task.wtf.asm | 15 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Thread.class.cpp | 59 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Thread.class.h | 1 |
11 files changed, 162 insertions, 10 deletions
diff --git a/Source/Kernel/Core/Sys.ns.cpp b/Source/Kernel/Core/Sys.ns.cpp index c0218d8..a8a6c91 100644 --- a/Source/Kernel/Core/Sys.ns.cpp +++ b/Source/Kernel/Core/Sys.ns.cpp @@ -93,7 +93,14 @@ void panic(char *message, registers_t *regs, char *file, u32int line) { vt << "eax=" << (u32int)regs->eax << ", ebx=" << (u32int)regs->ebx << ", ecx=" << (u32int)regs->ecx << ", edx=" << (u32int)regs->edx << "\n"; vt << "int_no=" << (s32int)regs->int_no << ", err_code=" << (u32int)regs->err_code << "\n"; - vt << "eflags=" << (u32int)regs->eflags << ", useresp=" << (u32int)regs->useresp << ", ss=" << (u32int)regs->ss << "\n\n"; + vt << "eflags=" << (u32int)regs->eflags << ", useresp=" << (u32int)regs->useresp << ", ss=" << (u32int)regs->ss << "\n"; + if (regs->int_no == 14) { + u32int cr2; + asm volatile("mov %%cr2, %0" : "=r"(cr2)); + vt << "cr2=" << (u32int)cr2 << "\n"; + } + vt << "\n"; + while (1) asm volatile("cli; hlt"); u32int *v = (u32int*)regs->ebp; diff --git a/Source/Kernel/Core/kmain.wtf.cpp b/Source/Kernel/Core/kmain.wtf.cpp index c7b47e1..655bd8b 100644 --- a/Source/Kernel/Core/kmain.wtf.cpp +++ b/Source/Kernel/Core/kmain.wtf.cpp @@ -35,6 +35,9 @@ extern u32int end; //Placement address extern "C" void kmain(multiboot_info_t* mbd, u32int magic); +extern "C" void sample_task(); +extern u32int sample_task_size; + #define INFO(vt) vt->setColor(KVT_FGCOLOR); *vt << " - "; vt->setColor(KVT_LIGHTCOLOR); #define PROCESSING(vt, m) vt->setColor(KVT_BLECOLOR); *vt << " > "; vt->setColor(KVT_FGCOLOR); *vt << m; \ vt->setCursorCol(60); vt->setColor(KVT_LIGHTCOLOR); *vt << ": "; @@ -164,6 +167,14 @@ void kmain(multiboot_info_t* mbd, u32int magic) { FloppyController::detect(); Log::log(KL_STATUS, "kmain : Floppy drives detected"); + //Create dummy process, for testing user mode + Process* p; + p = new Process("dummy task", 0); + u8int *ptr = (u8int*)p->heap().alloc(sample_task_size); + memcpy(ptr, (const u8int*)sample_task, sample_task_size); + new Thread(p, (thread_entry_t)ptr, 0); + kernelPageDirectory->switchTo(); + asm volatile("sti"); Log::log(KL_STATUS, "kmain : Interrupts enabled."); diff --git a/Source/Kernel/MemoryManager/GDT.ns.cpp b/Source/Kernel/MemoryManager/GDT.ns.cpp index 0bb606d..f1f5c94 100644 --- a/Source/Kernel/MemoryManager/GDT.ns.cpp +++ b/Source/Kernel/MemoryManager/GDT.ns.cpp @@ -1,6 +1,9 @@ #include "GDT.ns.h" extern "C" void gdt_flush(u32int); +extern "C" void tss_flush(); + +using namespace CMem; //For memset #define GDT_ENTRIES 6 @@ -8,6 +11,7 @@ namespace GDT { gdt_entry_t gdt_entries[GDT_ENTRIES]; gdt_ptr_t gdt_ptr; +tss_entry_t tss_entry; void setGate(s32int num, u32int base, u32int limit, u8int access, u8int gran) { gdt_entries[num].base_low = (base & 0xFFFF); @@ -20,6 +24,22 @@ void setGate(s32int num, u32int base, u32int limit, u8int access, u8int gran) { gdt_entries[num].access = access; } +void writeTSS(s32int num, u16int ss0, u32int esp0) { + u32int base = (u32int)&tss_entry; + u32int limit = base + sizeof(tss_entry); + + setGate(num, base, limit, 0xE9, 0x00); + + memset((u8int*)&tss_entry, 0, sizeof(tss_entry_t)); + + tss_entry.ss0 = ss0; + tss_entry.esp0 = esp0; + + tss_entry.cs = 0x0B; //0x0B = Kernel code segment + RPL=3 (meaning it is supposed to be called from user mode) + //0x13 = Kernel data segment + RPL=3 (meaning to be called from ring3) + tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; +} + void init() { gdt_ptr.limit = (sizeof(gdt_entry_t) * GDT_ENTRIES) - 1; gdt_ptr.base = (u32int)&gdt_entries; @@ -29,8 +49,10 @@ void init() { setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment + writeTSS(5, 0x10, 0x0); gdt_flush((u32int)&gdt_ptr); + tss_flush(); } } diff --git a/Source/Kernel/MemoryManager/GDT.ns.h b/Source/Kernel/MemoryManager/GDT.ns.h index 7a9f95f..94306a4 100644 --- a/Source/Kernel/MemoryManager/GDT.ns.h +++ b/Source/Kernel/MemoryManager/GDT.ns.h @@ -13,12 +13,44 @@ namespace GDT { u8int base_high; } __attribute__((packed)); + // A struct describing a Task State Segment. + struct tss_entry_t { + u32int prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list. + u32int esp0; // The stack pointer to load when we change to kernel mode. + u32int ss0; // The stack segment to load when we change to kernel mode. + u32int esp1; // Unused... + u32int ss1; + u32int esp2; + u32int ss2; + u32int cr3; + u32int eip; + u32int eflags; + u32int eax; + u32int ecx; + u32int edx; + u32int ebx; + u32int esp; + u32int ebp; + u32int esi; + u32int edi; + u32int es; // The value to load into ES when we change to kernel mode. + u32int cs; // The value to load into CS when we change to kernel mode. + u32int ss; // The value to load into SS when we change to kernel mode. + u32int ds; // The value to load into DS when we change to kernel mode. + u32int fs; // The value to load into FS when we change to kernel mode. + u32int gs; // The value to load into GS when we change to kernel mode. + u32int ldt; // Unused... + u16int trap; + u16int iomap_base; + } __attribute__((packed)); + struct gdt_ptr_t { u16int limit; u32int base; } __attribute__((packed)); void init(); + extern tss_entry_t tss_entry; //Used for setting kernel stack } #endif diff --git a/Source/Kernel/MemoryManager/GDT.wtf.asm b/Source/Kernel/MemoryManager/GDT.wtf.asm index eb216ed..beb668d 100644 --- a/Source/Kernel/MemoryManager/GDT.wtf.asm +++ b/Source/Kernel/MemoryManager/GDT.wtf.asm @@ -15,3 +15,9 @@ gdt_flush: .flush: ret + +[GLOBAL tss_flush] +tss_flush: + mov ax, 0x2B ;entry 5 = 0x28, with RPL=3 + ltr ax + ret diff --git a/Source/Kernel/MemoryManager/PhysMem.ns.cpp b/Source/Kernel/MemoryManager/PhysMem.ns.cpp index 382e8a4..eb6fbf1 100644 --- a/Source/Kernel/MemoryManager/PhysMem.ns.cpp +++ b/Source/Kernel/MemoryManager/PhysMem.ns.cpp @@ -28,7 +28,6 @@ void initPaging(u32int mem_size) { kernelPageDirectory->tables[i] = kernelPageDirectory->tables[768 + i]; } DEBUG_HEX((u32int)kernelPageDirectory->physicalAddr); DEBUG(" is page dir phys addr."); - //asm volatile("hlt"); kernelPageDirectory->switchTo(); DEBUG("Paging enabled !"); diff --git a/Source/Kernel/SyscallManager/IDT.ns.cpp b/Source/Kernel/SyscallManager/IDT.ns.cpp index fcab741..fcdf2ff 100644 --- a/Source/Kernel/SyscallManager/IDT.ns.cpp +++ b/Source/Kernel/SyscallManager/IDT.ns.cpp @@ -55,6 +55,7 @@ extern "C" void irq13(); extern "C" void irq14(); extern "C" void irq15(); +extern "C" void int64(); //Main syscall extern "C" void int65(); //Syscall to request a task switch extern "C" void int66(); //Syscall to signal that thread ended @@ -73,6 +74,13 @@ extern "C" void interrupt_handler(registers_t regs) { Dev::handleIRQ(regs, (regs.int_no - 32)); doSwitch = doSwitch or Task::IRQwakeup(regs.int_no - 32); } + if (regs.int_no == 64) { + if (regs.eax == 1) { + Task::currProcess()->getVirtualTerminal()->put(WChar(regs.ebx)); + } else if (regs.eax == 2) { + Task::currThread()->sleep(regs.ebx); + } + } if (regs.int_no == 66) { //This syscall signals to kernel that thread ended. Task::currentThreadExits(regs.eax); //DO NOT COUNT ON COMMING BACK FROM HERE } @@ -89,7 +97,7 @@ void setGate(u8int num, u32int base, u16int sel, u8int flags) { idt_entries[num].base_hi = (base >> 16) & 0xFFFF; idt_entries[num].sel = sel; - idt_entries[num].flags = flags; + idt_entries[num].flags = flags | 0x60; idt_entries[num].always0 = 0; } @@ -161,6 +169,7 @@ void init() { setGate(46, (u32int)irq14, 0x08, 0x8E); setGate(47, (u32int)irq15, 0x08, 0x8E); + setGate(64, (u32int)int64, 0x08, 0x8E); setGate(65, (u32int)int65, 0x08, 0x8E); setGate(66, (u32int)int66, 0x08, 0x8E); diff --git a/Source/Kernel/TaskManager/Task.ns.cpp b/Source/Kernel/TaskManager/Task.ns.cpp index a34f14f..1d1676e 100644 --- a/Source/Kernel/TaskManager/Task.ns.cpp +++ b/Source/Kernel/TaskManager/Task.ns.cpp @@ -94,8 +94,11 @@ void doSwitch() { eip = t->getEip(); cr3 = currentProcess->getPagedir()->physicalAddr; + asm volatile("cli"); + + t->setKernelStack(); + asm volatile(" \ - cli; \ mov %0, %%ebp; \ mov %1, %%esp; \ mov %2, %%ecx; \ diff --git a/Source/Kernel/TaskManager/Task.wtf.asm b/Source/Kernel/TaskManager/Task.wtf.asm index 77db18e..2e5b9f8 100644 --- a/Source/Kernel/TaskManager/Task.wtf.asm +++ b/Source/Kernel/TaskManager/Task.wtf.asm @@ -47,3 +47,18 @@ copy_page_physical: popf ; Pop EFLAGS back. pop ebx ; Get the original value of EBX back. ret + + +[GLOBAL sample_task] +sample_task: + mov eax, 0x00000001 ;temporarily defined as syscall id for writing one char to screen + mov ebx, 'a' ;loopingly write a's to screen + int 64 + mov eax, 0x00000002 ;temporary syscall for sleeping + mov ebx, 20 ;20ms + int 64 + jmp sample_task + int 66 ;finish task - will never happen since we have an infinite loop +[GLOBAL sample_task_size] +sample_task_size: + dd sample_task_size - sample_task diff --git a/Source/Kernel/TaskManager/Thread.class.cpp b/Source/Kernel/TaskManager/Thread.class.cpp index 6d62474..63d8160 100644 --- a/Source/Kernel/TaskManager/Thread.class.cpp +++ b/Source/Kernel/TaskManager/Thread.class.cpp @@ -2,11 +2,51 @@ #include <TaskManager/Task.ns.h> #include <MemoryManager/PageAlloc.ns.h> #include <DeviceManager/Time.ns.h> +#include <MemoryManager/GDT.ns.h> void runThread(Thread* thread, void* data, thread_entry_t entry_point) { - asm volatile("sti"); - u32int ret = entry_point(data); //Run ! - asm volatile("mov %0, %%eax; int $66;" : : "r"(ret)); //Syscall for thread ending + if (thread->m_isKernel) { + asm volatile("sti"); + u32int ret = entry_point(data); //Run ! + asm volatile("mov %0, %%eax; int $66;" : : "r"(ret)); //Syscall for thread ending + } else { + //Setup values on user stack + u32int *stack = (u32int*)((u32int)thread->m_userStack.addr + thread->m_userStack.size); + stack--; + *stack = (u32int)data; + stack--; + *stack = 0; + u32int esp = (u32int)stack, eip = (u32int)entry_point; + //Setup a false structure for returning from an interrupt : + //- update data segments to 0x23 = user data segment with RPL=3 + //- mov esp in ebx and eip in ecx + //- push value for ss : 0x23 (user data seg rpl3) + //- push value for esp + //- push flags + //- update flags, set IF = 1 (interrupts flag) + //- push value for cs : 0x1B = user code segment with RPL=3 + //- push eip + //- return from fake interrupt + asm volatile(" \ + mov $0x23, %%ax; \ + mov %%ax, %%ds; \ + mov %%ax, %%es; \ + mov %%ax, %%fs; \ + mov %%ax, %%gs; \ + \ + mov %0, %%ebx; \ + mov %1, %%ecx; \ + pushl $0x23; \ + pushl %%ebx; \ + pushf; \ + pop %%eax; \ + or $0x200, %%eax; \ + push %%eax; \ + pushl $0x1B; \ + push %%ecx; \ + iret; \ + " : : "r"(esp), "r"(eip)); + } } Thread::Thread() { //Private constructor, does nothing @@ -27,7 +67,10 @@ Thread::Thread(Process* process, thread_entry_t entry_point, void* data) { Thread::~Thread() { Task::unregisterThread(this); Mem::kfree(m_kernelStack.addr); - if (!m_isKernel) m_process->heap().free(m_userStack.addr); + if (m_userStack.addr != 0) { + m_process->getPagedir()->switchTo(); + m_process->heap().free(m_userStack.addr); + } //Don't unregister thread in process, it has probably already been done } @@ -111,11 +154,11 @@ void Thread::handleException(registers_t regs, int no) { *(m_process->m_vt) << "At:" << (u32int)faddr; *(m_process->m_vt) << "\nThread finishing.\n"; - finish(E_PAGEFAULT); + Task::currentThreadExits(E_PAGEFAULT); //Calling this will setup a new stack return; } *(m_process->m_vt) << "\nThread finishing.\n"; - finish(E_UNHANDLED_EXCEPTION); + Task::currentThreadExits(E_UNHANDLED_EXCEPTION); } void Thread::setState(u32int esp, u32int ebp, u32int eip) { @@ -124,6 +167,10 @@ void Thread::setState(u32int esp, u32int ebp, u32int eip) { m_eip = eip; } +void Thread::setKernelStack() { + GDT::tss_entry.esp0 = (u32int)(m_kernelStack.addr) + m_kernelStack.size; +} + u32int Thread::getEsp() { return m_esp; } u32int Thread::getEbp() { return m_ebp; } u32int Thread::getEip() { return m_eip; } diff --git a/Source/Kernel/TaskManager/Thread.class.h b/Source/Kernel/TaskManager/Thread.class.h index 9c8fa26..aeb1f93 100644 --- a/Source/Kernel/TaskManager/Thread.class.h +++ b/Source/Kernel/TaskManager/Thread.class.h @@ -43,6 +43,7 @@ class Thread { void handleException(registers_t regs, int no); void setState(u32int esp, u32int ebp, u32int eip); + void setKernelStack(); u32int getEsp(); u32int getEbp(); u32int getEip(); |