diff --git a/libmaxsi/x64/start.s b/libmaxsi/x64/start.s index e3aeafda..bb2a5b48 100644 --- a/libmaxsi/x64/start.s +++ b/libmaxsi/x64/start.s @@ -29,10 +29,15 @@ .type _start, @function _start: + pushq %rsi + pushq %rdi + call initialize_standard_library + popq %rdi + popq %rsi + # Run main - # TODO: Sortix should set the initial values before this point! call main # Terminate the process with main's exit code. diff --git a/sortix/Makefile b/sortix/Makefile index e2d5609c..d2079ef6 100644 --- a/sortix/Makefile +++ b/sortix/Makefile @@ -37,6 +37,7 @@ ifdef X86FAMILY $(CPU)/syscall.o \ $(CPU)/thread.o \ $(CPU)/scheduler.o \ + $(CPU)/process.o \ x86-family/x86-family.o CPUFLAGS:=$(CPUFLAGS) -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow endif diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp index b7b8c5bb..07049700 100644 --- a/sortix/kernel.cpp +++ b/sortix/kernel.cpp @@ -214,10 +214,10 @@ namespace Sortix GDT::Init(); #ifdef PLATFORM_X64 - Log::Print("Halt: CPU X64 cannot boot because interrupts are not yet " + Log::Print("Halt: CPU x64 cannot boot because interrupts are not yet " "supported under 64-bit Sortix.\n"); Log::Print("Sorry, it simply isn't possible to fully boot Sortix in x64 mode yet.\n"); - Log::Print("X64 may be working when Sortix 0.5 comes out, or try the git master.\n"); + Log::Print("x64 may be working when Sortix 0.6 comes out, or try the git master.\n"); while(true); #endif diff --git a/sortix/process.cpp b/sortix/process.cpp index c2f774fd..e4d6952a 100644 --- a/sortix/process.cpp +++ b/sortix/process.cpp @@ -273,8 +273,6 @@ namespace Sortix addr_t stackpos = CurrentThread()->stackpos + CurrentThread()->stacksize; addr_t argvpos = stackpos - sizeof(char*) * argc; char** stackargv = (char**) argvpos; - regs->eax = argc; - regs->ebx = argvpos; size_t argvsize = 0; for ( int i = 0; i < argc; i++ ) @@ -288,9 +286,7 @@ namespace Sortix stackpos = argvpos - argvsize; - regs->eip = entry; - regs->useresp = stackpos; - regs->ebp = stackpos; + ExecuteCPU(argc, stackargv, stackpos, entry, regs); return 0; } diff --git a/sortix/process.h b/sortix/process.h index 25cd3bc1..b0d360dc 100644 --- a/sortix/process.h +++ b/sortix/process.h @@ -101,6 +101,7 @@ namespace Sortix private: Thread* ForkThreads(Process* processclone); + void ExecuteCPU(int argc, char** argv, addr_t stackpos, addr_t entry, CPU::InterruptRegisters* regs); public: void ResetForExecute(); diff --git a/sortix/x64/memorymanagement.cpp b/sortix/x64/memorymanagement.cpp index f420addf..bacd2050 100644 --- a/sortix/x64/memorymanagement.cpp +++ b/sortix/x64/memorymanagement.cpp @@ -106,5 +106,42 @@ namespace Sortix // up, the calling function will fill up the physical allocator with // plenty of nice physical pages. (see Page::InitPushRegion) } + + // Please note that even if this function exists, you should still clean + // up the address space of a process _before_ calling + // DestroyAddressSpace. This is just a hack because it currently is + // impossible to clean up PLM1's using the MM api! + // --- + // TODO: This function is duplicated in {x86,x64}/memorymanagement.cpp! + // --- + void RecursiveFreeUserspacePages(size_t level, size_t offset) + { + PML* pml = PMLS[level] + offset; + for ( size_t i = 0; i < ENTRIES; i++ ) + { + if ( !(pml->entry[i] & PML_PRESENT) ) { continue; } + if ( !(pml->entry[i] & PML_USERSPACE) ) { continue; } + if ( !(pml->entry[i] & PML_FORK) ) { continue; } + if ( level > 1 ) { RecursiveFreeUserspacePages(level-1, offset * ENTRIES + i); } + addr_t addr = pml->entry[i] & PML_ADDRESS; + pml->entry[i] = 0; + Page::Put(addr); + } + } + + void DestroyAddressSpace() + { + // First let's do the safe part. Garbage collect any PML1/0's left + // behind by user-space. These are completely safe to delete. + RecursiveFreeUserspacePages(TOPPMLLEVEL, 0); + + // TODO: Right now this just leaks memory. + + // Switch to the address space from when the world was originally + // created. It should contain the kernel, the whole kernel, and + // nothing but the kernel. + PML* const BOOTPML4 = (PML* const) 0x01000UL; + SwitchAddressSpace((addr_t) BOOTPML4); + } } } diff --git a/sortix/x64/process.cpp b/sortix/x64/process.cpp new file mode 100644 index 00000000..b08a2877 --- /dev/null +++ b/sortix/x64/process.cpp @@ -0,0 +1,38 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with Sortix. If not, see . + + x64/process.cpp + CPU-specific process code. + +******************************************************************************/ + +#include "platform.h" +#include "process.h" + +namespace Sortix +{ + void Process::ExecuteCPU(int argc, char** argv, addr_t stackpos, addr_t entry, CPU::InterruptRegisters* regs) + { + regs->rdi = argc; + regs->rsi = (size_t) argv; + regs->rip = entry; + regs->userrsp = stackpos; + regs->rbp = stackpos; + } +} diff --git a/sortix/x64/scheduler.cpp b/sortix/x64/scheduler.cpp new file mode 100644 index 00000000..49b08b89 --- /dev/null +++ b/sortix/x64/scheduler.cpp @@ -0,0 +1,52 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with Sortix. If not, see . + + x64/scheduler.cpp + CPU specific things related to the scheduler. + +******************************************************************************/ + +#include "platform.h" +#include "scheduler.h" +#include "../memorymanagement.h" +#include "descriptor_tables.h" + +namespace Sortix +{ + namespace Scheduler + { + const size_t KERNEL_STACK_SIZE = 256UL * 1024UL; + const addr_t KERNEL_STACK_END = 0xFFFF800000001000UL; + const addr_t KERNEL_STACK_START = KERNEL_STACK_END + KERNEL_STACK_SIZE; + + void InitCPU() + { + // TODO: Prevent the kernel heap and other stuff from accidentally + // also allocating this virtual memory region! + + if ( !Memory::MapRangeKernel(KERNEL_STACK_END, KERNEL_STACK_SIZE) ) + { + PanicF("could not create kernel stack (%zx to %zx)", + KERNEL_STACK_END, KERNEL_STACK_START); + } + + GDT::SetKernelStack((size_t*) KERNEL_STACK_START); + } + } +} diff --git a/sortix/x64/syscall.s b/sortix/x64/syscall.s new file mode 100644 index 00000000..c3dc44c6 --- /dev/null +++ b/sortix/x64/syscall.s @@ -0,0 +1,157 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with Sortix. If not, see . + + syscall.s + An assembly stub that acts as glue for system calls. + +******************************************************************************/ + +.global syscall_handler +.global resume_syscall + +.section .text +.type syscall_handler, @function +syscall_handler: + cli + + # Compabillity with InterruptRegisters. + pushq $0x0 + pushq $0x80 + + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rax + pushq %rcx + pushq %rdx + pushq %rbx + pushq %rsp + pushq %rsi + pushq %rdi + + # Push the user-space data segment. + movl %ds, %ebp + pushq %rbp + + # Load the kernel data segment. + movw $0x10, %bp + movl %ebp, %ds + movl %ebp, %es + movl %ebp, %fs + movl %ebp, %gs + + # Compabillity with InterruptRegisters. + movq %cr2, %rbp + pushq %rbp + + # Store the state structure's pointer so the call can modify it if needed. + movq %rsp, syscall_state_ptr + + # By default, assume the system call was complete. + movl $0, system_was_incomplete + + # Reset the kernel errno. + movl $0, errno + + # Make sure the requested system call is valid. + cmp SYSCALL_MAX, %rax + jb valid_rax + xorq %rax, %rax + +valid_rax: + # Read a system call function pointer. + xorq %rbp, %rbp + movq syscall_list(%rbp,%rax,4), %rax + + # Oh how nice, user-space put the parameters in: rdi, rsi, rdx, rcx, r8, r9 + + # Call the system call. + callq *%rax + + # Test if the system call was incomplete + movl system_was_incomplete, %ebx + testl %ebx, %ebx + + # If the system call was incomplete, the value in %eax is meaningless. + jg return_to_userspace + + # The system call was completed, so store the return value. + movq %rax, 72(%rsp) + + # Don't forget to update userspace's errno value. + call update_userspace_errno + +return_to_userspace: + # Compabillity with InterruptRegisters. + addq $8, %rsp + + # Restore the user-space data segment. + popq %rbp + movl %ebp, %ds + movl %ebp, %es + movl %ebp, %fs + movl %ebp, %gs + + popq %rdi + popq %rsi + popq %rsp + popq %rbx + popq %rdx + popq %rcx + popq %rax + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + # Compabillity with InterruptRegisters. + addq $16, %rsp + + # Return to user-space. + iretq + +.type resume_syscall, @function +resume_syscall: + pushq %rbp + movq %rsp, %rbp + + movq %rdi, %rax + movq %rsi, %r11 + + movq 0(%r11), %rdi + movq 8(%r11), %rsi + movq 16(%r11), %rdx + movq 24(%r11), %rcx + movq 32(%r11), %r8 + movq 40(%r11), %r9 + + callq *%rax + + leaveq + retq + diff --git a/sortix/x64/thread.cpp b/sortix/x64/thread.cpp new file mode 100644 index 00000000..9c63a9fc --- /dev/null +++ b/sortix/x64/thread.cpp @@ -0,0 +1,139 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with Sortix. If not, see . + + thread.cpp + x64 specific parts of thread.cpp. + +******************************************************************************/ + +#include "platform.h" +#include "thread.h" + +namespace Sortix +{ + void Thread::SaveRegisters(const CPU::InterruptRegisters* src) + { + registers.rip = src->rip; + registers.userrsp = src->userrsp; + registers.rax = src->rax; + registers.rbx = src->rbx; + registers.rcx = src->rcx; + registers.rdx = src->rdx; + registers.rdi = src->rdi; + registers.rsi = src->rsi; + registers.rbp = src->rbp; + registers.r8 = src->r8; + registers.r9 = src->r9; + registers.r10 = src->r10; + registers.r11 = src->r11; + registers.r12 = src->r12; + registers.r13 = src->r13; + registers.r14 = src->r14; + registers.r15 = src->r15; + registers.cs = src->cs; + registers.ds = src->ds; + registers.ss = src->ss; + registers.rflags = src->rflags; + } + + void Thread::LoadRegisters(CPU::InterruptRegisters* dest) + { + dest->rip = registers.rip; + dest->userrsp = registers.userrsp; + dest->rax = registers.rax; + dest->rbx = registers.rbx; + dest->rcx = registers.rcx; + dest->rdx = registers.rdx; + dest->rdi = registers.rdi; + dest->rsi = registers.rsi; + dest->rbp = registers.rbp; + dest->r8 = registers.r8; + dest->r9 = registers.r9; + dest->r10 = registers.r10; + dest->r11 = registers.r11; + dest->r12 = registers.r12; + dest->r13 = registers.r13; + dest->r14 = registers.r14; + dest->r15 = registers.r15; + dest->cs = registers.cs; + dest->ds = registers.ds; + dest->ss = registers.ss; + dest->rflags = registers.rflags; + } + + const size_t FLAGS_CARRY = (1<<0); + const size_t FLAGS_RESERVED1 = (1<<1); /* read as one */ + const size_t FLAGS_PARITY = (1<<2); + const size_t FLAGS_RESERVED2 = (1<<3); + const size_t FLAGS_AUX = (1<<4); + const size_t FLAGS_RESERVED3 = (1<<5); + const size_t FLAGS_ZERO = (1<<6); + const size_t FLAGS_SIGN = (1<<7); + const size_t FLAGS_TRAP = (1<<8); + const size_t FLAGS_INTERRUPT = (1<<9); + const size_t FLAGS_DIRECTION = (1<<10); + const size_t FLAGS_OVERFLOW = (1<<11); + const size_t FLAGS_IOPRIVLEVEL = (1<<12) | (1<<13); + const size_t FLAGS_NESTEDTASK = (1<<14); + const size_t FLAGS_RESERVED4 = (1<<15); + const size_t FLAGS_RESUME = (1<<16); + const size_t FLAGS_VIRTUAL8086 = (1<<17); + const size_t FLAGS_ALIGNCHECK = (1<<18); + const size_t FLAGS_VIRTINTR = (1<<19); + const size_t FLAGS_VIRTINTRPEND = (1<<20); + const size_t FLAGS_ID = (1<<21); + + void CreateThreadCPU(Thread* thread, addr_t entry) + { + const uint64_t CS = 0x18; + const uint64_t DS = 0x20; + const uint64_t RPL = 0x3; + + CPU::InterruptRegisters regs; + regs.rip = entry; + regs.userrsp = thread->stackpos + thread->stacksize; + regs.rax = 0; + regs.rbx = 0; + regs.rcx = 0; + regs.rdx = 0; + regs.rdi = 0; + regs.rsi = 0; + regs.rbp = thread->stackpos + thread->stacksize; + regs.r8 = 0; + regs.r9 = 0; + regs.r10 = 0; + regs.r11 = 0; + regs.r12 = 0; + regs.r13 = 0; + regs.r14 = 0; + regs.r15 = 0; + regs.cs = CS | RPL; + regs.ds = DS | RPL; + regs.ss = DS | RPL; + regs.rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + + thread->SaveRegisters(®s); + } + + void Thread::HandleSignalCPU(CPU::InterruptRegisters* regs) + { + regs->rdi = currentsignal->signum; + regs->rip = (size_t) sighandler; + } +} diff --git a/sortix/x64/x64.cpp b/sortix/x64/x64.cpp index f34d5db2..f102075e 100644 --- a/sortix/x64/x64.cpp +++ b/sortix/x64/x64.cpp @@ -24,10 +24,26 @@ #include #include "x64.h" +#include "log.h" namespace Sortix { namespace X64 { + void InterruptRegisters::LogRegisters() const + { + Log::PrintF("[cr2=0x%zx,ds=0x%zx,rdi=0x%zx,rsi=0x%zx,rbp=0x%zx," + "rsp=0x%zx,rbx=0x%zx,rcx=0x%zx,rax=0x%zx,r8=0x%zx," + "r9=0x%zx,r10=0x%zx,r11=0x%zx,r12=0x%zx,r13=0x%zx," + "r14=0x%zx,r15=0x%zx,int_no=0x%zx,err_code=0x%zx," + "rip=0x%zx,cs=0x%zx,rflags=0x%zx,userrsp=0x%zx," + "ss=0x%zx]", + cr2, ds, rdi, rsi, rbp, + rsp, rbx, rcx, rax, r8, + r9, r10, r11, r12, r13, + r14, r15, int_no, err_code, + rip, cs, rflags, userrsp, + ss); + } } } diff --git a/sortix/x64/x64.h b/sortix/x64/x64.h index 17c6abb0..b7ad489b 100644 --- a/sortix/x64/x64.h +++ b/sortix/x64/x64.h @@ -35,10 +35,23 @@ namespace Sortix { uint64_t cr2; uint64_t ds; // Data segment selector - uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax; // Pushed by pusha. - uint64_t r8, r9, r10, r11, r12, r13, r14, r15; // Pushed by pusha. + uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; uint64_t int_no, err_code; // Interrupt number and error code (if applicable) - uint64_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically. + uint64_t rip, cs, rflags, userrsp, ss; // Pushed by the processor automatically. + + public: + void LogRegisters() const; + }; + + struct SyscallRegisters + { + uint64_t cr2; // For compabillity with above, may be removed soon. + uint64_t ds; + uint64_t di, si, bp, trash, b, d, c; union { uint64_t a; uint64_t result; }; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; + uint64_t int_no, err_code; // Also compabillity. + uint64_t ip, cs, flags, sp, ss; }; } } diff --git a/sortix/x86-family/memorymanagement.cpp b/sortix/x86-family/memorymanagement.cpp index 9be88df5..cb3cb235 100644 --- a/sortix/x86-family/memorymanagement.cpp +++ b/sortix/x86-family/memorymanagement.cpp @@ -115,7 +115,7 @@ namespace Sortix // until the pebibyte era of RAM. if ( 0 < Page::pagesnotonstack ) { - Log::PrintF("%zu bytes of RAM aren't used due to technical" + Log::PrintF("%zu bytes of RAM aren't used due to technical " "restrictions.\n", Page::pagesnotonstack * 0x1000UL); } @@ -178,7 +178,10 @@ namespace Sortix // This call will also succeed, since there are plenty of physical // pages available and it might need some. - Memory::MapKernel(page, (addr_t) (STACK + stacklength)); + if ( !Memory::MapKernel(page, (addr_t) (STACK + stacklength)) ) + { + Panic("Unable to extend page stack, which should have worked"); + } // TODO: This may not be needed during the boot process! //Memory::InvalidatePage((addr_t) (STACK + stacklength)); @@ -345,6 +348,9 @@ namespace Sortix addr_t& entry = pml->entry[childid]; + // Find the index of the next PML in the fractal mapped memory. + size_t childoffset = offset * ENTRIES + childid; + if ( !(entry & PML_PRESENT) ) { // TODO: Possible memory leak when page allocation fails. @@ -353,7 +359,7 @@ namespace Sortix entry = page | flags; // Invalidate the new PML and reset it to zeroes. - addr_t pmladdr = (addr_t) (PMLS[i-1] + childid); + addr_t pmladdr = (addr_t) (PMLS[i-1] + childoffset); InvalidatePage(pmladdr); Maxsi::Memory::Set((void*) pmladdr, 0, sizeof(PML)); } @@ -365,8 +371,7 @@ namespace Sortix "code calling this function", physical, mapto, i-1); } - // Find the index of the next PML in the fractal mapped memory. - offset = offset * ENTRIES + childid; + offset = childoffset; } // Actually map the physical page to the virtual page. diff --git a/sortix/x86/memorymanagement.cpp b/sortix/x86/memorymanagement.cpp index a185512f..37fdddf9 100644 --- a/sortix/x86/memorymanagement.cpp +++ b/sortix/x86/memorymanagement.cpp @@ -106,6 +106,9 @@ namespace Sortix // up the address space of a process _before_ calling // DestroyAddressSpace. This is just a hack because it currently is // impossible to clean up PLM1's using the MM api! + // --- + // TODO: This function is duplicated in {x86,x64}/memorymanagement.cpp! + // --- void RecursiveFreeUserspacePages(size_t level, size_t offset) { PML* pml = PMLS[level] + offset; diff --git a/sortix/x86/process.cpp b/sortix/x86/process.cpp new file mode 100644 index 00000000..0095e841 --- /dev/null +++ b/sortix/x86/process.cpp @@ -0,0 +1,38 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with Sortix. If not, see . + + x86/process.cpp + CPU-specific process code. + +******************************************************************************/ + +#include "platform.h" +#include "process.h" + +namespace Sortix +{ + void Process::ExecuteCPU(int argc, char** argv, addr_t stackpos, addr_t entry, CPU::InterruptRegisters* regs) + { + regs->eax = argc; + regs->ebx = (size_t) argv; + regs->eip = entry; + regs->useresp = stackpos; + regs->ebp = stackpos; + } +}