mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Refactor kernel interrupt and thread register support.
This commit is contained in:
parent
c2f9c0bb12
commit
25e07a9083
39 changed files with 866 additions and 998 deletions
|
@ -31,13 +31,13 @@ BOOTOBJS:=
|
|||
|
||||
ifeq ($(CPU),x86)
|
||||
X86FAMILY:=1
|
||||
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o $(CPU)/x86.o
|
||||
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o
|
||||
endif
|
||||
|
||||
ifeq ($(CPU),x64)
|
||||
X86FAMILY:=1
|
||||
CXXFLAGS:=$(CXXFLAGS) -mno-red-zone -mno-mmx -mno-sse -mno-sse2
|
||||
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o $(CPU)/x64.o
|
||||
CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o
|
||||
endif
|
||||
|
||||
ifdef X86FAMILY
|
||||
|
@ -50,7 +50,6 @@ ifdef X86FAMILY
|
|||
x86-family/gdt.o \
|
||||
x86-family/idt.o \
|
||||
$(CPU)/syscall.o \
|
||||
$(CPU)/process.o \
|
||||
x86-family/cmos.o \
|
||||
x86-family/time.o \
|
||||
x86-family/mtrr.o \
|
||||
|
@ -124,6 +123,7 @@ pipe.o \
|
|||
poll.o \
|
||||
process.o \
|
||||
refcount.o \
|
||||
registers.o \
|
||||
resource.o \
|
||||
scheduler.o \
|
||||
segment.o \
|
||||
|
|
|
@ -406,7 +406,7 @@ void DevCOMPort::OnInterrupt()
|
|||
|
||||
Ref<DevCOMPort> comdevices[1+NUMCOMPORTS];
|
||||
|
||||
static void UARTIRQHandler(CPU::InterruptRegisters* /*regs*/, void* /*user*/)
|
||||
static void UARTIRQHandler(struct interrupt_context* /*intctx*/, void* /*user*/)
|
||||
{
|
||||
for ( size_t i = 1; i <= NUMCOMPORTS; i++ )
|
||||
{
|
||||
|
|
|
@ -337,14 +337,12 @@ int ThreadId(Thread* thread)
|
|||
|
||||
int main_bt(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
CPU::InterruptRegisters regs;
|
||||
current_thread->LoadRegisters(®s);
|
||||
#if defined(__x86_64__)
|
||||
unsigned long ip = regs.rip;
|
||||
unsigned long bp = regs.rbp;
|
||||
unsigned long ip = current_thread->registers.rip;
|
||||
unsigned long bp = current_thread->registers.rbp;
|
||||
#elif defined(__i386__)
|
||||
unsigned long ip = regs.eip;
|
||||
unsigned long bp = regs.ebp;
|
||||
unsigned long ip = current_thread->registers.eip;
|
||||
unsigned long bp = current_thread->registers.ebp;
|
||||
#endif
|
||||
|
||||
bool userspace = false;
|
||||
|
@ -434,7 +432,7 @@ int main_pid(int argc, char* argv[])
|
|||
return 1;
|
||||
}
|
||||
current_thread = process->firstthread;
|
||||
Memory::SwitchAddressSpace(current_thread->addrspace);
|
||||
Memory::SwitchAddressSpace(current_thread->registers.cr3);
|
||||
}
|
||||
Print("%c %i\t`%s'\n", '*', (int) current_process->pid,
|
||||
current_process->program_image_path);
|
||||
|
@ -455,54 +453,48 @@ int main_ps(int /*argc*/, char* /*argv*/[])
|
|||
|
||||
int main_rs(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
CPU::InterruptRegisters regs;
|
||||
current_thread->LoadRegisters(®s);
|
||||
#if defined(__x86_64__)
|
||||
Print("rax=0x%lx, ", regs.rax);
|
||||
Print("rbx=0x%lx, ", regs.rbx);
|
||||
Print("rcx=0x%lx, ", regs.rcx);
|
||||
Print("rdx=0x%lx, ", regs.rdx);
|
||||
Print("rdi=0x%lx, ", regs.rdi);
|
||||
Print("rsi=0x%lx, ", regs.rsi);
|
||||
Print("rsp=0x%lx, ", regs.rsp);
|
||||
Print("rbp=0x%lx, ", regs.rbp);
|
||||
Print("r8=0x%lx, ", regs.r8);
|
||||
Print("r9=0x%lx, ", regs.r9);
|
||||
Print("r10=0x%lx, ", regs.r10);
|
||||
Print("r11=0x%lx, ", regs.r11);
|
||||
Print("r12=0x%lx, ", regs.r12);
|
||||
Print("r13=0x%lx, ", regs.r13);
|
||||
Print("r14=0x%lx, ", regs.r14);
|
||||
Print("r15=0x%lx, ", regs.r15);
|
||||
Print("rip=0x%lx, ", regs.rip);
|
||||
Print("rflags=0x%lx, ", regs.rflags);
|
||||
Print("int_no=%lu, ", regs.int_no);
|
||||
Print("err_code=0x%lx, ", regs.err_code);
|
||||
Print("cs=0x%lx, ", regs.cs);
|
||||
Print("ds=0x%lx, ", regs.ds);
|
||||
Print("ss=0x%lx, ", regs.ss);
|
||||
Print("kerrno=%lu, ", regs.kerrno);
|
||||
Print("cr2=%lx, ", regs.cr2);
|
||||
Print("signal_pending=%lu.", regs.signal_pending);
|
||||
Print("rax=0x%lX, ", current_thread->registers.rax);
|
||||
Print("rbx=0x%lX, ", current_thread->registers.rbx);
|
||||
Print("rcx=0x%lX, ", current_thread->registers.rcx);
|
||||
Print("rdx=0x%lX, ", current_thread->registers.rdx);
|
||||
Print("rdi=0x%lX, ", current_thread->registers.rdi);
|
||||
Print("rsi=0x%lX, ", current_thread->registers.rsi);
|
||||
Print("rsp=0x%lX, ", current_thread->registers.rsp);
|
||||
Print("rbp=0x%lX, ", current_thread->registers.rbp);
|
||||
Print("r8=0x%lX, ", current_thread->registers.r8);
|
||||
Print("r9=0x%lX, ", current_thread->registers.r9);
|
||||
Print("r10=0x%lX, ", current_thread->registers.r10);
|
||||
Print("r11=0x%lX, ", current_thread->registers.r11);
|
||||
Print("r12=0x%lX, ", current_thread->registers.r12);
|
||||
Print("r13=0x%lX, ", current_thread->registers.r13);
|
||||
Print("r14=0x%lX, ", current_thread->registers.r14);
|
||||
Print("r15=0x%lX, ", current_thread->registers.r15);
|
||||
Print("rip=0x%lX, ", current_thread->registers.rip);
|
||||
Print("rflags=0x%lX, ", current_thread->registers.rflags);
|
||||
Print("fsbase=0x%lX, ", current_thread->registers.fsbase);
|
||||
Print("gsbase=0x%lX, ", current_thread->registers.gsbase);
|
||||
Print("cr3=0x%lX, ", current_thread->registers.cr3);
|
||||
Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack);
|
||||
Print("kerrno=%lu, ", current_thread->registers.kerrno);
|
||||
Print("signal_pending=%lu.", current_thread->registers.signal_pending);
|
||||
#elif defined(__i386__)
|
||||
Print("eax=0x%lx, ", regs.eax);
|
||||
Print("ebx=0x%lx, ", regs.ebx);
|
||||
Print("ecx=0x%lx, ", regs.ecx);
|
||||
Print("edx=0x%lx, ", regs.edx);
|
||||
Print("edi=0x%lx, ", regs.edi);
|
||||
Print("esi=0x%lx, ", regs.esi);
|
||||
Print("esp=0x%lx, ", regs.esp);
|
||||
Print("ebp=0x%lx, ", regs.ebp);
|
||||
Print("eip=0x%lx, ", regs.eip);
|
||||
Print("eflags=0x%lx, ", regs.eflags);
|
||||
Print("int_no=%lu, ", regs.int_no);
|
||||
Print("err_code=0x%lx, ", regs.err_code);
|
||||
Print("cs=0x%lx, ", regs.cs);
|
||||
Print("ds=0x%lx, ", regs.ds);
|
||||
Print("ss=0x%lx, ", regs.ss);
|
||||
Print("kerrno=%lu, ", regs.kerrno);
|
||||
Print("cr2=%lx, ", regs.cr2);
|
||||
Print("signal_pending=%lu.", regs.signal_pending);
|
||||
Print("eax=0x%lX, ", current_thread->registers.eax);
|
||||
Print("ebx=0x%lX, ", current_thread->registers.ebx);
|
||||
Print("ecx=0x%lX, ", current_thread->registers.ecx);
|
||||
Print("edx=0x%lX, ", current_thread->registers.edx);
|
||||
Print("edi=0x%lX, ", current_thread->registers.edi);
|
||||
Print("esi=0x%lX, ", current_thread->registers.esi);
|
||||
Print("esp=0x%lX, ", current_thread->registers.esp);
|
||||
Print("ebp=0x%lX, ", current_thread->registers.ebp);
|
||||
Print("eip=0x%lX, ", current_thread->registers.eip);
|
||||
Print("eflags=0x%lX, ", current_thread->registers.eflags);
|
||||
Print("fsbase=0x%lX, ", current_thread->registers.fsbase);
|
||||
Print("gsbase=0x%lX, ", current_thread->registers.gsbase);
|
||||
Print("cr3=0x%lX, ", current_thread->registers.cr3);
|
||||
Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack);
|
||||
Print("kerrno=%lX, ", current_thread->registers.kerrno);
|
||||
Print("signal_pending=%lu.", current_thread->registers.signal_pending);
|
||||
#endif
|
||||
Print("\n");
|
||||
return 0;
|
||||
|
@ -510,12 +502,10 @@ int main_rs(int /*argc*/, char* /*argv*/[])
|
|||
|
||||
static void DescribeThread(int tid, Thread* thread)
|
||||
{
|
||||
CPU::InterruptRegisters regs;
|
||||
thread->LoadRegisters(®s);
|
||||
#if defined(__x86_64__)
|
||||
unsigned long ip = regs.rip;
|
||||
unsigned long ip = thread->registers.rip;
|
||||
#elif defined(__i386__)
|
||||
unsigned long ip = regs.eip;
|
||||
unsigned long ip = thread->registers.eip;
|
||||
#endif
|
||||
|
||||
Print("%c ", thread == current_thread ? '*' : ' ');
|
||||
|
@ -538,7 +528,7 @@ int main_tid(int argc, char* argv[])
|
|||
return 1;
|
||||
}
|
||||
current_thread = thread;
|
||||
Memory::SwitchAddressSpace(current_thread->addrspace);
|
||||
Memory::SwitchAddressSpace(current_thread->registers.cr3);
|
||||
}
|
||||
DescribeThread(ThreadId(current_thread), current_thread);
|
||||
return 0;
|
||||
|
@ -624,7 +614,7 @@ void Run()
|
|||
|
||||
first_f10 = true;
|
||||
|
||||
addr_t saved_addrspace = current_thread->addrspace;
|
||||
addr_t saved_addrspace = current_thread->registers.cr3;
|
||||
|
||||
memcpy(saved_video_memory, VIDEO_MEMORY, sizeof(saved_video_memory));
|
||||
int saved_x, saved_y;
|
||||
|
|
|
@ -40,92 +40,6 @@ void ShutDown();
|
|||
} // namespace CPU
|
||||
#endif
|
||||
|
||||
// CPU flag register bits for 32-bit and 64-bit x86.
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
const size_t FLAGS_CARRY = 1<<0; // 0x000001
|
||||
const size_t FLAGS_RESERVED1 = 1<<1; // 0x000002, read as one
|
||||
const size_t FLAGS_PARITY = 1<<2; // 0x000004
|
||||
const size_t FLAGS_RESERVED2 = 1<<3; // 0x000008
|
||||
const size_t FLAGS_AUX = 1<<4; // 0x000010
|
||||
const size_t FLAGS_RESERVED3 = 1<<5; // 0x000020
|
||||
const size_t FLAGS_ZERO = 1<<6; // 0x000040
|
||||
const size_t FLAGS_SIGN = 1<<7; // 0x000080
|
||||
const size_t FLAGS_TRAP = 1<<8; // 0x000100
|
||||
const size_t FLAGS_INTERRUPT = 1<<9; // 0x000200
|
||||
const size_t FLAGS_DIRECTION = 1<<10; // 0x000400
|
||||
const size_t FLAGS_OVERFLOW = 1<<11; // 0x000800
|
||||
const size_t FLAGS_IOPRIVLEVEL = 1<<12 | 1<<13;
|
||||
const size_t FLAGS_NESTEDTASK = 1<<14; // 0x004000
|
||||
const size_t FLAGS_RESERVED4 = 1<<15; // 0x008000
|
||||
const size_t FLAGS_RESUME = 1<<16; // 0x010000
|
||||
const size_t FLAGS_VIRTUAL8086 = 1<<17; // 0x020000
|
||||
const size_t FLAGS_ALIGNCHECK = 1<<18; // 0x040000
|
||||
const size_t FLAGS_VIRTINTR = 1<<19; // 0x080000
|
||||
const size_t FLAGS_VIRTINTRPEND = 1<<20; // 0x100000
|
||||
const size_t FLAGS_ID = 1<<21; // 0x200000
|
||||
#endif
|
||||
|
||||
// x86 interrupt registers structure.
|
||||
#if defined(__i386__)
|
||||
namespace X86 {
|
||||
struct InterruptRegisters
|
||||
{
|
||||
uint32_t signal_pending, kerrno, cr2;
|
||||
uint32_t ds; // Data segment selector
|
||||
uint32_t edi, esi, ebp, not_esp, ebx, edx, ecx, eax; // Pushed by pusha.
|
||||
uint32_t int_no, err_code; // Interrupt number and error code (if applicable)
|
||||
uint32_t eip, cs, eflags, esp, ss; // Pushed by the processor automatically.
|
||||
|
||||
public:
|
||||
void LogRegisters() const;
|
||||
bool InUserspace() const { return (cs & 0x3) != 0; }
|
||||
|
||||
};
|
||||
} // namespace X86
|
||||
#endif
|
||||
|
||||
// x86_64 interrupt
|
||||
#if defined(__x86_64__)
|
||||
namespace X64 {
|
||||
struct InterruptRegisters
|
||||
{
|
||||
uint64_t signal_pending, kerrno, cr2;
|
||||
uint64_t ds; // Data segment selector
|
||||
uint64_t rdi, rsi, rbp, not_rsp, rbx, rdx, rcx, rax;
|
||||
uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
uint64_t int_no, err_code; // Interrupt number and error code (if applicable)
|
||||
uint64_t rip, cs, rflags, rsp, ss; // Pushed by the processor automatically.
|
||||
|
||||
public:
|
||||
void LogRegisters() const;
|
||||
bool InUserspace() const { return (cs & 0x3) != 0; }
|
||||
|
||||
};
|
||||
} // namespace X64
|
||||
#endif
|
||||
|
||||
// Segment values for 32-bit and 64-bit x86.
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
const uint64_t KCS = 0x08;
|
||||
const uint64_t KDS = 0x10;
|
||||
const uint64_t KRPL = 0x0;
|
||||
const uint64_t UCS = 0x18;
|
||||
const uint64_t UDS = 0x20;
|
||||
const uint64_t URPL = 0x3;
|
||||
#endif
|
||||
|
||||
// Portable functions for loading registers.
|
||||
namespace CPU {
|
||||
extern "C" __attribute__((noreturn))
|
||||
void load_registers(InterruptRegisters* regs, size_t size);
|
||||
|
||||
__attribute__((noreturn))
|
||||
inline void LoadRegisters(InterruptRegisters* regs)
|
||||
{
|
||||
load_registers(regs, sizeof(*regs));
|
||||
}
|
||||
} // namespace CPU
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,14 +28,7 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include <sortix/kernel/decl.h>
|
||||
|
||||
namespace Sortix {
|
||||
namespace CPU {
|
||||
|
||||
struct InterruptRegisters;
|
||||
|
||||
} // namespace CPU
|
||||
} // namespace Sortix
|
||||
#include <sortix/kernel/registers.h>
|
||||
|
||||
namespace Sortix {
|
||||
namespace Interrupt {
|
||||
|
@ -108,7 +101,7 @@ inline bool SetEnabled(bool is_enabled)
|
|||
}
|
||||
|
||||
|
||||
typedef void (*Handler)(CPU::InterruptRegisters* regs, void* user);
|
||||
typedef void (*Handler)(struct interrupt_context* intctx, void* user);
|
||||
void RegisterHandler(unsigned int index, Handler handler, void* user);
|
||||
|
||||
void Init();
|
||||
|
|
|
@ -77,9 +77,7 @@ void Flush();
|
|||
addr_t Fork();
|
||||
addr_t GetAddressSpace();
|
||||
addr_t SwitchAddressSpace(addr_t addrspace);
|
||||
void DestroyAddressSpace(addr_t fallback = 0,
|
||||
void (*func)(addr_t, void*) = NULL,
|
||||
void* user = NULL);
|
||||
void DestroyAddressSpace(addr_t fallback = 0);
|
||||
bool Map(addr_t physical, addr_t mapto, int prot);
|
||||
addr_t Unmap(addr_t mapto);
|
||||
addr_t Physical(addr_t mapto);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <sortix/kernel/clock.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/registers.h>
|
||||
#include <sortix/kernel/segment.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
#include <sortix/kernel/timer.h>
|
||||
|
@ -168,7 +169,7 @@ public:
|
|||
int Execute(const char* programname, const uint8_t* program,
|
||||
size_t programsize, int argc, const char* const* argv,
|
||||
int envc, const char* const* envp,
|
||||
CPU::InterruptRegisters* regs);
|
||||
struct thread_registers* regs);
|
||||
void ResetAddressSpace();
|
||||
void ExitThroughSignal(int signal);
|
||||
void ExitWithCode(int exit_code);
|
||||
|
@ -187,9 +188,6 @@ public:
|
|||
Process* Fork();
|
||||
|
||||
private:
|
||||
void ExecuteCPU(int argc, char** argv, int envc, char** envp,
|
||||
addr_t stackpos, addr_t entry,
|
||||
CPU::InterruptRegisters* regs);
|
||||
void OnLastThreadExit();
|
||||
void LastPrayer();
|
||||
void NotifyMemberExit(Process* child);
|
||||
|
@ -212,8 +210,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
|
||||
const struct tfork* requested);
|
||||
Process* CurrentProcess();
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
207
kernel/include/sortix/kernel/registers.h
Normal file
207
kernel/include/sortix/kernel/registers.h
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/kernel/registers.h
|
||||
Register structures and platform-specific bits.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_KERNEL_REGISTERS_H
|
||||
#define INCLUDE_SORTIX_KERNEL_REGISTERS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Sortix {
|
||||
// CPU flag register bits for 32-bit and 64-bit x86.
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
const size_t FLAGS_CARRY = 1 << 0; // 0x000001
|
||||
const size_t FLAGS_RESERVED1 = 1 << 1; // 0x000002, read as one
|
||||
const size_t FLAGS_PARITY = 1 << 2; // 0x000004
|
||||
const size_t FLAGS_RESERVED2 = 1 << 3; // 0x000008
|
||||
const size_t FLAGS_AUX = 1 << 4; // 0x000010
|
||||
const size_t FLAGS_RESERVED3 = 1 << 5; // 0x000020
|
||||
const size_t FLAGS_ZERO = 1 << 6; // 0x000040
|
||||
const size_t FLAGS_SIGN = 1 << 7; // 0x000080
|
||||
const size_t FLAGS_TRAP = 1 << 8; // 0x000100
|
||||
const size_t FLAGS_INTERRUPT = 1 << 9; // 0x000200
|
||||
const size_t FLAGS_DIRECTION = 1 << 10; // 0x000400
|
||||
const size_t FLAGS_OVERFLOW = 1 << 11; // 0x000800
|
||||
const size_t FLAGS_IOPRIVLEVEL = 1 << 12 | 1 << 13;
|
||||
const size_t FLAGS_NESTEDTASK = 1 << 14; // 0x004000
|
||||
const size_t FLAGS_RESERVED4 = 1 << 15; // 0x008000
|
||||
const size_t FLAGS_RESUME = 1 << 16; // 0x010000
|
||||
const size_t FLAGS_VIRTUAL8086 = 1 << 17; // 0x020000
|
||||
const size_t FLAGS_ALIGNCHECK = 1 << 18; // 0x040000
|
||||
const size_t FLAGS_VIRTINTR = 1 << 19; // 0x080000
|
||||
const size_t FLAGS_VIRTINTRPEND = 1 << 20; // 0x100000
|
||||
const size_t FLAGS_ID = 1 << 21; // 0x200000
|
||||
#endif
|
||||
|
||||
// i386 registers structures.
|
||||
#if defined(__i386__)
|
||||
const uint32_t KCS = 0x08;
|
||||
const uint32_t KDS = 0x10;
|
||||
const uint32_t KRPL = 0x0;
|
||||
const uint32_t UCS = 0x18;
|
||||
const uint32_t UDS = 0x20;
|
||||
const uint32_t URPL = 0x3;
|
||||
const uint32_t RPLMASK = 0x3;
|
||||
|
||||
struct interrupt_context
|
||||
{
|
||||
uint32_t signal_pending;
|
||||
uint32_t kerrno;
|
||||
uint32_t cr2;
|
||||
uint32_t ds;
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebp;
|
||||
uint32_t not_esp;
|
||||
uint32_t ebx;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t eax;
|
||||
uint32_t int_no;
|
||||
uint32_t err_code;
|
||||
uint32_t eip;
|
||||
uint32_t cs;
|
||||
uint32_t eflags;
|
||||
uint32_t esp;
|
||||
uint32_t ss;
|
||||
};
|
||||
|
||||
__attribute__((unused))
|
||||
static inline bool InUserspace(const struct interrupt_context* intctx)
|
||||
{
|
||||
return (intctx->cs & RPLMASK) != KRPL;
|
||||
}
|
||||
|
||||
struct thread_registers
|
||||
{
|
||||
uint32_t signal_pending;
|
||||
uint32_t kerrno;
|
||||
uint32_t eax;
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t fsbase;
|
||||
uint32_t gsbase;
|
||||
uint32_t cr3;
|
||||
uint32_t kernel_stack;
|
||||
uint32_t cs;
|
||||
uint32_t ds;
|
||||
uint32_t ss;
|
||||
__attribute__((aligned(16))) uint8_t fpuenv[512];
|
||||
};
|
||||
#endif
|
||||
|
||||
// x86_64 registers structures.
|
||||
#if defined(__x86_64__)
|
||||
const uint64_t KCS = 0x08;
|
||||
const uint64_t KDS = 0x10;
|
||||
const uint64_t KRPL = 0x0;
|
||||
const uint64_t UCS = 0x18;
|
||||
const uint64_t UDS = 0x20;
|
||||
const uint64_t URPL = 0x3;
|
||||
const uint64_t RPLMASK = 0x3;
|
||||
|
||||
struct interrupt_context
|
||||
{
|
||||
uint64_t signal_pending;
|
||||
uint64_t kerrno;
|
||||
uint64_t cr2;
|
||||
uint64_t ds;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rbp;
|
||||
uint64_t not_rsp;
|
||||
uint64_t rbx;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rax;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
uint64_t int_no;
|
||||
uint64_t err_code;
|
||||
uint64_t rip;
|
||||
uint64_t cs;
|
||||
uint64_t rflags;
|
||||
uint64_t rsp;
|
||||
uint64_t ss;
|
||||
};
|
||||
|
||||
__attribute__((unused))
|
||||
static inline bool InUserspace(const struct interrupt_context* intctx)
|
||||
{
|
||||
return (intctx->cs & RPLMASK) != KRPL;
|
||||
}
|
||||
|
||||
struct thread_registers
|
||||
{
|
||||
uint64_t signal_pending;
|
||||
uint64_t kerrno;
|
||||
uint64_t rax;
|
||||
uint64_t rbx;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rsp;
|
||||
uint64_t rbp;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
uint64_t rip;
|
||||
uint64_t rflags;
|
||||
uint64_t fsbase;
|
||||
uint64_t gsbase;
|
||||
uint64_t cr3;
|
||||
uint64_t kernel_stack;
|
||||
uint64_t cs;
|
||||
uint64_t ds;
|
||||
uint64_t ss;
|
||||
__attribute__((aligned(16))) uint8_t fpuenv[512];
|
||||
};
|
||||
#endif
|
||||
|
||||
void LogInterruptContext(const struct interrupt_context* intctx);
|
||||
__attribute__((noreturn))
|
||||
void LoadRegisters(const struct thread_registers* registers);
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -26,18 +26,13 @@
|
|||
#define INCLUDE_SORTIX_KERNEL_SCHEDULER_H
|
||||
|
||||
#include <sortix/kernel/decl.h>
|
||||
#include <sortix/kernel/registers.h>
|
||||
|
||||
namespace Sortix {
|
||||
class Process;
|
||||
class Thread;
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
namespace CPU {
|
||||
struct InterruptRegisters;
|
||||
} // namespace CPU
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
enum ThreadState { NONE, RUNNABLE, BLOCKING, DEAD };
|
||||
} // namespace Sortix
|
||||
|
@ -59,15 +54,19 @@ static inline void ExitThread()
|
|||
#endif
|
||||
|
||||
void Init();
|
||||
void Switch(CPU::InterruptRegisters* regs);
|
||||
void Switch(struct interrupt_context* intctx);
|
||||
void SetThreadState(Thread* thread, ThreadState state);
|
||||
ThreadState GetThreadState(Thread* thread);
|
||||
void SetIdleThread(Thread* thread);
|
||||
void SetInitProcess(Process* init);
|
||||
Process* GetInitProcess();
|
||||
Process* GetKernelProcess();
|
||||
void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* user);
|
||||
void ThreadExitCPU(CPU::InterruptRegisters* regs, void* user);
|
||||
void InterruptYieldCPU(struct interrupt_context* intctx, void* user);
|
||||
void ThreadExitCPU(struct interrupt_context* intctx, void* user);
|
||||
void SaveInterruptedContext(const struct interrupt_context* intctx,
|
||||
struct thread_registers* registers);
|
||||
void LoadInterruptedContext(struct interrupt_context* intctx,
|
||||
const struct thread_registers* registers);
|
||||
|
||||
} // namespace Scheduler
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <sortix/sigset.h>
|
||||
|
||||
#include <sortix/kernel/cpu.h>
|
||||
#include <sortix/kernel/registers.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
|
@ -38,8 +39,8 @@ namespace Signal {
|
|||
|
||||
void Init();
|
||||
inline bool IsPending() { return asm_signal_is_pending != 0; }
|
||||
void DispatchHandler(CPU::InterruptRegisters* regs, void* user);
|
||||
void ReturnHandler(CPU::InterruptRegisters* regs, void* user);
|
||||
void DispatchHandler(struct interrupt_context* intctx, void* user);
|
||||
void ReturnHandler(struct interrupt_context* intctx, void* user);
|
||||
|
||||
} // namespace Signal
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <sortix/stack.h>
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/registers.h>
|
||||
#include <sortix/kernel/scheduler.h>
|
||||
#include <sortix/kernel/signal.h>
|
||||
|
||||
|
@ -40,8 +41,7 @@ class Process;
|
|||
class Thread;
|
||||
|
||||
// These functions create a new kernel process but doesn't start it.
|
||||
Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
|
||||
unsigned long fsbase, unsigned long gsbase);
|
||||
Thread* CreateKernelThread(Process* process, struct thread_registers* regs);
|
||||
Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user,
|
||||
size_t stacksize = 0);
|
||||
Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0);
|
||||
|
@ -50,18 +50,13 @@ Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize =
|
|||
void StartKernelThread(Thread* thread);
|
||||
|
||||
// Alternatively, these functions both create and start the thread.
|
||||
Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs);
|
||||
Thread* RunKernelThread(Process* process, struct thread_registers* regs);
|
||||
Thread* RunKernelThread(Process* process, void (*entry)(void*), void* user,
|
||||
size_t stacksize = 0);
|
||||
Thread* RunKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0);
|
||||
|
||||
class Thread
|
||||
{
|
||||
friend Thread* CreateKernelThread(Process* process,
|
||||
CPU::InterruptRegisters* regs,
|
||||
unsigned long fsbase, unsigned long gsbase);
|
||||
friend void UpdatePendingSignals(Thread* thread);
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
|
||||
|
@ -70,49 +65,34 @@ public:
|
|||
~Thread();
|
||||
|
||||
public:
|
||||
struct thread_registers registers;
|
||||
uint8_t* self_allocation;
|
||||
size_t id;
|
||||
Process* process;
|
||||
Thread* prevsibling;
|
||||
Thread* nextsibling;
|
||||
|
||||
public:
|
||||
Thread* scheduler_list_prev;
|
||||
Thread* scheduler_list_next;
|
||||
volatile ThreadState state;
|
||||
uint8_t fpuenv[512UL + 16UL];
|
||||
uint8_t* fpuenvaligned;
|
||||
bool fpuinitialized;
|
||||
|
||||
public:
|
||||
sigset_t signal_pending;
|
||||
sigset_t signal_mask;
|
||||
stack_t signal_stack;
|
||||
addr_t addrspace;
|
||||
addr_t kernelstackpos;
|
||||
size_t kernelstacksize;
|
||||
bool kernelstackmalloced;
|
||||
bool pledged_destruction;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
public:
|
||||
unsigned long fsbase;
|
||||
unsigned long gsbase;
|
||||
#endif
|
||||
|
||||
private:
|
||||
CPU::InterruptRegisters registers;
|
||||
|
||||
public:
|
||||
void SaveRegisters(const CPU::InterruptRegisters* src);
|
||||
void LoadRegisters(CPU::InterruptRegisters* dest);
|
||||
void HandleSignal(CPU::InterruptRegisters* regs);
|
||||
void HandleSigreturn(CPU::InterruptRegisters* regs);
|
||||
void HandleSignal(struct interrupt_context* intctx);
|
||||
void HandleSigreturn(struct interrupt_context* intctx);
|
||||
bool DeliverSignal(int signum);
|
||||
bool DeliverSignalUnlocked(int signum);
|
||||
addr_t SwitchAddressSpace(addr_t newaddrspace);
|
||||
|
||||
};
|
||||
|
||||
Thread* AllocateThread();
|
||||
void FreeThread(Thread* thread);
|
||||
|
||||
Thread* CurrentThread();
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <sortix/kernel/ioport.h>
|
||||
#include <sortix/kernel/kernel.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/kernel/scheduler.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
|
||||
#if defined(__i386__)
|
||||
|
@ -57,9 +58,9 @@ const uint8_t LED_SCRLCK = 1 << 0;
|
|||
const uint8_t LED_NUMLCK = 1 << 1;
|
||||
const uint8_t LED_CAPSLCK = 1 << 2;
|
||||
|
||||
void PS2Keyboard__OnInterrupt(CPU::InterruptRegisters* regs, void* user)
|
||||
void PS2Keyboard__OnInterrupt(struct interrupt_context* intctx, void* user)
|
||||
{
|
||||
((PS2Keyboard*) user)->OnInterrupt(regs);
|
||||
((PS2Keyboard*) user)->OnInterrupt(intctx);
|
||||
}
|
||||
|
||||
PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt)
|
||||
|
@ -100,20 +101,12 @@ static void PS2Keyboard__InterruptWork(void* kb_ptr, void* payload, size_t size)
|
|||
((PS2Keyboard*) kb_ptr)->InterruptWork(work->scancode);
|
||||
}
|
||||
|
||||
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs)
|
||||
void PS2Keyboard::OnInterrupt(struct interrupt_context* intctx)
|
||||
{
|
||||
uint8_t scancode = PopScancode();
|
||||
if ( scancode == KBKEY_F10 )
|
||||
{
|
||||
Thread* thread = CurrentThread();
|
||||
#if defined(__i386__)
|
||||
thread->fsbase = (unsigned long) GDT::GetFSBase();
|
||||
thread->gsbase = (unsigned long) GDT::GetGSBase();
|
||||
#elif defined(__x86_64__)
|
||||
thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
|
||||
thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
|
||||
#endif
|
||||
thread->SaveRegisters(regs);
|
||||
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
|
||||
Debugger::Run();
|
||||
}
|
||||
PS2KeyboardWork work;
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
virtual void SetOwner(KeyboardOwner* owner, void* user);
|
||||
|
||||
public:
|
||||
void OnInterrupt(CPU::InterruptRegisters* regs);
|
||||
void OnInterrupt(struct interrupt_context* intctx);
|
||||
void InterruptWork(uint8_t scancode);
|
||||
|
||||
private:
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
|
||||
// Keep the stack size aligned with $CPU/base.s
|
||||
const size_t STACK_SIZE = 64*1024;
|
||||
extern "C" { size_t stack[STACK_SIZE / sizeof(size_t)] = {0}; }
|
||||
extern "C" { __attribute__((aligned(16))) size_t stack[STACK_SIZE / sizeof(size_t)]; }
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
|
@ -290,6 +290,7 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
|
||||
// Initialize the GDT and TSS structures.
|
||||
GDT::Init();
|
||||
GDT::SetKernelStack((uintptr_t) stack + STACK_SIZE);
|
||||
|
||||
// Initialize the interrupt handler table and enable interrupts.
|
||||
Interrupt::Init();
|
||||
|
@ -436,9 +437,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
// Now that the base system has been loaded, it's time to go threaded. First
|
||||
// we create an object that represents this thread.
|
||||
Process* system = new Process;
|
||||
if ( !system ) { Panic("Could not allocate the system process"); }
|
||||
addr_t systemaddrspace = Memory::GetAddressSpace();
|
||||
system->addrspace = systemaddrspace;
|
||||
if ( !system )
|
||||
Panic("Could not allocate the system process");
|
||||
system->addrspace = Memory::GetAddressSpace();
|
||||
system->group = system;
|
||||
system->groupprev = NULL;
|
||||
system->groupnext = NULL;
|
||||
|
@ -451,13 +452,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
// create a kernel thread that is the current thread and isn't put into the
|
||||
// scheduler's set of runnable threads, but rather run whenever there is
|
||||
// _nothing_ else to run on this CPU.
|
||||
Thread* idlethread = new Thread;
|
||||
Thread* idlethread = AllocateThread();
|
||||
idlethread->process = system;
|
||||
idlethread->addrspace = idlethread->process->addrspace;
|
||||
idlethread->kernelstackpos = (addr_t) stack;
|
||||
idlethread->kernelstacksize = STACK_SIZE;
|
||||
idlethread->kernelstackmalloced = false;
|
||||
idlethread->fpuinitialized = true;
|
||||
system->firstthread = idlethread;
|
||||
Scheduler::SetIdleThread(idlethread);
|
||||
|
||||
|
@ -467,9 +466,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
// we must become the system idle thread.
|
||||
RunKernelThread(BootThread, NULL);
|
||||
|
||||
// Set up such that floating point registers are lazily switched.
|
||||
Float::Init();
|
||||
|
||||
// The time driver will run the scheduler on the next timer interrupt.
|
||||
Time::Start();
|
||||
|
||||
|
@ -766,7 +762,8 @@ static void InitThread(void* /*user*/)
|
|||
const char* cputype = "cputype=" CPUTYPE_STR;
|
||||
int envc = 1;
|
||||
const char* envp[] = { cputype, NULL };
|
||||
CPU::InterruptRegisters regs;
|
||||
struct thread_registers regs;
|
||||
assert((((uintptr_t) ®s) & (alignof(regs)-1)) == 0);
|
||||
|
||||
if ( process->Execute(initpath, program, programsize, argc, argv, envc,
|
||||
envp, ®s) )
|
||||
|
@ -775,7 +772,7 @@ static void InitThread(void* /*user*/)
|
|||
delete[] program;
|
||||
|
||||
// Now become the init process and the operation system shall run.
|
||||
CPU::LoadRegisters(®s);
|
||||
LoadRegisters(®s);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -39,7 +39,7 @@ static void kthread_do_kill_thread(void* user)
|
|||
Thread* thread = (Thread*) user;
|
||||
while ( thread->state != ThreadState::DEAD )
|
||||
kthread_yield();
|
||||
delete thread;
|
||||
FreeThread(thread);
|
||||
}
|
||||
|
||||
extern "C" void kthread_exit()
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "initrd.h"
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include "x86-family/float.h"
|
||||
#include "x86-family/gdt.h"
|
||||
#endif
|
||||
|
||||
|
@ -249,11 +250,6 @@ void Process::OnLastThreadExit()
|
|||
LastPrayer();
|
||||
}
|
||||
|
||||
static void SwitchCurrentAddrspace(addr_t addrspace, void* user)
|
||||
{
|
||||
((Thread*) user)->SwitchAddressSpace(addrspace);
|
||||
}
|
||||
|
||||
void Process::DeleteTimers()
|
||||
{
|
||||
for ( timer_t i = 0; i < PROCESS_TIMER_NUM_MAX; i++ )
|
||||
|
@ -290,7 +286,7 @@ void Process::LastPrayer()
|
|||
|
||||
// We need to temporarily reload the correct addrese space of the dying
|
||||
// process such that we can unmap and free its memory.
|
||||
addr_t prevaddrspace = curthread->SwitchAddressSpace(addrspace);
|
||||
addr_t prevaddrspace = Memory::SwitchAddressSpace(addrspace);
|
||||
|
||||
ResetAddressSpace();
|
||||
|
||||
|
@ -301,9 +297,7 @@ void Process::LastPrayer()
|
|||
|
||||
// Destroy the address space and safely switch to the replacement
|
||||
// address space before things get dangerous.
|
||||
Memory::DestroyAddressSpace(prevaddrspace,
|
||||
SwitchCurrentAddrspace,
|
||||
curthread);
|
||||
Memory::DestroyAddressSpace(prevaddrspace);
|
||||
addrspace = 0;
|
||||
|
||||
// Unload the process symbol and string tables.
|
||||
|
@ -814,7 +808,7 @@ bool Process::MapSegment(struct segment* result, void* hint, size_t size,
|
|||
int Process::Execute(const char* programname, const uint8_t* program,
|
||||
size_t programsize, int argc, const char* const* argv,
|
||||
int envc, const char* const* envp,
|
||||
CPU::InterruptRegisters* regs)
|
||||
struct thread_registers* regs)
|
||||
{
|
||||
assert(argc != INT_MAX);
|
||||
assert(envc != INT_MAX);
|
||||
|
@ -969,10 +963,43 @@ int Process::Execute(const char* programname, const uint8_t* program,
|
|||
uthread->arg_size = arg_segment.size;
|
||||
memset(uthread + 1, 0, aux.uthread_size - sizeof(struct uthread));
|
||||
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
#if defined(__i386__)
|
||||
GDT::SetGSBase((uint32_t) uthread);
|
||||
regs->eax = argc;
|
||||
regs->ebx = (size_t) target_argv;
|
||||
regs->edx = envc;
|
||||
regs->ecx = (size_t) target_envp;
|
||||
regs->eip = entry;
|
||||
regs->esp = (stack_segment.addr + stack_segment.size) & ~15UL;
|
||||
regs->ebp = regs->esp;
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->signal_pending = 0;
|
||||
regs->gsbase = (uint32_t) uthread;
|
||||
regs->cr3 = addrspace;
|
||||
regs->kernel_stack = GDT::GetKernelStack();
|
||||
memcpy(regs->fpuenv, Float::fpu_initialized_regs, 512);
|
||||
#elif defined(__x86_64__)
|
||||
wrmsr(MSRID_FSBASE, (uint64_t) uthread);
|
||||
regs->rdi = argc;
|
||||
regs->rsi = (size_t) target_argv;
|
||||
regs->rdx = envc;
|
||||
regs->rcx = (size_t) target_envp;
|
||||
regs->rip = entry;
|
||||
regs->rsp = (stack_segment.addr + stack_segment.size) & ~15UL;
|
||||
regs->rbp = regs->rsp;
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->signal_pending = 0;
|
||||
regs->fsbase = (uint64_t) uthread;
|
||||
regs->cr3 = addrspace;
|
||||
regs->kernel_stack = GDT::GetKernelStack();
|
||||
memcpy(regs->fpuenv, Float::fpu_initialized_regs, 512);
|
||||
#else
|
||||
#warning "You need to implement initializing the first thread after execute"
|
||||
#endif
|
||||
|
||||
uint8_t* auxcode = (uint8_t*) auxcode_segment.addr;
|
||||
|
@ -991,8 +1018,6 @@ int Process::Execute(const char* programname, const uint8_t* program,
|
|||
|
||||
dtable->OnExecute();
|
||||
|
||||
ExecuteCPU(argc, target_argv, envc, target_envp, stack_segment.addr + stack_segment.size, entry, regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1002,7 +1027,7 @@ int sys_execve_kernel(const char* filename,
|
|||
char* const argv[],
|
||||
int envc,
|
||||
char* const envp[],
|
||||
CPU::InterruptRegisters* regs)
|
||||
struct thread_registers* regs)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
|
||||
|
@ -1054,7 +1079,7 @@ int sys_execve(const char* user_filename,
|
|||
char** argv;
|
||||
char** envp;
|
||||
int result = -1;
|
||||
CPU::InterruptRegisters regs;
|
||||
struct thread_registers regs;
|
||||
memset(®s, 0, sizeof(regs));
|
||||
|
||||
if ( !user_filename || !user_argv || !user_envp )
|
||||
|
@ -1135,7 +1160,7 @@ cleanup_filename:
|
|||
delete[] filename;
|
||||
cleanup_done:
|
||||
if ( result == 0 )
|
||||
CPU::LoadRegisters(®s);
|
||||
LoadRegisters(®s);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1158,15 +1183,22 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
|
|||
if ( regs.altstack.ss_flags & ~__SS_SUPPORTED_FLAGS )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
CPU::InterruptRegisters cpuregs;
|
||||
InitializeThreadRegisters(&cpuregs, ®s);
|
||||
size_t stack_alignment = 16;
|
||||
|
||||
// TODO: Is it a hack to create a new kernel stack here?
|
||||
Thread* curthread = CurrentThread();
|
||||
uint8_t* newkernelstack = new uint8_t[curthread->kernelstacksize];
|
||||
size_t newkernelstacksize = curthread->kernelstacksize;
|
||||
uint8_t* newkernelstack = new uint8_t[newkernelstacksize + stack_alignment];
|
||||
if ( !newkernelstack )
|
||||
return -1;
|
||||
|
||||
uintptr_t stack_aligned = (uintptr_t) newkernelstack;
|
||||
size_t stack_aligned_size = newkernelstacksize;
|
||||
|
||||
if ( ((uintptr_t) stack_aligned) & (stack_alignment-1) )
|
||||
stack_aligned = (stack_aligned + 16) & ~(stack_alignment-1);
|
||||
stack_aligned_size &= 0xFFFFFFF0;
|
||||
|
||||
Process* child_process;
|
||||
if ( making_thread )
|
||||
child_process = CurrentProcess();
|
||||
|
@ -1176,10 +1208,59 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
|
|||
return -1;
|
||||
}
|
||||
|
||||
struct thread_registers cpuregs;
|
||||
memset(&cpuregs, 0, sizeof(cpuregs));
|
||||
#if defined(__i386__)
|
||||
cpuregs.eip = regs.eip;
|
||||
cpuregs.esp = regs.esp;
|
||||
cpuregs.eax = regs.eax;
|
||||
cpuregs.ebx = regs.ebx;
|
||||
cpuregs.ecx = regs.ecx;
|
||||
cpuregs.edx = regs.edx;
|
||||
cpuregs.edi = regs.edi;
|
||||
cpuregs.esi = regs.esi;
|
||||
cpuregs.ebp = regs.ebp;
|
||||
cpuregs.cs = UCS | URPL;
|
||||
cpuregs.ds = UDS | URPL;
|
||||
cpuregs.ss = UDS | URPL;
|
||||
cpuregs.eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
cpuregs.fsbase = regs.fsbase;
|
||||
cpuregs.gsbase = regs.gsbase;
|
||||
cpuregs.cr3 = child_process->addrspace;
|
||||
cpuregs.kernel_stack = stack_aligned + stack_aligned_size;
|
||||
#elif defined(__x86_64__)
|
||||
cpuregs.rip = regs.rip;
|
||||
cpuregs.rsp = regs.rsp;
|
||||
cpuregs.rax = regs.rax;
|
||||
cpuregs.rbx = regs.rbx;
|
||||
cpuregs.rcx = regs.rcx;
|
||||
cpuregs.rdx = regs.rdx;
|
||||
cpuregs.rdi = regs.rdi;
|
||||
cpuregs.rsi = regs.rsi;
|
||||
cpuregs.rbp = regs.rbp;
|
||||
cpuregs.r8 = regs.r8;
|
||||
cpuregs.r9 = regs.r9;
|
||||
cpuregs.r10 = regs.r10;
|
||||
cpuregs.r11 = regs.r11;
|
||||
cpuregs.r12 = regs.r12;
|
||||
cpuregs.r13 = regs.r13;
|
||||
cpuregs.r14 = regs.r14;
|
||||
cpuregs.r15 = regs.r15;
|
||||
cpuregs.cs = UCS | URPL;
|
||||
cpuregs.ds = UDS | URPL;
|
||||
cpuregs.ss = UDS | URPL;
|
||||
cpuregs.rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
cpuregs.fsbase = regs.fsbase;
|
||||
cpuregs.gsbase = regs.gsbase;
|
||||
cpuregs.cr3 = child_process->addrspace;
|
||||
cpuregs.kernel_stack = stack_aligned + stack_aligned_size;
|
||||
#else
|
||||
#warning "You need to implement initializing the registers of the new thread"
|
||||
#endif
|
||||
|
||||
// If the thread could not be created, make the process commit suicide
|
||||
// in a manner such that we don't wait for its zombie.
|
||||
Thread* thread = CreateKernelThread(child_process, &cpuregs, regs.fsbase,
|
||||
regs.gsbase);
|
||||
Thread* thread = CreateKernelThread(child_process, &cpuregs);
|
||||
if ( !thread )
|
||||
{
|
||||
if ( making_process )
|
||||
|
@ -1188,7 +1269,7 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs)
|
|||
}
|
||||
|
||||
thread->kernelstackpos = (addr_t) newkernelstack;
|
||||
thread->kernelstacksize = curthread->kernelstacksize;
|
||||
thread->kernelstacksize = newkernelstacksize;
|
||||
thread->kernelstackmalloced = true;
|
||||
memcpy(&thread->signal_mask, ®s.sigmask, sizeof(sigset_t));
|
||||
memcpy(&thread->signal_stack, ®s.altstack, sizeof(stack_t));
|
||||
|
|
76
kernel/registers.cpp
Normal file
76
kernel/registers.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
registers.cpp
|
||||
Register structures and platform-specific bits.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sortix/kernel/log.h>
|
||||
#include <sortix/kernel/registers.h>
|
||||
#include <sortix/kernel/scheduler.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
void LogInterruptContext(const struct interrupt_context* intctx)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
Log::PrintF("[cr2=0x%zx,ds=0x%zx,edi=0x%zx,esi=0x%zx,ebp=0x%zx,"
|
||||
"ebx=0x%zx,edx=0x%zx,ecx=0x%zx,eax=0x%zx,"
|
||||
"int_no=0x%zx,err_code=0x%zx,eip=0x%zx,cs=0x%zx,"
|
||||
"eflags=0x%zx,esp=0x%zx,ss=0x%zx]",
|
||||
intctx->cr2, intctx->ds, intctx->edi, intctx->esi, intctx->ebp,
|
||||
intctx->ebx, intctx->edx, intctx->ecx, intctx->eax,
|
||||
intctx->int_no, intctx->err_code, intctx->eip, intctx->cs,
|
||||
intctx->eflags, intctx->esp, intctx->ss);
|
||||
#elif defined(__x86_64__)
|
||||
Log::PrintF("[cr2=0x%zx,ds=0x%zx,rdi=0x%zx,rsi=0x%zx,rbp=0x%zx,"
|
||||
"rbx=0x%zx,rdx=0x%zx,rcx=0x%zx,rax=0x%zx,"
|
||||
"r8=0x%zx,r9=0x%zx,r10=0x%zx,r11=0x%zx,r12=0x%zx,"
|
||||
"r13=0x%zx,r14=0x%zx,r15=0x%zx,int_no=0x%zx,"
|
||||
"err_code=0x%zx,rip=0x%zx,cs=0x%zx,rflags=0x%zx,"
|
||||
"rsp=0x%zx,ss=0x%zx]",
|
||||
intctx->cr2, intctx->ds, intctx->rdi, intctx->rsi, intctx->rbp,
|
||||
intctx->rbx, intctx->rdx, intctx->rcx, intctx->rax,
|
||||
intctx->r8, intctx->r9, intctx->r10, intctx->r11, intctx->r12,
|
||||
intctx->r13, intctx->r14, intctx->r15, intctx->int_no,
|
||||
intctx->err_code, intctx->rip, intctx->cs, intctx->rflags,
|
||||
intctx->rsp, intctx->ss);
|
||||
#else
|
||||
#warning "You need to implement printing an interrupt context"
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" __attribute__((noreturn))
|
||||
void load_registers(const struct interrupt_context* inctx);
|
||||
|
||||
__attribute__((noreturn))
|
||||
void LoadRegisters(const struct thread_registers* registers)
|
||||
{
|
||||
struct interrupt_context intctx;
|
||||
memset(&intctx, 0, sizeof(intctx));
|
||||
|
||||
Scheduler::LoadInterruptedContext(&intctx, registers);
|
||||
|
||||
load_registers(&intctx);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
|
@ -25,10 +25,13 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <msr.h>
|
||||
#include <string.h>
|
||||
#include <timespec.h>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#include <msr.h>
|
||||
#endif
|
||||
|
||||
#include <sortix/clock.h>
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
|
@ -37,6 +40,7 @@
|
|||
#include <sortix/kernel/kernel.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/registers.h>
|
||||
#include <sortix/kernel/scheduler.h>
|
||||
#include <sortix/kernel/signal.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
|
@ -52,9 +56,143 @@ namespace Sortix {
|
|||
namespace Scheduler {
|
||||
|
||||
static Thread* current_thread;
|
||||
|
||||
void SaveInterruptedContext(const struct interrupt_context* intctx,
|
||||
struct thread_registers* registers)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
registers->signal_pending = intctx->signal_pending;
|
||||
registers->kerrno = intctx->kerrno;
|
||||
registers->eax = intctx->eax;
|
||||
registers->ebx = intctx->ebx;
|
||||
registers->ecx = intctx->ecx;
|
||||
registers->edx = intctx->edx;
|
||||
registers->edi = intctx->edi;
|
||||
registers->esi = intctx->esi;
|
||||
registers->esp = intctx->esp;
|
||||
registers->ebp = intctx->ebp;
|
||||
registers->eip = intctx->eip;
|
||||
registers->eflags = intctx->eflags;
|
||||
registers->fsbase = (unsigned long) GDT::GetFSBase();
|
||||
registers->gsbase = (unsigned long) GDT::GetGSBase();
|
||||
asm ( "mov %%cr3, %0" : "=r"(registers->cr3) );
|
||||
registers->kernel_stack = GDT::GetKernelStack();
|
||||
registers->cs = intctx->cs;
|
||||
registers->ds = intctx->ds;
|
||||
registers->ss = intctx->ss;
|
||||
asm volatile ("fxsave (%0)" : : "r"(registers->fpuenv));
|
||||
#elif defined(__x86_64__)
|
||||
registers->signal_pending = intctx->signal_pending;
|
||||
registers->kerrno = intctx->kerrno;
|
||||
registers->rax = intctx->rax;
|
||||
registers->rbx = intctx->rbx;
|
||||
registers->rcx = intctx->rcx;
|
||||
registers->rdx = intctx->rdx;
|
||||
registers->rdi = intctx->rdi;
|
||||
registers->rsi = intctx->rsi;
|
||||
registers->rsp = intctx->rsp;
|
||||
registers->rbp = intctx->rbp;
|
||||
registers->r8 = intctx->r8;
|
||||
registers->r9 = intctx->r9;
|
||||
registers->r10 = intctx->r10;
|
||||
registers->r11 = intctx->r11;
|
||||
registers->r12 = intctx->r12;
|
||||
registers->r13 = intctx->r13;
|
||||
registers->r14 = intctx->r14;
|
||||
registers->r15 = intctx->r15;
|
||||
registers->r15 = intctx->r15;
|
||||
registers->rip = intctx->rip;
|
||||
registers->rflags = intctx->rflags;
|
||||
registers->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
|
||||
registers->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
|
||||
asm ( "mov %%cr3, %0" : "=r"(registers->cr3) );
|
||||
registers->kernel_stack = GDT::GetKernelStack();
|
||||
registers->cs = intctx->cs;
|
||||
registers->ds = intctx->ds;
|
||||
registers->ss = intctx->ss;
|
||||
asm volatile ("fxsave (%0)" : : "r"(registers->fpuenv));
|
||||
#else
|
||||
#warning "You need to implement register saving"
|
||||
#endif
|
||||
}
|
||||
|
||||
void LoadInterruptedContext(struct interrupt_context* intctx,
|
||||
const struct thread_registers* registers)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
intctx->signal_pending = registers->signal_pending;
|
||||
intctx->kerrno = registers->kerrno;
|
||||
intctx->eax = registers->eax;
|
||||
intctx->ebx = registers->ebx;
|
||||
intctx->ecx = registers->ecx;
|
||||
intctx->edx = registers->edx;
|
||||
intctx->edi = registers->edi;
|
||||
intctx->esi = registers->esi;
|
||||
intctx->esp = registers->esp;
|
||||
intctx->ebp = registers->ebp;
|
||||
intctx->eip = registers->eip;
|
||||
intctx->eflags = registers->eflags;
|
||||
GDT::SetFSBase(registers->fsbase);
|
||||
GDT::SetGSBase(registers->gsbase);
|
||||
asm volatile ( "mov %0, %%cr3" : : "r"(registers->cr3) );
|
||||
GDT::SetKernelStack(registers->kernel_stack);
|
||||
intctx->cs = registers->cs;
|
||||
intctx->ds = registers->ds;
|
||||
intctx->ss = registers->ss;
|
||||
asm volatile ("fxrstor (%0)" : : "r"(registers->fpuenv));
|
||||
#elif defined(__x86_64__)
|
||||
intctx->signal_pending = registers->signal_pending;
|
||||
intctx->kerrno = registers->kerrno;
|
||||
intctx->rax = registers->rax;
|
||||
intctx->rbx = registers->rbx;
|
||||
intctx->rcx = registers->rcx;
|
||||
intctx->rdx = registers->rdx;
|
||||
intctx->rdi = registers->rdi;
|
||||
intctx->rsi = registers->rsi;
|
||||
intctx->rsp = registers->rsp;
|
||||
intctx->rbp = registers->rbp;
|
||||
intctx->r8 = registers->r8;
|
||||
intctx->r9 = registers->r9;
|
||||
intctx->r10 = registers->r10;
|
||||
intctx->r11 = registers->r11;
|
||||
intctx->r12 = registers->r12;
|
||||
intctx->r13 = registers->r13;
|
||||
intctx->r14 = registers->r14;
|
||||
intctx->r15 = registers->r15;
|
||||
intctx->r15 = registers->r15;
|
||||
intctx->rip = registers->rip;
|
||||
intctx->rflags = registers->rflags;
|
||||
wrmsr(MSRID_FSBASE, registers->fsbase);
|
||||
wrmsr(MSRID_GSBASE, registers->gsbase);
|
||||
asm volatile ( "mov %0, %%cr3" : : "r"(registers->cr3) );
|
||||
GDT::SetKernelStack(registers->kernel_stack);
|
||||
intctx->cs = registers->cs;
|
||||
intctx->ds = registers->ds;
|
||||
intctx->ss = registers->ss;
|
||||
asm volatile ("fxrstor (%0)" : : "r"(registers->fpuenv));
|
||||
#else
|
||||
#warning "You need to implement register loading"
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next)
|
||||
{
|
||||
if ( prev == next )
|
||||
return;
|
||||
|
||||
SaveInterruptedContext(intctx, &prev->registers);
|
||||
if ( !prev->registers.cr3 )
|
||||
Log::PrintF("Thread %p had cr3=0x%zx\n", prev, prev->registers.cr3);
|
||||
if ( !next->registers.cr3 )
|
||||
Log::PrintF("Thread %p has cr3=0x%zx\n", next, next->registers.cr3);
|
||||
LoadInterruptedContext(intctx, &next->registers);
|
||||
|
||||
current_thread = next;
|
||||
}
|
||||
|
||||
static Thread* idle_thread;
|
||||
static Thread* first_runnable_thread;
|
||||
static Thread* first_sleeping_thread;
|
||||
static Process* init_process;
|
||||
|
||||
static Thread* PopNextThread()
|
||||
|
@ -69,63 +207,26 @@ static Thread* PopNextThread()
|
|||
return idle_thread;
|
||||
}
|
||||
|
||||
static void DoActualSwitch(CPU::InterruptRegisters* regs)
|
||||
void Switch(struct interrupt_context* intctx)
|
||||
{
|
||||
Thread* prev = CurrentThread();
|
||||
Thread* next = PopNextThread();
|
||||
SwitchThread(intctx, CurrentThread(), PopNextThread());
|
||||
|
||||
if ( prev == next )
|
||||
return;
|
||||
|
||||
prev->SaveRegisters(regs);
|
||||
next->LoadRegisters(regs);
|
||||
|
||||
Memory::SwitchAddressSpace(next->addrspace);
|
||||
current_thread = next;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
Float::NotityTaskSwitch();
|
||||
GDT::SetKernelStack(next->kernelstackpos, next->kernelstacksize,
|
||||
next->kernelstackpos + next->kernelstacksize);
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
prev->fsbase = (unsigned long) GDT::GetFSBase();
|
||||
prev->gsbase = (unsigned long) GDT::GetGSBase();
|
||||
GDT::SetFSBase((uint32_t) next->fsbase);
|
||||
GDT::SetGSBase((uint32_t) next->gsbase);
|
||||
#elif defined(__x86_64__)
|
||||
prev->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
|
||||
prev->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
|
||||
wrmsr(MSRID_FSBASE, (uint64_t) next->fsbase);
|
||||
wrmsr(MSRID_GSBASE, (uint64_t) next->gsbase);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Switch(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
DoActualSwitch(regs);
|
||||
|
||||
if ( regs->signal_pending && regs->InUserspace() )
|
||||
if ( intctx->signal_pending && InUserspace(intctx) )
|
||||
{
|
||||
Interrupt::Enable();
|
||||
Signal::DispatchHandler(regs, NULL);
|
||||
Signal::DispatchHandler(intctx, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void InterruptYieldCPU(struct interrupt_context* intctx, void* /*user*/)
|
||||
{
|
||||
Switch(regs);
|
||||
Switch(intctx);
|
||||
}
|
||||
|
||||
void ThreadExitCPU(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void ThreadExitCPU(struct interrupt_context* intctx, void* /*user*/)
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
// Can't use floating point instructions from now.
|
||||
Float::NofityTaskExit(current_thread);
|
||||
#endif
|
||||
SetThreadState(current_thread, ThreadState::DEAD);
|
||||
InterruptYieldCPU(regs, NULL);
|
||||
InterruptYieldCPU(intctx, NULL);
|
||||
}
|
||||
|
||||
// The idle thread serves no purpose except being an infinite loop that does
|
||||
|
@ -206,7 +307,6 @@ static int sys_sched_yield(void)
|
|||
void Init()
|
||||
{
|
||||
first_runnable_thread = NULL;
|
||||
first_sleeping_thread = NULL;
|
||||
idle_thread = NULL;
|
||||
|
||||
Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield);
|
||||
|
|
|
@ -44,10 +44,6 @@
|
|||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include "x86-family/float.h"
|
||||
#endif
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
sigset_t default_ignored_signals;
|
||||
|
@ -57,6 +53,7 @@ sigset_t unblockable_signals;
|
|||
// A per-cpu value whether a signal is pending in the running task.
|
||||
extern "C" { volatile unsigned long asm_signal_is_pending = 0; }
|
||||
|
||||
static
|
||||
void UpdatePendingSignals(Thread* thread) // thread->process->signal_lock held
|
||||
{
|
||||
struct sigaction* signal_actions = thread->process->signal_actions;
|
||||
|
@ -400,7 +397,9 @@ static int PickImportantSignal(const sigset_t* set)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs)
|
||||
static void EncodeMachineContext(mcontext_t* mctx,
|
||||
const struct thread_registers* regs,
|
||||
const struct interrupt_context* intctx)
|
||||
{
|
||||
memset(mctx, 0, sizeof(*mctx));
|
||||
#if defined(__i386__)
|
||||
|
@ -419,10 +418,9 @@ static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
|
|||
mctx->gregs[REG_EIP] = regs->eip;
|
||||
// TODO: REG_CS
|
||||
mctx->gregs[REG_EFL] = regs->eflags & 0x0000FFFF;
|
||||
mctx->gregs[REG_CR2] = regs->cr2;
|
||||
mctx->gregs[REG_CR2] = intctx->cr2;
|
||||
// TODO: REG_SS
|
||||
Float::Yield();
|
||||
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
|
||||
memcpy(mctx->fpuenv, regs->fpuenv, 512);
|
||||
#elif defined(__x86_64__)
|
||||
mctx->gregs[REG_R8] = regs->r8;
|
||||
mctx->gregs[REG_R9] = regs->r9;
|
||||
|
@ -443,17 +441,17 @@ static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
|
|||
mctx->gregs[REG_RIP] = regs->rip;
|
||||
mctx->gregs[REG_EFL] = regs->rflags & 0x000000000000FFFF;
|
||||
// TODO: REG_CSGSFS.
|
||||
mctx->gregs[REG_CR2] = regs->cr2;
|
||||
mctx->gregs[REG_CR2] = intctx->cr2;
|
||||
mctx->gregs[REG_FSBASE] = 0x0;
|
||||
mctx->gregs[REG_GSBASE] = 0x0;
|
||||
Float::Yield();
|
||||
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
|
||||
memcpy(mctx->fpuenv, regs->fpuenv, 512);
|
||||
#else
|
||||
#error "You need to implement conversion to mcontext"
|
||||
#endif
|
||||
}
|
||||
|
||||
static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs)
|
||||
static void DecodeMachineContext(const mcontext_t* mctx,
|
||||
struct thread_registers* regs)
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
unsigned long user_flags = FLAGS_CARRY | FLAGS_PARITY | FLAGS_AUX
|
||||
|
@ -472,9 +470,7 @@ static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
|
|||
regs->eip = mctx->gregs[REG_EIP];
|
||||
regs->eflags &= ~user_flags;
|
||||
regs->eflags |= mctx->gregs[REG_EFL] & user_flags;
|
||||
regs->cr2 = mctx->gregs[REG_CR2];
|
||||
Float::Yield();
|
||||
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
|
||||
memcpy(regs->fpuenv, mctx->fpuenv, 512);
|
||||
#elif defined(__x86_64__)
|
||||
regs->r8 = mctx->gregs[REG_R8];
|
||||
regs->r9 = mctx->gregs[REG_R9];
|
||||
|
@ -495,9 +491,7 @@ static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs
|
|||
regs->rip = mctx->gregs[REG_RIP];
|
||||
regs->rflags &= ~user_flags;
|
||||
regs->rflags |= mctx->gregs[REG_EFL] & user_flags;
|
||||
regs->cr2 = mctx->gregs[REG_CR2];
|
||||
Float::Yield();
|
||||
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
|
||||
memcpy(regs->fpuenv, mctx->fpuenv, 512);
|
||||
#else
|
||||
#error "You need to implement conversion to mcontext"
|
||||
#endif
|
||||
|
@ -525,7 +519,7 @@ struct stack_frame
|
|||
#error "You need to implement struct stack_frame"
|
||||
#endif
|
||||
|
||||
void Thread::HandleSignal(CPU::InterruptRegisters* regs)
|
||||
void Thread::HandleSignal(struct interrupt_context* intctx)
|
||||
{
|
||||
assert(Interrupt::IsEnabled());
|
||||
assert(this == CurrentThread());
|
||||
|
@ -553,7 +547,7 @@ retry_another_signal:
|
|||
// Unmark the selected signal as pending.
|
||||
sigdelset(&signal_pending, signum);
|
||||
UpdatePendingSignals(this);
|
||||
regs->signal_pending = asm_signal_is_pending;
|
||||
intctx->signal_pending = asm_signal_is_pending;
|
||||
|
||||
// Destroy the current thread if the signal is critical.
|
||||
if ( signum == SIGKILL )
|
||||
|
@ -614,28 +608,31 @@ retry_another_signal:
|
|||
// threads in the kernel cannot be delivered signals except when returning
|
||||
// from a system call, so we'll simply save the state that would have been
|
||||
// returned to user-space had no signal occured.
|
||||
if ( !regs->InUserspace() )
|
||||
if ( !InUserspace(intctx) )
|
||||
{
|
||||
#if defined(__i386__)
|
||||
uint32_t* params = (uint32_t*) regs->ebx;
|
||||
regs->eip = params[0];
|
||||
regs->eflags = params[2];
|
||||
regs->esp = params[3];
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
uint32_t* params = (uint32_t*) intctx->ebx;
|
||||
intctx->eip = params[0];
|
||||
intctx->eflags = params[2];
|
||||
intctx->esp = params[3];
|
||||
intctx->cs = UCS | URPL;
|
||||
intctx->ds = UDS | URPL;
|
||||
intctx->ss = UDS | URPL;
|
||||
#elif defined(__x86_64__)
|
||||
regs->rip = regs->rdi;
|
||||
regs->rflags = regs->rsi;
|
||||
regs->rsp = regs->r8;
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
intctx->rip = intctx->rdi;
|
||||
intctx->rflags = intctx->rsi;
|
||||
intctx->rsp = intctx->r8;
|
||||
intctx->cs = UCS | URPL;
|
||||
intctx->ds = UDS | URPL;
|
||||
intctx->ss = UDS | URPL;
|
||||
#else
|
||||
#error "You may need to fix the registers"
|
||||
#endif
|
||||
}
|
||||
|
||||
struct thread_registers stopped_regs;
|
||||
Scheduler::SaveInterruptedContext(intctx, &stopped_regs);
|
||||
|
||||
sigset_t new_signal_mask;
|
||||
memcpy(&new_signal_mask, &action->sa_mask, sizeof(sigset_t));
|
||||
sigorset(&new_signal_mask, &new_signal_mask, &signal_mask);
|
||||
|
@ -670,15 +667,16 @@ retry_another_signal:
|
|||
old_signal_stack.ss_size = 0;
|
||||
new_signal_stack = signal_stack;
|
||||
#if defined(__i386__)
|
||||
stack_location = (uintptr_t) regs->esp;
|
||||
stack_location = (uintptr_t) stopped_regs.esp;
|
||||
#elif defined(__x86_64__)
|
||||
stack_location = (uintptr_t) regs->rsp;
|
||||
stack_location = (uintptr_t) stopped_regs.rsp;
|
||||
#else
|
||||
#error "You need to implement getting the user-space stack pointer"
|
||||
#endif
|
||||
}
|
||||
|
||||
CPU::InterruptRegisters new_regs = *regs;
|
||||
struct thread_registers handler_regs;
|
||||
memcpy(&handler_regs, &stopped_regs, sizeof(handler_regs));
|
||||
|
||||
struct stack_frame stack_frame;
|
||||
memset(&stack_frame, 0, sizeof(stack_frame));
|
||||
|
@ -700,9 +698,9 @@ retry_another_signal:
|
|||
stack_frame.ucontext_param = &stack->ucontext;
|
||||
stack_frame.cookie_param = action->sa_cookie;
|
||||
|
||||
new_regs.esp = (unsigned long) stack;
|
||||
new_regs.eip = (unsigned long) handler_ptr;
|
||||
new_regs.eflags &= ~FLAGS_DIRECTION;
|
||||
handler_regs.esp = (unsigned long) stack;
|
||||
handler_regs.eip = (unsigned long) handler_ptr;
|
||||
handler_regs.eflags &= ~FLAGS_DIRECTION;
|
||||
#elif defined(__x86_64__)
|
||||
stack_location -= 128; /* Red zone. */
|
||||
stack_location -= sizeof(stack_frame);
|
||||
|
@ -710,14 +708,14 @@ retry_another_signal:
|
|||
struct stack_frame* stack = (struct stack_frame*) stack_location;
|
||||
|
||||
stack_frame.sigreturn = (unsigned long) process->sigreturn;
|
||||
new_regs.rdi = (unsigned long) signum;
|
||||
new_regs.rsi = (unsigned long) &stack->siginfo;
|
||||
new_regs.rdx = (unsigned long) &stack->ucontext;
|
||||
new_regs.rcx = (unsigned long) action->sa_cookie;
|
||||
handler_regs.rdi = (unsigned long) signum;
|
||||
handler_regs.rsi = (unsigned long) &stack->siginfo;
|
||||
handler_regs.rdx = (unsigned long) &stack->ucontext;
|
||||
handler_regs.rcx = (unsigned long) action->sa_cookie;
|
||||
|
||||
new_regs.rsp = (unsigned long) stack;
|
||||
new_regs.rip = (unsigned long) handler_ptr;
|
||||
new_regs.rflags &= ~FLAGS_DIRECTION;
|
||||
handler_regs.rsp = (unsigned long) stack;
|
||||
handler_regs.rip = (unsigned long) handler_ptr;
|
||||
handler_regs.rflags &= ~FLAGS_DIRECTION;
|
||||
#else
|
||||
#error "You need to format the stack frame"
|
||||
#endif
|
||||
|
@ -727,7 +725,7 @@ retry_another_signal:
|
|||
#if defined(__i386__) || defined(__x86_64__)
|
||||
// TODO: Is this cr2 value trustworthy? I don't think it is.
|
||||
if ( signum == SIGSEGV )
|
||||
stack_frame.siginfo.si_addr = (void*) regs->cr2;
|
||||
stack_frame.siginfo.si_addr = (void*) intctx->cr2;
|
||||
#else
|
||||
#warning "You need to tell user-space where it crashed"
|
||||
#endif
|
||||
|
@ -736,7 +734,7 @@ retry_another_signal:
|
|||
stack_frame.ucontext.uc_link = NULL;
|
||||
memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask));
|
||||
memcpy(&stack_frame.ucontext.uc_stack, &signal_stack, sizeof(signal_stack));
|
||||
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs);
|
||||
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, &stopped_regs, intctx);
|
||||
|
||||
if ( !CopyToUser(stack, &stack_frame, sizeof(stack_frame)) )
|
||||
{
|
||||
|
@ -764,7 +762,7 @@ retry_another_signal:
|
|||
signal_stack = new_signal_stack;
|
||||
|
||||
// Update the current registers.
|
||||
*regs = new_regs;
|
||||
Scheduler::LoadInterruptedContext(intctx, &handler_regs);
|
||||
|
||||
// TODO: SA_RESETHAND:
|
||||
// "If set, the disposition of the signal shall be reset to SIG_DFL
|
||||
|
@ -776,7 +774,7 @@ retry_another_signal:
|
|||
return;
|
||||
}
|
||||
|
||||
void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
||||
void Thread::HandleSigreturn(struct interrupt_context* intctx)
|
||||
{
|
||||
assert(Interrupt::IsEnabled());
|
||||
assert(this == CurrentThread());
|
||||
|
@ -786,9 +784,9 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
|||
struct stack_frame stack_frame;
|
||||
const struct stack_frame* user_stack_frame;
|
||||
#if defined(__i386__)
|
||||
user_stack_frame = (const struct stack_frame*) (regs->esp - 4);
|
||||
user_stack_frame = (const struct stack_frame*) (intctx->esp - 4);
|
||||
#elif defined(__x86_64__)
|
||||
user_stack_frame = (const struct stack_frame*) (regs->rsp - 8);
|
||||
user_stack_frame = (const struct stack_frame*) (intctx->rsp - 8);
|
||||
#else
|
||||
#error "You need to locate the stack we passed the signal handler"
|
||||
#endif
|
||||
|
@ -798,27 +796,30 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
|||
memcpy(&signal_mask, &stack_frame.ucontext.uc_sigmask, sizeof(signal_mask));
|
||||
memcpy(&signal_stack, &stack_frame.ucontext.uc_stack, sizeof(signal_stack));
|
||||
signal_stack.ss_flags &= __SS_SUPPORTED_FLAGS;
|
||||
DecodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs);
|
||||
struct thread_registers resume_regs;
|
||||
Scheduler::SaveInterruptedContext(intctx, &resume_regs);
|
||||
DecodeMachineContext(&stack_frame.ucontext.uc_mcontext, &resume_regs);
|
||||
Scheduler::LoadInterruptedContext(intctx, &resume_regs);
|
||||
}
|
||||
|
||||
UpdatePendingSignals(this);
|
||||
regs->signal_pending = asm_signal_is_pending;
|
||||
intctx->signal_pending = asm_signal_is_pending;
|
||||
|
||||
lock.Reset();
|
||||
|
||||
HandleSignal(regs);
|
||||
HandleSignal(intctx);
|
||||
}
|
||||
|
||||
namespace Signal {
|
||||
|
||||
void DispatchHandler(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void DispatchHandler(struct interrupt_context* intctx, void* /*user*/)
|
||||
{
|
||||
return CurrentThread()->HandleSignal(regs);
|
||||
return CurrentThread()->HandleSignal(intctx);
|
||||
}
|
||||
|
||||
void ReturnHandler(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void ReturnHandler(struct interrupt_context* intctx, void* /*user*/)
|
||||
{
|
||||
return CurrentThread()->HandleSigreturn(regs);
|
||||
return CurrentThread()->HandleSigreturn(intctx);
|
||||
}
|
||||
|
||||
void Init()
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/exit.h>
|
||||
|
@ -44,10 +45,39 @@
|
|||
#include <sortix/kernel/thread.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
|
||||
void* operator new (size_t /*size*/, void* address) throw()
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
Thread* AllocateThread()
|
||||
{
|
||||
uint8_t* allocation = (uint8_t*) malloc(sizeof(class Thread) + 16);
|
||||
if ( !allocation )
|
||||
return NULL;
|
||||
|
||||
uint8_t* aligned = allocation;
|
||||
if ( ((uintptr_t) aligned & 0xFUL) )
|
||||
aligned = (uint8_t*) (((uintptr_t) aligned + 16) & ~0xFUL);
|
||||
|
||||
assert(!((uintptr_t) aligned & 0xFUL));
|
||||
Thread* thread = new (aligned) Thread;
|
||||
assert(!((uintptr_t) thread->registers.fpuenv & 0xFUL));
|
||||
return thread->self_allocation = allocation, thread;
|
||||
}
|
||||
|
||||
void FreeThread(Thread* thread)
|
||||
{
|
||||
uint8_t* allocation = thread->self_allocation;
|
||||
thread->~Thread();
|
||||
free(allocation);
|
||||
}
|
||||
|
||||
Thread::Thread()
|
||||
{
|
||||
assert(!((uintptr_t) registers.fpuenv & 0xFUL));
|
||||
id = 0; // TODO: Make a thread id.
|
||||
process = NULL;
|
||||
prevsibling = NULL;
|
||||
|
@ -56,17 +86,10 @@ Thread::Thread()
|
|||
scheduler_list_next = NULL;
|
||||
state = NONE;
|
||||
memset(®isters, 0, sizeof(registers));
|
||||
fsbase = 0;
|
||||
gsbase = 0;
|
||||
kernelstackpos = 0;
|
||||
kernelstacksize = 0;
|
||||
kernelstackmalloced = false;
|
||||
pledged_destruction = false;
|
||||
fpuinitialized = false;
|
||||
// If malloc isn't 16-byte aligned, then we can't rely on offsets in
|
||||
// our own class, so we'll just fix ourselves nicely up.
|
||||
unsigned long fpuaddr = ((unsigned long) fpuenv+16UL) & ~(16UL-1UL);
|
||||
fpuenvaligned = (uint8_t*) fpuaddr;
|
||||
sigemptyset(&signal_pending);
|
||||
sigemptyset(&signal_mask);
|
||||
memset(&signal_stack, 0, sizeof(signal_stack));
|
||||
|
@ -82,129 +105,22 @@ Thread::~Thread()
|
|||
delete[] (uint8_t*) kernelstackpos;
|
||||
}
|
||||
|
||||
void Thread::SaveRegisters(const CPU::InterruptRegisters* src)
|
||||
Thread* CreateKernelThread(Process* process, struct thread_registers* regs)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
registers.eip = src->eip;
|
||||
registers.esp = src->esp;
|
||||
registers.eax = src->eax;
|
||||
registers.ebx = src->ebx;
|
||||
registers.ecx = src->ecx;
|
||||
registers.edx = src->edx;
|
||||
registers.edi = src->edi;
|
||||
registers.esi = src->esi;
|
||||
registers.ebp = src->ebp;
|
||||
registers.cs = src->cs;
|
||||
registers.ds = src->ds;
|
||||
registers.ss = src->ss;
|
||||
registers.eflags = src->eflags;
|
||||
registers.kerrno = src->kerrno;
|
||||
registers.signal_pending = src->signal_pending;
|
||||
#elif defined(__x86_64__)
|
||||
registers.rip = src->rip;
|
||||
registers.rsp = src->rsp;
|
||||
registers.rax = src->rax;
|
||||
registers.rbx = src->rbx;
|
||||
registers.rcx = src->rcx;
|
||||
registers.rdx = src->rdx;
|
||||
registers.rdi = src->rdi;
|
||||
registers.rsi = src->rsi;
|
||||
registers.rbp = src->rbp;
|
||||
registers.r8 = src->r8;
|
||||
registers.r9 = src->r9;
|
||||
registers.r10 = src->r10;
|
||||
registers.r11 = src->r11;
|
||||
registers.r12 = src->r12;
|
||||
registers.r13 = src->r13;
|
||||
registers.r14 = src->r14;
|
||||
registers.r15 = src->r15;
|
||||
registers.cs = src->cs;
|
||||
registers.ds = src->ds;
|
||||
registers.ss = src->ss;
|
||||
registers.rflags = src->rflags;
|
||||
registers.kerrno = src->kerrno;
|
||||
registers.signal_pending = src->signal_pending;
|
||||
#else
|
||||
#warning "You need to add register saving support"
|
||||
#endif
|
||||
}
|
||||
|
||||
void Thread::LoadRegisters(CPU::InterruptRegisters* dest)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
dest->eip = registers.eip;
|
||||
dest->esp = registers.esp;
|
||||
dest->eax = registers.eax;
|
||||
dest->ebx = registers.ebx;
|
||||
dest->ecx = registers.ecx;
|
||||
dest->edx = registers.edx;
|
||||
dest->edi = registers.edi;
|
||||
dest->esi = registers.esi;
|
||||
dest->ebp = registers.ebp;
|
||||
dest->cs = registers.cs;
|
||||
dest->ds = registers.ds;
|
||||
dest->ss = registers.ss;
|
||||
dest->eflags = registers.eflags;
|
||||
dest->kerrno = registers.kerrno;
|
||||
dest->signal_pending = registers.signal_pending;
|
||||
#elif defined(__x86_64__)
|
||||
dest->rip = registers.rip;
|
||||
dest->rsp = registers.rsp;
|
||||
dest->rax = registers.rax;
|
||||
dest->rbx = registers.rbx;
|
||||
dest->rcx = registers.rcx;
|
||||
dest->rdx = registers.rdx;
|
||||
dest->rdi = registers.rdi;
|
||||
dest->rsi = registers.rsi;
|
||||
dest->rbp = registers.rbp;
|
||||
dest->r8 = registers.r8;
|
||||
dest->r9 = registers.r9;
|
||||
dest->r10 = registers.r10;
|
||||
dest->r11 = registers.r11;
|
||||
dest->r12 = registers.r12;
|
||||
dest->r13 = registers.r13;
|
||||
dest->r14 = registers.r14;
|
||||
dest->r15 = registers.r15;
|
||||
dest->cs = registers.cs;
|
||||
dest->ds = registers.ds;
|
||||
dest->ss = registers.ss;
|
||||
dest->rflags = registers.rflags;
|
||||
dest->kerrno = registers.kerrno;
|
||||
dest->signal_pending = registers.signal_pending;
|
||||
#else
|
||||
#warning "You need to add register loading support"
|
||||
#endif
|
||||
}
|
||||
|
||||
addr_t Thread::SwitchAddressSpace(addr_t newaddrspace)
|
||||
{
|
||||
bool wasenabled = Interrupt::SetEnabled(false);
|
||||
addr_t result = addrspace;
|
||||
addrspace = newaddrspace;
|
||||
Memory::SwitchAddressSpace(newaddrspace);
|
||||
Interrupt::SetEnabled(wasenabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
|
||||
unsigned long fsbase, unsigned long gsbase)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
if ( fsbase >> 48 != 0x0000 && fsbase >> 48 != 0xFFFF )
|
||||
return errno = EINVAL, (Thread*) NULL;
|
||||
if ( gsbase >> 48 != 0x0000 && gsbase >> 48 != 0xFFFF )
|
||||
return errno = EINVAL, (Thread*) NULL;
|
||||
#endif
|
||||
|
||||
assert(process && regs && process->addrspace);
|
||||
Thread* thread = new Thread;
|
||||
|
||||
#if defined(__x86_64__)
|
||||
if ( regs->fsbase >> 48 != 0x0000 && regs->fsbase >> 48 != 0xFFFF )
|
||||
return errno = EINVAL, (Thread*) NULL;
|
||||
if ( regs->gsbase >> 48 != 0x0000 && regs->gsbase >> 48 != 0xFFFF )
|
||||
return errno = EINVAL, (Thread*) NULL;
|
||||
#endif
|
||||
|
||||
Thread* thread = AllocateThread();
|
||||
if ( !thread )
|
||||
return NULL;
|
||||
|
||||
thread->addrspace = process->addrspace;
|
||||
thread->SaveRegisters(regs);
|
||||
thread->fsbase = fsbase;
|
||||
thread->gsbase = gsbase;
|
||||
memcpy(&thread->registers, regs, sizeof(struct thread_registers));
|
||||
|
||||
kthread_mutex_lock(&process->threadlock);
|
||||
|
||||
|
@ -221,48 +137,62 @@ Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs,
|
|||
return thread;
|
||||
}
|
||||
|
||||
static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs,
|
||||
static void SetupKernelThreadRegs(struct thread_registers* regs,
|
||||
Process* process,
|
||||
void (*entry)(void*),
|
||||
void* user,
|
||||
uintptr_t stack,
|
||||
size_t stack_size)
|
||||
{
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
|
||||
size_t stack_alignment = 16;
|
||||
while ( stack & (stack_alignment-1) )
|
||||
{
|
||||
assert(stack_size);
|
||||
stack++;
|
||||
stack_size--;
|
||||
}
|
||||
|
||||
stack_size &= ~(stack_alignment-1);
|
||||
|
||||
#if defined(__i386__)
|
||||
uintptr_t* stack_values = (uintptr_t*) (stack + stack_size);
|
||||
|
||||
assert(!((uintptr_t) stack_values & 3UL));
|
||||
assert(4 * sizeof(uintptr_t) <= stack_size);
|
||||
assert(5 * sizeof(uintptr_t) <= stack_size);
|
||||
|
||||
stack_values[-1] = (uintptr_t) 0; /* null eip */
|
||||
stack_values[-2] = (uintptr_t) 0; /* null ebp */
|
||||
stack_values[-3] = (uintptr_t) user; /* thread parameter */
|
||||
stack_values[-4] = (uintptr_t) kthread_exit; /* return to kthread_exit */
|
||||
/* -- 16-byte aligned -- */
|
||||
/* -1 padding */
|
||||
stack_values[-2] = (uintptr_t) 0; /* null eip */
|
||||
stack_values[-3] = (uintptr_t) 0; /* null ebp */
|
||||
stack_values[-4] = (uintptr_t) user; /* thread parameter */
|
||||
/* -- 16-byte aligned -- */
|
||||
stack_values[-5] = (uintptr_t) kthread_exit; /* return to kthread_exit */
|
||||
/* upcoming ebp */
|
||||
/* -7 padding */
|
||||
/* -8 padding */
|
||||
/* -- 16-byte aligned -- */
|
||||
|
||||
regs->eip = (uintptr_t) entry;
|
||||
regs->esp = (uintptr_t) (stack_values - 4);
|
||||
regs->esp = (uintptr_t) (stack_values - 5);
|
||||
regs->eax = 0;
|
||||
regs->ebx = 0;
|
||||
regs->ecx = 0;
|
||||
regs->edx = 0;
|
||||
regs->edi = 0;
|
||||
regs->esi = 0;
|
||||
regs->ebp = (uintptr_t) (stack_values - 2);
|
||||
regs->ebp = (uintptr_t) (stack_values - 3);
|
||||
regs->cs = KCS | KRPL;
|
||||
regs->ds = KDS | KRPL;
|
||||
regs->ss = KDS | KRPL;
|
||||
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->kerrno = 0;
|
||||
regs->signal_pending = 0;
|
||||
regs->kernel_stack = stack + stack_size;
|
||||
regs->cr3 = process->addrspace;
|
||||
#elif defined(__x86_64__)
|
||||
if ( (stack & 15UL) == 8 && 8 <= stack_size )
|
||||
{
|
||||
stack += 8;
|
||||
stack_size -= 8;
|
||||
}
|
||||
|
||||
uintptr_t* stack_values = (uintptr_t*) (stack + stack_size);
|
||||
|
||||
assert(!((uintptr_t) stack_values & 15UL));
|
||||
assert(3 * sizeof(uintptr_t) <= stack_size);
|
||||
|
||||
stack_values[-1] = (uintptr_t) 0; /* null rip */
|
||||
|
@ -292,8 +222,10 @@ static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs,
|
|||
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->kerrno = 0;
|
||||
regs->signal_pending = 0;
|
||||
regs->kernel_stack = stack + stack_size;
|
||||
regs->cr3 = process->addrspace;
|
||||
#else
|
||||
#warning "You need to add thread register initialization support"
|
||||
#warning "You need to add kernel thread register initialization support"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -307,10 +239,10 @@ Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user,
|
|||
if ( !stack )
|
||||
return NULL;
|
||||
|
||||
CPU::InterruptRegisters regs;
|
||||
SetupKernelThreadRegs(®s, entry, user, (uintptr_t) stack, stacksize);
|
||||
struct thread_registers regs;
|
||||
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; }
|
||||
|
||||
thread->kernelstackpos = (uintptr_t) stack;
|
||||
|
@ -330,9 +262,9 @@ void StartKernelThread(Thread* thread)
|
|||
Scheduler::SetThreadState(thread, ThreadState::RUNNABLE);
|
||||
}
|
||||
|
||||
Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs)
|
||||
Thread* RunKernelThread(Process* process, struct thread_registers* regs)
|
||||
{
|
||||
Thread* thread = CreateKernelThread(process, regs, 0, 0);
|
||||
Thread* thread = CreateKernelThread(process, regs);
|
||||
if ( !thread )
|
||||
return NULL;
|
||||
StartKernelThread(thread);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -141,6 +141,9 @@ Realm64:
|
|||
or $0x600, %rax
|
||||
mov %rax, %cr4
|
||||
|
||||
# Store a copy of the initialial floating point registers.
|
||||
fxsave fpu_initialized_regs
|
||||
|
||||
# Alright, that was the bootstrap code. Now begin preparing to run the
|
||||
# actual 64-bit kernel.
|
||||
jmp Main
|
||||
|
|
|
@ -386,7 +386,10 @@ interrupt_handler_prepare:
|
|||
|
||||
# Now call the interrupt handler.
|
||||
movq %rsp, %rdi
|
||||
movq %rsp, %rbx
|
||||
andq $0xFFFFFFFFFFFFFFF0, %rsp
|
||||
call interrupt_handler
|
||||
movq %rbx, %rsp
|
||||
|
||||
load_interrupted_registers:
|
||||
# Restore whether signals are pending.
|
||||
|
|
|
@ -44,8 +44,6 @@ void ExtendStack();
|
|||
namespace Sortix {
|
||||
namespace Memory {
|
||||
|
||||
extern addr_t currentdir;
|
||||
|
||||
void InitCPU()
|
||||
{
|
||||
// The x64 boot code already set up virtual memory and identity
|
||||
|
@ -87,8 +85,6 @@ void InitCPU()
|
|||
BOOTPML3->entry[0] = (addr_t) FORKPML2 | flags | PML_FORK;
|
||||
FORKPML2->entry[0] = (addr_t) FORKPML1 | flags | PML_FORK;
|
||||
|
||||
currentdir = (addr_t) BOOTPML4;
|
||||
|
||||
// The virtual memory structures are now available on the predefined
|
||||
// locations. This means the virtual memory code is bootstrapped. Of
|
||||
// course, we still have no physical page allocator, so that's the
|
||||
|
@ -139,7 +135,7 @@ void RecursiveFreeUserspacePages(size_t level, size_t offset)
|
|||
}
|
||||
}
|
||||
|
||||
void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* user)
|
||||
void DestroyAddressSpace(addr_t fallback)
|
||||
{
|
||||
// Look up the last few entries used for the fractal mapping. These
|
||||
// cannot be unmapped as that would destroy the world. Instead, we
|
||||
|
@ -150,7 +146,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use
|
|||
addr_t fractal2 = (PMLS[3] + 510UL)->entry[510];
|
||||
addr_t fork1 = (PMLS[2] + 510UL * 512UL + 0)->entry[0];
|
||||
addr_t fractal1 = (PMLS[2] + 510UL * 512UL + 510UL)->entry[510];
|
||||
addr_t dir = currentdir;
|
||||
addr_t dir = GetAddressSpace();
|
||||
|
||||
// We want to free the pages, but we are still using them ourselves,
|
||||
// so lock the page allocation structure until we are done.
|
||||
|
@ -167,10 +163,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use
|
|||
if ( !fallback )
|
||||
fallback = (addr_t) BOOTPML4;
|
||||
|
||||
if ( func )
|
||||
func(fallback, user);
|
||||
else
|
||||
SwitchAddressSpace(fallback);
|
||||
SwitchAddressSpace(fallback);
|
||||
|
||||
// Ok, now we got marked everything left behind as unused, we can
|
||||
// now safely let another thread use the pages.
|
||||
|
|
|
@ -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 Float {
|
||||
|
||||
static Thread* fputhread;
|
||||
bool fpu_is_enabled = false;
|
||||
|
||||
static inline void InitFPU()
|
||||
{
|
||||
asm volatile ("fninit");
|
||||
}
|
||||
|
||||
static inline void SaveState(uint8_t* dest)
|
||||
{
|
||||
assert( (((unsigned long) dest) & (16UL-1UL)) == 0 );
|
||||
asm volatile ("fxsave (%0)" : : "r"(dest));
|
||||
}
|
||||
|
||||
static inline void LoadState(const uint8_t* src)
|
||||
{
|
||||
assert( (((unsigned long) src) & (16UL-1UL)) == 0 );
|
||||
asm volatile ("fxrstor (%0)" : : "r"(src));
|
||||
}
|
||||
|
||||
void Yield()
|
||||
{
|
||||
Thread* thread = CurrentThread();
|
||||
|
||||
Interrupt::Disable();
|
||||
|
||||
bool fpu_was_enabled = fpu_is_enabled;
|
||||
|
||||
// The FPU contains the registers for this thread.
|
||||
if ( fputhread == thread )
|
||||
{
|
||||
if ( !fpu_was_enabled )
|
||||
EnableFPU();
|
||||
SaveState(thread->fpuenvaligned);
|
||||
fputhread = NULL;
|
||||
DisableFPU();
|
||||
}
|
||||
|
||||
// This thread has used the FPU once.
|
||||
else if ( thread->fpuinitialized )
|
||||
{
|
||||
// Nothing needs to be done, the FPU is owned by another thread and the
|
||||
// FPU registers are already stored in the thread structure.
|
||||
}
|
||||
|
||||
// This thread has never used the FPU and needs its registers initialized.
|
||||
else
|
||||
{
|
||||
if ( !fpu_was_enabled )
|
||||
EnableFPU();
|
||||
|
||||
if ( fputhread )
|
||||
SaveState(fputhread->fpuenvaligned);
|
||||
|
||||
InitFPU();
|
||||
SaveState(thread->fpuenvaligned);
|
||||
|
||||
if ( fputhread )
|
||||
LoadState(fputhread->fpuenvaligned);
|
||||
|
||||
if ( !fpu_was_enabled )
|
||||
DisableFPU();
|
||||
}
|
||||
|
||||
Interrupt::Enable();
|
||||
}
|
||||
|
||||
static void OnFPUAccess(CPU::InterruptRegisters* /*regs*/, void* /*user*/)
|
||||
{
|
||||
EnableFPU();
|
||||
Thread* thread = CurrentThread();
|
||||
if ( thread == fputhread )
|
||||
return;
|
||||
if ( fputhread )
|
||||
SaveState(fputhread->fpuenvaligned);
|
||||
fputhread = thread;
|
||||
if ( !thread->fpuinitialized )
|
||||
{
|
||||
InitFPU();
|
||||
thread->fpuinitialized = true;
|
||||
return;
|
||||
}
|
||||
LoadState(thread->fpuenvaligned);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
fputhread = CurrentThread();
|
||||
assert(fputhread);
|
||||
Interrupt::RegisterHandler(7, OnFPUAccess, NULL);
|
||||
}
|
||||
|
||||
void NofityTaskExit(Thread* thread)
|
||||
{
|
||||
if ( fputhread == thread )
|
||||
fputhread = NULL;
|
||||
DisableFPU();
|
||||
}
|
||||
extern "C" { __attribute__((aligned(16))) uint8_t fpu_initialized_regs[512]; }
|
||||
|
||||
} // namespace Float
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -25,39 +25,14 @@
|
|||
#ifndef SORTIX_FLOAT_H
|
||||
#define SORTIX_FLOAT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Thread;
|
||||
|
||||
namespace Float {
|
||||
|
||||
extern bool fpu_is_enabled;
|
||||
|
||||
void Init();
|
||||
void NofityTaskExit(Thread* thread);
|
||||
void Yield();
|
||||
|
||||
static inline void EnableFPU()
|
||||
{
|
||||
asm volatile ("clts");
|
||||
fpu_is_enabled = true;
|
||||
}
|
||||
|
||||
static inline void DisableFPU()
|
||||
{
|
||||
fpu_is_enabled = false;
|
||||
unsigned long cr0;
|
||||
asm volatile ("mov %%cr0, %0" : "=r"(cr0));
|
||||
cr0 |= 1UL<<3UL;
|
||||
asm volatile ("mov %0, %%cr0" : : "r"(cr0));
|
||||
}
|
||||
|
||||
static inline void NotityTaskSwitch()
|
||||
{
|
||||
DisableFPU();
|
||||
}
|
||||
extern "C" uint8_t fpu_initialized_regs[512];
|
||||
|
||||
} // namespace Float
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -22,10 +22,12 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/kernel/cpu.h>
|
||||
#include <sortix/kernel/registers.h>
|
||||
|
||||
#include "gdt.h"
|
||||
|
||||
|
@ -254,16 +256,22 @@ void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0)
|
|||
#endif
|
||||
}
|
||||
|
||||
void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher)
|
||||
uintptr_t GetKernelStack()
|
||||
{
|
||||
#if defined(__i386__)
|
||||
(void) stacklower;
|
||||
(void) stacksize;
|
||||
tss_entry.esp0 = (uint32_t) stackhigher;
|
||||
return tss_entry.esp0;
|
||||
#elif defined(__x86_64__)
|
||||
(void) stacklower;
|
||||
(void) stacksize;
|
||||
tss_entry.stack0 = (uint64_t) stackhigher;
|
||||
return tss_entry.stack0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetKernelStack(uintptr_t stack_pointer)
|
||||
{
|
||||
assert((stack_pointer & 0xF) == 0);
|
||||
#if defined(__i386__)
|
||||
tss_entry.esp0 = (uint32_t) stack_pointer;
|
||||
#elif defined(__x86_64__)
|
||||
tss_entry.stack0 = (uint64_t) stack_pointer;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ namespace GDT {
|
|||
|
||||
void Init();
|
||||
void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0);
|
||||
void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher);
|
||||
uintptr_t GetKernelStack();
|
||||
void SetKernelStack(uintptr_t stack_pointer);
|
||||
#if defined(__i386__)
|
||||
uint32_t GetFSBase();
|
||||
uint32_t GetGSBase();
|
||||
|
|
|
@ -244,49 +244,41 @@ void Init()
|
|||
Interrupt::Enable();
|
||||
}
|
||||
|
||||
const char* ExceptionName(const CPU::InterruptRegisters* regs)
|
||||
const char* ExceptionName(const struct interrupt_context* intctx)
|
||||
{
|
||||
if ( regs->int_no < NUM_KNOWN_EXCEPTIONS )
|
||||
return exception_names[regs->int_no];
|
||||
if ( intctx->int_no < NUM_KNOWN_EXCEPTIONS )
|
||||
return exception_names[intctx->int_no];
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
uintptr_t ExceptionLocation(const CPU::InterruptRegisters* regs)
|
||||
uintptr_t ExceptionLocation(const struct interrupt_context* intctx)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
return regs->rip;
|
||||
return intctx->rip;
|
||||
#elif defined(__i386__)
|
||||
return regs->eip;
|
||||
return intctx->eip;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CrashCalltrace(const CPU::InterruptRegisters* regs)
|
||||
void CrashCalltrace(const struct interrupt_context* intctx)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
Calltrace::Perform(regs->rbp);
|
||||
Calltrace::Perform(intctx->rbp);
|
||||
#elif defined(__i386__)
|
||||
Calltrace::Perform(regs->ebp);
|
||||
Calltrace::Perform(intctx->ebp);
|
||||
#else
|
||||
#warning "Please provide a calltrace implementation for your CPU."
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
void KernelCrashHandler(CPU::InterruptRegisters* regs)
|
||||
void KernelCrashHandler(struct interrupt_context* intctx)
|
||||
{
|
||||
Thread* thread = CurrentThread();
|
||||
#if defined(__i386__)
|
||||
thread->fsbase = (unsigned long) GDT::GetFSBase();
|
||||
thread->gsbase = (unsigned long) GDT::GetGSBase();
|
||||
#elif defined(__x86_64__)
|
||||
thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
|
||||
thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
|
||||
#endif
|
||||
thread->SaveRegisters(regs);
|
||||
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
|
||||
|
||||
// Walk and print the stack frames if this is a debug build.
|
||||
if ( CALLTRACE_KERNEL )
|
||||
CrashCalltrace(regs);
|
||||
CrashCalltrace(intctx);
|
||||
|
||||
// Possibly switch to the kernel debugger in event of a crash.
|
||||
if ( RUN_DEBUGGER_ON_KERNEL_CRASH )
|
||||
|
@ -294,27 +286,19 @@ void KernelCrashHandler(CPU::InterruptRegisters* regs)
|
|||
|
||||
// Panic the kernel with a diagnostic message.
|
||||
PanicF("Unhandled CPU Exception id %zu `%s' at ip=0x%zx (cr2=0x%zx, "
|
||||
"err_code=0x%zx)", regs->int_no, ExceptionName(regs),
|
||||
ExceptionLocation(regs), regs->cr2, regs->err_code);
|
||||
"err_code=0x%zx)", intctx->int_no, ExceptionName(intctx),
|
||||
ExceptionLocation(intctx), intctx->cr2, intctx->err_code);
|
||||
}
|
||||
|
||||
void UserCrashHandler(CPU::InterruptRegisters* regs)
|
||||
void UserCrashHandler(struct interrupt_context* intctx)
|
||||
{
|
||||
Thread* thread = CurrentThread();
|
||||
#if defined(__i386__)
|
||||
thread->fsbase = (unsigned long) GDT::GetFSBase();
|
||||
thread->gsbase = (unsigned long) GDT::GetGSBase();
|
||||
#elif defined(__x86_64__)
|
||||
thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE);
|
||||
thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE);
|
||||
#endif
|
||||
thread->SaveRegisters(regs);
|
||||
Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers);
|
||||
|
||||
// Execute this crash handler with preemption on.
|
||||
Interrupt::Enable();
|
||||
|
||||
// TODO: Also send signals for other types of user-space crashes.
|
||||
if ( regs->int_no == 14 /* Page fault */ )
|
||||
if ( intctx->int_no == 14 /* Page fault */ )
|
||||
{
|
||||
struct sigaction* act = &CurrentProcess()->signal_actions[SIGSEGV];
|
||||
kthread_mutex_lock(&CurrentProcess()->signal_lock);
|
||||
|
@ -323,12 +307,12 @@ void UserCrashHandler(CPU::InterruptRegisters* regs)
|
|||
CurrentThread()->DeliverSignalUnlocked(SIGSEGV);
|
||||
kthread_mutex_unlock(&CurrentProcess()->signal_lock);
|
||||
if ( handled )
|
||||
return Signal::DispatchHandler(regs, NULL);
|
||||
return Signal::DispatchHandler(intctx, NULL);
|
||||
}
|
||||
|
||||
// Walk and print the stack frames if this is a debug build.
|
||||
if ( CALLTRACE_USER )
|
||||
CrashCalltrace(regs);
|
||||
CrashCalltrace(intctx);
|
||||
|
||||
// Possibly switch to the kernel debugger in event of a crash.
|
||||
if ( RUN_DEBUGGER_ON_USER_CRASH )
|
||||
|
@ -338,20 +322,20 @@ void UserCrashHandler(CPU::InterruptRegisters* regs)
|
|||
Log::PrintF("The current process (pid %ji `%s') crashed and was terminated:\n",
|
||||
(intmax_t) CurrentProcess()->pid, CurrentProcess()->program_image_path);
|
||||
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%zx, err_code=0x%zx)\n",
|
||||
ExceptionName(regs), ExceptionLocation(regs), regs->cr2,
|
||||
regs->err_code);
|
||||
ExceptionName(intctx), ExceptionLocation(intctx), intctx->cr2,
|
||||
intctx->err_code);
|
||||
|
||||
// Exit the process with the right error code.
|
||||
// TODO: Send a SIGINT, SIGBUS, or whatever instead.
|
||||
CurrentProcess()->ExitThroughSignal(SIGSEGV);
|
||||
|
||||
// Deliver signals to this thread so it can exit correctly.
|
||||
Signal::DispatchHandler(regs, NULL);
|
||||
Signal::DispatchHandler(intctx, NULL);
|
||||
}
|
||||
|
||||
extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
|
||||
extern "C" void interrupt_handler(struct interrupt_context* intctx)
|
||||
{
|
||||
unsigned int int_no = regs->int_no;
|
||||
unsigned int int_no = intctx->int_no;
|
||||
|
||||
// IRQ 7 and 15 might be spurious and might need to be ignored.
|
||||
if ( int_no == IRQ7 && !(PIC::ReadISR() & (1 << 7)) )
|
||||
|
@ -362,17 +346,17 @@ extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
|
|||
return;
|
||||
}
|
||||
|
||||
bool is_in_kernel = (regs->cs & 0x3) == KRPL;
|
||||
bool is_in_kernel = (intctx->cs & 0x3) == KRPL;
|
||||
bool is_in_user = !is_in_kernel;
|
||||
bool is_crash = int_no < 32 && int_no != 7;
|
||||
|
||||
// Invoke the appropriate interrupt handler.
|
||||
if ( is_crash && is_in_kernel )
|
||||
KernelCrashHandler(regs);
|
||||
KernelCrashHandler(intctx);
|
||||
else if ( is_crash && is_in_user )
|
||||
UserCrashHandler(regs);
|
||||
UserCrashHandler(intctx);
|
||||
else if ( interrupt_handlers[int_no] )
|
||||
interrupt_handlers[int_no](regs, interrupt_handler_context[int_no]);
|
||||
interrupt_handlers[int_no](intctx, interrupt_handler_context[int_no]);
|
||||
|
||||
// Send an end of interrupt signal to the PICs if we got an IRQ.
|
||||
if ( IRQ0 <= int_no && int_no <= IRQ15 )
|
||||
|
|
|
@ -62,8 +62,6 @@ kthread_mutex_t pagelock;
|
|||
namespace Sortix {
|
||||
namespace Memory {
|
||||
|
||||
addr_t currentdir = 0;
|
||||
|
||||
void InitCPU();
|
||||
void AllocateKernelPMLs();
|
||||
int SysMemStat(size_t* memused, size_t* memtotal);
|
||||
|
@ -485,42 +483,30 @@ void InvalidatePage(addr_t /*addr*/)
|
|||
Flush();
|
||||
}
|
||||
|
||||
// Flushes the Translation Lookaside Buffer (TLB).
|
||||
void Flush()
|
||||
{
|
||||
asm volatile("mov %0, %%cr3":: "r"(currentdir));
|
||||
}
|
||||
|
||||
addr_t GetAddressSpace()
|
||||
{
|
||||
return currentdir;
|
||||
addr_t result;
|
||||
asm ( "mov %%cr3, %0" : "=r"(result) );
|
||||
return result;
|
||||
}
|
||||
|
||||
addr_t SwitchAddressSpace(addr_t addrspace)
|
||||
{
|
||||
// Have fun debugging this.
|
||||
if ( currentdir != Page::AlignDown(currentdir) )
|
||||
PanicF("The variable containing the current address space "
|
||||
"contains garbage all of sudden: it isn't page-aligned. "
|
||||
"It contains the value 0x%zx.", currentdir);
|
||||
|
||||
// Don't switch if we are already there.
|
||||
if ( addrspace == currentdir )
|
||||
return currentdir;
|
||||
|
||||
if ( addrspace & 0xFFFUL )
|
||||
PanicF("addrspace 0x%zx was not page-aligned!", addrspace);
|
||||
|
||||
addr_t previous = currentdir;
|
||||
|
||||
// Switch and flush the TLB.
|
||||
asm volatile("mov %0, %%cr3":: "r"(addrspace));
|
||||
|
||||
currentdir = addrspace;
|
||||
assert(Page::IsAligned(addrspace));
|
||||
|
||||
addr_t previous = GetAddressSpace();
|
||||
asm volatile ( "mov %0, %%cr3" : : "r"(addrspace) );
|
||||
return previous;
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
addr_t previous;
|
||||
asm ( "mov %%cr3, %0" : "=r"(previous) );
|
||||
asm volatile ( "mov %0, %%cr3" : : "r"(previous) );
|
||||
}
|
||||
|
||||
bool MapRange(addr_t where, size_t bytes, int protection)
|
||||
{
|
||||
for ( addr_t page = where; page < where + bytes; page += 4096UL )
|
||||
|
|
|
@ -78,10 +78,10 @@ static struct timespec tick_period;
|
|||
static long tick_frequency;
|
||||
static uint16_t tick_divisor;
|
||||
|
||||
static void OnIRQ0(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
static void OnIRQ0(struct interrupt_context* intctx, void* /*user*/)
|
||||
{
|
||||
OnTick(tick_period, !regs->InUserspace());
|
||||
Scheduler::Switch(regs);
|
||||
OnTick(tick_period, !InUserspace(intctx));
|
||||
Scheduler::Switch(intctx);
|
||||
|
||||
// TODO: There is a horrible bug that causes Sortix to only receive
|
||||
// one IRQ0 on my laptop, but it works in virtual machines. But
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -62,4 +62,7 @@ prepare_kernel_execution:
|
|||
mov %eax, %cr4
|
||||
mov 0x100000, %eax
|
||||
|
||||
# Store a copy of the initialial floating point registers.
|
||||
fxsave fpu_initialized_regs
|
||||
|
||||
jmp beginkernel
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -382,9 +382,12 @@ fixup_relocate_stack_complete:
|
|||
pushl %ebp
|
||||
|
||||
# Now call the interrupt handler.
|
||||
pushl %esp
|
||||
movl %esp, %ebx
|
||||
subl $4, %esp
|
||||
andl $0xFFFFFFF0, %esp
|
||||
movl %ebx, (%esp)
|
||||
call interrupt_handler
|
||||
addl $4, %esp
|
||||
movl %ebx, %esp
|
||||
|
||||
load_interrupted_registers:
|
||||
# Restore whether signals are pending.
|
||||
|
|
|
@ -45,8 +45,6 @@ void ExtendStack();
|
|||
namespace Sortix {
|
||||
namespace Memory {
|
||||
|
||||
extern addr_t currentdir;
|
||||
|
||||
void InitCPU()
|
||||
{
|
||||
PML* const BOOTPML2 = (PML* const) 0x11000UL;
|
||||
|
@ -132,14 +130,14 @@ void RecursiveFreeUserspacePages(size_t level, size_t offset)
|
|||
}
|
||||
}
|
||||
|
||||
void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* user)
|
||||
void DestroyAddressSpace(addr_t fallback)
|
||||
{
|
||||
// Look up the last few entries used for the fractal mapping. These
|
||||
// cannot be unmapped as that would destroy the world. Instead, we
|
||||
// will remember them, switch to another adress space, and safely
|
||||
// mark them as unused. Also handling the forking related pages.
|
||||
addr_t fractal1 = PMLS[2]->entry[1022];
|
||||
addr_t dir = currentdir;
|
||||
addr_t dir = GetAddressSpace();
|
||||
|
||||
// We want to free the pages, but we are still using them ourselves,
|
||||
// so lock the page allocation structure until we are done.
|
||||
|
@ -156,10 +154,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use
|
|||
if ( !fallback )
|
||||
fallback = (addr_t) BOOTPML2;
|
||||
|
||||
if ( func )
|
||||
func(fallback, user);
|
||||
else
|
||||
SwitchAddressSpace(fallback);
|
||||
SwitchAddressSpace(fallback);
|
||||
|
||||
// Ok, now we got marked everything left behind as unused, we can
|
||||
// now safely let another thread use the pages.
|
||||
|
|
|
@ -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
|
||||
.type syscall_handler, @function
|
||||
syscall_handler:
|
||||
/* -- stack is 12 bytes from being 16-byte aligned -- */
|
||||
movl $0, global_errno # Reset errno
|
||||
|
||||
pushl %ebp
|
||||
/* -- stack is 8 bytes from being 16-byte aligned -- */
|
||||
|
||||
# Grant ourselves kernel permissions to the data segment.
|
||||
movl %ds, %ebp
|
||||
pushl %ebp
|
||||
/* -- stack is 4 bytes from being 16-byte aligned -- */
|
||||
movw $0x10, %bp
|
||||
movl %ebp, %ds
|
||||
movl %ebp, %es
|
||||
|
@ -53,10 +56,12 @@ valid_syscall:
|
|||
|
||||
# Call the system call.
|
||||
pushl %esi
|
||||
/* -- stack is 16-byte aligned -- */
|
||||
pushl %edi
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
/* -- stack is 16-byte aligned -- */
|
||||
calll *%eax
|
||||
addl $20, %esp
|
||||
|
||||
|
|
|
@ -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…
Add table
Reference in a new issue