The CPU should be in 64-bit mode (I'm not sure, I don't know how to check through bochs). All methods of System are static methods. callDebugger contains only one line: asm volatile("xchg %bx, %bx"). This is bochs' message after callDebugger:
Bochs' message shows that my code segment is 16-bit and TSS segment selector is 32-bit. I double checked amd's manual, I think the format of the two selectors are correct 64-bit code segment selector and 64-bit TSS selector (???)<bochs:4> info gdt
Global Descriptor Table (base=0x00000000001062c0, limit=40):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Code segment, laddr=00000000, limit=f0000 * 4Kbytes, Execute-Only, 16-bit
GDT[0x02]=Data segment, laddr=00000000, limit=f0000 * 4Kbytes, Read/Write
GDT[0x03]=32-Bit TSS (Busy) at 0x00104040, length 0x02068
GDT[0x04]=??? descriptor hi=0x00000000, lo=0x00000000
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
<bochs:5> info idt 0
Interrupt Descriptor Table (base=0x00000000001060c0, limit=512):
IDT[0x00]=64-Bit Interrupt Gate target=0x0008:0000000000100ae0, DPL=0
<bochs:6> c
00260411420e[CPU0 ] LTR: doesn't point to an available TSS descriptor!
00261010082e[CPU0 ] read_RMW_virtual_byte_64(): canonical failure, 1ecf1f61
00261010082e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
00261010082e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
00261010082i[CPU0 ] CPU is in long mode (active)
00261010082i[CPU0 ] CS.d_b = 16 bit
00261010082i[CPU0 ] SS.d_b = 32 bit
00261010082i[CPU0 ] EFER = 0x00000500
00261010082i[CPU0 ] | RAX=c03160661ecf1f61 RBX=0000000000000000
00261010082i[CPU0 ] | RCX=00000000a9a7e8d8 RDX=000000000000002e
00261010082i[CPU0 ] | RSP=00000000000ffe68 RBP=00000000000ffe78
00261010082i[CPU0 ] | RSI=000000000000002e RDI=c03160661ecf1f61
00261010082i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00261010082i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00261010082i[CPU0 ] | R12=00000000001062d8 R13=0000000000030d48
00261010082i[CPU0 ] | R14=0000000000100018 R15=0000000000000010
00261010082i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00261010082i[CPU0 ] | SEG selector base limit G D
00261010082i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00261010082i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 f0000fff 1 0
00261010082i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00261010082i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00261010082i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00261010082i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00261010082i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00261010082i[CPU0 ] | MSR_FS_BASE:0000000000000000
00261010082i[CPU0 ] | MSR_GS_BASE:0000000000000000
00261010082i[CPU0 ] | RIP=0000000000102045 (0000000000102045)
00261010082i[CPU0 ] | CR0=0xc000003f CR2=0x0000000000000000
00261010082i[CPU0 ] | CR3=0x00207000 CR4=0x00000020
(0).[261010082] [0x00102045] 0008:0000000000102045 (unk. ctxt): add byte ptr ds:[rax], al ; 0000
00261010082e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Page map is identity map.
Attached file is the compressed binary. The binary has multiboot header
Source code.
Code: Select all
#include "System.h"
#include "bit.h"
namespace kernel {
void System::init() {
System::loadGlobalDescriptorTable();
System::loadInterruptGateDescriptorTable();
System::callDebugger();
System::loadTaskRegister();
System::enableInterrupt();
}
void System::loadTaskRegister() {
asm volatile("mov $24, %ax;"
"ltr %ax");
}
void System::enableInterrupt() {
asm volatile("sti");
}
struct TaskStateSegment {
U32 ignored0;
U64 rsp0;
U64 rsp1;
U64 rsp2;
U64 ist[8]; /* ist[0] is ignored, ist[1] to ist[7] will be used */
U64 ignored1;
U16 ignored2;
U16 ioMapBase;
char ioPermissionMap[8192];
TaskStateSegment() :
ioMapBase((char*)(&(this->ioPermissionMap)) - (char*)this) {}
} __attribute__((packed));
struct DescriptorTablePointer {
U16 limit;
void* base;
} __attribute__((packed));
struct NullSegmentDescriptor {
U64 ignored;
NullSegmentDescriptor() : ignored(0) {}
} __attribute__((packed));
struct DataSegmentDescriptor {
U32 ignored;
U32 attribute;
DataSegmentDescriptor() : attribute(DEFAULT) {}
enum {
DEFAULT = 0x008f9200,
P = 15,
};
} __attribute__((packed));
struct CodeSegmentDescriptor {
U32 ignored;
U32 attribute;
CodeSegmentDescriptor() : attribute(DEFAULT) {}
enum {
DEFAULT = 0x00af9800,
C = 10,
P = 15,
L = 21,
D = 22,
DPL_LOW = 11,
DPL_HIGH = 12,
};
} __attribute__((packed));
struct SystemSegmentDescriptor {
U16 limit;
U16 base01;
U8 base2;
U8 typeAndAttribute;
U8 limitAndAttribute;
U8 base3;
U32 baseHigh;
U32 zero;
SystemSegmentDescriptor() : limit(0), base01(0), base2(0),
typeAndAttribute(0x89), limitAndAttribute(0), base3(0),
baseHigh(0), zero(0) {}
void setType(U8 t) {
this->typeAndAttribute &= 0xf0;
this->typeAndAttribute |= t & 0x0f;
}
void setLimit(U32 l) {
this->limit = (U16)l;
this->limitAndAttribute |= (l & 0x0f0000) >> 16;
}
void setBaseAddress(void* base) {
UPointer value = (UPointer)base;
this->base01 = (U16)value;
this->base2 = (U8)(value >> 16);
this->base3 = (U8)(value >> 24);
this->baseHigh = (U32)(value >> 32);
}
enum {
DPL_LOW = 5,
DPL_HIGH = 6,
TYPE_LDT = 2,
TYPE_AVAILABLE_TSS = 9,
TYPE_BUSY_TSS = 0xb,
TYPE_CALL_GATE = 0xc,
TYPE_INTERRUPT_GATE = 0xe,
TYPE_TRAP_GATE = 0xf,
};
} __attribute__((packed));
struct InterruptGateDescriptor {
U16 offsetLow;
U16 selector;
U16 attribute;
U16 offsetMiddle;
U32 offsetHigh;
U32 ignored;
} __attribute__((packed));
static void installGeneralDescriptor(char* table, const void* descriptor,
int size) {
const char* p = (const char*)descriptor;
for (int i = 0; i < size; ++i, ++p, ++table) {
*table = *p;
}
}
static TaskStateSegment taskStateSegment;
extern "C" DescriptorTablePointer globalDescriptorTablePointer;
DescriptorTablePointer globalDescriptorTablePointer;
void System::loadGlobalDescriptorTable() {
static char globalDescriptorTable[128];
globalDescriptorTablePointer.base = globalDescriptorTable;
int offset = 0;
NullSegmentDescriptor nullSegmentDescriptor;
installGeneralDescriptor(globalDescriptorTable + offset,
&nullSegmentDescriptor, sizeof(nullSegmentDescriptor));
offset += sizeof(nullSegmentDescriptor);
CodeSegmentDescriptor codeSegment;
installGeneralDescriptor(globalDescriptorTable + offset,
&codeSegment, sizeof(codeSegment));
offset += sizeof(codeSegment);
DataSegmentDescriptor dataSegment;
installGeneralDescriptor(globalDescriptorTable + offset,
&dataSegment, sizeof(dataSegment));
offset += sizeof(dataSegment);
SystemSegmentDescriptor taskStateSegmentDescriptor;
taskStateSegmentDescriptor.setType(SystemSegmentDescriptor::TYPE_BUSY_TSS);
taskStateSegmentDescriptor.setBaseAddress(&taskStateSegment);
taskStateSegmentDescriptor.setLimit(sizeof(taskStateSegment));
installGeneralDescriptor(globalDescriptorTable + offset,
&taskStateSegmentDescriptor, sizeof(taskStateSegmentDescriptor));
offset += sizeof(taskStateSegmentDescriptor);
globalDescriptorTablePointer.limit = offset;
asm volatile("lgdt globalDescriptorTablePointer");
}
extern "C" void isr0(void); extern "C" void isr1(void);
extern "C" void isr2(void); extern "C" void isr3(void);
extern "C" void isr4(void); extern "C" void isr5(void);
extern "C" void isr6(void); extern "C" void isr7(void);
extern "C" void isr8(void); extern "C" void isr9(void);
extern "C" void isr10(void); extern "C" void isr11(void);
extern "C" void isr12(void); extern "C" void isr13(void);
extern "C" void isr14(void); extern "C" void isr15(void);
extern "C" void isr16(void); extern "C" void isr17(void);
extern "C" void isr18(void); extern "C" void isr19(void);
extern "C" void isr20(void); extern "C" void isr21(void);
extern "C" void isr22(void); extern "C" void isr23(void);
extern "C" void isr24(void); extern "C" void isr25(void);
extern "C" void isr26(void); extern "C" void isr27(void);
extern "C" void isr28(void); extern "C" void isr29(void);
extern "C" void isr30(void); extern "C" void isr31(void);
static void installInterruptGateDescriptor(InterruptGateDescriptor* vector,
unsigned short attribute, void (*function)(void)) {
UPointer address = (UPointer)function;
vector->offsetLow = address & 0xffff;
vector->selector = System::CODE_SELECTOR;
vector->attribute = attribute;
vector->offsetMiddle = (U16)((0xffff0000 & address) >> 16);
vector->offsetHigh = (U32)(address >> 32);
}
extern "C" DescriptorTablePointer interruptDescriptorTablePointer;
DescriptorTablePointer interruptDescriptorTablePointer;
void System::loadInterruptGateDescriptorTable() {
static bool enabled = false;
if (enabled) return;
static InterruptGateDescriptor table[32];
installInterruptGateDescriptor(table, IDT_ENTRY_ATTRIBUTE, isr0);
installInterruptGateDescriptor(table + 1, IDT_ENTRY_ATTRIBUTE, isr1);
installInterruptGateDescriptor(table + 2, IDT_ENTRY_ATTRIBUTE, isr2);
installInterruptGateDescriptor(table + 3, IDT_ENTRY_ATTRIBUTE, isr3);
installInterruptGateDescriptor(table + 4, IDT_ENTRY_ATTRIBUTE, isr4);
installInterruptGateDescriptor(table + 5, IDT_ENTRY_ATTRIBUTE, isr5);
installInterruptGateDescriptor(table + 6, IDT_ENTRY_ATTRIBUTE, isr6);
installInterruptGateDescriptor(table + 7, IDT_ENTRY_ATTRIBUTE, isr7);
installInterruptGateDescriptor(table + 8, IDT_ENTRY_ATTRIBUTE, isr8);
installInterruptGateDescriptor(table + 9, 0, 0);
installInterruptGateDescriptor(table + 10, IDT_ENTRY_ATTRIBUTE, isr10);
installInterruptGateDescriptor(table + 11, IDT_ENTRY_ATTRIBUTE, isr11);
installInterruptGateDescriptor(table + 12, IDT_ENTRY_ATTRIBUTE, isr12);
installInterruptGateDescriptor(table + 13, IDT_ENTRY_ATTRIBUTE, isr13);
installInterruptGateDescriptor(table + 14, IDT_ENTRY_ATTRIBUTE, isr14);
installInterruptGateDescriptor(table + 15, 0, 0);
installInterruptGateDescriptor(table + 16, IDT_ENTRY_ATTRIBUTE, isr16);
installInterruptGateDescriptor(table + 17, IDT_ENTRY_ATTRIBUTE, isr17);
installInterruptGateDescriptor(table + 18, IDT_ENTRY_ATTRIBUTE, isr18);
installInterruptGateDescriptor(table + 19, IDT_ENTRY_ATTRIBUTE, isr19);
installInterruptGateDescriptor(table + 20, 0, 0);
installInterruptGateDescriptor(table + 21, 0, 0);
installInterruptGateDescriptor(table + 22, 0, 0);
installInterruptGateDescriptor(table + 23, 0, 0);
installInterruptGateDescriptor(table + 24, 0, 0);
installInterruptGateDescriptor(table + 25, 0, 0);
installInterruptGateDescriptor(table + 26, 0, 0);
installInterruptGateDescriptor(table + 27, 0, 0);
installInterruptGateDescriptor(table + 28, 0, 0);
installInterruptGateDescriptor(table + 29, 0, 0);
installInterruptGateDescriptor(table + 30, IDT_ENTRY_ATTRIBUTE, isr30);
installInterruptGateDescriptor(table + 31, 0, 0);
interruptDescriptorTablePointer.limit = sizeof(table);
interruptDescriptorTablePointer.base = table;
asm volatile("lidt interruptDescriptorTablePointer");
enabled = true;
}
}
1. Zero out the TaskStateSegment
2. Set TaskStateSegmentSelector to AVAILABEL instead of BUSY
But I get another problem:
After firing the instruction "sti" every branch (jmp, call, ret) instruction causes triple fault. Bochs's message is:
Could anybody help me?00231397233e[CPU0 ] read_RMW_virtual_byte_64(): canonical failure, eefed6c6
00231397233e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
00231397233e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
00231397233i[CPU0 ] CPU is in long mode (active)
00231397233i[CPU0 ] CS.d_b = 16 bit
00231397233i[CPU0 ] SS.d_b = 32 bit
00231397233i[CPU0 ] EFER = 0x00000500
00231397233i[CPU0 ] | RAX=c6c600c6eefed6c6 RBX=0000000000000000
00231397233i[CPU0 ] | RCX=00000000c6c60030 RDX=000000000000002e
00231397233i[CPU0 ] | RSP=00000000000ffd00 RBP=00000000000ffd10
00231397233i[CPU0 ] | RSI=7000000000001040 RDI=c6c600c6eefed6c6
00231397233i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00231397233i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00231397233i[CPU0 ] | R12=00000000001062d8 R13=0000000000030d48
00231397233i[CPU0 ] | R14=0000000000100018 R15=0000000000206fd0
00231397233i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af pf cf
00231397233i[CPU0 ] | SEG selector base limit G D
00231397233i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00231397233i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 f0000fff 1 0
00231397233i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00231397233i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00231397233i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00231397233i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00231397233i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00231397233i[CPU0 ] | MSR_FS_BASE:0000000000000000
00231397233i[CPU0 ] | MSR_GS_BASE:0000000000000000
00231397233i[CPU0 ] | RIP=0000000000102049 (0000000000102049)
00231397233i[CPU0 ] | CR0=0xc000003f CR2=0x0000000000000000
00231397233i[CPU0 ] | CR3=0x00207000 CR4=0x00000020
Thanks