Refactor kernel interrupt and thread register support.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-03-04 00:11:13 +01:00
parent c2f9c0bb12
commit 25e07a9083
39 changed files with 866 additions and 998 deletions

View File

@ -31,13 +31,13 @@ BOOTOBJS:=
ifeq ($(CPU),x86)
X86FAMILY:=1
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o $(CPU)/x86.o
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o
endif
ifeq ($(CPU),x64)
X86FAMILY:=1
CXXFLAGS:=$(CXXFLAGS) -mno-red-zone -mno-mmx -mno-sse -mno-sse2
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o $(CPU)/x64.o
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o
endif
ifdef X86FAMILY
@ -50,7 +50,6 @@ ifdef X86FAMILY
x86-family/gdt.o \
x86-family/idt.o \
$(CPU)/syscall.o \
$(CPU)/process.o \
x86-family/cmos.o \
x86-family/time.o \
x86-family/mtrr.o \
@ -124,6 +123,7 @@ pipe.o \
poll.o \
process.o \
refcount.o \
registers.o \
resource.o \
scheduler.o \
segment.o \

View File

@ -406,7 +406,7 @@ void DevCOMPort::OnInterrupt()
Ref<DevCOMPort> comdevices[1+NUMCOMPORTS];
static void UARTIRQHandler(CPU::InterruptRegisters* /*regs*/, void* /*user*/)
static void UARTIRQHandler(struct interrupt_context* /*intctx*/, void* /*user*/)
{
for ( size_t i = 1; i <= NUMCOMPORTS; i++ )
{

View File

@ -337,14 +337,12 @@ int ThreadId(Thread* thread)
int main_bt(int /*argc*/, char* /*argv*/[])
{
CPU::InterruptRegisters regs;
current_thread->LoadRegisters(&regs);
#if defined(__x86_64__)
unsigned long ip = regs.rip;
unsigned long bp = regs.rbp;
unsigned long ip = current_thread->registers.rip;
unsigned long bp = current_thread->registers.rbp;
#elif defined(__i386__)
unsigned long ip = regs.eip;
unsigned long bp = regs.ebp;
unsigned long ip = current_thread->registers.eip;
unsigned long bp = current_thread->registers.ebp;
#endif
bool userspace = false;
@ -434,7 +432,7 @@ int main_pid(int argc, char* argv[])
return 1;
}
current_thread = process->firstthread;
Memory::SwitchAddressSpace(current_thread->addrspace);
Memory::SwitchAddressSpace(current_thread->registers.cr3);
}
Print("%c %i\t`%s'\n", '*', (int) current_process->pid,
current_process->program_image_path);
@ -455,54 +453,48 @@ int main_ps(int /*argc*/, char* /*argv*/[])
int main_rs(int /*argc*/, char* /*argv*/[])
{
CPU::InterruptRegisters regs;
current_thread->LoadRegisters(&regs);
#if defined(__x86_64__)
Print("rax=0x%lx, ", regs.rax);
Print("rbx=0x%lx, ", regs.rbx);
Print("rcx=0x%lx, ", regs.rcx);
Print("rdx=0x%lx, ", regs.rdx);
Print("rdi=0x%lx, ", regs.rdi);
Print("rsi=0x%lx, ", regs.rsi);
Print("rsp=0x%lx, ", regs.rsp);
Print("rbp=0x%lx, ", regs.rbp);
Print("r8=0x%lx, ", regs.r8);
Print("r9=0x%lx, ", regs.r9);
Print("r10=0x%lx, ", regs.r10);
Print("r11=0x%lx, ", regs.r11);
Print("r12=0x%lx, ", regs.r12);
Print("r13=0x%lx, ", regs.r13);
Print("r14=0x%lx, ", regs.r14);
Print("r15=0x%lx, ", regs.r15);
Print("rip=0x%lx, ", regs.rip);
Print("rflags=0x%lx, ", regs.rflags);
Print("int_no=%lu, ", regs.int_no);
Print("err_code=0x%lx, ", regs.err_code);
Print("cs=0x%lx, ", regs.cs);
Print("ds=0x%lx, ", regs.ds);
Print("ss=0x%lx, ", regs.ss);
Print("kerrno=%lu, ", regs.kerrno);
Print("cr2=%lx, ", regs.cr2);
Print("signal_pending=%lu.", regs.signal_pending);
Print("rax=0x%lX, ", current_thread->registers.rax);
Print("rbx=0x%lX, ", current_thread->registers.rbx);
Print("rcx=0x%lX, ", current_thread->registers.rcx);
Print("rdx=0x%lX, ", current_thread->registers.rdx);
Print("rdi=0x%lX, ", current_thread->registers.rdi);
Print("rsi=0x%lX, ", current_thread->registers.rsi);
Print("rsp=0x%lX, ", current_thread->registers.rsp);
Print("rbp=0x%lX, ", current_thread->registers.rbp);
Print("r8=0x%lX, ", current_thread->registers.r8);
Print("r9=0x%lX, ", current_thread->registers.r9);
Print("r10=0x%lX, ", current_thread->registers.r10);
Print("r11=0x%lX, ", current_thread->registers.r11);
Print("r12=0x%lX, ", current_thread->registers.r12);
Print("r13=0x%lX, ", current_thread->registers.r13);
Print("r14=0x%lX, ", current_thread->registers.r14);
Print("r15=0x%lX, ", current_thread->registers.r15);
Print("rip=0x%lX, ", current_thread->registers.rip);
Print("rflags=0x%lX, ", current_thread->registers.rflags);
Print("fsbase=0x%lX, ", current_thread->registers.fsbase);
Print("gsbase=0x%lX, ", current_thread->registers.gsbase);
Print("cr3=0x%lX, ", current_thread->registers.cr3);
Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack);
Print("kerrno=%lu, ", current_thread->registers.kerrno);
Print("signal_pending=%lu.", current_thread->registers.signal_pending);
#elif defined(__i386__)
Print("eax=0x%lx, ", regs.eax);
Print("ebx=0x%lx, ", regs.ebx);
Print("ecx=0x%lx, ", regs.ecx);
Print("edx=0x%lx, ", regs.edx);
Print("edi=0x%lx, ", regs.edi);
Print("esi=0x%lx, ", regs.esi);
Print("esp=0x%lx, ", regs.esp);
Print("ebp=0x%lx, ", regs.ebp);
Print("eip=0x%lx, ", regs.eip);
Print("eflags=0x%lx, ", regs.eflags);
Print("int_no=%lu, ", regs.int_no);
Print("err_code=0x%lx, ", regs.err_code);
Print("cs=0x%lx, ", regs.cs);
Print("ds=0x%lx, ", regs.ds);
Print("ss=0x%lx, ", regs.ss);
Print("kerrno=%lu, ", regs.kerrno);
Print("cr2=%lx, ", regs.cr2);
Print("signal_pending=%lu.", regs.signal_pending);
Print("eax=0x%lX, ", current_thread->registers.eax);
Print("ebx=0x%lX, ", current_thread->registers.ebx);
Print("ecx=0x%lX, ", current_thread->registers.ecx);
Print("edx=0x%lX, ", current_thread->registers.edx);
Print("edi=0x%lX, ", current_thread->registers.edi);
Print("esi=0x%lX, ", current_thread->registers.esi);
Print("esp=0x%lX, ", current_thread->registers.esp);
Print("ebp=0x%lX, ", current_thread->registers.ebp);
Print("eip=0x%lX, ", current_thread->registers.eip);
Print("eflags=0x%lX, ", current_thread->registers.eflags);
Print("fsbase=0x%lX, ", current_thread->registers.fsbase);
Print("gsbase=0x%lX, ", current_thread->registers.gsbase);
Print("cr3=0x%lX, ", current_thread->registers.cr3);
Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack);
Print("kerrno=%lX, ", current_thread->registers.kerrno);
Print("signal_pending=%lu.", current_thread->registers.signal_pending);
#endif
Print("\n");
return 0;
@ -510,12 +502,10 @@ int main_rs(int /*argc*/, char* /*argv*/[])
static void DescribeThread(int tid, Thread* thread)
{
CPU::InterruptRegisters regs;
thread->LoadRegisters(&regs);
#if defined(__x86_64__)
unsigned long ip = regs.rip;
unsigned long ip = thread->registers.rip;
#elif defined(__i386__)
unsigned long ip = regs.eip;
unsigned long ip = thread->registers.eip;
#endif
Print("%c ", thread == current_thread ? '*' : ' ');
@ -538,7 +528,7 @@ int main_tid(int argc, char* argv[])
return 1;
}
current_thread = thread;
Memory::SwitchAddressSpace(current_thread->addrspace);
Memory::SwitchAddressSpace(current_thread->registers.cr3);
}
DescribeThread(ThreadId(current_thread), current_thread);
return 0;
@ -624,7 +614,7 @@ void Run()
first_f10 = true;
addr_t saved_addrspace = current_thread->addrspace;
addr_t saved_addrspace = current_thread->registers.cr3;
memcpy(saved_video_memory, VIDEO_MEMORY, sizeof(saved_video_memory));
int saved_x, saved_y;

View File

@ -40,92 +40,6 @@ void ShutDown();
} // namespace CPU
#endif
// CPU flag register bits for 32-bit and 64-bit x86.
#if defined(__i386__) || defined(__x86_64__)
const size_t FLAGS_CARRY = 1<<0; // 0x000001
const size_t FLAGS_RESERVED1 = 1<<1; // 0x000002, read as one
const size_t FLAGS_PARITY = 1<<2; // 0x000004
const size_t FLAGS_RESERVED2 = 1<<3; // 0x000008
const size_t FLAGS_AUX = 1<<4; // 0x000010
const size_t FLAGS_RESERVED3 = 1<<5; // 0x000020
const size_t FLAGS_ZERO = 1<<6; // 0x000040
const size_t FLAGS_SIGN = 1<<7; // 0x000080
const size_t FLAGS_TRAP = 1<<8; // 0x000100
const size_t FLAGS_INTERRUPT = 1<<9; // 0x000200
const size_t FLAGS_DIRECTION = 1<<10; // 0x000400
const size_t FLAGS_OVERFLOW = 1<<11; // 0x000800
const size_t FLAGS_IOPRIVLEVEL = 1<<12 | 1<<13;
const size_t FLAGS_NESTEDTASK = 1<<14; // 0x004000
const size_t FLAGS_RESERVED4 = 1<<15; // 0x008000
const size_t FLAGS_RESUME = 1<<16; // 0x010000
const size_t FLAGS_VIRTUAL8086 = 1<<17; // 0x020000
const size_t FLAGS_ALIGNCHECK = 1<<18; // 0x040000
const size_t FLAGS_VIRTINTR = 1<<19; // 0x080000
const size_t FLAGS_VIRTINTRPEND = 1<<20; // 0x100000
const size_t FLAGS_ID = 1<<21; // 0x200000
#endif
// x86 interrupt registers structure.
#if defined(__i386__)
namespace X86 {
struct InterruptRegisters
{
uint32_t signal_pending, kerrno, cr2;
uint32_t ds; // Data segment selector
uint32_t edi, esi, ebp, not_esp, ebx, edx, ecx, eax; // Pushed by pusha.
uint32_t int_no, err_code; // Interrupt number and error code (if applicable)
uint32_t eip, cs, eflags, esp, ss; // Pushed by the processor automatically.
public:
void LogRegisters() const;
bool InUserspace() const { return (cs & 0x3) != 0; }
};
} // namespace X86
#endif
// x86_64 interrupt
#if defined(__x86_64__)
namespace X64 {
struct InterruptRegisters
{
uint64_t signal_pending, kerrno, cr2;
uint64_t ds; // Data segment selector
uint64_t rdi, rsi, rbp, not_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 rip, cs, rflags, rsp, ss; // Pushed by the processor automatically.
public:
void LogRegisters() const;
bool InUserspace() const { return (cs & 0x3) != 0; }
};
} // namespace X64
#endif
// Segment values for 32-bit and 64-bit x86.
#if defined(__i386__) || defined(__x86_64__)
const uint64_t KCS = 0x08;
const uint64_t KDS = 0x10;
const uint64_t KRPL = 0x0;
const uint64_t UCS = 0x18;
const uint64_t UDS = 0x20;
const uint64_t URPL = 0x3;
#endif
// Portable functions for loading registers.
namespace CPU {
extern "C" __attribute__((noreturn))
void load_registers(InterruptRegisters* regs, size_t size);
__attribute__((noreturn))
inline void LoadRegisters(InterruptRegisters* regs)
{
load_registers(regs, sizeof(*regs));
}
} // namespace CPU
} // namespace Sortix
#endif

View File

@ -28,14 +28,7 @@
#include <stddef.h>
#include <sortix/kernel/decl.h>
namespace Sortix {
namespace CPU {
struct InterruptRegisters;
} // namespace CPU
} // namespace Sortix
#include <sortix/kernel/registers.h>
namespace Sortix {
namespace Interrupt {
@ -108,7 +101,7 @@ inline bool SetEnabled(bool is_enabled)
}
typedef void (*Handler)(CPU::InterruptRegisters* regs, void* user);
typedef void (*Handler)(struct interrupt_context* intctx, void* user);
void RegisterHandler(unsigned int index, Handler handler, void* user);
void Init();

View File

@ -77,9 +77,7 @@ void Flush();
addr_t Fork();
addr_t GetAddressSpace();
addr_t SwitchAddressSpace(addr_t addrspace);
void DestroyAddressSpace(addr_t fallback = 0,
void (*func)(addr_t, void*) = NULL,
void* user = NULL);
void DestroyAddressSpace(addr_t fallback = 0);
bool Map(addr_t physical, addr_t mapto, int prot);
addr_t Unmap(addr_t mapto);
addr_t Physical(addr_t mapto);

View File

@ -34,6 +34,7 @@
#include <sortix/kernel/clock.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/registers.h>
#include <sortix/kernel/segment.h>
#include <sortix/kernel/time.h>
#include <sortix/kernel/timer.h>
@ -168,7 +169,7 @@ public:
int Execute(const char* programname, const uint8_t* program,
size_t programsize, int argc, const char* const* argv,
int envc, const char* const* envp,
CPU::InterruptRegisters* regs);
struct thread_registers* regs);
void ResetAddressSpace();
void ExitThroughSignal(int signal);
void ExitWithCode(int exit_code);
@ -187,9 +188,6 @@ public:
Process* Fork();
private:
void ExecuteCPU(int argc, char** argv, int envc, char** envp,
addr_t stackpos, addr_t entry,
CPU::InterruptRegisters* regs);
void OnLastThreadExit();
void LastPrayer();
void NotifyMemberExit(Process* child);
@ -212,8 +210,6 @@ private:
};
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
const struct tfork* requested);
Process* CurrentProcess();
} // namespace Sortix

View File

@ -0,0 +1,207 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
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 <http://www.gnu.org/licenses/>.
sortix/kernel/registers.h
Register structures and platform-specific bits.
*******************************************************************************/
#ifndef INCLUDE_SORTIX_KERNEL_REGISTERS_H
#define INCLUDE_SORTIX_KERNEL_REGISTERS_H
#include <stddef.h>
#include <stdint.h>
namespace Sortix {
// CPU flag register bits for 32-bit and 64-bit x86.
#if defined(__i386__) || defined(__x86_64__)
const size_t FLAGS_CARRY = 1 << 0; // 0x000001
const size_t FLAGS_RESERVED1 = 1 << 1; // 0x000002, read as one
const size_t FLAGS_PARITY = 1 << 2; // 0x000004
const size_t FLAGS_RESERVED2 = 1 << 3; // 0x000008
const size_t FLAGS_AUX = 1 << 4; // 0x000010
const size_t FLAGS_RESERVED3 = 1 << 5; // 0x000020
const size_t FLAGS_ZERO = 1 << 6; // 0x000040
const size_t FLAGS_SIGN = 1 << 7; // 0x000080
const size_t FLAGS_TRAP = 1 << 8; // 0x000100
const size_t FLAGS_INTERRUPT = 1 << 9; // 0x000200
const size_t FLAGS_DIRECTION = 1 << 10; // 0x000400
const size_t FLAGS_OVERFLOW = 1 << 11; // 0x000800
const size_t FLAGS_IOPRIVLEVEL = 1 << 12 | 1 << 13;
const size_t FLAGS_NESTEDTASK = 1 << 14; // 0x004000
const size_t FLAGS_RESERVED4 = 1 << 15; // 0x008000
const size_t FLAGS_RESUME = 1 << 16; // 0x010000
const size_t FLAGS_VIRTUAL8086 = 1 << 17; // 0x020000
const size_t FLAGS_ALIGNCHECK = 1 << 18; // 0x040000
const size_t FLAGS_VIRTINTR = 1 << 19; // 0x080000
const size_t FLAGS_VIRTINTRPEND = 1 << 20; // 0x100000
const size_t FLAGS_ID = 1 << 21; // 0x200000
#endif
// i386 registers structures.
#if defined(__i386__)
const uint32_t KCS = 0x08;
const uint32_t KDS = 0x10;
const uint32_t KRPL = 0x0;
const uint32_t UCS = 0x18;
const uint32_t UDS = 0x20;
const uint32_t URPL = 0x3;
const uint32_t RPLMASK = 0x3;
struct interrupt_context
{
uint32_t signal_pending;
uint32_t kerrno;
uint32_t cr2;
uint32_t ds;
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t not_esp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t int_no;
uint32_t err_code;
uint32_t eip;
uint32_t cs;
uint32_t eflags;
uint32_t esp;
uint32_t ss;
};
__attribute__((unused))
static inline bool InUserspace(const struct interrupt_context* intctx)
{
return (intctx->cs & RPLMASK) != KRPL;
}
struct thread_registers
{
uint32_t signal_pending;
uint32_t kerrno;
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t edi;
uint32_t esi;
uint32_t esp;
uint32_t ebp;
uint32_t eip;
uint32_t eflags;
uint32_t fsbase;
uint32_t gsbase;
uint32_t cr3;
uint32_t kernel_stack;
uint32_t cs;
uint32_t ds;
uint32_t ss;
__attribute__((aligned(16))) uint8_t fpuenv[512];
};
#endif
// x86_64 registers structures.
#if defined(__x86_64__)
const uint64_t KCS = 0x08;
const uint64_t KDS = 0x10;
const uint64_t KRPL = 0x0;
const uint64_t UCS = 0x18;
const uint64_t UDS = 0x20;
const uint64_t URPL = 0x3;
const uint64_t RPLMASK = 0x3;
struct interrupt_context
{
uint64_t signal_pending;
uint64_t kerrno;
uint64_t cr2;
uint64_t ds;
uint64_t rdi;
uint64_t rsi;
uint64_t rbp;
uint64_t not_rsp;
uint64_t rbx;
uint64_t rdx;
uint64_t rcx;
uint64_t rax;
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
uint64_t int_no;
uint64_t err_code;
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
};
__attribute__((unused))
static inline bool InUserspace(const struct interrupt_context* intctx)
{
return (intctx->cs & RPLMASK) != KRPL;
}
struct thread_registers
{
uint64_t signal_pending;
uint64_t kerrno;
uint64_t rax;
uint64_t rbx;
uint64_t rcx;
uint64_t rdx;
uint64_t rdi;
uint64_t rsi;
uint64_t rsp;
uint64_t rbp;
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
uint64_t rip;
uint64_t rflags;
uint64_t fsbase;
uint64_t gsbase;
uint64_t cr3;
uint64_t kernel_stack;
uint64_t cs;
uint64_t ds;
uint64_t ss;
__attribute__((aligned(16))) uint8_t fpuenv[512];
};
#endif
void LogInterruptContext(const struct interrupt_context* intctx);
__attribute__((noreturn))
void LoadRegisters(const struct thread_registers* registers);
} // namespace Sortix
#endif

View File

@ -26,18 +26,13 @@
#define INCLUDE_SORTIX_KERNEL_SCHEDULER_H
#include <sortix/kernel/decl.h>
#include <sortix/kernel/registers.h>
namespace Sortix {
class Process;
class Thread;
} // namespace Sortix
namespace Sortix {
namespace CPU {
struct InterruptRegisters;
} // namespace CPU
} // namespace Sortix
namespace Sortix {
enum ThreadState { NONE, RUNNABLE, BLOCKING, DEAD };
} // namespace Sortix
@ -59,15 +54,19 @@ static inline void ExitThread()
#endif
void Init();
void Switch(CPU::InterruptRegisters* regs);
void Switch(struct interrupt_context* intctx);
void SetThreadState(Thread* thread, ThreadState state);
ThreadState GetThreadState(Thread* thread);
void SetIdleThread(Thread* thread);
void SetInitProcess(Process* init);
Process* GetInitProcess();
Process* GetKernelProcess();
void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* user);
void ThreadExitCPU(CPU::InterruptRegisters* regs, void* user);
void InterruptYieldCPU(struct interrupt_context* intctx, void* user);
void ThreadExitCPU(struct interrupt_context* intctx, void* user);
void SaveInterruptedContext(const struct interrupt_context* intctx,
struct thread_registers* registers);
void LoadInterruptedContext(struct interrupt_context* intctx,
const struct thread_registers* registers);
} // namespace Scheduler
} // namespace Sortix

View File

@ -29,6 +29,7 @@
#include <sortix/sigset.h>
#include <sortix/kernel/cpu.h>
#include <sortix/kernel/registers.h>
namespace Sortix {
@ -38,8 +39,8 @@ namespace Signal {
void Init();
inline bool IsPending() { return asm_signal_is_pending != 0; }
void DispatchHandler(CPU::InterruptRegisters* regs, void* user);
void ReturnHandler(CPU::InterruptRegisters* regs, void* user);
void DispatchHandler(struct interrupt_context* intctx, void* user);
void ReturnHandler(struct interrupt_context* intctx, void* user);
} // namespace Signal

View File

@ -31,6 +31,7 @@
#include <sortix/stack.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/registers.h>
#include <sortix/kernel/scheduler.h>
#include <sortix/kernel/signal.h>
@ -40,8 +41,7 @@ class Process;
class Thread;
// These functions create a new kernel process but doesn't start it.
Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
unsigned long fsbase, unsigned long gsbase);
Thread* CreateKernelThread(Process* process, struct thread_registers* regs);
Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user,
size_t stacksize = 0);
Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0);
@ -50,18 +50,13 @@ Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize =
void StartKernelThread(Thread* thread);
// Alternatively, these functions both create and start the thread.
Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs);
Thread* RunKernelThread(Process* process, struct thread_registers* regs);
Thread* RunKernelThread(Process* process, void (*entry)(void*), void* user,
size_t stacksize = 0);
Thread* RunKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0);
class Thread
{
friend Thread* CreateKernelThread(Process* process,
CPU::InterruptRegisters* regs,
unsigned long fsbase, unsigned long gsbase);
friend void UpdatePendingSignals(Thread* thread);
public:
static void Init();
@ -70,49 +65,34 @@ public:
~Thread();
public:
struct thread_registers registers;
uint8_t* self_allocation;
size_t id;
Process* process;
Thread* prevsibling;
Thread* nextsibling;
public:
Thread* scheduler_list_prev;
Thread* scheduler_list_next;
volatile ThreadState state;
uint8_t fpuenv[512UL + 16UL];
uint8_t* fpuenvaligned;
bool fpuinitialized;
public:
sigset_t signal_pending;
sigset_t signal_mask;
stack_t signal_stack;
addr_t addrspace;
addr_t kernelstackpos;
size_t kernelstacksize;
bool kernelstackmalloced;
bool pledged_destruction;
#if defined(__i386__) || defined(__x86_64__)
public:
unsigned long fsbase;
unsigned long gsbase;
#endif
private:
CPU::InterruptRegisters registers;
public:
void SaveRegisters(const CPU::InterruptRegisters* src);
void LoadRegisters(CPU::InterruptRegisters* dest);
void HandleSignal(CPU::InterruptRegisters* regs);
void HandleSigreturn(CPU::InterruptRegisters* regs);
void HandleSignal(struct interrupt_context* intctx);
void HandleSigreturn(struct interrupt_context* intctx);
bool DeliverSignal(int signum);
bool DeliverSignalUnlocked(int signum);
addr_t SwitchAddressSpace(addr_t newaddrspace);
};
Thread* AllocateThread();
void FreeThread(Thread* thread);
Thread* CurrentThread();
} // namespace Sortix

View File

@ -39,6 +39,7 @@
#include <sortix/kernel/ioport.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/keyboard.h>
#include <sortix/kernel/scheduler.h>
#include <sortix/kernel/thread.h>
#if defined(__i386__)
@ -57,9 +58,9 @@ const uint8_t LED_SCRLCK = 1 << 0;
const uint8_t LED_NUMLCK = 1 << 1;
const uint8_t LED_CAPSLCK = 1 << 2;
void PS2Keyboard__OnInterrupt(CPU::InterruptRegisters* regs, void* user)
void PS2Keyboard__OnInterrupt(struct interrupt_context* intctx, void* user)
{
((PS2Keyboard*) user)->OnInterrupt(regs);
((PS2Keyboard*) user)->OnInterrupt(intctx);
}
PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt)
@ -100,20 +101,12 @@ static void PS2Keyboard__InterruptWork(void* kb_ptr, void* payload, size_t size)
((PS2Keyboard*) kb_ptr)->InterruptWork(work->scancode);
}
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs)
void PS2Keyboard::OnInterrupt(struct interrupt_context* intctx)
{
uint8_t scancode = PopScancode();
if ( scancode == KBKEY_F10 )
{
Thread* thread = CurrentThread();
#if defined(__i386__)
thread->fsbase = (unsigned long) GDT::GetFSBase();
thread->gsbase = (unsigned long) GDT::GetGSBase();
#elif defined(__x86_64__)
thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
#endif
thread->SaveRegisters(regs);
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
Debugger::Run();
}
PS2KeyboardWork work;

View File

@ -44,7 +44,7 @@ public:
virtual void SetOwner(KeyboardOwner* owner, void* user);
public:
void OnInterrupt(CPU::InterruptRegisters* regs);
void OnInterrupt(struct interrupt_context* intctx);
void InterruptWork(uint8_t scancode);
private:

View File

@ -104,7 +104,7 @@
// Keep the stack size aligned with $CPU/base.s
const size_t STACK_SIZE = 64*1024;
extern "C" { size_t stack[STACK_SIZE / sizeof(size_t)] = {0}; }
extern "C" { __attribute__((aligned(16))) size_t stack[STACK_SIZE / sizeof(size_t)]; }
namespace Sortix {
@ -290,6 +290,7 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Initialize the GDT and TSS structures.
GDT::Init();
GDT::SetKernelStack((uintptr_t) stack + STACK_SIZE);
// Initialize the interrupt handler table and enable interrupts.
Interrupt::Init();
@ -436,9 +437,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Now that the base system has been loaded, it's time to go threaded. First
// we create an object that represents this thread.
Process* system = new Process;
if ( !system ) { Panic("Could not allocate the system process"); }
addr_t systemaddrspace = Memory::GetAddressSpace();
system->addrspace = systemaddrspace;
if ( !system )
Panic("Could not allocate the system process");
system->addrspace = Memory::GetAddressSpace();
system->group = system;
system->groupprev = NULL;
system->groupnext = NULL;
@ -451,13 +452,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// create a kernel thread that is the current thread and isn't put into the
// scheduler's set of runnable threads, but rather run whenever there is
// _nothing_ else to run on this CPU.
Thread* idlethread = new Thread;
Thread* idlethread = AllocateThread();
idlethread->process = system;
idlethread->addrspace = idlethread->process->addrspace;
idlethread->kernelstackpos = (addr_t) stack;
idlethread->kernelstacksize = STACK_SIZE;
idlethread->kernelstackmalloced = false;
idlethread->fpuinitialized = true;
system->firstthread = idlethread;
Scheduler::SetIdleThread(idlethread);
@ -467,9 +466,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// we must become the system idle thread.
RunKernelThread(BootThread, NULL);
// Set up such that floating point registers are lazily switched.
Float::Init();
// The time driver will run the scheduler on the next timer interrupt.
Time::Start();
@ -766,7 +762,8 @@ static void InitThread(void* /*user*/)
const char* cputype = "cputype=" CPUTYPE_STR;
int envc = 1;
const char* envp[] = { cputype, NULL };
CPU::InterruptRegisters regs;
struct thread_registers regs;
assert((((uintptr_t) &regs) & (alignof(regs)-1)) == 0);
if ( process->Execute(initpath, program, programsize, argc, argv, envc,
envp, &regs) )
@ -775,7 +772,7 @@ static void InitThread(void* /*user*/)
delete[] program;
// Now become the init process and the operation system shall run.
CPU::LoadRegisters(&regs);
LoadRegisters(&regs);
}
} // namespace Sortix

View File

@ -39,7 +39,7 @@ static void kthread_do_kill_thread(void* user)
Thread* thread = (Thread*) user;
while ( thread->state != ThreadState::DEAD )
kthread_yield();
delete thread;
FreeThread(thread);
}
extern "C" void kthread_exit()

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
This file is part of Sortix.

View File

@ -67,6 +67,7 @@
#include "initrd.h"
#if defined(__i386__) || defined(__x86_64__)
#include "x86-family/float.h"
#include "x86-family/gdt.h"
#endif
@ -249,11 +250,6 @@ void Process::OnLastThreadExit()
LastPrayer();
}
static void SwitchCurrentAddrspace(addr_t addrspace, void* user)
{
((Thread*) user)->SwitchAddressSpace(addrspace);
}
void Process::DeleteTimers()
{
for ( timer_t i = 0; i < PROCESS_TIMER_NUM_MAX; i++ )
@ -290,7 +286,7 @@ void Process::LastPrayer()
// We need to temporarily reload the correct addrese space of the dying
// process such that we can unmap and free its memory.
addr_t prevaddrspace = curthread->SwitchAddressSpace(addrspace);
addr_t prevaddrspace = Memory::SwitchAddressSpace(addrspace);
ResetAddressSpace();
@ -301,9 +297,7 @@ void Process::LastPrayer()
// Destroy the address space and safely switch to the replacement
// address space before things get dangerous.
Memory::DestroyAddressSpace(prevaddrspace,
SwitchCurrentAddrspace,
curthread);
Memory::DestroyAddressSpace(prevaddrspace);
addrspace = 0;
// Unload the process symbol and string tables.
@ -814,7 +808,7 @@ bool Process::MapSegment(struct segment* result, void* hint, size_t size,
int Process::Execute(const char* programname, const uint8_t* program,
size_t programsize, int argc, const char* const* argv,
int envc, const char* const* envp,
CPU::InterruptRegisters* regs)
struct thread_registers* regs)
{
assert(argc != INT_MAX);
assert(envc != INT_MAX);
@ -969,10 +963,43 @@ int Process::Execute(const char* programname, const uint8_t* program,
uthread->arg_size = arg_segment.size;
memset(uthread + 1, 0, aux.uthread_size - sizeof(struct uthread));
memset(regs, 0, sizeof(*regs));
#if defined(__i386__)
GDT::SetGSBase((uint32_t) uthread);
regs->eax = argc;
regs->ebx = (size_t) target_argv;
regs->edx = envc;
regs->ecx = (size_t) target_envp;
regs->eip = entry;
regs->esp = (stack_segment.addr + stack_segment.size) & ~15UL;
regs->ebp = regs->esp;
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->signal_pending = 0;
regs->gsbase = (uint32_t) uthread;
regs->cr3 = addrspace;
regs->kernel_stack = GDT::GetKernelStack();
memcpy(regs->fpuenv, Float::fpu_initialized_regs, 512);
#elif defined(__x86_64__)
wrmsr(MSRID_FSBASE, (uint64_t) uthread);
regs->rdi = argc;
regs->rsi = (size_t) target_argv;
regs->rdx = envc;
regs->rcx = (size_t) target_envp;
regs->rip = entry;
regs->rsp = (stack_segment.addr + stack_segment.size) & ~15UL;
regs->rbp = regs->rsp;
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->signal_pending = 0;
regs->fsbase = (uint64_t) uthread;
regs->cr3 = addrspace;
regs->kernel_stack = GDT::GetKernelStack();
memcpy(regs->fpuenv, Float::fpu_initialized_regs, 512);
#else
#warning "You need to implement initializing the first thread after execute"
#endif
uint8_t* auxcode = (uint8_t*) auxcode_segment.addr;
@ -991,8 +1018,6 @@ int Process::Execute(const char* programname, const uint8_t* program,
dtable->OnExecute();
ExecuteCPU(argc, target_argv, envc, target_envp, stack_segment.addr + stack_segment.size, entry, regs);
return 0;
}
@ -1002,7 +1027,7 @@ int sys_execve_kernel(const char* filename,
char* const argv[],
int envc,
char* const envp[],
CPU::InterruptRegisters* regs)
struct thread_registers* regs)
{
Process* process = CurrentProcess();
@ -1054,7 +1079,7 @@ int sys_execve(const char* user_filename,
char** argv;
char** envp;
int result = -1;
CPU::InterruptRegisters regs;
struct thread_registers regs;
memset(&regs, 0, sizeof(regs));
if ( !user_filename || !user_argv || !user_envp )
@ -1135,7 +1160,7 @@ cleanup_filename:
delete[] filename;
cleanup_done:
if ( result == 0 )
CPU::LoadRegisters(&regs);
LoadRegisters(&regs);
return result;
}
@ -1158,15 +1183,22 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
if ( regs.altstack.ss_flags & ~__SS_SUPPORTED_FLAGS )
return errno = EINVAL, -1;
CPU::InterruptRegisters cpuregs;
InitializeThreadRegisters(&cpuregs, &regs);
size_t stack_alignment = 16;
// TODO: Is it a hack to create a new kernel stack here?
Thread* curthread = CurrentThread();
uint8_t* newkernelstack = new uint8_t[curthread->kernelstacksize];
size_t newkernelstacksize = curthread->kernelstacksize;
uint8_t* newkernelstack = new uint8_t[newkernelstacksize + stack_alignment];
if ( !newkernelstack )
return -1;
uintptr_t stack_aligned = (uintptr_t) newkernelstack;
size_t stack_aligned_size = newkernelstacksize;
if ( ((uintptr_t) stack_aligned) & (stack_alignment-1) )
stack_aligned = (stack_aligned + 16) & ~(stack_alignment-1);
stack_aligned_size &= 0xFFFFFFF0;
Process* child_process;
if ( making_thread )
child_process = CurrentProcess();
@ -1176,10 +1208,59 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
return -1;
}
struct thread_registers cpuregs;
memset(&cpuregs, 0, sizeof(cpuregs));
#if defined(__i386__)
cpuregs.eip = regs.eip;
cpuregs.esp = regs.esp;
cpuregs.eax = regs.eax;
cpuregs.ebx = regs.ebx;
cpuregs.ecx = regs.ecx;
cpuregs.edx = regs.edx;
cpuregs.edi = regs.edi;
cpuregs.esi = regs.esi;
cpuregs.ebp = regs.ebp;
cpuregs.cs = UCS | URPL;
cpuregs.ds = UDS | URPL;
cpuregs.ss = UDS | URPL;
cpuregs.eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
cpuregs.fsbase = regs.fsbase;
cpuregs.gsbase = regs.gsbase;
cpuregs.cr3 = child_process->addrspace;
cpuregs.kernel_stack = stack_aligned + stack_aligned_size;
#elif defined(__x86_64__)
cpuregs.rip = regs.rip;
cpuregs.rsp = regs.rsp;
cpuregs.rax = regs.rax;
cpuregs.rbx = regs.rbx;
cpuregs.rcx = regs.rcx;
cpuregs.rdx = regs.rdx;
cpuregs.rdi = regs.rdi;
cpuregs.rsi = regs.rsi;
cpuregs.rbp = regs.rbp;
cpuregs.r8 = regs.r8;
cpuregs.r9 = regs.r9;
cpuregs.r10 = regs.r10;
cpuregs.r11 = regs.r11;
cpuregs.r12 = regs.r12;
cpuregs.r13 = regs.r13;
cpuregs.r14 = regs.r14;
cpuregs.r15 = regs.r15;
cpuregs.cs = UCS | URPL;
cpuregs.ds = UDS | URPL;
cpuregs.ss = UDS | URPL;
cpuregs.rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
cpuregs.fsbase = regs.fsbase;
cpuregs.gsbase = regs.gsbase;
cpuregs.cr3 = child_process->addrspace;
cpuregs.kernel_stack = stack_aligned + stack_aligned_size;
#else
#warning "You need to implement initializing the registers of the new thread"
#endif
// If the thread could not be created, make the process commit suicide
// in a manner such that we don't wait for its zombie.
Thread* thread = CreateKernelThread(child_process, &cpuregs, regs.fsbase,
regs.gsbase);
Thread* thread = CreateKernelThread(child_process, &cpuregs);
if ( !thread )
{
if ( making_process )
@ -1188,7 +1269,7 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
}
thread->kernelstackpos = (addr_t) newkernelstack;
thread->kernelstacksize = curthread->kernelstacksize;
thread->kernelstacksize = newkernelstacksize;
thread->kernelstackmalloced = true;
memcpy(&thread->signal_mask, &regs.sigmask, sizeof(sigset_t));
memcpy(&thread->signal_stack, &regs.altstack, sizeof(stack_t));

76
kernel/registers.cpp Normal file
View File

@ -0,0 +1,76 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
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 <http://www.gnu.org/licenses/>.
registers.cpp
Register structures and platform-specific bits.
*******************************************************************************/
#include <stdint.h>
#include <sortix/kernel/log.h>
#include <sortix/kernel/registers.h>
#include <sortix/kernel/scheduler.h>
namespace Sortix {
void LogInterruptContext(const struct interrupt_context* intctx)
{
#if defined(__i386__)
Log::PrintF("[cr2=0x%zx,ds=0x%zx,edi=0x%zx,esi=0x%zx,ebp=0x%zx,"
"ebx=0x%zx,edx=0x%zx,ecx=0x%zx,eax=0x%zx,"
"int_no=0x%zx,err_code=0x%zx,eip=0x%zx,cs=0x%zx,"
"eflags=0x%zx,esp=0x%zx,ss=0x%zx]",
intctx->cr2, intctx->ds, intctx->edi, intctx->esi, intctx->ebp,
intctx->ebx, intctx->edx, intctx->ecx, intctx->eax,
intctx->int_no, intctx->err_code, intctx->eip, intctx->cs,
intctx->eflags, intctx->esp, intctx->ss);
#elif defined(__x86_64__)
Log::PrintF("[cr2=0x%zx,ds=0x%zx,rdi=0x%zx,rsi=0x%zx,rbp=0x%zx,"
"rbx=0x%zx,rdx=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,"
"rsp=0x%zx,ss=0x%zx]",
intctx->cr2, intctx->ds, intctx->rdi, intctx->rsi, intctx->rbp,
intctx->rbx, intctx->rdx, intctx->rcx, intctx->rax,
intctx->r8, intctx->r9, intctx->r10, intctx->r11, intctx->r12,
intctx->r13, intctx->r14, intctx->r15, intctx->int_no,
intctx->err_code, intctx->rip, intctx->cs, intctx->rflags,
intctx->rsp, intctx->ss);
#else
#warning "You need to implement printing an interrupt context"
#endif
}
extern "C" __attribute__((noreturn))
void load_registers(const struct interrupt_context* inctx);
__attribute__((noreturn))
void LoadRegisters(const struct thread_registers* registers)
{
struct interrupt_context intctx;
memset(&intctx, 0, sizeof(intctx));
Scheduler::LoadInterruptedContext(&intctx, registers);
load_registers(&intctx);
}
} // namespace Sortix

View File

@ -25,10 +25,13 @@
#include <sys/types.h>
#include <assert.h>
#include <msr.h>
#include <string.h>
#include <timespec.h>
#if defined(__x86_64__)
#include <msr.h>
#endif
#include <sortix/clock.h>
#include <sortix/timespec.h>
@ -37,6 +40,7 @@
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/memorymanagement.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/registers.h>
#include <sortix/kernel/scheduler.h>
#include <sortix/kernel/signal.h>
#include <sortix/kernel/syscall.h>
@ -52,9 +56,143 @@ namespace Sortix {
namespace Scheduler {
static Thread* current_thread;
void SaveInterruptedContext(const struct interrupt_context* intctx,
struct thread_registers* registers)
{
#if defined(__i386__)
registers->signal_pending = intctx->signal_pending;
registers->kerrno = intctx->kerrno;
registers->eax = intctx->eax;
registers->ebx = intctx->ebx;
registers->ecx = intctx->ecx;
registers->edx = intctx->edx;
registers->edi = intctx->edi;
registers->esi = intctx->esi;
registers->esp = intctx->esp;
registers->ebp = intctx->ebp;
registers->eip = intctx->eip;
registers->eflags = intctx->eflags;
registers->fsbase = (unsigned long) GDT::GetFSBase();
registers->gsbase = (unsigned long) GDT::GetGSBase();
asm ( "mov %%cr3, %0" : "=r"(registers->cr3) );
registers->kernel_stack = GDT::GetKernelStack();
registers->cs = intctx->cs;
registers->ds = intctx->ds;
registers->ss = intctx->ss;
asm volatile ("fxsave (%0)" : : "r"(registers->fpuenv));
#elif defined(__x86_64__)
registers->signal_pending = intctx->signal_pending;
registers->kerrno = intctx->kerrno;
registers->rax = intctx->rax;
registers->rbx = intctx->rbx;
registers->rcx = intctx->rcx;
registers->rdx = intctx->rdx;
registers->rdi = intctx->rdi;
registers->rsi = intctx->rsi;
registers->rsp = intctx->rsp;
registers->rbp = intctx->rbp;
registers->r8 = intctx->r8;
registers->r9 = intctx->r9;
registers->r10 = intctx->r10;
registers->r11 = intctx->r11;
registers->r12 = intctx->r12;
registers->r13 = intctx->r13;
registers->r14 = intctx->r14;
registers->r15 = intctx->r15;
registers->r15 = intctx->r15;
registers->rip = intctx->rip;
registers->rflags = intctx->rflags;
registers->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
registers->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
asm ( "mov %%cr3, %0" : "=r"(registers->cr3) );
registers->kernel_stack = GDT::GetKernelStack();
registers->cs = intctx->cs;
registers->ds = intctx->ds;
registers->ss = intctx->ss;
asm volatile ("fxsave (%0)" : : "r"(registers->fpuenv));
#else
#warning "You need to implement register saving"
#endif
}
void LoadInterruptedContext(struct interrupt_context* intctx,
const struct thread_registers* registers)
{
#if defined(__i386__)
intctx->signal_pending = registers->signal_pending;
intctx->kerrno = registers->kerrno;
intctx->eax = registers->eax;
intctx->ebx = registers->ebx;
intctx->ecx = registers->ecx;
intctx->edx = registers->edx;
intctx->edi = registers->edi;
intctx->esi = registers->esi;
intctx->esp = registers->esp;
intctx->ebp = registers->ebp;
intctx->eip = registers->eip;
intctx->eflags = registers->eflags;
GDT::SetFSBase(registers->fsbase);
GDT::SetGSBase(registers->gsbase);
asm volatile ( "mov %0, %%cr3" : : "r"(registers->cr3) );
GDT::SetKernelStack(registers->kernel_stack);
intctx->cs = registers->cs;
intctx->ds = registers->ds;
intctx->ss = registers->ss;
asm volatile ("fxrstor (%0)" : : "r"(registers->fpuenv));
#elif defined(__x86_64__)
intctx->signal_pending = registers->signal_pending;
intctx->kerrno = registers->kerrno;
intctx->rax = registers->rax;
intctx->rbx = registers->rbx;
intctx->rcx = registers->rcx;
intctx->rdx = registers->rdx;
intctx->rdi = registers->rdi;
intctx->rsi = registers->rsi;
intctx->rsp = registers->rsp;
intctx->rbp = registers->rbp;
intctx->r8 = registers->r8;
intctx->r9 = registers->r9;
intctx->r10 = registers->r10;
intctx->r11 = registers->r11;
intctx->r12 = registers->r12;
intctx->r13 = registers->r13;
intctx->r14 = registers->r14;
intctx->r15 = registers->r15;
intctx->r15 = registers->r15;
intctx->rip = registers->rip;
intctx->rflags = registers->rflags;
wrmsr(MSRID_FSBASE, registers->fsbase);
wrmsr(MSRID_GSBASE, registers->gsbase);
asm volatile ( "mov %0, %%cr3" : : "r"(registers->cr3) );
GDT::SetKernelStack(registers->kernel_stack);
intctx->cs = registers->cs;
intctx->ds = registers->ds;
intctx->ss = registers->ss;
asm volatile ("fxrstor (%0)" : : "r"(registers->fpuenv));
#else
#warning "You need to implement register loading"
#endif
}
static
void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next)
{
if ( prev == next )
return;
SaveInterruptedContext(intctx, &prev->registers);
if ( !prev->registers.cr3 )
Log::PrintF("Thread %p had cr3=0x%zx\n", prev, prev->registers.cr3);
if ( !next->registers.cr3 )
Log::PrintF("Thread %p has cr3=0x%zx\n", next, next->registers.cr3);
LoadInterruptedContext(intctx, &next->registers);
current_thread = next;
}
static Thread* idle_thread;
static Thread* first_runnable_thread;
static Thread* first_sleeping_thread;
static Process* init_process;
static Thread* PopNextThread()
@ -69,63 +207,26 @@ static Thread* PopNextThread()
return idle_thread;
}
static void DoActualSwitch(CPU::InterruptRegisters* regs)
void Switch(struct interrupt_context* intctx)
{
Thread* prev = CurrentThread();
Thread* next = PopNextThread();
SwitchThread(intctx, CurrentThread(), PopNextThread());
if ( prev == next )
return;
prev->SaveRegisters(regs);
next->LoadRegisters(regs);
Memory::SwitchAddressSpace(next->addrspace);
current_thread = next;
#if defined(__i386__) || defined(__x86_64__)
Float::NotityTaskSwitch();
GDT::SetKernelStack(next->kernelstackpos, next->kernelstacksize,
next->kernelstackpos + next->kernelstacksize);
#endif
#if defined(__i386__)
prev->fsbase = (unsigned long) GDT::GetFSBase();
prev->gsbase = (unsigned long) GDT::GetGSBase();
GDT::SetFSBase((uint32_t) next->fsbase);
GDT::SetGSBase((uint32_t) next->gsbase);
#elif defined(__x86_64__)
prev->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
prev->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
wrmsr(MSRID_FSBASE, (uint64_t) next->fsbase);
wrmsr(MSRID_GSBASE, (uint64_t) next->gsbase);
#endif
}
void Switch(CPU::InterruptRegisters* regs)
{
DoActualSwitch(regs);
if ( regs->signal_pending && regs->InUserspace() )
if ( intctx->signal_pending && InUserspace(intctx) )
{
Interrupt::Enable();
Signal::DispatchHandler(regs, NULL);
Signal::DispatchHandler(intctx, NULL);
}
}
void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* /*user*/)
void InterruptYieldCPU(struct interrupt_context* intctx, void* /*user*/)
{
Switch(regs);
Switch(intctx);
}
void ThreadExitCPU(CPU::InterruptRegisters* regs, void* /*user*/)
void ThreadExitCPU(struct interrupt_context* intctx, void* /*user*/)
{
#if defined(__i386__) || defined(__x86_64__)
// Can't use floating point instructions from now.
Float::NofityTaskExit(current_thread);
#endif
SetThreadState(current_thread, ThreadState::DEAD);
InterruptYieldCPU(regs, NULL);
InterruptYieldCPU(intctx, NULL);
}
// The idle thread serves no purpose except being an infinite loop that does
@ -206,7 +307,6 @@ static int sys_sched_yield(void)
void Init()
{
first_runnable_thread = NULL;
first_sleeping_thread = NULL;
idle_thread = NULL;
Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield);

View File

@ -44,10 +44,6 @@
#include <sortix/kernel/syscall.h>
#include <sortix/kernel/thread.h>
#if defined(__i386__) || defined(__x86_64__)
#include "x86-family/float.h"
#endif
namespace Sortix {
sigset_t default_ignored_signals;
@ -57,6 +53,7 @@ sigset_t unblockable_signals;
// A per-cpu value whether a signal is pending in the running task.
extern "C" { volatile unsigned long asm_signal_is_pending = 0; }
static
void UpdatePendingSignals(Thread* thread) // thread->process->signal_lock held
{
struct sigaction* signal_actions = thread->process->signal_actions;
@ -400,7 +397,9 @@ static int PickImportantSignal(const sigset_t* set)
return 0;
}
static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs)
static void EncodeMachineContext(mcontext_t* mctx,
const struct thread_registers* regs,
const struct interrupt_context* intctx)
{
memset(mctx, 0, sizeof(*mctx));
#if defined(__i386__)
@ -419,10 +418,9 @@ static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
mctx->gregs[REG_EIP] = regs->eip;
// TODO: REG_CS
mctx->gregs[REG_EFL] = regs->eflags & 0x0000FFFF;
mctx->gregs[REG_CR2] = regs->cr2;
mctx->gregs[REG_CR2] = intctx->cr2;
// TODO: REG_SS
Float::Yield();
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
memcpy(mctx->fpuenv, regs->fpuenv, 512);
#elif defined(__x86_64__)
mctx->gregs[REG_R8] = regs->r8;
mctx->gregs[REG_R9] = regs->r9;
@ -443,17 +441,17 @@ static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
mctx->gregs[REG_RIP] = regs->rip;
mctx->gregs[REG_EFL] = regs->rflags & 0x000000000000FFFF;
// TODO: REG_CSGSFS.
mctx->gregs[REG_CR2] = regs->cr2;
mctx->gregs[REG_CR2] = intctx->cr2;
mctx->gregs[REG_FSBASE] = 0x0;
mctx->gregs[REG_GSBASE] = 0x0;
Float::Yield();
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
memcpy(mctx->fpuenv, regs->fpuenv, 512);
#else
#error "You need to implement conversion to mcontext"
#endif
}
static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs)
static void DecodeMachineContext(const mcontext_t* mctx,
struct thread_registers* regs)
{
#if defined(__i386__) || defined(__x86_64__)
unsigned long user_flags = FLAGS_CARRY | FLAGS_PARITY | FLAGS_AUX
@ -472,9 +470,7 @@ static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
regs->eip = mctx->gregs[REG_EIP];
regs->eflags &= ~user_flags;
regs->eflags |= mctx->gregs[REG_EFL] & user_flags;
regs->cr2 = mctx->gregs[REG_CR2];
Float::Yield();
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
memcpy(regs->fpuenv, mctx->fpuenv, 512);
#elif defined(__x86_64__)
regs->r8 = mctx->gregs[REG_R8];
regs->r9 = mctx->gregs[REG_R9];
@ -495,9 +491,7 @@ static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
regs->rip = mctx->gregs[REG_RIP];
regs->rflags &= ~user_flags;
regs->rflags |= mctx->gregs[REG_EFL] & user_flags;
regs->cr2 = mctx->gregs[REG_CR2];
Float::Yield();
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
memcpy(regs->fpuenv, mctx->fpuenv, 512);
#else
#error "You need to implement conversion to mcontext"
#endif
@ -525,7 +519,7 @@ struct stack_frame
#error "You need to implement struct stack_frame"
#endif
void Thread::HandleSignal(CPU::InterruptRegisters* regs)
void Thread::HandleSignal(struct interrupt_context* intctx)
{
assert(Interrupt::IsEnabled());
assert(this == CurrentThread());
@ -553,7 +547,7 @@ retry_another_signal:
// Unmark the selected signal as pending.
sigdelset(&signal_pending, signum);
UpdatePendingSignals(this);
regs->signal_pending = asm_signal_is_pending;
intctx->signal_pending = asm_signal_is_pending;
// Destroy the current thread if the signal is critical.
if ( signum == SIGKILL )
@ -614,28 +608,31 @@ retry_another_signal:
// threads in the kernel cannot be delivered signals except when returning
// from a system call, so we'll simply save the state that would have been
// returned to user-space had no signal occured.
if ( !regs->InUserspace() )
if ( !InUserspace(intctx) )
{
#if defined(__i386__)
uint32_t* params = (uint32_t*) regs->ebx;
regs->eip = params[0];
regs->eflags = params[2];
regs->esp = params[3];
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
uint32_t* params = (uint32_t*) intctx->ebx;
intctx->eip = params[0];
intctx->eflags = params[2];
intctx->esp = params[3];
intctx->cs = UCS | URPL;
intctx->ds = UDS | URPL;
intctx->ss = UDS | URPL;
#elif defined(__x86_64__)
regs->rip = regs->rdi;
regs->rflags = regs->rsi;
regs->rsp = regs->r8;
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
intctx->rip = intctx->rdi;
intctx->rflags = intctx->rsi;
intctx->rsp = intctx->r8;
intctx->cs = UCS | URPL;
intctx->ds = UDS | URPL;
intctx->ss = UDS | URPL;
#else
#error "You may need to fix the registers"
#endif
}
struct thread_registers stopped_regs;
Scheduler::SaveInterruptedContext(intctx, &stopped_regs);
sigset_t new_signal_mask;
memcpy(&new_signal_mask, &action->sa_mask, sizeof(sigset_t));
sigorset(&new_signal_mask, &new_signal_mask, &signal_mask);
@ -670,15 +667,16 @@ retry_another_signal:
old_signal_stack.ss_size = 0;
new_signal_stack = signal_stack;
#if defined(__i386__)
stack_location = (uintptr_t) regs->esp;
stack_location = (uintptr_t) stopped_regs.esp;
#elif defined(__x86_64__)
stack_location = (uintptr_t) regs->rsp;
stack_location = (uintptr_t) stopped_regs.rsp;
#else
#error "You need to implement getting the user-space stack pointer"
#endif
}
CPU::InterruptRegisters new_regs = *regs;
struct thread_registers handler_regs;
memcpy(&handler_regs, &stopped_regs, sizeof(handler_regs));
struct stack_frame stack_frame;
memset(&stack_frame, 0, sizeof(stack_frame));
@ -700,9 +698,9 @@ retry_another_signal:
stack_frame.ucontext_param = &stack->ucontext;
stack_frame.cookie_param = action->sa_cookie;
new_regs.esp = (unsigned long) stack;
new_regs.eip = (unsigned long) handler_ptr;
new_regs.eflags &= ~FLAGS_DIRECTION;
handler_regs.esp = (unsigned long) stack;
handler_regs.eip = (unsigned long) handler_ptr;
handler_regs.eflags &= ~FLAGS_DIRECTION;
#elif defined(__x86_64__)
stack_location -= 128; /* Red zone. */
stack_location -= sizeof(stack_frame);
@ -710,14 +708,14 @@ retry_another_signal:
struct stack_frame* stack = (struct stack_frame*) stack_location;
stack_frame.sigreturn = (unsigned long) process->sigreturn;
new_regs.rdi = (unsigned long) signum;
new_regs.rsi = (unsigned long) &stack->siginfo;
new_regs.rdx = (unsigned long) &stack->ucontext;
new_regs.rcx = (unsigned long) action->sa_cookie;
handler_regs.rdi = (unsigned long) signum;
handler_regs.rsi = (unsigned long) &stack->siginfo;
handler_regs.rdx = (unsigned long) &stack->ucontext;
handler_regs.rcx = (unsigned long) action->sa_cookie;
new_regs.rsp = (unsigned long) stack;
new_regs.rip = (unsigned long) handler_ptr;
new_regs.rflags &= ~FLAGS_DIRECTION;
handler_regs.rsp = (unsigned long) stack;
handler_regs.rip = (unsigned long) handler_ptr;
handler_regs.rflags &= ~FLAGS_DIRECTION;
#else
#error "You need to format the stack frame"
#endif
@ -727,7 +725,7 @@ retry_another_signal:
#if defined(__i386__) || defined(__x86_64__)
// TODO: Is this cr2 value trustworthy? I don't think it is.
if ( signum == SIGSEGV )
stack_frame.siginfo.si_addr = (void*) regs->cr2;
stack_frame.siginfo.si_addr = (void*) intctx->cr2;
#else
#warning "You need to tell user-space where it crashed"
#endif
@ -736,7 +734,7 @@ retry_another_signal:
stack_frame.ucontext.uc_link = NULL;
memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask));
memcpy(&stack_frame.ucontext.uc_stack, &signal_stack, sizeof(signal_stack));
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs);
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, &stopped_regs, intctx);
if ( !CopyToUser(stack, &stack_frame, sizeof(stack_frame)) )
{
@ -764,7 +762,7 @@ retry_another_signal:
signal_stack = new_signal_stack;
// Update the current registers.
*regs = new_regs;
Scheduler::LoadInterruptedContext(intctx, &handler_regs);
// TODO: SA_RESETHAND:
// "If set, the disposition of the signal shall be reset to SIG_DFL
@ -776,7 +774,7 @@ retry_another_signal:
return;
}
void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
void Thread::HandleSigreturn(struct interrupt_context* intctx)
{
assert(Interrupt::IsEnabled());
assert(this == CurrentThread());
@ -786,9 +784,9 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
struct stack_frame stack_frame;
const struct stack_frame* user_stack_frame;
#if defined(__i386__)
user_stack_frame = (const struct stack_frame*) (regs->esp - 4);
user_stack_frame = (const struct stack_frame*) (intctx->esp - 4);
#elif defined(__x86_64__)
user_stack_frame = (const struct stack_frame*) (regs->rsp - 8);
user_stack_frame = (const struct stack_frame*) (intctx->rsp - 8);
#else
#error "You need to locate the stack we passed the signal handler"
#endif
@ -798,27 +796,30 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
memcpy(&signal_mask, &stack_frame.ucontext.uc_sigmask, sizeof(signal_mask));
memcpy(&signal_stack, &stack_frame.ucontext.uc_stack, sizeof(signal_stack));
signal_stack.ss_flags &= __SS_SUPPORTED_FLAGS;
DecodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs);
struct thread_registers resume_regs;
Scheduler::SaveInterruptedContext(intctx, &resume_regs);
DecodeMachineContext(&stack_frame.ucontext.uc_mcontext, &resume_regs);
Scheduler::LoadInterruptedContext(intctx, &resume_regs);
}
UpdatePendingSignals(this);
regs->signal_pending = asm_signal_is_pending;
intctx->signal_pending = asm_signal_is_pending;
lock.Reset();
HandleSignal(regs);
HandleSignal(intctx);
}
namespace Signal {
void DispatchHandler(CPU::InterruptRegisters* regs, void* /*user*/)
void DispatchHandler(struct interrupt_context* intctx, void* /*user*/)
{
return CurrentThread()->HandleSignal(regs);
return CurrentThread()->HandleSignal(intctx);
}
void ReturnHandler(CPU::InterruptRegisters* regs, void* /*user*/)
void ReturnHandler(struct interrupt_context* intctx, void* /*user*/)
{
return CurrentThread()->HandleSigreturn(regs);
return CurrentThread()->HandleSigreturn(intctx);
}
void Init()

View File

@ -27,6 +27,7 @@
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sortix/exit.h>
@ -44,10 +45,39 @@
#include <sortix/kernel/thread.h>
#include <sortix/kernel/time.h>
void* operator new (size_t /*size*/, void* address) throw()
{
return address;
}
namespace Sortix {
Thread* AllocateThread()
{
uint8_t* allocation = (uint8_t*) malloc(sizeof(class Thread) + 16);
if ( !allocation )
return NULL;
uint8_t* aligned = allocation;
if ( ((uintptr_t) aligned & 0xFUL) )
aligned = (uint8_t*) (((uintptr_t) aligned + 16) & ~0xFUL);
assert(!((uintptr_t) aligned & 0xFUL));
Thread* thread = new (aligned) Thread;
assert(!((uintptr_t) thread->registers.fpuenv & 0xFUL));
return thread->self_allocation = allocation, thread;
}
void FreeThread(Thread* thread)
{
uint8_t* allocation = thread->self_allocation;
thread->~Thread();
free(allocation);
}
Thread::Thread()
{
assert(!((uintptr_t) registers.fpuenv & 0xFUL));
id = 0; // TODO: Make a thread id.
process = NULL;
prevsibling = NULL;
@ -56,17 +86,10 @@ Thread::Thread()
scheduler_list_next = NULL;
state = NONE;
memset(&registers, 0, sizeof(registers));
fsbase = 0;
gsbase = 0;
kernelstackpos = 0;
kernelstacksize = 0;
kernelstackmalloced = false;
pledged_destruction = false;
fpuinitialized = false;
// If malloc isn't 16-byte aligned, then we can't rely on offsets in
// our own class, so we'll just fix ourselves nicely up.
unsigned long fpuaddr = ((unsigned long) fpuenv+16UL) & ~(16UL-1UL);
fpuenvaligned = (uint8_t*) fpuaddr;
sigemptyset(&signal_pending);
sigemptyset(&signal_mask);
memset(&signal_stack, 0, sizeof(signal_stack));
@ -82,129 +105,22 @@ Thread::~Thread()
delete[] (uint8_t*) kernelstackpos;
}
void Thread::SaveRegisters(const CPU::InterruptRegisters* src)
Thread* CreateKernelThread(Process* process, struct thread_registers* regs)
{
#if defined(__i386__)
registers.eip = src->eip;
registers.esp = src->esp;
registers.eax = src->eax;
registers.ebx = src->ebx;
registers.ecx = src->ecx;
registers.edx = src->edx;
registers.edi = src->edi;
registers.esi = src->esi;
registers.ebp = src->ebp;
registers.cs = src->cs;
registers.ds = src->ds;
registers.ss = src->ss;
registers.eflags = src->eflags;
registers.kerrno = src->kerrno;
registers.signal_pending = src->signal_pending;
#elif defined(__x86_64__)
registers.rip = src->rip;
registers.rsp = src->rsp;
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;
registers.kerrno = src->kerrno;
registers.signal_pending = src->signal_pending;
#else
#warning "You need to add register saving support"
#endif
}
void Thread::LoadRegisters(CPU::InterruptRegisters* dest)
{
#if defined(__i386__)
dest->eip = registers.eip;
dest->esp = registers.esp;
dest->eax = registers.eax;
dest->ebx = registers.ebx;
dest->ecx = registers.ecx;
dest->edx = registers.edx;
dest->edi = registers.edi;
dest->esi = registers.esi;
dest->ebp = registers.ebp;
dest->cs = registers.cs;
dest->ds = registers.ds;
dest->ss = registers.ss;
dest->eflags = registers.eflags;
dest->kerrno = registers.kerrno;
dest->signal_pending = registers.signal_pending;
#elif defined(__x86_64__)
dest->rip = registers.rip;
dest->rsp = registers.rsp;
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;
dest->kerrno = registers.kerrno;
dest->signal_pending = registers.signal_pending;
#else
#warning "You need to add register loading support"
#endif
}
addr_t Thread::SwitchAddressSpace(addr_t newaddrspace)
{
bool wasenabled = Interrupt::SetEnabled(false);
addr_t result = addrspace;
addrspace = newaddrspace;
Memory::SwitchAddressSpace(newaddrspace);
Interrupt::SetEnabled(wasenabled);
return result;
}
Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
unsigned long fsbase, unsigned long gsbase)
{
#if defined(__x86_64__)
if ( fsbase >> 48 != 0x0000 && fsbase >> 48 != 0xFFFF )
return errno = EINVAL, (Thread*) NULL;
if ( gsbase >> 48 != 0x0000 && gsbase >> 48 != 0xFFFF )
return errno = EINVAL, (Thread*) NULL;
#endif
assert(process && regs && process->addrspace);
Thread* thread = new Thread;
#if defined(__x86_64__)
if ( regs->fsbase >> 48 != 0x0000 && regs->fsbase >> 48 != 0xFFFF )
return errno = EINVAL, (Thread*) NULL;
if ( regs->gsbase >> 48 != 0x0000 && regs->gsbase >> 48 != 0xFFFF )
return errno = EINVAL, (Thread*) NULL;
#endif
Thread* thread = AllocateThread();
if ( !thread )
return NULL;
thread->addrspace = process->addrspace;
thread->SaveRegisters(regs);
thread->fsbase = fsbase;
thread->gsbase = gsbase;
memcpy(&thread->registers, regs, sizeof(struct thread_registers));
kthread_mutex_lock(&process->threadlock);
@ -221,48 +137,62 @@ Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
return thread;
}
static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs,
static void SetupKernelThreadRegs(struct thread_registers* regs,
Process* process,
void (*entry)(void*),
void* user,
uintptr_t stack,
size_t stack_size)
{
memset(regs, 0, sizeof(*regs));
size_t stack_alignment = 16;
while ( stack & (stack_alignment-1) )
{
assert(stack_size);
stack++;
stack_size--;
}
stack_size &= ~(stack_alignment-1);
#if defined(__i386__)
uintptr_t* stack_values = (uintptr_t*) (stack + stack_size);
assert(!((uintptr_t) stack_values & 3UL));
assert(4 * sizeof(uintptr_t) <= stack_size);
assert(5 * sizeof(uintptr_t) <= stack_size);
stack_values[-1] = (uintptr_t) 0; /* null eip */
stack_values[-2] = (uintptr_t) 0; /* null ebp */
stack_values[-3] = (uintptr_t) user; /* thread parameter */
stack_values[-4] = (uintptr_t) kthread_exit; /* return to kthread_exit */
/* -- 16-byte aligned -- */
/* -1 padding */
stack_values[-2] = (uintptr_t) 0; /* null eip */
stack_values[-3] = (uintptr_t) 0; /* null ebp */
stack_values[-4] = (uintptr_t) user; /* thread parameter */
/* -- 16-byte aligned -- */
stack_values[-5] = (uintptr_t) kthread_exit; /* return to kthread_exit */
/* upcoming ebp */
/* -7 padding */
/* -8 padding */
/* -- 16-byte aligned -- */
regs->eip = (uintptr_t) entry;
regs->esp = (uintptr_t) (stack_values - 4);
regs->esp = (uintptr_t) (stack_values - 5);
regs->eax = 0;
regs->ebx = 0;
regs->ecx = 0;
regs->edx = 0;
regs->edi = 0;
regs->esi = 0;
regs->ebp = (uintptr_t) (stack_values - 2);
regs->ebp = (uintptr_t) (stack_values - 3);
regs->cs = KCS | KRPL;
regs->ds = KDS | KRPL;
regs->ss = KDS | KRPL;
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->kerrno = 0;
regs->signal_pending = 0;
regs->kernel_stack = stack + stack_size;
regs->cr3 = process->addrspace;
#elif defined(__x86_64__)
if ( (stack & 15UL) == 8 && 8 <= stack_size )
{
stack += 8;
stack_size -= 8;
}
uintptr_t* stack_values = (uintptr_t*) (stack + stack_size);
assert(!((uintptr_t) stack_values & 15UL));
assert(3 * sizeof(uintptr_t) <= stack_size);
stack_values[-1] = (uintptr_t) 0; /* null rip */
@ -292,8 +222,10 @@ static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs,
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->kerrno = 0;
regs->signal_pending = 0;
regs->kernel_stack = stack + stack_size;
regs->cr3 = process->addrspace;
#else
#warning "You need to add thread register initialization support"
#warning "You need to add kernel thread register initialization support"
#endif
}
@ -307,10 +239,10 @@ Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user,
if ( !stack )
return NULL;
CPU::InterruptRegisters regs;
SetupKernelThreadRegs(&regs, entry, user, (uintptr_t) stack, stacksize);
struct thread_registers regs;
SetupKernelThreadRegs(&regs, process, entry, user, (uintptr_t) stack, stacksize);
Thread* thread = CreateKernelThread(process, &regs, 0, 0);
Thread* thread = CreateKernelThread(process, &regs);
if ( !thread ) { delete[] stack; return NULL; }
thread->kernelstackpos = (uintptr_t) stack;
@ -330,9 +262,9 @@ void StartKernelThread(Thread* thread)
Scheduler::SetThreadState(thread, ThreadState::RUNNABLE);
}
Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs)
Thread* RunKernelThread(Process* process, struct thread_registers* regs)
{
Thread* thread = CreateKernelThread(process, regs, 0, 0);
Thread* thread = CreateKernelThread(process, regs);
if ( !thread )
return NULL;
StartKernelThread(thread);

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of Sortix.
@ -141,6 +141,9 @@ Realm64:
or $0x600, %rax
mov %rax, %cr4
# Store a copy of the initialial floating point registers.
fxsave fpu_initialized_regs
# Alright, that was the bootstrap code. Now begin preparing to run the
# actual 64-bit kernel.
jmp Main

View File

@ -386,7 +386,10 @@ interrupt_handler_prepare:
# Now call the interrupt handler.
movq %rsp, %rdi
movq %rsp, %rbx
andq $0xFFFFFFFFFFFFFFF0, %rsp
call interrupt_handler
movq %rbx, %rsp
load_interrupted_registers:
# Restore whether signals are pending.

View File

@ -44,8 +44,6 @@ void ExtendStack();
namespace Sortix {
namespace Memory {
extern addr_t currentdir;
void InitCPU()
{
// The x64 boot code already set up virtual memory and identity
@ -87,8 +85,6 @@ void InitCPU()
BOOTPML3->entry[0] = (addr_t) FORKPML2 | flags | PML_FORK;
FORKPML2->entry[0] = (addr_t) FORKPML1 | flags | PML_FORK;
currentdir = (addr_t) BOOTPML4;
// The virtual memory structures are now available on the predefined
// locations. This means the virtual memory code is bootstrapped. Of
// course, we still have no physical page allocator, so that's the
@ -139,7 +135,7 @@ void RecursiveFreeUserspacePages(size_t level, size_t offset)
}
}
void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* user)
void DestroyAddressSpace(addr_t fallback)
{
// Look up the last few entries used for the fractal mapping. These
// cannot be unmapped as that would destroy the world. Instead, we
@ -150,7 +146,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use
addr_t fractal2 = (PMLS[3] + 510UL)->entry[510];
addr_t fork1 = (PMLS[2] + 510UL * 512UL + 0)->entry[0];
addr_t fractal1 = (PMLS[2] + 510UL * 512UL + 510UL)->entry[510];
addr_t dir = currentdir;
addr_t dir = GetAddressSpace();
// We want to free the pages, but we are still using them ourselves,
// so lock the page allocation structure until we are done.
@ -167,10 +163,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use
if ( !fallback )
fallback = (addr_t) BOOTPML4;
if ( func )
func(fallback, user);
else
SwitchAddressSpace(fallback);
SwitchAddressSpace(fallback);
// Ok, now we got marked everything left behind as unused, we can
// now safely let another thread use the pages.

View File

@ -1,83 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
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 <http://www.gnu.org/licenses/>.
x64/process.cpp
CPU-specific process code.
*******************************************************************************/
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <sortix/fork.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/process.h>
namespace Sortix {
void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp,
addr_t stackpos, addr_t entry,
CPU::InterruptRegisters* regs)
{
memset(regs, 0, sizeof(*regs));
regs->rdi = argc;
regs->rsi = (size_t) argv;
regs->rdx = envc;
regs->rcx = (size_t) envp;
regs->rip = entry;
regs->rsp = stackpos & ~15UL;
regs->rbp = regs->rsp;
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->signal_pending = 0;
}
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
const struct tfork* requested)
{
memset(regs, 0, sizeof(*regs));
regs->rip = requested->rip;
regs->rsp = requested->rsp;
regs->rax = requested->rax;
regs->rbx = requested->rbx;
regs->rcx = requested->rcx;
regs->rdx = requested->rdx;
regs->rdi = requested->rdi;
regs->rsi = requested->rsi;
regs->rbp = requested->rbp;
regs->r8 = requested->r8;
regs->r9 = requested->r9;
regs->r10 = requested->r10;
regs->r11 = requested->r11;
regs->r12 = requested->r12;
regs->r13 = requested->r13;
regs->r14 = requested->r14;
regs->r15 = requested->r15;
regs->cs = 0x18 | 0x3;
regs->ds = 0x20 | 0x3;
regs->ss = 0x20 | 0x3;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
}
} // namespace Sortix

View File

@ -1,49 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
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 <http://www.gnu.org/licenses/>.
x64/x64.cpp
CPU stuff for the x64 platform.
*******************************************************************************/
#include <sortix/kernel/cpu.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/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,"
"rbx=0x%zx,rdx=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,"
"rsp=0x%zx,ss=0x%zx]",
cr2, ds, rdi, rsi, rbp,
rbx, rdx, rcx, rax,
r8, r9, r10, r11, r12,
r13, r14, r15, int_no,
err_code, rip, cs, rflags,
rsp, ss);
}
} // namespace X64
} // namespace Sortix

View File

@ -33,104 +33,7 @@
namespace Sortix {
namespace Float {
static Thread* fputhread;
bool fpu_is_enabled = false;
static inline void InitFPU()
{
asm volatile ("fninit");
}
static inline void SaveState(uint8_t* dest)
{
assert( (((unsigned long) dest) & (16UL-1UL)) == 0 );
asm volatile ("fxsave (%0)" : : "r"(dest));
}
static inline void LoadState(const uint8_t* src)
{
assert( (((unsigned long) src) & (16UL-1UL)) == 0 );
asm volatile ("fxrstor (%0)" : : "r"(src));
}
void Yield()
{
Thread* thread = CurrentThread();
Interrupt::Disable();
bool fpu_was_enabled = fpu_is_enabled;
// The FPU contains the registers for this thread.
if ( fputhread == thread )
{
if ( !fpu_was_enabled )
EnableFPU();
SaveState(thread->fpuenvaligned);
fputhread = NULL;
DisableFPU();
}
// This thread has used the FPU once.
else if ( thread->fpuinitialized )
{
// Nothing needs to be done, the FPU is owned by another thread and the
// FPU registers are already stored in the thread structure.
}
// This thread has never used the FPU and needs its registers initialized.
else
{
if ( !fpu_was_enabled )
EnableFPU();
if ( fputhread )
SaveState(fputhread->fpuenvaligned);
InitFPU();
SaveState(thread->fpuenvaligned);
if ( fputhread )
LoadState(fputhread->fpuenvaligned);
if ( !fpu_was_enabled )
DisableFPU();
}
Interrupt::Enable();
}
static void OnFPUAccess(CPU::InterruptRegisters* /*regs*/, void* /*user*/)
{
EnableFPU();
Thread* thread = CurrentThread();
if ( thread == fputhread )
return;
if ( fputhread )
SaveState(fputhread->fpuenvaligned);
fputhread = thread;
if ( !thread->fpuinitialized )
{
InitFPU();
thread->fpuinitialized = true;
return;
}
LoadState(thread->fpuenvaligned);
}
void Init()
{
fputhread = CurrentThread();
assert(fputhread);
Interrupt::RegisterHandler(7, OnFPUAccess, NULL);
}
void NofityTaskExit(Thread* thread)
{
if ( fputhread == thread )
fputhread = NULL;
DisableFPU();
}
extern "C" { __attribute__((aligned(16))) uint8_t fpu_initialized_regs[512]; }
} // namespace Float
} // namespace Sortix

View File

@ -25,39 +25,14 @@
#ifndef SORTIX_FLOAT_H
#define SORTIX_FLOAT_H
#include <stdint.h>
namespace Sortix {
class Thread;
namespace Float {
extern bool fpu_is_enabled;
void Init();
void NofityTaskExit(Thread* thread);
void Yield();
static inline void EnableFPU()
{
asm volatile ("clts");
fpu_is_enabled = true;
}
static inline void DisableFPU()
{
fpu_is_enabled = false;
unsigned long cr0;
asm volatile ("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 1UL<<3UL;
asm volatile ("mov %0, %%cr0" : : "r"(cr0));
}
static inline void NotityTaskSwitch()
{
DisableFPU();
}
extern "C" uint8_t fpu_initialized_regs[512];
} // namespace Float
} // namespace Sortix
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
This file is part of Sortix.
@ -22,10 +22,12 @@
*******************************************************************************/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <sortix/kernel/cpu.h>
#include <sortix/kernel/registers.h>
#include "gdt.h"
@ -254,16 +256,22 @@ void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0)
#endif
}
void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher)
uintptr_t GetKernelStack()
{
#if defined(__i386__)
(void) stacklower;
(void) stacksize;
tss_entry.esp0 = (uint32_t) stackhigher;
return tss_entry.esp0;
#elif defined(__x86_64__)
(void) stacklower;
(void) stacksize;
tss_entry.stack0 = (uint64_t) stackhigher;
return tss_entry.stack0;
#endif
}
void SetKernelStack(uintptr_t stack_pointer)
{
assert((stack_pointer & 0xF) == 0);
#if defined(__i386__)
tss_entry.esp0 = (uint32_t) stack_pointer;
#elif defined(__x86_64__)
tss_entry.stack0 = (uint64_t) stack_pointer;
#endif
}

View File

@ -32,7 +32,8 @@ namespace GDT {
void Init();
void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0);
void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher);
uintptr_t GetKernelStack();
void SetKernelStack(uintptr_t stack_pointer);
#if defined(__i386__)
uint32_t GetFSBase();
uint32_t GetGSBase();

View File

@ -244,49 +244,41 @@ void Init()
Interrupt::Enable();
}
const char* ExceptionName(const CPU::InterruptRegisters* regs)
const char* ExceptionName(const struct interrupt_context* intctx)
{
if ( regs->int_no < NUM_KNOWN_EXCEPTIONS )
return exception_names[regs->int_no];
if ( intctx->int_no < NUM_KNOWN_EXCEPTIONS )
return exception_names[intctx->int_no];
return "Unknown";
}
uintptr_t ExceptionLocation(const CPU::InterruptRegisters* regs)
uintptr_t ExceptionLocation(const struct interrupt_context* intctx)
{
#if defined(__x86_64__)
return regs->rip;
return intctx->rip;
#elif defined(__i386__)
return regs->eip;
return intctx->eip;
#endif
}
void CrashCalltrace(const CPU::InterruptRegisters* regs)
void CrashCalltrace(const struct interrupt_context* intctx)
{
#if defined(__x86_64__)
Calltrace::Perform(regs->rbp);
Calltrace::Perform(intctx->rbp);
#elif defined(__i386__)
Calltrace::Perform(regs->ebp);
Calltrace::Perform(intctx->ebp);
#else
#warning "Please provide a calltrace implementation for your CPU."
#endif
}
__attribute__((noreturn))
void KernelCrashHandler(CPU::InterruptRegisters* regs)
void KernelCrashHandler(struct interrupt_context* intctx)
{
Thread* thread = CurrentThread();
#if defined(__i386__)
thread->fsbase = (unsigned long) GDT::GetFSBase();
thread->gsbase = (unsigned long) GDT::GetGSBase();
#elif defined(__x86_64__)
thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
#endif
thread->SaveRegisters(regs);
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
// Walk and print the stack frames if this is a debug build.
if ( CALLTRACE_KERNEL )
CrashCalltrace(regs);
CrashCalltrace(intctx);
// Possibly switch to the kernel debugger in event of a crash.
if ( RUN_DEBUGGER_ON_KERNEL_CRASH )
@ -294,27 +286,19 @@ void KernelCrashHandler(CPU::InterruptRegisters* regs)
// Panic the kernel with a diagnostic message.
PanicF("Unhandled CPU Exception id %zu `%s' at ip=0x%zx (cr2=0x%zx, "
"err_code=0x%zx)", regs->int_no, ExceptionName(regs),
ExceptionLocation(regs), regs->cr2, regs->err_code);
"err_code=0x%zx)", intctx->int_no, ExceptionName(intctx),
ExceptionLocation(intctx), intctx->cr2, intctx->err_code);
}
void UserCrashHandler(CPU::InterruptRegisters* regs)
void UserCrashHandler(struct interrupt_context* intctx)
{
Thread* thread = CurrentThread();
#if defined(__i386__)
thread->fsbase = (unsigned long) GDT::GetFSBase();
thread->gsbase = (unsigned long) GDT::GetGSBase();
#elif defined(__x86_64__)
thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
#endif
thread->SaveRegisters(regs);
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
// Execute this crash handler with preemption on.
Interrupt::Enable();
// TODO: Also send signals for other types of user-space crashes.
if ( regs->int_no == 14 /* Page fault */ )
if ( intctx->int_no == 14 /* Page fault */ )
{
struct sigaction* act = &CurrentProcess()->signal_actions[SIGSEGV];
kthread_mutex_lock(&CurrentProcess()->signal_lock);
@ -323,12 +307,12 @@ void UserCrashHandler(CPU::InterruptRegisters* regs)
CurrentThread()->DeliverSignalUnlocked(SIGSEGV);
kthread_mutex_unlock(&CurrentProcess()->signal_lock);
if ( handled )
return Signal::DispatchHandler(regs, NULL);
return Signal::DispatchHandler(intctx, NULL);
}
// Walk and print the stack frames if this is a debug build.
if ( CALLTRACE_USER )
CrashCalltrace(regs);
CrashCalltrace(intctx);
// Possibly switch to the kernel debugger in event of a crash.
if ( RUN_DEBUGGER_ON_USER_CRASH )
@ -338,20 +322,20 @@ void UserCrashHandler(CPU::InterruptRegisters* regs)
Log::PrintF("The current process (pid %ji `%s') crashed and was terminated:\n",
(intmax_t) CurrentProcess()->pid, CurrentProcess()->program_image_path);
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%zx, err_code=0x%zx)\n",
ExceptionName(regs), ExceptionLocation(regs), regs->cr2,
regs->err_code);
ExceptionName(intctx), ExceptionLocation(intctx), intctx->cr2,
intctx->err_code);
// Exit the process with the right error code.
// TODO: Send a SIGINT, SIGBUS, or whatever instead.
CurrentProcess()->ExitThroughSignal(SIGSEGV);
// Deliver signals to this thread so it can exit correctly.
Signal::DispatchHandler(regs, NULL);
Signal::DispatchHandler(intctx, NULL);
}
extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
extern "C" void interrupt_handler(struct interrupt_context* intctx)
{
unsigned int int_no = regs->int_no;
unsigned int int_no = intctx->int_no;
// IRQ 7 and 15 might be spurious and might need to be ignored.
if ( int_no == IRQ7 && !(PIC::ReadISR() & (1 << 7)) )
@ -362,17 +346,17 @@ extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
return;
}
bool is_in_kernel = (regs->cs & 0x3) == KRPL;
bool is_in_kernel = (intctx->cs & 0x3) == KRPL;
bool is_in_user = !is_in_kernel;
bool is_crash = int_no < 32 && int_no != 7;
// Invoke the appropriate interrupt handler.
if ( is_crash && is_in_kernel )
KernelCrashHandler(regs);
KernelCrashHandler(intctx);
else if ( is_crash && is_in_user )
UserCrashHandler(regs);
UserCrashHandler(intctx);
else if ( interrupt_handlers[int_no] )
interrupt_handlers[int_no](regs, interrupt_handler_context[int_no]);
interrupt_handlers[int_no](intctx, interrupt_handler_context[int_no]);
// Send an end of interrupt signal to the PICs if we got an IRQ.
if ( IRQ0 <= int_no && int_no <= IRQ15 )

View File

@ -62,8 +62,6 @@ kthread_mutex_t pagelock;
namespace Sortix {
namespace Memory {
addr_t currentdir = 0;
void InitCPU();
void AllocateKernelPMLs();
int SysMemStat(size_t* memused, size_t* memtotal);
@ -485,42 +483,30 @@ void InvalidatePage(addr_t /*addr*/)
Flush();
}
// Flushes the Translation Lookaside Buffer (TLB).
void Flush()
{
asm volatile("mov %0, %%cr3":: "r"(currentdir));
}
addr_t GetAddressSpace()
{
return currentdir;
addr_t result;
asm ( "mov %%cr3, %0" : "=r"(result) );
return result;
}
addr_t SwitchAddressSpace(addr_t addrspace)
{
// Have fun debugging this.
if ( currentdir != Page::AlignDown(currentdir) )
PanicF("The variable containing the current address space "
"contains garbage all of sudden: it isn't page-aligned. "
"It contains the value 0x%zx.", currentdir);
// Don't switch if we are already there.
if ( addrspace == currentdir )
return currentdir;
if ( addrspace & 0xFFFUL )
PanicF("addrspace 0x%zx was not page-aligned!", addrspace);
addr_t previous = currentdir;
// Switch and flush the TLB.
asm volatile("mov %0, %%cr3":: "r"(addrspace));
currentdir = addrspace;
assert(Page::IsAligned(addrspace));
addr_t previous = GetAddressSpace();
asm volatile ( "mov %0, %%cr3" : : "r"(addrspace) );
return previous;
}
void Flush()
{
addr_t previous;
asm ( "mov %%cr3, %0" : "=r"(previous) );
asm volatile ( "mov %0, %%cr3" : : "r"(previous) );
}
bool MapRange(addr_t where, size_t bytes, int protection)
{
for ( addr_t page = where; page < where + bytes; page += 4096UL )

View File

@ -78,10 +78,10 @@ static struct timespec tick_period;
static long tick_frequency;
static uint16_t tick_divisor;
static void OnIRQ0(CPU::InterruptRegisters* regs, void* /*user*/)
static void OnIRQ0(struct interrupt_context* intctx, void* /*user*/)
{
OnTick(tick_period, !regs->InUserspace());
Scheduler::Switch(regs);
OnTick(tick_period, !InUserspace(intctx));
Scheduler::Switch(intctx);
// TODO: There is a horrible bug that causes Sortix to only receive
// one IRQ0 on my laptop, but it works in virtual machines. But

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of Sortix.
@ -62,4 +62,7 @@ prepare_kernel_execution:
mov %eax, %cr4
mov 0x100000, %eax
# Store a copy of the initialial floating point registers.
fxsave fpu_initialized_regs
jmp beginkernel

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
This file is part of Sortix.
@ -382,9 +382,12 @@ fixup_relocate_stack_complete:
pushl %ebp
# Now call the interrupt handler.
pushl %esp
movl %esp, %ebx
subl $4, %esp
andl $0xFFFFFFF0, %esp
movl %ebx, (%esp)
call interrupt_handler
addl $4, %esp
movl %ebx, %esp
load_interrupted_registers:
# Restore whether signals are pending.

View File

@ -45,8 +45,6 @@ void ExtendStack();
namespace Sortix {
namespace Memory {
extern addr_t currentdir;
void InitCPU()
{
PML* const BOOTPML2 = (PML* const) 0x11000UL;
@ -132,14 +130,14 @@ void RecursiveFreeUserspacePages(size_t level, size_t offset)
}
}
void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* user)
void DestroyAddressSpace(addr_t fallback)
{
// Look up the last few entries used for the fractal mapping. These
// cannot be unmapped as that would destroy the world. Instead, we
// will remember them, switch to another adress space, and safely
// mark them as unused. Also handling the forking related pages.
addr_t fractal1 = PMLS[2]->entry[1022];
addr_t dir = currentdir;
addr_t dir = GetAddressSpace();
// We want to free the pages, but we are still using them ourselves,
// so lock the page allocation structure until we are done.
@ -156,10 +154,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use
if ( !fallback )
fallback = (addr_t) BOOTPML2;
if ( func )
func(fallback, user);
else
SwitchAddressSpace(fallback);
SwitchAddressSpace(fallback);
// Ok, now we got marked everything left behind as unused, we can
// now safely let another thread use the pages.

View File

@ -1,75 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
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 <http://www.gnu.org/licenses/>.
x86/process.cpp
CPU-specific process code.
*******************************************************************************/
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <sortix/fork.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/process.h>
namespace Sortix {
void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp,
addr_t stackpos, addr_t entry,
CPU::InterruptRegisters* regs)
{
memset(regs, 0, sizeof(*regs));
regs->eax = argc;
regs->ebx = (size_t) argv;
regs->edx = envc;
regs->ecx = (size_t) envp;
regs->eip = entry;
regs->esp = stackpos & ~(15UL);
regs->ebp = regs->esp;
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->signal_pending = 0;
}
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
const struct tfork* requested)
{
memset(regs, 0, sizeof(*regs));
regs->eip = requested->eip;
regs->esp = requested->esp;
regs->eax = requested->eax;
regs->ebx = requested->ebx;
regs->ecx = requested->ecx;
regs->edx = requested->edx;
regs->edi = requested->edi;
regs->esi = requested->esi;
regs->ebp = requested->ebp;
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
}
} // namespace Sortix

View File

@ -27,13 +27,16 @@
.section .text
.type syscall_handler, @function
syscall_handler:
/* -- stack is 12 bytes from being 16-byte aligned -- */
movl $0, global_errno # Reset errno
pushl %ebp
/* -- stack is 8 bytes from being 16-byte aligned -- */
# Grant ourselves kernel permissions to the data segment.
movl %ds, %ebp
pushl %ebp
/* -- stack is 4 bytes from being 16-byte aligned -- */
movw $0x10, %bp
movl %ebp, %ds
movl %ebp, %es
@ -53,10 +56,12 @@ valid_syscall:
# Call the system call.
pushl %esi
/* -- stack is 16-byte aligned -- */
pushl %edi
pushl %edx
pushl %ecx
pushl %ebx
/* -- stack is 16-byte aligned -- */
calll *%eax
addl $20, %esp

View File

@ -1,45 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
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 <http://www.gnu.org/licenses/>.
x86/x86.cpp
CPU stuff for the x86 platform.
*******************************************************************************/
#include <sortix/kernel/cpu.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/log.h>
namespace Sortix {
namespace X86 {
void InterruptRegisters::LogRegisters() const
{
Log::PrintF("[cr2=0x%zx,ds=0x%zx,edi=0x%zx,esi=0x%zx,ebp=0x%zx,"
"ebx=0x%zx,edx=0x%zx,ecx=0x%zx,eax=0x%zx,"
"int_no=0x%zx,err_code=0x%zx,eip=0x%zx,cs=0x%zx,"
"eflags=0x%zx,esp=0x%zx,ss=0x%zx]",
cr2, ds, edi, esi, ebp,
ebx, edx, ecx, eax,
int_no, err_code, eip, cs,
eflags, esp, ss);
}
} // namespace X86
} // namespace Sortix