1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-29 10:37:42 +00:00

Add notes to self on exceptions.

This commit is contained in:
Thomas Harte 2025-03-27 18:08:09 -04:00
parent cfba8aeb89
commit 4247da9118
4 changed files with 68 additions and 31 deletions

View File

@ -30,40 +30,38 @@ struct Descriptor {
} }
void set(const uint16_t descriptor[4]) { void set(const uint16_t descriptor[4]) {
// TODO: something.
base_ = uint32_t(descriptor[1] | ((descriptor[2] & 0xff) << 16)); base_ = uint32_t(descriptor[1] | ((descriptor[2] & 0xff) << 16));
limit_ = descriptor[0]; limit_ = descriptor[0];
printf("%04x %04x %04x %04x\n", descriptor[0], descriptor[1], descriptor[2], descriptor[3]); printf("%04x %04x %04x %04x\n", descriptor[0], descriptor[1], descriptor[2], descriptor[3]);
if(descriptor[2] & 0x1000) {
// Is segment descriptor.
present_ = descriptor[2] & 0x8000; present_ = descriptor[2] & 0x8000;
privilege_level_ = (descriptor[2] >> 13) & 3; privilege_level_ = (descriptor[2] >> 13) & 3;
accessed_ = descriptor[2] & 0x100;
readable_ = descriptor[2] & 0x200; // TODO: need to know more about the below.
conforming_ = descriptor[2] & 0x400; if(descriptor[2] & 0x1000) {
executable_ = descriptor[2] & 0x800; 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 { } else {
assert(false); 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 { uint32_t to_linear(const uint32_t address) const {
return base_ + address; return base_ + address;
} }
uint32_t base() const { return base_; }
uint32_t limit() const { return limit_; }
uint32_t base() const { int privilege_level() const {
return base_; return privilege_level_;
} }
private: private:
@ -71,8 +69,7 @@ private:
uint32_t limit_; uint32_t limit_;
// TODO: permissions, type, etc. // TODO: permissions, type, etc.
bool present_; int privilege_level_;
uint8_t privilege_level_;
enum class Type { enum class Type {
AvailableTaskStateSegment = 1, AvailableTaskStateSegment = 1,
LDTDescriptor = 2, LDTDescriptor = 2,
@ -85,7 +82,8 @@ private:
Reserved9 = 9, ReservedA = 10, ReservedB = 11, ReservedC = 12, Reserved9 = 9, ReservedA = 10, ReservedB = 11, ReservedC = 12,
ReservedD = 13, ReservedE = 14, ReservedF = 15, ReservedD = 13, ReservedE = 14, ReservedF = 15,
} type_; } type_;
bool accessed_;
bool present_;
bool readable_; bool readable_;
bool conforming_; bool conforming_;
bool executable_; bool executable_;

View File

@ -33,4 +33,17 @@ enum Interrupt {
}; };
struct ProtectedException {
Interrupt cause;
uint16_t code;
// Code:
// b3b15: 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.
};
} }

View File

@ -19,6 +19,7 @@
namespace PCCompatible { namespace PCCompatible {
// TODO: the following need to apply linear memory semantics, including potential A20 wrapping.
template <InstructionSet::x86::Model model> struct ProgramFetcher { template <InstructionSet::x86::Model model> struct ProgramFetcher {
std::pair<const uint8_t *, size_t> next_code( std::pair<const uint8_t *, size_t> next_code(
const Registers<model> &registers, const Registers<model> &registers,
@ -26,11 +27,11 @@ template <InstructionSet::x86::Model model> struct ProgramFetcher {
LinearMemory<model> &linear_memory LinearMemory<model> &linear_memory
) const { ) const {
const uint16_t ip = registers.ip(); const uint16_t ip = registers.ip();
const uint32_t start = const auto &descriptor = segments.descriptors[InstructionSet::x86::Source::CS];
segments.descriptors[InstructionSet::x86::Source::CS].to_linear(ip) & (linear_memory.MaxAddress - 1); const uint32_t start = descriptor.to_linear(ip) & (linear_memory.MaxAddress - 1);
return std::make_pair( return std::make_pair(
linear_memory.at(start), 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, const Segments<model> &segments,
LinearMemory<model> &linear_memory LinearMemory<model> &linear_memory
) const { ) 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( return std::make_pair(
linear_memory.at(base), linear_memory.at(base),
std::min<size_t>(0x1'0000, linear_memory.MaxAddress - base) std::min<size_t>(0x1'0000, 1 + descriptor.limit() - base)
); );
} }

View File

@ -43,12 +43,23 @@ public:
break; break;
case Mode::Protected286: { case Mode::Protected286: {
// TODO: when to use the local table? Is this right? // Check privilege level.
assert(!(value & 0x8000)); const auto requested_privilege_level = value & 3;
const auto &table = registers_.template get<DescriptorTable::Global>(); if(requested_privilege_level < descriptors[Source::CS].privilege_level()) {
const uint32_t table_address = table.base + value; 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; using AccessType = InstructionSet::x86::AccessType;
const uint32_t table_end = table.base + table.limit; const uint32_t table_end = table.base + table.limit;
const uint16_t entry[] = { 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 + 4, table_end),
memory_.template access<uint16_t, AccessType::Read>(table_address + 6, 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); descriptors[segment].set(entry);
// TODO: set descriptor accessed bit in memory if it's a segment.
} break; } break;
} }
} }