Refactor kernel interrupt and thread register support.
This commit is contained in:
parent
c2f9c0bb12
commit
25e07a9083
|
@ -31,13 +31,13 @@ BOOTOBJS:=
|
||||||
|
|
||||||
ifeq ($(CPU),x86)
|
ifeq ($(CPU),x86)
|
||||||
X86FAMILY:=1
|
X86FAMILY:=1
|
||||||
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o $(CPU)/x86.o
|
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CPU),x64)
|
ifeq ($(CPU),x64)
|
||||||
X86FAMILY:=1
|
X86FAMILY:=1
|
||||||
CXXFLAGS:=$(CXXFLAGS) -mno-red-zone -mno-mmx -mno-sse -mno-sse2
|
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
|
endif
|
||||||
|
|
||||||
ifdef X86FAMILY
|
ifdef X86FAMILY
|
||||||
|
@ -50,7 +50,6 @@ ifdef X86FAMILY
|
||||||
x86-family/gdt.o \
|
x86-family/gdt.o \
|
||||||
x86-family/idt.o \
|
x86-family/idt.o \
|
||||||
$(CPU)/syscall.o \
|
$(CPU)/syscall.o \
|
||||||
$(CPU)/process.o \
|
|
||||||
x86-family/cmos.o \
|
x86-family/cmos.o \
|
||||||
x86-family/time.o \
|
x86-family/time.o \
|
||||||
x86-family/mtrr.o \
|
x86-family/mtrr.o \
|
||||||
|
@ -124,6 +123,7 @@ pipe.o \
|
||||||
poll.o \
|
poll.o \
|
||||||
process.o \
|
process.o \
|
||||||
refcount.o \
|
refcount.o \
|
||||||
|
registers.o \
|
||||||
resource.o \
|
resource.o \
|
||||||
scheduler.o \
|
scheduler.o \
|
||||||
segment.o \
|
segment.o \
|
||||||
|
|
|
@ -406,7 +406,7 @@ void DevCOMPort::OnInterrupt()
|
||||||
|
|
||||||
Ref<DevCOMPort> comdevices[1+NUMCOMPORTS];
|
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++ )
|
for ( size_t i = 1; i <= NUMCOMPORTS; i++ )
|
||||||
{
|
{
|
||||||
|
|
|
@ -337,14 +337,12 @@ int ThreadId(Thread* thread)
|
||||||
|
|
||||||
int main_bt(int /*argc*/, char* /*argv*/[])
|
int main_bt(int /*argc*/, char* /*argv*/[])
|
||||||
{
|
{
|
||||||
CPU::InterruptRegisters regs;
|
|
||||||
current_thread->LoadRegisters(®s);
|
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
unsigned long ip = regs.rip;
|
unsigned long ip = current_thread->registers.rip;
|
||||||
unsigned long bp = regs.rbp;
|
unsigned long bp = current_thread->registers.rbp;
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
unsigned long ip = regs.eip;
|
unsigned long ip = current_thread->registers.eip;
|
||||||
unsigned long bp = regs.ebp;
|
unsigned long bp = current_thread->registers.ebp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool userspace = false;
|
bool userspace = false;
|
||||||
|
@ -434,7 +432,7 @@ int main_pid(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
current_thread = process->firstthread;
|
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,
|
Print("%c %i\t`%s'\n", '*', (int) current_process->pid,
|
||||||
current_process->program_image_path);
|
current_process->program_image_path);
|
||||||
|
@ -455,54 +453,48 @@ int main_ps(int /*argc*/, char* /*argv*/[])
|
||||||
|
|
||||||
int main_rs(int /*argc*/, char* /*argv*/[])
|
int main_rs(int /*argc*/, char* /*argv*/[])
|
||||||
{
|
{
|
||||||
CPU::InterruptRegisters regs;
|
|
||||||
current_thread->LoadRegisters(®s);
|
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
Print("rax=0x%lx, ", regs.rax);
|
Print("rax=0x%lX, ", current_thread->registers.rax);
|
||||||
Print("rbx=0x%lx, ", regs.rbx);
|
Print("rbx=0x%lX, ", current_thread->registers.rbx);
|
||||||
Print("rcx=0x%lx, ", regs.rcx);
|
Print("rcx=0x%lX, ", current_thread->registers.rcx);
|
||||||
Print("rdx=0x%lx, ", regs.rdx);
|
Print("rdx=0x%lX, ", current_thread->registers.rdx);
|
||||||
Print("rdi=0x%lx, ", regs.rdi);
|
Print("rdi=0x%lX, ", current_thread->registers.rdi);
|
||||||
Print("rsi=0x%lx, ", regs.rsi);
|
Print("rsi=0x%lX, ", current_thread->registers.rsi);
|
||||||
Print("rsp=0x%lx, ", regs.rsp);
|
Print("rsp=0x%lX, ", current_thread->registers.rsp);
|
||||||
Print("rbp=0x%lx, ", regs.rbp);
|
Print("rbp=0x%lX, ", current_thread->registers.rbp);
|
||||||
Print("r8=0x%lx, ", regs.r8);
|
Print("r8=0x%lX, ", current_thread->registers.r8);
|
||||||
Print("r9=0x%lx, ", regs.r9);
|
Print("r9=0x%lX, ", current_thread->registers.r9);
|
||||||
Print("r10=0x%lx, ", regs.r10);
|
Print("r10=0x%lX, ", current_thread->registers.r10);
|
||||||
Print("r11=0x%lx, ", regs.r11);
|
Print("r11=0x%lX, ", current_thread->registers.r11);
|
||||||
Print("r12=0x%lx, ", regs.r12);
|
Print("r12=0x%lX, ", current_thread->registers.r12);
|
||||||
Print("r13=0x%lx, ", regs.r13);
|
Print("r13=0x%lX, ", current_thread->registers.r13);
|
||||||
Print("r14=0x%lx, ", regs.r14);
|
Print("r14=0x%lX, ", current_thread->registers.r14);
|
||||||
Print("r15=0x%lx, ", regs.r15);
|
Print("r15=0x%lX, ", current_thread->registers.r15);
|
||||||
Print("rip=0x%lx, ", regs.rip);
|
Print("rip=0x%lX, ", current_thread->registers.rip);
|
||||||
Print("rflags=0x%lx, ", regs.rflags);
|
Print("rflags=0x%lX, ", current_thread->registers.rflags);
|
||||||
Print("int_no=%lu, ", regs.int_no);
|
Print("fsbase=0x%lX, ", current_thread->registers.fsbase);
|
||||||
Print("err_code=0x%lx, ", regs.err_code);
|
Print("gsbase=0x%lX, ", current_thread->registers.gsbase);
|
||||||
Print("cs=0x%lx, ", regs.cs);
|
Print("cr3=0x%lX, ", current_thread->registers.cr3);
|
||||||
Print("ds=0x%lx, ", regs.ds);
|
Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack);
|
||||||
Print("ss=0x%lx, ", regs.ss);
|
Print("kerrno=%lu, ", current_thread->registers.kerrno);
|
||||||
Print("kerrno=%lu, ", regs.kerrno);
|
Print("signal_pending=%lu.", current_thread->registers.signal_pending);
|
||||||
Print("cr2=%lx, ", regs.cr2);
|
|
||||||
Print("signal_pending=%lu.", regs.signal_pending);
|
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
Print("eax=0x%lx, ", regs.eax);
|
Print("eax=0x%lX, ", current_thread->registers.eax);
|
||||||
Print("ebx=0x%lx, ", regs.ebx);
|
Print("ebx=0x%lX, ", current_thread->registers.ebx);
|
||||||
Print("ecx=0x%lx, ", regs.ecx);
|
Print("ecx=0x%lX, ", current_thread->registers.ecx);
|
||||||
Print("edx=0x%lx, ", regs.edx);
|
Print("edx=0x%lX, ", current_thread->registers.edx);
|
||||||
Print("edi=0x%lx, ", regs.edi);
|
Print("edi=0x%lX, ", current_thread->registers.edi);
|
||||||
Print("esi=0x%lx, ", regs.esi);
|
Print("esi=0x%lX, ", current_thread->registers.esi);
|
||||||
Print("esp=0x%lx, ", regs.esp);
|
Print("esp=0x%lX, ", current_thread->registers.esp);
|
||||||
Print("ebp=0x%lx, ", regs.ebp);
|
Print("ebp=0x%lX, ", current_thread->registers.ebp);
|
||||||
Print("eip=0x%lx, ", regs.eip);
|
Print("eip=0x%lX, ", current_thread->registers.eip);
|
||||||
Print("eflags=0x%lx, ", regs.eflags);
|
Print("eflags=0x%lX, ", current_thread->registers.eflags);
|
||||||
Print("int_no=%lu, ", regs.int_no);
|
Print("fsbase=0x%lX, ", current_thread->registers.fsbase);
|
||||||
Print("err_code=0x%lx, ", regs.err_code);
|
Print("gsbase=0x%lX, ", current_thread->registers.gsbase);
|
||||||
Print("cs=0x%lx, ", regs.cs);
|
Print("cr3=0x%lX, ", current_thread->registers.cr3);
|
||||||
Print("ds=0x%lx, ", regs.ds);
|
Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack);
|
||||||
Print("ss=0x%lx, ", regs.ss);
|
Print("kerrno=%lX, ", current_thread->registers.kerrno);
|
||||||
Print("kerrno=%lu, ", regs.kerrno);
|
Print("signal_pending=%lu.", current_thread->registers.signal_pending);
|
||||||
Print("cr2=%lx, ", regs.cr2);
|
|
||||||
Print("signal_pending=%lu.", regs.signal_pending);
|
|
||||||
#endif
|
#endif
|
||||||
Print("\n");
|
Print("\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -510,12 +502,10 @@ int main_rs(int /*argc*/, char* /*argv*/[])
|
||||||
|
|
||||||
static void DescribeThread(int tid, Thread* thread)
|
static void DescribeThread(int tid, Thread* thread)
|
||||||
{
|
{
|
||||||
CPU::InterruptRegisters regs;
|
|
||||||
thread->LoadRegisters(®s);
|
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
unsigned long ip = regs.rip;
|
unsigned long ip = thread->registers.rip;
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
unsigned long ip = regs.eip;
|
unsigned long ip = thread->registers.eip;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Print("%c ", thread == current_thread ? '*' : ' ');
|
Print("%c ", thread == current_thread ? '*' : ' ');
|
||||||
|
@ -538,7 +528,7 @@ int main_tid(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
current_thread = thread;
|
current_thread = thread;
|
||||||
Memory::SwitchAddressSpace(current_thread->addrspace);
|
Memory::SwitchAddressSpace(current_thread->registers.cr3);
|
||||||
}
|
}
|
||||||
DescribeThread(ThreadId(current_thread), current_thread);
|
DescribeThread(ThreadId(current_thread), current_thread);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -624,7 +614,7 @@ void Run()
|
||||||
|
|
||||||
first_f10 = true;
|
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));
|
memcpy(saved_video_memory, VIDEO_MEMORY, sizeof(saved_video_memory));
|
||||||
int saved_x, saved_y;
|
int saved_x, saved_y;
|
||||||
|
|
|
@ -40,92 +40,6 @@ void ShutDown();
|
||||||
} // namespace CPU
|
} // namespace CPU
|
||||||
#endif
|
#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
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,14 +28,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <sortix/kernel/decl.h>
|
#include <sortix/kernel/decl.h>
|
||||||
|
#include <sortix/kernel/registers.h>
|
||||||
namespace Sortix {
|
|
||||||
namespace CPU {
|
|
||||||
|
|
||||||
struct InterruptRegisters;
|
|
||||||
|
|
||||||
} // namespace CPU
|
|
||||||
} // namespace Sortix
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Interrupt {
|
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 RegisterHandler(unsigned int index, Handler handler, void* user);
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
|
|
|
@ -77,9 +77,7 @@ void Flush();
|
||||||
addr_t Fork();
|
addr_t Fork();
|
||||||
addr_t GetAddressSpace();
|
addr_t GetAddressSpace();
|
||||||
addr_t SwitchAddressSpace(addr_t addrspace);
|
addr_t SwitchAddressSpace(addr_t addrspace);
|
||||||
void DestroyAddressSpace(addr_t fallback = 0,
|
void DestroyAddressSpace(addr_t fallback = 0);
|
||||||
void (*func)(addr_t, void*) = NULL,
|
|
||||||
void* user = NULL);
|
|
||||||
bool Map(addr_t physical, addr_t mapto, int prot);
|
bool Map(addr_t physical, addr_t mapto, int prot);
|
||||||
addr_t Unmap(addr_t mapto);
|
addr_t Unmap(addr_t mapto);
|
||||||
addr_t Physical(addr_t mapto);
|
addr_t Physical(addr_t mapto);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <sortix/kernel/clock.h>
|
#include <sortix/kernel/clock.h>
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
#include <sortix/kernel/refcount.h>
|
#include <sortix/kernel/refcount.h>
|
||||||
|
#include <sortix/kernel/registers.h>
|
||||||
#include <sortix/kernel/segment.h>
|
#include <sortix/kernel/segment.h>
|
||||||
#include <sortix/kernel/time.h>
|
#include <sortix/kernel/time.h>
|
||||||
#include <sortix/kernel/timer.h>
|
#include <sortix/kernel/timer.h>
|
||||||
|
@ -168,7 +169,7 @@ public:
|
||||||
int Execute(const char* programname, const uint8_t* program,
|
int Execute(const char* programname, const uint8_t* program,
|
||||||
size_t programsize, int argc, const char* const* argv,
|
size_t programsize, int argc, const char* const* argv,
|
||||||
int envc, const char* const* envp,
|
int envc, const char* const* envp,
|
||||||
CPU::InterruptRegisters* regs);
|
struct thread_registers* regs);
|
||||||
void ResetAddressSpace();
|
void ResetAddressSpace();
|
||||||
void ExitThroughSignal(int signal);
|
void ExitThroughSignal(int signal);
|
||||||
void ExitWithCode(int exit_code);
|
void ExitWithCode(int exit_code);
|
||||||
|
@ -187,9 +188,6 @@ public:
|
||||||
Process* Fork();
|
Process* Fork();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ExecuteCPU(int argc, char** argv, int envc, char** envp,
|
|
||||||
addr_t stackpos, addr_t entry,
|
|
||||||
CPU::InterruptRegisters* regs);
|
|
||||||
void OnLastThreadExit();
|
void OnLastThreadExit();
|
||||||
void LastPrayer();
|
void LastPrayer();
|
||||||
void NotifyMemberExit(Process* child);
|
void NotifyMemberExit(Process* child);
|
||||||
|
@ -212,8 +210,6 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
|
|
||||||
const struct tfork* requested);
|
|
||||||
Process* CurrentProcess();
|
Process* CurrentProcess();
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -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
|
|
@ -26,18 +26,13 @@
|
||||||
#define INCLUDE_SORTIX_KERNEL_SCHEDULER_H
|
#define INCLUDE_SORTIX_KERNEL_SCHEDULER_H
|
||||||
|
|
||||||
#include <sortix/kernel/decl.h>
|
#include <sortix/kernel/decl.h>
|
||||||
|
#include <sortix/kernel/registers.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
class Process;
|
class Process;
|
||||||
class Thread;
|
class Thread;
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
||||||
namespace Sortix {
|
|
||||||
namespace CPU {
|
|
||||||
struct InterruptRegisters;
|
|
||||||
} // namespace CPU
|
|
||||||
} // namespace Sortix
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
enum ThreadState { NONE, RUNNABLE, BLOCKING, DEAD };
|
enum ThreadState { NONE, RUNNABLE, BLOCKING, DEAD };
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
@ -59,15 +54,19 @@ static inline void ExitThread()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void Switch(CPU::InterruptRegisters* regs);
|
void Switch(struct interrupt_context* intctx);
|
||||||
void SetThreadState(Thread* thread, ThreadState state);
|
void SetThreadState(Thread* thread, ThreadState state);
|
||||||
ThreadState GetThreadState(Thread* thread);
|
ThreadState GetThreadState(Thread* thread);
|
||||||
void SetIdleThread(Thread* thread);
|
void SetIdleThread(Thread* thread);
|
||||||
void SetInitProcess(Process* init);
|
void SetInitProcess(Process* init);
|
||||||
Process* GetInitProcess();
|
Process* GetInitProcess();
|
||||||
Process* GetKernelProcess();
|
Process* GetKernelProcess();
|
||||||
void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* user);
|
void InterruptYieldCPU(struct interrupt_context* intctx, void* user);
|
||||||
void ThreadExitCPU(CPU::InterruptRegisters* regs, 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 Scheduler
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <sortix/sigset.h>
|
#include <sortix/sigset.h>
|
||||||
|
|
||||||
#include <sortix/kernel/cpu.h>
|
#include <sortix/kernel/cpu.h>
|
||||||
|
#include <sortix/kernel/registers.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
|
@ -38,8 +39,8 @@ namespace Signal {
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
inline bool IsPending() { return asm_signal_is_pending != 0; }
|
inline bool IsPending() { return asm_signal_is_pending != 0; }
|
||||||
void DispatchHandler(CPU::InterruptRegisters* regs, void* user);
|
void DispatchHandler(struct interrupt_context* intctx, void* user);
|
||||||
void ReturnHandler(CPU::InterruptRegisters* regs, void* user);
|
void ReturnHandler(struct interrupt_context* intctx, void* user);
|
||||||
|
|
||||||
} // namespace Signal
|
} // namespace Signal
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <sortix/stack.h>
|
#include <sortix/stack.h>
|
||||||
|
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
#include <sortix/kernel/registers.h>
|
||||||
#include <sortix/kernel/scheduler.h>
|
#include <sortix/kernel/scheduler.h>
|
||||||
#include <sortix/kernel/signal.h>
|
#include <sortix/kernel/signal.h>
|
||||||
|
|
||||||
|
@ -40,8 +41,7 @@ class Process;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
// These functions create a new kernel process but doesn't start it.
|
// These functions create a new kernel process but doesn't start it.
|
||||||
Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
|
Thread* CreateKernelThread(Process* process, struct thread_registers* regs);
|
||||||
unsigned long fsbase, unsigned long gsbase);
|
|
||||||
Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user,
|
Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user,
|
||||||
size_t stacksize = 0);
|
size_t stacksize = 0);
|
||||||
Thread* CreateKernelThread(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);
|
void StartKernelThread(Thread* thread);
|
||||||
|
|
||||||
// Alternatively, these functions both create and start the 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,
|
Thread* RunKernelThread(Process* process, void (*entry)(void*), void* user,
|
||||||
size_t stacksize = 0);
|
size_t stacksize = 0);
|
||||||
Thread* RunKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0);
|
Thread* RunKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0);
|
||||||
|
|
||||||
class Thread
|
class Thread
|
||||||
{
|
{
|
||||||
friend Thread* CreateKernelThread(Process* process,
|
|
||||||
CPU::InterruptRegisters* regs,
|
|
||||||
unsigned long fsbase, unsigned long gsbase);
|
|
||||||
friend void UpdatePendingSignals(Thread* thread);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void Init();
|
static void Init();
|
||||||
|
|
||||||
|
@ -70,49 +65,34 @@ public:
|
||||||
~Thread();
|
~Thread();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
struct thread_registers registers;
|
||||||
|
uint8_t* self_allocation;
|
||||||
size_t id;
|
size_t id;
|
||||||
Process* process;
|
Process* process;
|
||||||
Thread* prevsibling;
|
Thread* prevsibling;
|
||||||
Thread* nextsibling;
|
Thread* nextsibling;
|
||||||
|
|
||||||
public:
|
|
||||||
Thread* scheduler_list_prev;
|
Thread* scheduler_list_prev;
|
||||||
Thread* scheduler_list_next;
|
Thread* scheduler_list_next;
|
||||||
volatile ThreadState state;
|
volatile ThreadState state;
|
||||||
uint8_t fpuenv[512UL + 16UL];
|
|
||||||
uint8_t* fpuenvaligned;
|
|
||||||
bool fpuinitialized;
|
|
||||||
|
|
||||||
public:
|
|
||||||
sigset_t signal_pending;
|
sigset_t signal_pending;
|
||||||
sigset_t signal_mask;
|
sigset_t signal_mask;
|
||||||
stack_t signal_stack;
|
stack_t signal_stack;
|
||||||
addr_t addrspace;
|
|
||||||
addr_t kernelstackpos;
|
addr_t kernelstackpos;
|
||||||
size_t kernelstacksize;
|
size_t kernelstacksize;
|
||||||
bool kernelstackmalloced;
|
bool kernelstackmalloced;
|
||||||
bool pledged_destruction;
|
bool pledged_destruction;
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
|
||||||
public:
|
public:
|
||||||
unsigned long fsbase;
|
void HandleSignal(struct interrupt_context* intctx);
|
||||||
unsigned long gsbase;
|
void HandleSigreturn(struct interrupt_context* intctx);
|
||||||
#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);
|
|
||||||
bool DeliverSignal(int signum);
|
bool DeliverSignal(int signum);
|
||||||
bool DeliverSignalUnlocked(int signum);
|
bool DeliverSignalUnlocked(int signum);
|
||||||
addr_t SwitchAddressSpace(addr_t newaddrspace);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Thread* AllocateThread();
|
||||||
|
void FreeThread(Thread* thread);
|
||||||
|
|
||||||
Thread* CurrentThread();
|
Thread* CurrentThread();
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <sortix/kernel/ioport.h>
|
#include <sortix/kernel/ioport.h>
|
||||||
#include <sortix/kernel/kernel.h>
|
#include <sortix/kernel/kernel.h>
|
||||||
#include <sortix/kernel/keyboard.h>
|
#include <sortix/kernel/keyboard.h>
|
||||||
|
#include <sortix/kernel/scheduler.h>
|
||||||
#include <sortix/kernel/thread.h>
|
#include <sortix/kernel/thread.h>
|
||||||
|
|
||||||
#if defined(__i386__)
|
#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_NUMLCK = 1 << 1;
|
||||||
const uint8_t LED_CAPSLCK = 1 << 2;
|
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)
|
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);
|
((PS2Keyboard*) kb_ptr)->InterruptWork(work->scancode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs)
|
void PS2Keyboard::OnInterrupt(struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
uint8_t scancode = PopScancode();
|
uint8_t scancode = PopScancode();
|
||||||
if ( scancode == KBKEY_F10 )
|
if ( scancode == KBKEY_F10 )
|
||||||
{
|
{
|
||||||
Thread* thread = CurrentThread();
|
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
|
||||||
#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);
|
|
||||||
Debugger::Run();
|
Debugger::Run();
|
||||||
}
|
}
|
||||||
PS2KeyboardWork work;
|
PS2KeyboardWork work;
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
virtual void SetOwner(KeyboardOwner* owner, void* user);
|
virtual void SetOwner(KeyboardOwner* owner, void* user);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void OnInterrupt(CPU::InterruptRegisters* regs);
|
void OnInterrupt(struct interrupt_context* intctx);
|
||||||
void InterruptWork(uint8_t scancode);
|
void InterruptWork(uint8_t scancode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
|
|
||||||
// Keep the stack size aligned with $CPU/base.s
|
// Keep the stack size aligned with $CPU/base.s
|
||||||
const size_t STACK_SIZE = 64*1024;
|
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 {
|
namespace Sortix {
|
||||||
|
|
||||||
|
@ -290,6 +290,7 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
|
|
||||||
// Initialize the GDT and TSS structures.
|
// Initialize the GDT and TSS structures.
|
||||||
GDT::Init();
|
GDT::Init();
|
||||||
|
GDT::SetKernelStack((uintptr_t) stack + STACK_SIZE);
|
||||||
|
|
||||||
// Initialize the interrupt handler table and enable interrupts.
|
// Initialize the interrupt handler table and enable interrupts.
|
||||||
Interrupt::Init();
|
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
|
// Now that the base system has been loaded, it's time to go threaded. First
|
||||||
// we create an object that represents this thread.
|
// we create an object that represents this thread.
|
||||||
Process* system = new Process;
|
Process* system = new Process;
|
||||||
if ( !system ) { Panic("Could not allocate the system process"); }
|
if ( !system )
|
||||||
addr_t systemaddrspace = Memory::GetAddressSpace();
|
Panic("Could not allocate the system process");
|
||||||
system->addrspace = systemaddrspace;
|
system->addrspace = Memory::GetAddressSpace();
|
||||||
system->group = system;
|
system->group = system;
|
||||||
system->groupprev = NULL;
|
system->groupprev = NULL;
|
||||||
system->groupnext = 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
|
// 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
|
// scheduler's set of runnable threads, but rather run whenever there is
|
||||||
// _nothing_ else to run on this CPU.
|
// _nothing_ else to run on this CPU.
|
||||||
Thread* idlethread = new Thread;
|
Thread* idlethread = AllocateThread();
|
||||||
idlethread->process = system;
|
idlethread->process = system;
|
||||||
idlethread->addrspace = idlethread->process->addrspace;
|
|
||||||
idlethread->kernelstackpos = (addr_t) stack;
|
idlethread->kernelstackpos = (addr_t) stack;
|
||||||
idlethread->kernelstacksize = STACK_SIZE;
|
idlethread->kernelstacksize = STACK_SIZE;
|
||||||
idlethread->kernelstackmalloced = false;
|
idlethread->kernelstackmalloced = false;
|
||||||
idlethread->fpuinitialized = true;
|
|
||||||
system->firstthread = idlethread;
|
system->firstthread = idlethread;
|
||||||
Scheduler::SetIdleThread(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.
|
// we must become the system idle thread.
|
||||||
RunKernelThread(BootThread, NULL);
|
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.
|
// The time driver will run the scheduler on the next timer interrupt.
|
||||||
Time::Start();
|
Time::Start();
|
||||||
|
|
||||||
|
@ -766,7 +762,8 @@ static void InitThread(void* /*user*/)
|
||||||
const char* cputype = "cputype=" CPUTYPE_STR;
|
const char* cputype = "cputype=" CPUTYPE_STR;
|
||||||
int envc = 1;
|
int envc = 1;
|
||||||
const char* envp[] = { cputype, NULL };
|
const char* envp[] = { cputype, NULL };
|
||||||
CPU::InterruptRegisters regs;
|
struct thread_registers regs;
|
||||||
|
assert((((uintptr_t) ®s) & (alignof(regs)-1)) == 0);
|
||||||
|
|
||||||
if ( process->Execute(initpath, program, programsize, argc, argv, envc,
|
if ( process->Execute(initpath, program, programsize, argc, argv, envc,
|
||||||
envp, ®s) )
|
envp, ®s) )
|
||||||
|
@ -775,7 +772,7 @@ static void InitThread(void* /*user*/)
|
||||||
delete[] program;
|
delete[] program;
|
||||||
|
|
||||||
// Now become the init process and the operation system shall run.
|
// Now become the init process and the operation system shall run.
|
||||||
CPU::LoadRegisters(®s);
|
LoadRegisters(®s);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -39,7 +39,7 @@ static void kthread_do_kill_thread(void* user)
|
||||||
Thread* thread = (Thread*) user;
|
Thread* thread = (Thread*) user;
|
||||||
while ( thread->state != ThreadState::DEAD )
|
while ( thread->state != ThreadState::DEAD )
|
||||||
kthread_yield();
|
kthread_yield();
|
||||||
delete thread;
|
FreeThread(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void kthread_exit()
|
extern "C" void kthread_exit()
|
||||||
|
|
|
@ -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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#include "initrd.h"
|
#include "initrd.h"
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
#include "x86-family/float.h"
|
||||||
#include "x86-family/gdt.h"
|
#include "x86-family/gdt.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -249,11 +250,6 @@ void Process::OnLastThreadExit()
|
||||||
LastPrayer();
|
LastPrayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SwitchCurrentAddrspace(addr_t addrspace, void* user)
|
|
||||||
{
|
|
||||||
((Thread*) user)->SwitchAddressSpace(addrspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::DeleteTimers()
|
void Process::DeleteTimers()
|
||||||
{
|
{
|
||||||
for ( timer_t i = 0; i < PROCESS_TIMER_NUM_MAX; i++ )
|
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
|
// We need to temporarily reload the correct addrese space of the dying
|
||||||
// process such that we can unmap and free its memory.
|
// process such that we can unmap and free its memory.
|
||||||
addr_t prevaddrspace = curthread->SwitchAddressSpace(addrspace);
|
addr_t prevaddrspace = Memory::SwitchAddressSpace(addrspace);
|
||||||
|
|
||||||
ResetAddressSpace();
|
ResetAddressSpace();
|
||||||
|
|
||||||
|
@ -301,9 +297,7 @@ void Process::LastPrayer()
|
||||||
|
|
||||||
// Destroy the address space and safely switch to the replacement
|
// Destroy the address space and safely switch to the replacement
|
||||||
// address space before things get dangerous.
|
// address space before things get dangerous.
|
||||||
Memory::DestroyAddressSpace(prevaddrspace,
|
Memory::DestroyAddressSpace(prevaddrspace);
|
||||||
SwitchCurrentAddrspace,
|
|
||||||
curthread);
|
|
||||||
addrspace = 0;
|
addrspace = 0;
|
||||||
|
|
||||||
// Unload the process symbol and string tables.
|
// 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,
|
int Process::Execute(const char* programname, const uint8_t* program,
|
||||||
size_t programsize, int argc, const char* const* argv,
|
size_t programsize, int argc, const char* const* argv,
|
||||||
int envc, const char* const* envp,
|
int envc, const char* const* envp,
|
||||||
CPU::InterruptRegisters* regs)
|
struct thread_registers* regs)
|
||||||
{
|
{
|
||||||
assert(argc != INT_MAX);
|
assert(argc != INT_MAX);
|
||||||
assert(envc != 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;
|
uthread->arg_size = arg_segment.size;
|
||||||
memset(uthread + 1, 0, aux.uthread_size - sizeof(struct uthread));
|
memset(uthread + 1, 0, aux.uthread_size - sizeof(struct uthread));
|
||||||
|
|
||||||
|
memset(regs, 0, sizeof(*regs));
|
||||||
#if defined(__i386__)
|
#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__)
|
#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
|
#endif
|
||||||
|
|
||||||
uint8_t* auxcode = (uint8_t*) auxcode_segment.addr;
|
uint8_t* auxcode = (uint8_t*) auxcode_segment.addr;
|
||||||
|
@ -991,8 +1018,6 @@ int Process::Execute(const char* programname, const uint8_t* program,
|
||||||
|
|
||||||
dtable->OnExecute();
|
dtable->OnExecute();
|
||||||
|
|
||||||
ExecuteCPU(argc, target_argv, envc, target_envp, stack_segment.addr + stack_segment.size, entry, regs);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,7 +1027,7 @@ int sys_execve_kernel(const char* filename,
|
||||||
char* const argv[],
|
char* const argv[],
|
||||||
int envc,
|
int envc,
|
||||||
char* const envp[],
|
char* const envp[],
|
||||||
CPU::InterruptRegisters* regs)
|
struct thread_registers* regs)
|
||||||
{
|
{
|
||||||
Process* process = CurrentProcess();
|
Process* process = CurrentProcess();
|
||||||
|
|
||||||
|
@ -1054,7 +1079,7 @@ int sys_execve(const char* user_filename,
|
||||||
char** argv;
|
char** argv;
|
||||||
char** envp;
|
char** envp;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
CPU::InterruptRegisters regs;
|
struct thread_registers regs;
|
||||||
memset(®s, 0, sizeof(regs));
|
memset(®s, 0, sizeof(regs));
|
||||||
|
|
||||||
if ( !user_filename || !user_argv || !user_envp )
|
if ( !user_filename || !user_argv || !user_envp )
|
||||||
|
@ -1135,7 +1160,7 @@ cleanup_filename:
|
||||||
delete[] filename;
|
delete[] filename;
|
||||||
cleanup_done:
|
cleanup_done:
|
||||||
if ( result == 0 )
|
if ( result == 0 )
|
||||||
CPU::LoadRegisters(®s);
|
LoadRegisters(®s);
|
||||||
return result;
|
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 )
|
if ( regs.altstack.ss_flags & ~__SS_SUPPORTED_FLAGS )
|
||||||
return errno = EINVAL, -1;
|
return errno = EINVAL, -1;
|
||||||
|
|
||||||
CPU::InterruptRegisters cpuregs;
|
size_t stack_alignment = 16;
|
||||||
InitializeThreadRegisters(&cpuregs, ®s);
|
|
||||||
|
|
||||||
// TODO: Is it a hack to create a new kernel stack here?
|
// TODO: Is it a hack to create a new kernel stack here?
|
||||||
Thread* curthread = CurrentThread();
|
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 )
|
if ( !newkernelstack )
|
||||||
return -1;
|
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;
|
Process* child_process;
|
||||||
if ( making_thread )
|
if ( making_thread )
|
||||||
child_process = CurrentProcess();
|
child_process = CurrentProcess();
|
||||||
|
@ -1176,10 +1208,59 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
|
||||||
return -1;
|
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
|
// If the thread could not be created, make the process commit suicide
|
||||||
// in a manner such that we don't wait for its zombie.
|
// in a manner such that we don't wait for its zombie.
|
||||||
Thread* thread = CreateKernelThread(child_process, &cpuregs, regs.fsbase,
|
Thread* thread = CreateKernelThread(child_process, &cpuregs);
|
||||||
regs.gsbase);
|
|
||||||
if ( !thread )
|
if ( !thread )
|
||||||
{
|
{
|
||||||
if ( making_process )
|
if ( making_process )
|
||||||
|
@ -1188,7 +1269,7 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->kernelstackpos = (addr_t) newkernelstack;
|
thread->kernelstackpos = (addr_t) newkernelstack;
|
||||||
thread->kernelstacksize = curthread->kernelstacksize;
|
thread->kernelstacksize = newkernelstacksize;
|
||||||
thread->kernelstackmalloced = true;
|
thread->kernelstackmalloced = true;
|
||||||
memcpy(&thread->signal_mask, ®s.sigmask, sizeof(sigset_t));
|
memcpy(&thread->signal_mask, ®s.sigmask, sizeof(sigset_t));
|
||||||
memcpy(&thread->signal_stack, ®s.altstack, sizeof(stack_t));
|
memcpy(&thread->signal_stack, ®s.altstack, sizeof(stack_t));
|
||||||
|
|
|
@ -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
|
|
@ -25,10 +25,13 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <msr.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <timespec.h>
|
#include <timespec.h>
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
#include <msr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sortix/clock.h>
|
#include <sortix/clock.h>
|
||||||
#include <sortix/timespec.h>
|
#include <sortix/timespec.h>
|
||||||
|
|
||||||
|
@ -37,6 +40,7 @@
|
||||||
#include <sortix/kernel/kernel.h>
|
#include <sortix/kernel/kernel.h>
|
||||||
#include <sortix/kernel/memorymanagement.h>
|
#include <sortix/kernel/memorymanagement.h>
|
||||||
#include <sortix/kernel/process.h>
|
#include <sortix/kernel/process.h>
|
||||||
|
#include <sortix/kernel/registers.h>
|
||||||
#include <sortix/kernel/scheduler.h>
|
#include <sortix/kernel/scheduler.h>
|
||||||
#include <sortix/kernel/signal.h>
|
#include <sortix/kernel/signal.h>
|
||||||
#include <sortix/kernel/syscall.h>
|
#include <sortix/kernel/syscall.h>
|
||||||
|
@ -52,9 +56,143 @@ namespace Sortix {
|
||||||
namespace Scheduler {
|
namespace Scheduler {
|
||||||
|
|
||||||
static Thread* current_thread;
|
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* idle_thread;
|
||||||
static Thread* first_runnable_thread;
|
static Thread* first_runnable_thread;
|
||||||
static Thread* first_sleeping_thread;
|
|
||||||
static Process* init_process;
|
static Process* init_process;
|
||||||
|
|
||||||
static Thread* PopNextThread()
|
static Thread* PopNextThread()
|
||||||
|
@ -69,63 +207,26 @@ static Thread* PopNextThread()
|
||||||
return idle_thread;
|
return idle_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoActualSwitch(CPU::InterruptRegisters* regs)
|
void Switch(struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
Thread* prev = CurrentThread();
|
SwitchThread(intctx, CurrentThread(), PopNextThread());
|
||||||
Thread* next = PopNextThread();
|
|
||||||
|
|
||||||
if ( prev == next )
|
if ( intctx->signal_pending && InUserspace(intctx) )
|
||||||
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() )
|
|
||||||
{
|
{
|
||||||
Interrupt::Enable();
|
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);
|
SetThreadState(current_thread, ThreadState::DEAD);
|
||||||
InterruptYieldCPU(regs, NULL);
|
InterruptYieldCPU(intctx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The idle thread serves no purpose except being an infinite loop that does
|
// 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()
|
void Init()
|
||||||
{
|
{
|
||||||
first_runnable_thread = NULL;
|
first_runnable_thread = NULL;
|
||||||
first_sleeping_thread = NULL;
|
|
||||||
idle_thread = NULL;
|
idle_thread = NULL;
|
||||||
|
|
||||||
Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield);
|
Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield);
|
||||||
|
|
|
@ -44,10 +44,6 @@
|
||||||
#include <sortix/kernel/syscall.h>
|
#include <sortix/kernel/syscall.h>
|
||||||
#include <sortix/kernel/thread.h>
|
#include <sortix/kernel/thread.h>
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
|
||||||
#include "x86-family/float.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
sigset_t default_ignored_signals;
|
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.
|
// A per-cpu value whether a signal is pending in the running task.
|
||||||
extern "C" { volatile unsigned long asm_signal_is_pending = 0; }
|
extern "C" { volatile unsigned long asm_signal_is_pending = 0; }
|
||||||
|
|
||||||
|
static
|
||||||
void UpdatePendingSignals(Thread* thread) // thread->process->signal_lock held
|
void UpdatePendingSignals(Thread* thread) // thread->process->signal_lock held
|
||||||
{
|
{
|
||||||
struct sigaction* signal_actions = thread->process->signal_actions;
|
struct sigaction* signal_actions = thread->process->signal_actions;
|
||||||
|
@ -400,7 +397,9 @@ static int PickImportantSignal(const sigset_t* set)
|
||||||
return 0;
|
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));
|
memset(mctx, 0, sizeof(*mctx));
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
@ -419,10 +418,9 @@ static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
|
||||||
mctx->gregs[REG_EIP] = regs->eip;
|
mctx->gregs[REG_EIP] = regs->eip;
|
||||||
// TODO: REG_CS
|
// TODO: REG_CS
|
||||||
mctx->gregs[REG_EFL] = regs->eflags & 0x0000FFFF;
|
mctx->gregs[REG_EFL] = regs->eflags & 0x0000FFFF;
|
||||||
mctx->gregs[REG_CR2] = regs->cr2;
|
mctx->gregs[REG_CR2] = intctx->cr2;
|
||||||
// TODO: REG_SS
|
// TODO: REG_SS
|
||||||
Float::Yield();
|
memcpy(mctx->fpuenv, regs->fpuenv, 512);
|
||||||
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
mctx->gregs[REG_R8] = regs->r8;
|
mctx->gregs[REG_R8] = regs->r8;
|
||||||
mctx->gregs[REG_R9] = regs->r9;
|
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_RIP] = regs->rip;
|
||||||
mctx->gregs[REG_EFL] = regs->rflags & 0x000000000000FFFF;
|
mctx->gregs[REG_EFL] = regs->rflags & 0x000000000000FFFF;
|
||||||
// TODO: REG_CSGSFS.
|
// TODO: REG_CSGSFS.
|
||||||
mctx->gregs[REG_CR2] = regs->cr2;
|
mctx->gregs[REG_CR2] = intctx->cr2;
|
||||||
mctx->gregs[REG_FSBASE] = 0x0;
|
mctx->gregs[REG_FSBASE] = 0x0;
|
||||||
mctx->gregs[REG_GSBASE] = 0x0;
|
mctx->gregs[REG_GSBASE] = 0x0;
|
||||||
Float::Yield();
|
memcpy(mctx->fpuenv, regs->fpuenv, 512);
|
||||||
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
|
|
||||||
#else
|
#else
|
||||||
#error "You need to implement conversion to mcontext"
|
#error "You need to implement conversion to mcontext"
|
||||||
#endif
|
#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__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
unsigned long user_flags = FLAGS_CARRY | FLAGS_PARITY | FLAGS_AUX
|
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->eip = mctx->gregs[REG_EIP];
|
||||||
regs->eflags &= ~user_flags;
|
regs->eflags &= ~user_flags;
|
||||||
regs->eflags |= mctx->gregs[REG_EFL] & user_flags;
|
regs->eflags |= mctx->gregs[REG_EFL] & user_flags;
|
||||||
regs->cr2 = mctx->gregs[REG_CR2];
|
memcpy(regs->fpuenv, mctx->fpuenv, 512);
|
||||||
Float::Yield();
|
|
||||||
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
regs->r8 = mctx->gregs[REG_R8];
|
regs->r8 = mctx->gregs[REG_R8];
|
||||||
regs->r9 = mctx->gregs[REG_R9];
|
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->rip = mctx->gregs[REG_RIP];
|
||||||
regs->rflags &= ~user_flags;
|
regs->rflags &= ~user_flags;
|
||||||
regs->rflags |= mctx->gregs[REG_EFL] & user_flags;
|
regs->rflags |= mctx->gregs[REG_EFL] & user_flags;
|
||||||
regs->cr2 = mctx->gregs[REG_CR2];
|
memcpy(regs->fpuenv, mctx->fpuenv, 512);
|
||||||
Float::Yield();
|
|
||||||
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
|
|
||||||
#else
|
#else
|
||||||
#error "You need to implement conversion to mcontext"
|
#error "You need to implement conversion to mcontext"
|
||||||
#endif
|
#endif
|
||||||
|
@ -525,7 +519,7 @@ struct stack_frame
|
||||||
#error "You need to implement struct stack_frame"
|
#error "You need to implement struct stack_frame"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Thread::HandleSignal(CPU::InterruptRegisters* regs)
|
void Thread::HandleSignal(struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
assert(Interrupt::IsEnabled());
|
assert(Interrupt::IsEnabled());
|
||||||
assert(this == CurrentThread());
|
assert(this == CurrentThread());
|
||||||
|
@ -553,7 +547,7 @@ retry_another_signal:
|
||||||
// Unmark the selected signal as pending.
|
// Unmark the selected signal as pending.
|
||||||
sigdelset(&signal_pending, signum);
|
sigdelset(&signal_pending, signum);
|
||||||
UpdatePendingSignals(this);
|
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.
|
// Destroy the current thread if the signal is critical.
|
||||||
if ( signum == SIGKILL )
|
if ( signum == SIGKILL )
|
||||||
|
@ -614,28 +608,31 @@ retry_another_signal:
|
||||||
// threads in the kernel cannot be delivered signals except when returning
|
// 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
|
// from a system call, so we'll simply save the state that would have been
|
||||||
// returned to user-space had no signal occured.
|
// returned to user-space had no signal occured.
|
||||||
if ( !regs->InUserspace() )
|
if ( !InUserspace(intctx) )
|
||||||
{
|
{
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
uint32_t* params = (uint32_t*) regs->ebx;
|
uint32_t* params = (uint32_t*) intctx->ebx;
|
||||||
regs->eip = params[0];
|
intctx->eip = params[0];
|
||||||
regs->eflags = params[2];
|
intctx->eflags = params[2];
|
||||||
regs->esp = params[3];
|
intctx->esp = params[3];
|
||||||
regs->cs = UCS | URPL;
|
intctx->cs = UCS | URPL;
|
||||||
regs->ds = UDS | URPL;
|
intctx->ds = UDS | URPL;
|
||||||
regs->ss = UDS | URPL;
|
intctx->ss = UDS | URPL;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
regs->rip = regs->rdi;
|
intctx->rip = intctx->rdi;
|
||||||
regs->rflags = regs->rsi;
|
intctx->rflags = intctx->rsi;
|
||||||
regs->rsp = regs->r8;
|
intctx->rsp = intctx->r8;
|
||||||
regs->cs = UCS | URPL;
|
intctx->cs = UCS | URPL;
|
||||||
regs->ds = UDS | URPL;
|
intctx->ds = UDS | URPL;
|
||||||
regs->ss = UDS | URPL;
|
intctx->ss = UDS | URPL;
|
||||||
#else
|
#else
|
||||||
#error "You may need to fix the registers"
|
#error "You may need to fix the registers"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct thread_registers stopped_regs;
|
||||||
|
Scheduler::SaveInterruptedContext(intctx, &stopped_regs);
|
||||||
|
|
||||||
sigset_t new_signal_mask;
|
sigset_t new_signal_mask;
|
||||||
memcpy(&new_signal_mask, &action->sa_mask, sizeof(sigset_t));
|
memcpy(&new_signal_mask, &action->sa_mask, sizeof(sigset_t));
|
||||||
sigorset(&new_signal_mask, &new_signal_mask, &signal_mask);
|
sigorset(&new_signal_mask, &new_signal_mask, &signal_mask);
|
||||||
|
@ -670,15 +667,16 @@ retry_another_signal:
|
||||||
old_signal_stack.ss_size = 0;
|
old_signal_stack.ss_size = 0;
|
||||||
new_signal_stack = signal_stack;
|
new_signal_stack = signal_stack;
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
stack_location = (uintptr_t) regs->esp;
|
stack_location = (uintptr_t) stopped_regs.esp;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
stack_location = (uintptr_t) regs->rsp;
|
stack_location = (uintptr_t) stopped_regs.rsp;
|
||||||
#else
|
#else
|
||||||
#error "You need to implement getting the user-space stack pointer"
|
#error "You need to implement getting the user-space stack pointer"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CPU::InterruptRegisters new_regs = *regs;
|
struct thread_registers handler_regs;
|
||||||
|
memcpy(&handler_regs, &stopped_regs, sizeof(handler_regs));
|
||||||
|
|
||||||
struct stack_frame stack_frame;
|
struct stack_frame stack_frame;
|
||||||
memset(&stack_frame, 0, sizeof(stack_frame));
|
memset(&stack_frame, 0, sizeof(stack_frame));
|
||||||
|
@ -700,9 +698,9 @@ retry_another_signal:
|
||||||
stack_frame.ucontext_param = &stack->ucontext;
|
stack_frame.ucontext_param = &stack->ucontext;
|
||||||
stack_frame.cookie_param = action->sa_cookie;
|
stack_frame.cookie_param = action->sa_cookie;
|
||||||
|
|
||||||
new_regs.esp = (unsigned long) stack;
|
handler_regs.esp = (unsigned long) stack;
|
||||||
new_regs.eip = (unsigned long) handler_ptr;
|
handler_regs.eip = (unsigned long) handler_ptr;
|
||||||
new_regs.eflags &= ~FLAGS_DIRECTION;
|
handler_regs.eflags &= ~FLAGS_DIRECTION;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
stack_location -= 128; /* Red zone. */
|
stack_location -= 128; /* Red zone. */
|
||||||
stack_location -= sizeof(stack_frame);
|
stack_location -= sizeof(stack_frame);
|
||||||
|
@ -710,14 +708,14 @@ retry_another_signal:
|
||||||
struct stack_frame* stack = (struct stack_frame*) stack_location;
|
struct stack_frame* stack = (struct stack_frame*) stack_location;
|
||||||
|
|
||||||
stack_frame.sigreturn = (unsigned long) process->sigreturn;
|
stack_frame.sigreturn = (unsigned long) process->sigreturn;
|
||||||
new_regs.rdi = (unsigned long) signum;
|
handler_regs.rdi = (unsigned long) signum;
|
||||||
new_regs.rsi = (unsigned long) &stack->siginfo;
|
handler_regs.rsi = (unsigned long) &stack->siginfo;
|
||||||
new_regs.rdx = (unsigned long) &stack->ucontext;
|
handler_regs.rdx = (unsigned long) &stack->ucontext;
|
||||||
new_regs.rcx = (unsigned long) action->sa_cookie;
|
handler_regs.rcx = (unsigned long) action->sa_cookie;
|
||||||
|
|
||||||
new_regs.rsp = (unsigned long) stack;
|
handler_regs.rsp = (unsigned long) stack;
|
||||||
new_regs.rip = (unsigned long) handler_ptr;
|
handler_regs.rip = (unsigned long) handler_ptr;
|
||||||
new_regs.rflags &= ~FLAGS_DIRECTION;
|
handler_regs.rflags &= ~FLAGS_DIRECTION;
|
||||||
#else
|
#else
|
||||||
#error "You need to format the stack frame"
|
#error "You need to format the stack frame"
|
||||||
#endif
|
#endif
|
||||||
|
@ -727,7 +725,7 @@ retry_another_signal:
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
// TODO: Is this cr2 value trustworthy? I don't think it is.
|
// TODO: Is this cr2 value trustworthy? I don't think it is.
|
||||||
if ( signum == SIGSEGV )
|
if ( signum == SIGSEGV )
|
||||||
stack_frame.siginfo.si_addr = (void*) regs->cr2;
|
stack_frame.siginfo.si_addr = (void*) intctx->cr2;
|
||||||
#else
|
#else
|
||||||
#warning "You need to tell user-space where it crashed"
|
#warning "You need to tell user-space where it crashed"
|
||||||
#endif
|
#endif
|
||||||
|
@ -736,7 +734,7 @@ retry_another_signal:
|
||||||
stack_frame.ucontext.uc_link = NULL;
|
stack_frame.ucontext.uc_link = NULL;
|
||||||
memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask));
|
memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask));
|
||||||
memcpy(&stack_frame.ucontext.uc_stack, &signal_stack, sizeof(signal_stack));
|
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)) )
|
if ( !CopyToUser(stack, &stack_frame, sizeof(stack_frame)) )
|
||||||
{
|
{
|
||||||
|
@ -764,7 +762,7 @@ retry_another_signal:
|
||||||
signal_stack = new_signal_stack;
|
signal_stack = new_signal_stack;
|
||||||
|
|
||||||
// Update the current registers.
|
// Update the current registers.
|
||||||
*regs = new_regs;
|
Scheduler::LoadInterruptedContext(intctx, &handler_regs);
|
||||||
|
|
||||||
// TODO: SA_RESETHAND:
|
// TODO: SA_RESETHAND:
|
||||||
// "If set, the disposition of the signal shall be reset to SIG_DFL
|
// "If set, the disposition of the signal shall be reset to SIG_DFL
|
||||||
|
@ -776,7 +774,7 @@ retry_another_signal:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
void Thread::HandleSigreturn(struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
assert(Interrupt::IsEnabled());
|
assert(Interrupt::IsEnabled());
|
||||||
assert(this == CurrentThread());
|
assert(this == CurrentThread());
|
||||||
|
@ -786,9 +784,9 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
||||||
struct stack_frame stack_frame;
|
struct stack_frame stack_frame;
|
||||||
const struct stack_frame* user_stack_frame;
|
const struct stack_frame* user_stack_frame;
|
||||||
#if defined(__i386__)
|
#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__)
|
#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
|
#else
|
||||||
#error "You need to locate the stack we passed the signal handler"
|
#error "You need to locate the stack we passed the signal handler"
|
||||||
#endif
|
#endif
|
||||||
|
@ -798,27 +796,30 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
||||||
memcpy(&signal_mask, &stack_frame.ucontext.uc_sigmask, sizeof(signal_mask));
|
memcpy(&signal_mask, &stack_frame.ucontext.uc_sigmask, sizeof(signal_mask));
|
||||||
memcpy(&signal_stack, &stack_frame.ucontext.uc_stack, sizeof(signal_stack));
|
memcpy(&signal_stack, &stack_frame.ucontext.uc_stack, sizeof(signal_stack));
|
||||||
signal_stack.ss_flags &= __SS_SUPPORTED_FLAGS;
|
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);
|
UpdatePendingSignals(this);
|
||||||
regs->signal_pending = asm_signal_is_pending;
|
intctx->signal_pending = asm_signal_is_pending;
|
||||||
|
|
||||||
lock.Reset();
|
lock.Reset();
|
||||||
|
|
||||||
HandleSignal(regs);
|
HandleSignal(intctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Signal {
|
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()
|
void Init()
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sortix/exit.h>
|
#include <sortix/exit.h>
|
||||||
|
@ -44,10 +45,39 @@
|
||||||
#include <sortix/kernel/thread.h>
|
#include <sortix/kernel/thread.h>
|
||||||
#include <sortix/kernel/time.h>
|
#include <sortix/kernel/time.h>
|
||||||
|
|
||||||
|
void* operator new (size_t /*size*/, void* address) throw()
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Sortix {
|
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()
|
Thread::Thread()
|
||||||
{
|
{
|
||||||
|
assert(!((uintptr_t) registers.fpuenv & 0xFUL));
|
||||||
id = 0; // TODO: Make a thread id.
|
id = 0; // TODO: Make a thread id.
|
||||||
process = NULL;
|
process = NULL;
|
||||||
prevsibling = NULL;
|
prevsibling = NULL;
|
||||||
|
@ -56,17 +86,10 @@ Thread::Thread()
|
||||||
scheduler_list_next = NULL;
|
scheduler_list_next = NULL;
|
||||||
state = NONE;
|
state = NONE;
|
||||||
memset(®isters, 0, sizeof(registers));
|
memset(®isters, 0, sizeof(registers));
|
||||||
fsbase = 0;
|
|
||||||
gsbase = 0;
|
|
||||||
kernelstackpos = 0;
|
kernelstackpos = 0;
|
||||||
kernelstacksize = 0;
|
kernelstacksize = 0;
|
||||||
kernelstackmalloced = false;
|
kernelstackmalloced = false;
|
||||||
pledged_destruction = 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_pending);
|
||||||
sigemptyset(&signal_mask);
|
sigemptyset(&signal_mask);
|
||||||
memset(&signal_stack, 0, sizeof(signal_stack));
|
memset(&signal_stack, 0, sizeof(signal_stack));
|
||||||
|
@ -82,129 +105,22 @@ Thread::~Thread()
|
||||||
delete[] (uint8_t*) kernelstackpos;
|
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);
|
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 )
|
if ( !thread )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
thread->addrspace = process->addrspace;
|
memcpy(&thread->registers, regs, sizeof(struct thread_registers));
|
||||||
thread->SaveRegisters(regs);
|
|
||||||
thread->fsbase = fsbase;
|
|
||||||
thread->gsbase = gsbase;
|
|
||||||
|
|
||||||
kthread_mutex_lock(&process->threadlock);
|
kthread_mutex_lock(&process->threadlock);
|
||||||
|
|
||||||
|
@ -221,48 +137,62 @@ Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs,
|
static void SetupKernelThreadRegs(struct thread_registers* regs,
|
||||||
|
Process* process,
|
||||||
void (*entry)(void*),
|
void (*entry)(void*),
|
||||||
void* user,
|
void* user,
|
||||||
uintptr_t stack,
|
uintptr_t stack,
|
||||||
size_t stack_size)
|
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__)
|
#if defined(__i386__)
|
||||||
uintptr_t* stack_values = (uintptr_t*) (stack + stack_size);
|
uintptr_t* stack_values = (uintptr_t*) (stack + stack_size);
|
||||||
|
|
||||||
assert(!((uintptr_t) stack_values & 3UL));
|
assert(5 * sizeof(uintptr_t) <= stack_size);
|
||||||
assert(4 * sizeof(uintptr_t) <= stack_size);
|
|
||||||
|
|
||||||
stack_values[-1] = (uintptr_t) 0; /* null eip */
|
/* -- 16-byte aligned -- */
|
||||||
stack_values[-2] = (uintptr_t) 0; /* null ebp */
|
/* -1 padding */
|
||||||
stack_values[-3] = (uintptr_t) user; /* thread parameter */
|
stack_values[-2] = (uintptr_t) 0; /* null eip */
|
||||||
stack_values[-4] = (uintptr_t) kthread_exit; /* return to kthread_exit */
|
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->eip = (uintptr_t) entry;
|
||||||
regs->esp = (uintptr_t) (stack_values - 4);
|
regs->esp = (uintptr_t) (stack_values - 5);
|
||||||
regs->eax = 0;
|
regs->eax = 0;
|
||||||
regs->ebx = 0;
|
regs->ebx = 0;
|
||||||
regs->ecx = 0;
|
regs->ecx = 0;
|
||||||
regs->edx = 0;
|
regs->edx = 0;
|
||||||
regs->edi = 0;
|
regs->edi = 0;
|
||||||
regs->esi = 0;
|
regs->esi = 0;
|
||||||
regs->ebp = (uintptr_t) (stack_values - 2);
|
regs->ebp = (uintptr_t) (stack_values - 3);
|
||||||
regs->cs = KCS | KRPL;
|
regs->cs = KCS | KRPL;
|
||||||
regs->ds = KDS | KRPL;
|
regs->ds = KDS | KRPL;
|
||||||
regs->ss = KDS | KRPL;
|
regs->ss = KDS | KRPL;
|
||||||
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||||
regs->kerrno = 0;
|
regs->kerrno = 0;
|
||||||
regs->signal_pending = 0;
|
regs->signal_pending = 0;
|
||||||
|
regs->kernel_stack = stack + stack_size;
|
||||||
|
regs->cr3 = process->addrspace;
|
||||||
#elif defined(__x86_64__)
|
#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);
|
uintptr_t* stack_values = (uintptr_t*) (stack + stack_size);
|
||||||
|
|
||||||
assert(!((uintptr_t) stack_values & 15UL));
|
|
||||||
assert(3 * sizeof(uintptr_t) <= stack_size);
|
assert(3 * sizeof(uintptr_t) <= stack_size);
|
||||||
|
|
||||||
stack_values[-1] = (uintptr_t) 0; /* null rip */
|
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->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||||
regs->kerrno = 0;
|
regs->kerrno = 0;
|
||||||
regs->signal_pending = 0;
|
regs->signal_pending = 0;
|
||||||
|
regs->kernel_stack = stack + stack_size;
|
||||||
|
regs->cr3 = process->addrspace;
|
||||||
#else
|
#else
|
||||||
#warning "You need to add thread register initialization support"
|
#warning "You need to add kernel thread register initialization support"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,10 +239,10 @@ Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user,
|
||||||
if ( !stack )
|
if ( !stack )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
CPU::InterruptRegisters regs;
|
struct thread_registers regs;
|
||||||
SetupKernelThreadRegs(®s, entry, user, (uintptr_t) stack, stacksize);
|
SetupKernelThreadRegs(®s, process, entry, user, (uintptr_t) stack, stacksize);
|
||||||
|
|
||||||
Thread* thread = CreateKernelThread(process, ®s, 0, 0);
|
Thread* thread = CreateKernelThread(process, ®s);
|
||||||
if ( !thread ) { delete[] stack; return NULL; }
|
if ( !thread ) { delete[] stack; return NULL; }
|
||||||
|
|
||||||
thread->kernelstackpos = (uintptr_t) stack;
|
thread->kernelstackpos = (uintptr_t) stack;
|
||||||
|
@ -330,9 +262,9 @@ void StartKernelThread(Thread* thread)
|
||||||
Scheduler::SetThreadState(thread, ThreadState::RUNNABLE);
|
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 )
|
if ( !thread )
|
||||||
return NULL;
|
return NULL;
|
||||||
StartKernelThread(thread);
|
StartKernelThread(thread);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -141,6 +141,9 @@ Realm64:
|
||||||
or $0x600, %rax
|
or $0x600, %rax
|
||||||
mov %rax, %cr4
|
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
|
# Alright, that was the bootstrap code. Now begin preparing to run the
|
||||||
# actual 64-bit kernel.
|
# actual 64-bit kernel.
|
||||||
jmp Main
|
jmp Main
|
||||||
|
|
|
@ -386,7 +386,10 @@ interrupt_handler_prepare:
|
||||||
|
|
||||||
# Now call the interrupt handler.
|
# Now call the interrupt handler.
|
||||||
movq %rsp, %rdi
|
movq %rsp, %rdi
|
||||||
|
movq %rsp, %rbx
|
||||||
|
andq $0xFFFFFFFFFFFFFFF0, %rsp
|
||||||
call interrupt_handler
|
call interrupt_handler
|
||||||
|
movq %rbx, %rsp
|
||||||
|
|
||||||
load_interrupted_registers:
|
load_interrupted_registers:
|
||||||
# Restore whether signals are pending.
|
# Restore whether signals are pending.
|
||||||
|
|
|
@ -44,8 +44,6 @@ void ExtendStack();
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
|
||||||
extern addr_t currentdir;
|
|
||||||
|
|
||||||
void InitCPU()
|
void InitCPU()
|
||||||
{
|
{
|
||||||
// The x64 boot code already set up virtual memory and identity
|
// 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;
|
BOOTPML3->entry[0] = (addr_t) FORKPML2 | flags | PML_FORK;
|
||||||
FORKPML2->entry[0] = (addr_t) FORKPML1 | 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
|
// The virtual memory structures are now available on the predefined
|
||||||
// locations. This means the virtual memory code is bootstrapped. Of
|
// locations. This means the virtual memory code is bootstrapped. Of
|
||||||
// course, we still have no physical page allocator, so that's the
|
// 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
|
// Look up the last few entries used for the fractal mapping. These
|
||||||
// cannot be unmapped as that would destroy the world. Instead, we
|
// 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 fractal2 = (PMLS[3] + 510UL)->entry[510];
|
||||||
addr_t fork1 = (PMLS[2] + 510UL * 512UL + 0)->entry[0];
|
addr_t fork1 = (PMLS[2] + 510UL * 512UL + 0)->entry[0];
|
||||||
addr_t fractal1 = (PMLS[2] + 510UL * 512UL + 510UL)->entry[510];
|
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,
|
// We want to free the pages, but we are still using them ourselves,
|
||||||
// so lock the page allocation structure until we are done.
|
// 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 )
|
if ( !fallback )
|
||||||
fallback = (addr_t) BOOTPML4;
|
fallback = (addr_t) BOOTPML4;
|
||||||
|
|
||||||
if ( func )
|
SwitchAddressSpace(fallback);
|
||||||
func(fallback, user);
|
|
||||||
else
|
|
||||||
SwitchAddressSpace(fallback);
|
|
||||||
|
|
||||||
// Ok, now we got marked everything left behind as unused, we can
|
// Ok, now we got marked everything left behind as unused, we can
|
||||||
// now safely let another thread use the pages.
|
// now safely let another thread use the pages.
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -33,104 +33,7 @@
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Float {
|
namespace Float {
|
||||||
|
|
||||||
static Thread* fputhread;
|
extern "C" { __attribute__((aligned(16))) uint8_t fpu_initialized_regs[512]; }
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Float
|
} // namespace Float
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -25,39 +25,14 @@
|
||||||
#ifndef SORTIX_FLOAT_H
|
#ifndef SORTIX_FLOAT_H
|
||||||
#define SORTIX_FLOAT_H
|
#define SORTIX_FLOAT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
class Thread;
|
|
||||||
|
|
||||||
namespace Float {
|
namespace Float {
|
||||||
|
|
||||||
extern bool fpu_is_enabled;
|
extern "C" uint8_t fpu_initialized_regs[512];
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Float
|
} // namespace Float
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -22,10 +22,12 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sortix/kernel/cpu.h>
|
#include <sortix/kernel/cpu.h>
|
||||||
|
#include <sortix/kernel/registers.h>
|
||||||
|
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
|
|
||||||
|
@ -254,16 +256,22 @@ void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher)
|
uintptr_t GetKernelStack()
|
||||||
{
|
{
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
(void) stacklower;
|
return tss_entry.esp0;
|
||||||
(void) stacksize;
|
|
||||||
tss_entry.esp0 = (uint32_t) stackhigher;
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
(void) stacklower;
|
return tss_entry.stack0;
|
||||||
(void) stacksize;
|
#endif
|
||||||
tss_entry.stack0 = (uint64_t) stackhigher;
|
}
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ namespace GDT {
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0);
|
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__)
|
#if defined(__i386__)
|
||||||
uint32_t GetFSBase();
|
uint32_t GetFSBase();
|
||||||
uint32_t GetGSBase();
|
uint32_t GetGSBase();
|
||||||
|
|
|
@ -244,49 +244,41 @@ void Init()
|
||||||
Interrupt::Enable();
|
Interrupt::Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ExceptionName(const CPU::InterruptRegisters* regs)
|
const char* ExceptionName(const struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
if ( regs->int_no < NUM_KNOWN_EXCEPTIONS )
|
if ( intctx->int_no < NUM_KNOWN_EXCEPTIONS )
|
||||||
return exception_names[regs->int_no];
|
return exception_names[intctx->int_no];
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t ExceptionLocation(const CPU::InterruptRegisters* regs)
|
uintptr_t ExceptionLocation(const struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
return regs->rip;
|
return intctx->rip;
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
return regs->eip;
|
return intctx->eip;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashCalltrace(const CPU::InterruptRegisters* regs)
|
void CrashCalltrace(const struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
Calltrace::Perform(regs->rbp);
|
Calltrace::Perform(intctx->rbp);
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
Calltrace::Perform(regs->ebp);
|
Calltrace::Perform(intctx->ebp);
|
||||||
#else
|
#else
|
||||||
#warning "Please provide a calltrace implementation for your CPU."
|
#warning "Please provide a calltrace implementation for your CPU."
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
void KernelCrashHandler(CPU::InterruptRegisters* regs)
|
void KernelCrashHandler(struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
Thread* thread = CurrentThread();
|
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
|
||||||
#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);
|
|
||||||
|
|
||||||
// Walk and print the stack frames if this is a debug build.
|
// Walk and print the stack frames if this is a debug build.
|
||||||
if ( CALLTRACE_KERNEL )
|
if ( CALLTRACE_KERNEL )
|
||||||
CrashCalltrace(regs);
|
CrashCalltrace(intctx);
|
||||||
|
|
||||||
// Possibly switch to the kernel debugger in event of a crash.
|
// Possibly switch to the kernel debugger in event of a crash.
|
||||||
if ( RUN_DEBUGGER_ON_KERNEL_CRASH )
|
if ( RUN_DEBUGGER_ON_KERNEL_CRASH )
|
||||||
|
@ -294,27 +286,19 @@ void KernelCrashHandler(CPU::InterruptRegisters* regs)
|
||||||
|
|
||||||
// Panic the kernel with a diagnostic message.
|
// Panic the kernel with a diagnostic message.
|
||||||
PanicF("Unhandled CPU Exception id %zu `%s' at ip=0x%zx (cr2=0x%zx, "
|
PanicF("Unhandled CPU Exception id %zu `%s' at ip=0x%zx (cr2=0x%zx, "
|
||||||
"err_code=0x%zx)", regs->int_no, ExceptionName(regs),
|
"err_code=0x%zx)", intctx->int_no, ExceptionName(intctx),
|
||||||
ExceptionLocation(regs), regs->cr2, regs->err_code);
|
ExceptionLocation(intctx), intctx->cr2, intctx->err_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserCrashHandler(CPU::InterruptRegisters* regs)
|
void UserCrashHandler(struct interrupt_context* intctx)
|
||||||
{
|
{
|
||||||
Thread* thread = CurrentThread();
|
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
|
||||||
#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);
|
|
||||||
|
|
||||||
// Execute this crash handler with preemption on.
|
// Execute this crash handler with preemption on.
|
||||||
Interrupt::Enable();
|
Interrupt::Enable();
|
||||||
|
|
||||||
// TODO: Also send signals for other types of user-space crashes.
|
// 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];
|
struct sigaction* act = &CurrentProcess()->signal_actions[SIGSEGV];
|
||||||
kthread_mutex_lock(&CurrentProcess()->signal_lock);
|
kthread_mutex_lock(&CurrentProcess()->signal_lock);
|
||||||
|
@ -323,12 +307,12 @@ void UserCrashHandler(CPU::InterruptRegisters* regs)
|
||||||
CurrentThread()->DeliverSignalUnlocked(SIGSEGV);
|
CurrentThread()->DeliverSignalUnlocked(SIGSEGV);
|
||||||
kthread_mutex_unlock(&CurrentProcess()->signal_lock);
|
kthread_mutex_unlock(&CurrentProcess()->signal_lock);
|
||||||
if ( handled )
|
if ( handled )
|
||||||
return Signal::DispatchHandler(regs, NULL);
|
return Signal::DispatchHandler(intctx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk and print the stack frames if this is a debug build.
|
// Walk and print the stack frames if this is a debug build.
|
||||||
if ( CALLTRACE_USER )
|
if ( CALLTRACE_USER )
|
||||||
CrashCalltrace(regs);
|
CrashCalltrace(intctx);
|
||||||
|
|
||||||
// Possibly switch to the kernel debugger in event of a crash.
|
// Possibly switch to the kernel debugger in event of a crash.
|
||||||
if ( RUN_DEBUGGER_ON_USER_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",
|
Log::PrintF("The current process (pid %ji `%s') crashed and was terminated:\n",
|
||||||
(intmax_t) CurrentProcess()->pid, CurrentProcess()->program_image_path);
|
(intmax_t) CurrentProcess()->pid, CurrentProcess()->program_image_path);
|
||||||
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%zx, err_code=0x%zx)\n",
|
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%zx, err_code=0x%zx)\n",
|
||||||
ExceptionName(regs), ExceptionLocation(regs), regs->cr2,
|
ExceptionName(intctx), ExceptionLocation(intctx), intctx->cr2,
|
||||||
regs->err_code);
|
intctx->err_code);
|
||||||
|
|
||||||
// Exit the process with the right error code.
|
// Exit the process with the right error code.
|
||||||
// TODO: Send a SIGINT, SIGBUS, or whatever instead.
|
// TODO: Send a SIGINT, SIGBUS, or whatever instead.
|
||||||
CurrentProcess()->ExitThroughSignal(SIGSEGV);
|
CurrentProcess()->ExitThroughSignal(SIGSEGV);
|
||||||
|
|
||||||
// Deliver signals to this thread so it can exit correctly.
|
// 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.
|
// IRQ 7 and 15 might be spurious and might need to be ignored.
|
||||||
if ( int_no == IRQ7 && !(PIC::ReadISR() & (1 << 7)) )
|
if ( int_no == IRQ7 && !(PIC::ReadISR() & (1 << 7)) )
|
||||||
|
@ -362,17 +346,17 @@ extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
|
||||||
return;
|
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_in_user = !is_in_kernel;
|
||||||
bool is_crash = int_no < 32 && int_no != 7;
|
bool is_crash = int_no < 32 && int_no != 7;
|
||||||
|
|
||||||
// Invoke the appropriate interrupt handler.
|
// Invoke the appropriate interrupt handler.
|
||||||
if ( is_crash && is_in_kernel )
|
if ( is_crash && is_in_kernel )
|
||||||
KernelCrashHandler(regs);
|
KernelCrashHandler(intctx);
|
||||||
else if ( is_crash && is_in_user )
|
else if ( is_crash && is_in_user )
|
||||||
UserCrashHandler(regs);
|
UserCrashHandler(intctx);
|
||||||
else if ( interrupt_handlers[int_no] )
|
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.
|
// Send an end of interrupt signal to the PICs if we got an IRQ.
|
||||||
if ( IRQ0 <= int_no && int_no <= IRQ15 )
|
if ( IRQ0 <= int_no && int_no <= IRQ15 )
|
||||||
|
|
|
@ -62,8 +62,6 @@ kthread_mutex_t pagelock;
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
|
||||||
addr_t currentdir = 0;
|
|
||||||
|
|
||||||
void InitCPU();
|
void InitCPU();
|
||||||
void AllocateKernelPMLs();
|
void AllocateKernelPMLs();
|
||||||
int SysMemStat(size_t* memused, size_t* memtotal);
|
int SysMemStat(size_t* memused, size_t* memtotal);
|
||||||
|
@ -485,42 +483,30 @@ void InvalidatePage(addr_t /*addr*/)
|
||||||
Flush();
|
Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flushes the Translation Lookaside Buffer (TLB).
|
|
||||||
void Flush()
|
|
||||||
{
|
|
||||||
asm volatile("mov %0, %%cr3":: "r"(currentdir));
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_t GetAddressSpace()
|
addr_t GetAddressSpace()
|
||||||
{
|
{
|
||||||
return currentdir;
|
addr_t result;
|
||||||
|
asm ( "mov %%cr3, %0" : "=r"(result) );
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t SwitchAddressSpace(addr_t addrspace)
|
addr_t SwitchAddressSpace(addr_t addrspace)
|
||||||
{
|
{
|
||||||
// Have fun debugging this.
|
assert(Page::IsAligned(addrspace));
|
||||||
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;
|
|
||||||
|
|
||||||
|
addr_t previous = GetAddressSpace();
|
||||||
|
asm volatile ( "mov %0, %%cr3" : : "r"(addrspace) );
|
||||||
return previous;
|
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)
|
bool MapRange(addr_t where, size_t bytes, int protection)
|
||||||
{
|
{
|
||||||
for ( addr_t page = where; page < where + bytes; page += 4096UL )
|
for ( addr_t page = where; page < where + bytes; page += 4096UL )
|
||||||
|
|
|
@ -78,10 +78,10 @@ static struct timespec tick_period;
|
||||||
static long tick_frequency;
|
static long tick_frequency;
|
||||||
static uint16_t tick_divisor;
|
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());
|
OnTick(tick_period, !InUserspace(intctx));
|
||||||
Scheduler::Switch(regs);
|
Scheduler::Switch(intctx);
|
||||||
|
|
||||||
// TODO: There is a horrible bug that causes Sortix to only receive
|
// TODO: There is a horrible bug that causes Sortix to only receive
|
||||||
// one IRQ0 on my laptop, but it works in virtual machines. But
|
// one IRQ0 on my laptop, but it works in virtual machines. But
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -62,4 +62,7 @@ prepare_kernel_execution:
|
||||||
mov %eax, %cr4
|
mov %eax, %cr4
|
||||||
mov 0x100000, %eax
|
mov 0x100000, %eax
|
||||||
|
|
||||||
|
# Store a copy of the initialial floating point registers.
|
||||||
|
fxsave fpu_initialized_regs
|
||||||
|
|
||||||
jmp beginkernel
|
jmp beginkernel
|
||||||
|
|
|
@ -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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -382,9 +382,12 @@ fixup_relocate_stack_complete:
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
|
|
||||||
# Now call the interrupt handler.
|
# Now call the interrupt handler.
|
||||||
pushl %esp
|
movl %esp, %ebx
|
||||||
|
subl $4, %esp
|
||||||
|
andl $0xFFFFFFF0, %esp
|
||||||
|
movl %ebx, (%esp)
|
||||||
call interrupt_handler
|
call interrupt_handler
|
||||||
addl $4, %esp
|
movl %ebx, %esp
|
||||||
|
|
||||||
load_interrupted_registers:
|
load_interrupted_registers:
|
||||||
# Restore whether signals are pending.
|
# Restore whether signals are pending.
|
||||||
|
|
|
@ -45,8 +45,6 @@ void ExtendStack();
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
|
||||||
extern addr_t currentdir;
|
|
||||||
|
|
||||||
void InitCPU()
|
void InitCPU()
|
||||||
{
|
{
|
||||||
PML* const BOOTPML2 = (PML* const) 0x11000UL;
|
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
|
// Look up the last few entries used for the fractal mapping. These
|
||||||
// cannot be unmapped as that would destroy the world. Instead, we
|
// cannot be unmapped as that would destroy the world. Instead, we
|
||||||
// will remember them, switch to another adress space, and safely
|
// will remember them, switch to another adress space, and safely
|
||||||
// mark them as unused. Also handling the forking related pages.
|
// mark them as unused. Also handling the forking related pages.
|
||||||
addr_t fractal1 = PMLS[2]->entry[1022];
|
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,
|
// We want to free the pages, but we are still using them ourselves,
|
||||||
// so lock the page allocation structure until we are done.
|
// 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 )
|
if ( !fallback )
|
||||||
fallback = (addr_t) BOOTPML2;
|
fallback = (addr_t) BOOTPML2;
|
||||||
|
|
||||||
if ( func )
|
SwitchAddressSpace(fallback);
|
||||||
func(fallback, user);
|
|
||||||
else
|
|
||||||
SwitchAddressSpace(fallback);
|
|
||||||
|
|
||||||
// Ok, now we got marked everything left behind as unused, we can
|
// Ok, now we got marked everything left behind as unused, we can
|
||||||
// now safely let another thread use the pages.
|
// now safely let another thread use the pages.
|
||||||
|
|
|
@ -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
|
|
|
@ -27,13 +27,16 @@
|
||||||
.section .text
|
.section .text
|
||||||
.type syscall_handler, @function
|
.type syscall_handler, @function
|
||||||
syscall_handler:
|
syscall_handler:
|
||||||
|
/* -- stack is 12 bytes from being 16-byte aligned -- */
|
||||||
movl $0, global_errno # Reset errno
|
movl $0, global_errno # Reset errno
|
||||||
|
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
|
/* -- stack is 8 bytes from being 16-byte aligned -- */
|
||||||
|
|
||||||
# Grant ourselves kernel permissions to the data segment.
|
# Grant ourselves kernel permissions to the data segment.
|
||||||
movl %ds, %ebp
|
movl %ds, %ebp
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
|
/* -- stack is 4 bytes from being 16-byte aligned -- */
|
||||||
movw $0x10, %bp
|
movw $0x10, %bp
|
||||||
movl %ebp, %ds
|
movl %ebp, %ds
|
||||||
movl %ebp, %es
|
movl %ebp, %es
|
||||||
|
@ -53,10 +56,12 @@ valid_syscall:
|
||||||
|
|
||||||
# Call the system call.
|
# Call the system call.
|
||||||
pushl %esi
|
pushl %esi
|
||||||
|
/* -- stack is 16-byte aligned -- */
|
||||||
pushl %edi
|
pushl %edi
|
||||||
pushl %edx
|
pushl %edx
|
||||||
pushl %ecx
|
pushl %ecx
|
||||||
pushl %ebx
|
pushl %ebx
|
||||||
|
/* -- stack is 16-byte aligned -- */
|
||||||
calll *%eax
|
calll *%eax
|
||||||
addl $20, %esp
|
addl $20, %esp
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
Loading…
Reference in New Issue