mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-28 19:37:12 +00:00
Add notes to self on exceptions.
This commit is contained in:
parent
cfba8aeb89
commit
4247da9118
@ -30,40 +30,38 @@ struct Descriptor {
|
||||
}
|
||||
|
||||
void set(const uint16_t descriptor[4]) {
|
||||
// TODO: something.
|
||||
|
||||
base_ = uint32_t(descriptor[1] | ((descriptor[2] & 0xff) << 16));
|
||||
limit_ = descriptor[0];
|
||||
|
||||
printf("%04x %04x %04x %04x\n", descriptor[0], descriptor[1], descriptor[2], descriptor[3]);
|
||||
|
||||
present_ = descriptor[2] & 0x8000;
|
||||
privilege_level_ = (descriptor[2] >> 13) & 3;
|
||||
|
||||
// TODO: need to know more about the below.
|
||||
if(descriptor[2] & 0x1000) {
|
||||
// Is segment descriptor.
|
||||
present_ = descriptor[2] & 0x8000;
|
||||
privilege_level_ = (descriptor[2] >> 13) & 3;
|
||||
accessed_ = descriptor[2] & 0x100;
|
||||
readable_ = descriptor[2] & 0x200;
|
||||
conforming_ = descriptor[2] & 0x400;
|
||||
executable_ = descriptor[2] & 0x800;
|
||||
|
||||
if(executable_) {
|
||||
conforming_ = descriptor[2] & 0x400;
|
||||
readable_ = descriptor[2] & 0x200;
|
||||
} else {
|
||||
// expand down = descriptor[2] & 0x400;
|
||||
// writeable_ = descriptor[2] & 0x200;
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 286:
|
||||
// 47...32 = 16-bit limit;
|
||||
// 31 = P
|
||||
// 30...29 = DPL
|
||||
// 28 = S
|
||||
// 27...24 = type;
|
||||
// 23...00 = 4-bit base.
|
||||
|
||||
uint32_t to_linear(const uint32_t address) const {
|
||||
return base_ + address;
|
||||
}
|
||||
uint32_t base() const { return base_; }
|
||||
uint32_t limit() const { return limit_; }
|
||||
|
||||
uint32_t base() const {
|
||||
return base_;
|
||||
int privilege_level() const {
|
||||
return privilege_level_;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -71,8 +69,7 @@ private:
|
||||
uint32_t limit_;
|
||||
// TODO: permissions, type, etc.
|
||||
|
||||
bool present_;
|
||||
uint8_t privilege_level_;
|
||||
int privilege_level_;
|
||||
enum class Type {
|
||||
AvailableTaskStateSegment = 1,
|
||||
LDTDescriptor = 2,
|
||||
@ -85,7 +82,8 @@ private:
|
||||
Reserved9 = 9, ReservedA = 10, ReservedB = 11, ReservedC = 12,
|
||||
ReservedD = 13, ReservedE = 14, ReservedF = 15,
|
||||
} type_;
|
||||
bool accessed_;
|
||||
|
||||
bool present_;
|
||||
bool readable_;
|
||||
bool conforming_;
|
||||
bool executable_;
|
||||
|
@ -33,4 +33,17 @@ enum Interrupt {
|
||||
|
||||
};
|
||||
|
||||
struct ProtectedException {
|
||||
Interrupt cause;
|
||||
uint16_t code;
|
||||
|
||||
// Code:
|
||||
// b3–b15: IDT/GDT/LDT entry
|
||||
// b2: 1 => in LDT; 0 => in GDT;
|
||||
// b1: 1 => in IDT, ignore b2; 0 => use b2;
|
||||
// b0:
|
||||
// 1 => trigger was external to program code;
|
||||
// 0 => trigger was caused by the instruction described by the CS:IP that is on the stack.
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
namespace PCCompatible {
|
||||
|
||||
// TODO: the following need to apply linear memory semantics, including potential A20 wrapping.
|
||||
template <InstructionSet::x86::Model model> struct ProgramFetcher {
|
||||
std::pair<const uint8_t *, size_t> next_code(
|
||||
const Registers<model> ®isters,
|
||||
@ -26,11 +27,11 @@ template <InstructionSet::x86::Model model> struct ProgramFetcher {
|
||||
LinearMemory<model> &linear_memory
|
||||
) const {
|
||||
const uint16_t ip = registers.ip();
|
||||
const uint32_t start =
|
||||
segments.descriptors[InstructionSet::x86::Source::CS].to_linear(ip) & (linear_memory.MaxAddress - 1);
|
||||
const auto &descriptor = segments.descriptors[InstructionSet::x86::Source::CS];
|
||||
const uint32_t start = descriptor.to_linear(ip) & (linear_memory.MaxAddress - 1);
|
||||
return std::make_pair(
|
||||
linear_memory.at(start),
|
||||
std::min<size_t>(linear_memory.MaxAddress - start, 0x10000 - ip)
|
||||
std::min<size_t>(linear_memory.MaxAddress - start, 1 + descriptor.limit() - ip)
|
||||
);
|
||||
}
|
||||
|
||||
@ -38,10 +39,11 @@ template <InstructionSet::x86::Model model> struct ProgramFetcher {
|
||||
const Segments<model> &segments,
|
||||
LinearMemory<model> &linear_memory
|
||||
) const {
|
||||
const auto base = segments.descriptors[InstructionSet::x86::Source::CS].base();
|
||||
const auto &descriptor = segments.descriptors[InstructionSet::x86::Source::CS];
|
||||
const auto base = descriptor.base() & (linear_memory.MaxAddress - 1);
|
||||
return std::make_pair(
|
||||
linear_memory.at(base),
|
||||
std::min<size_t>(0x1'0000, linear_memory.MaxAddress - base)
|
||||
std::min<size_t>(0x1'0000, 1 + descriptor.limit() - base)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -43,12 +43,23 @@ public:
|
||||
break;
|
||||
|
||||
case Mode::Protected286: {
|
||||
// TODO: when to use the local table? Is this right?
|
||||
assert(!(value & 0x8000));
|
||||
const auto &table = registers_.template get<DescriptorTable::Global>();
|
||||
const uint32_t table_address = table.base + value;
|
||||
// Check privilege level.
|
||||
const auto requested_privilege_level = value & 3;
|
||||
if(requested_privilege_level < descriptors[Source::CS].privilege_level()) {
|
||||
printf("TODO: privilege exception.");
|
||||
}
|
||||
|
||||
// TODO: authorisation required, possibly.
|
||||
// Check segment range.
|
||||
const auto &table =
|
||||
(value & 4) ?
|
||||
registers_.template get<DescriptorTable::Local>() :
|
||||
registers_.template get<DescriptorTable::Global>();
|
||||
const uint32_t table_address = table.base + (value & ~7);
|
||||
if(table_address > table.base + table.limit - 8) {
|
||||
printf("TODO: descriptor table overrun exception.\n");
|
||||
}
|
||||
|
||||
// Get descriptor contents.
|
||||
using AccessType = InstructionSet::x86::AccessType;
|
||||
const uint32_t table_end = table.base + table.limit;
|
||||
const uint16_t entry[] = {
|
||||
@ -57,7 +68,20 @@ public:
|
||||
memory_.template access<uint16_t, AccessType::Read>(table_address + 4, table_end),
|
||||
memory_.template access<uint16_t, AccessType::Read>(table_address + 6, table_end)
|
||||
};
|
||||
|
||||
// TODO: is this descriptor privilege within reach?
|
||||
// TODO: is this an empty descriptor*? If so: exception!
|
||||
// (* other than the 0 descriptor, which can be loaded to DS or ES)
|
||||
// TODO:
|
||||
// bool is_compatible(const Source reg) const {
|
||||
// switch(reg)
|
||||
// DS/ES: either readable code, or any sort of data
|
||||
// SS: writeable data
|
||||
// CS: any sort of code
|
||||
// }
|
||||
|
||||
descriptors[segment].set(entry);
|
||||
// TODO: set descriptor accessed bit in memory if it's a segment.
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user