1
0
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:
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]) {
// 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_;

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 {
// 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> &registers,
@ -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)
);
}

View File

@ -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;
}
}