134 lines
3.1 KiB
C++
134 lines
3.1 KiB
C++
/*
|
|
* \brief Kernel backend for protection domains
|
|
* \author Stefan Kalkowski
|
|
* \date 2015-03-20
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* core includes */
|
|
#include <cpu.h>
|
|
#include "../../kernel/thread.h"
|
|
#include "../../kernel/pd.h"
|
|
|
|
extern int __idt;
|
|
extern int __idt_end;
|
|
|
|
/**
|
|
* Pseudo Descriptor
|
|
*
|
|
* See Intel SDM Vol. 3A, section 3.5.1
|
|
*/
|
|
struct Pseudo_descriptor
|
|
{
|
|
Genode::uint16_t const limit = 0;
|
|
Genode::uint64_t const base = 0;
|
|
|
|
constexpr Pseudo_descriptor(Genode::uint16_t l, Genode::uint64_t b)
|
|
: limit(l), base(b) {}
|
|
} __attribute__((packed));
|
|
|
|
|
|
Genode::Cpu::Context::Context(bool core)
|
|
{
|
|
eflags = EFLAGS_IF_SET;
|
|
cs = core ? 0x8 : 0x1b;
|
|
ss = core ? 0x10 : 0x23;
|
|
}
|
|
|
|
|
|
Genode::Cpu::Mmu_context::Mmu_context(addr_t const table)
|
|
: cr3(Cr3::Pdb::masked(table)) {}
|
|
|
|
|
|
void Genode::Cpu::Tss::init()
|
|
{
|
|
enum { TSS_SELECTOR = 0x28, };
|
|
asm volatile ("ltr %w0" : : "r" (TSS_SELECTOR));
|
|
}
|
|
|
|
|
|
void Genode::Cpu::Idt::init()
|
|
{
|
|
Pseudo_descriptor descriptor {
|
|
(uint16_t)((addr_t)&__idt_end - (addr_t)&__idt),
|
|
(uint64_t)(&__idt) };
|
|
asm volatile ("lidt %0" : : "m" (descriptor));
|
|
}
|
|
|
|
|
|
void Genode::Cpu::Gdt::init(addr_t tss_addr)
|
|
{
|
|
tss_desc[0] = ((((tss_addr >> 24) & 0xff) << 24 |
|
|
((tss_addr >> 16) & 0xff) |
|
|
0x8900) << 32) |
|
|
((tss_addr & 0xffff) << 16 | 0x68);
|
|
tss_desc[1] = tss_addr >> 32;
|
|
|
|
Pseudo_descriptor descriptor {
|
|
(uint16_t)(sizeof(Gdt)),
|
|
(uint64_t)(this) };
|
|
asm volatile ("lgdt %0" :: "m" (descriptor));
|
|
}
|
|
|
|
|
|
void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault)
|
|
{
|
|
using Fault = Kernel::Thread_fault::Type;
|
|
|
|
/*
|
|
* Intel manual: 6.15 EXCEPTION AND INTERRUPT REFERENCE
|
|
* Interrupt 14—Page-Fault Exception (#PF)
|
|
*/
|
|
enum {
|
|
ERR_I = 1UL << 4,
|
|
ERR_R = 1UL << 3,
|
|
ERR_U = 1UL << 2,
|
|
ERR_W = 1UL << 1,
|
|
ERR_P = 1UL << 0,
|
|
};
|
|
|
|
auto fault_lambda = [] (addr_t err) {
|
|
if (err & ERR_W) return Fault::WRITE;
|
|
if (!(err & ERR_P)) return Fault::PAGE_MISSING;
|
|
if (err & ERR_I) return Fault::EXEC;
|
|
else return Fault::UNKNOWN;
|
|
};
|
|
|
|
fault.addr = Genode::Cpu::Cr2::read();
|
|
fault.type = fault_lambda(regs.errcode);
|
|
}
|
|
|
|
|
|
extern void const * const kernel_stack;
|
|
extern Genode::size_t const kernel_stack_size;
|
|
|
|
|
|
void Genode::Cpu::switch_to(Context & context, Mmu_context &mmu_context)
|
|
{
|
|
if ((context.cs != 0x8) && (mmu_context.cr3 != Cr3::read()))
|
|
Cr3::write(mmu_context.cr3);
|
|
|
|
tss.ist[0] = (addr_t)&context + sizeof(Genode::Cpu_state);
|
|
|
|
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
|
|
context.kernel_stack = stack_base +
|
|
(Cpu::executing_id() + 1) * kernel_stack_size -
|
|
sizeof(addr_t);
|
|
}
|
|
|
|
|
|
unsigned Genode::Cpu::executing_id()
|
|
{
|
|
void * const stack_ptr = nullptr;
|
|
addr_t const stack_addr = reinterpret_cast<addr_t>(&stack_ptr);
|
|
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
|
|
unsigned const cpu_id = (stack_addr - stack_base) / kernel_stack_size;
|
|
return cpu_id;
|
|
}
|