x86-64 single-core simple cte
This commit is contained in:
parent
61fe0809dd
commit
b339c0acf7
|
@ -1,6 +1,7 @@
|
|||
include $(AM_HOME)/am/arch/isa/x86.mk
|
||||
|
||||
AM_SRCS := x86_64/qemu/start.S \
|
||||
x86_64/qemu/trap.S \
|
||||
x86_64/qemu/trm.c \
|
||||
x86_64/qemu/cte.c \
|
||||
x86_64/qemu/ioe.c \
|
||||
|
@ -18,8 +19,8 @@ image:
|
|||
|
||||
run:
|
||||
@( echo -n $(mainargs); ) | dd if=/dev/stdin of=$(BINARY) bs=512 count=1 seek=1 conv=notrunc status=none
|
||||
@qemu-system-i386 -smp 2 -serial stdio -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY)
|
||||
@qemu-system-i386 -serial stdio -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY)
|
||||
|
||||
debug:
|
||||
@( echo -n $(mainargs); ) | dd if=/dev/stdin of=$(BINARY) bs=512 count=1 seek=1 conv=notrunc status=none
|
||||
@qemu-system-i386 -smp 2 -S -s -serial none -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY) -nographic # & pid=$$!; gdb -x x.gdb && kill -9 $$pid
|
||||
@qemu-system-i386 -S -s -serial none -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY) -nographic # & pid=$$!; gdb -x x.gdb && kill -9 $$pid
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
include $(AM_HOME)/am/arch/isa/x86_64.mk
|
||||
|
||||
AM_SRCS := x86_64/qemu/start.S \
|
||||
x86_64/qemu/trap.S \
|
||||
x86_64/qemu/trm.c \
|
||||
x86_64/qemu/cte.c \
|
||||
x86_64/qemu/ioe.c \
|
||||
|
@ -17,8 +18,8 @@ image:
|
|||
|
||||
run:
|
||||
@( echo -n $(mainargs); ) | dd if=/dev/stdin of=$(BINARY) bs=512 count=1 seek=1 conv=notrunc status=none
|
||||
@qemu-system-x86_64 -smp 2 -serial stdio -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY)
|
||||
@qemu-system-x86_64 -serial stdio -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY)
|
||||
|
||||
debug:
|
||||
@( echo -n $(mainargs); ) | dd if=/dev/stdin of=$(BINARY) bs=512 count=1 seek=1 conv=notrunc status=none
|
||||
@qemu-system-x86_64 -smp 2 -S -s -serial none -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY) -nographic # & pid=$$!; gdb -x x.gdb && kill -9 $$pid
|
||||
@qemu-system-x86_64 -S -s -serial none -machine accel=kvm:tcg -smp "$(smp)" -drive format=raw,file=$(BINARY) -nographic # & pid=$$!; gdb -x x.gdb && kill -9 $$pid
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
// System segment type bits
|
||||
#define STS_T32A 0x9 // Available 32-bit TSS
|
||||
#define STS_IG32 0xE // 32-bit Interrupt Gate
|
||||
#define STS_TG32 0xF // 32-bit Trap Gate
|
||||
#define STS_IG 0xE // 32/64-bit Interrupt Gate
|
||||
#define STS_TG 0xF // 32/64-bit Trap Gate
|
||||
|
||||
// Eflags register
|
||||
#define FL_TF 0x00000100 // Trap Flag
|
||||
|
@ -144,7 +144,7 @@ typedef struct SegDesc {
|
|||
(uint32_t)(lim) >> 16, 0, 0, 1, 0, (uint32_t)(base) >> 24 }
|
||||
|
||||
// Gate descriptors for interrupts and traps
|
||||
typedef struct GateDesc {
|
||||
typedef struct GateDesc32 {
|
||||
uint32_t off_15_0 : 16; // Low 16 bits of offset in segment
|
||||
uint32_t cs : 16; // Code segment selector
|
||||
uint32_t args : 5; // # args, 0 for interrupt/trap gates
|
||||
|
@ -154,12 +154,29 @@ typedef struct GateDesc {
|
|||
uint32_t dpl : 2; // Descriptor(meaning new) privilege level
|
||||
uint32_t p : 1; // Present
|
||||
uint32_t off_31_16 : 16; // High bits of offset in segment
|
||||
} GateDesc;
|
||||
} GateDesc32;
|
||||
|
||||
#define GATE(type, cs, entry, dpl) (GateDesc) \
|
||||
{ (uint32_t)(entry) & 0xffff, (cs), 0, 0, (type), 0, (dpl), \
|
||||
#define GATE32(type, cs, entry, dpl) (GateDesc32) \
|
||||
{ (uint32_t)(entry) & 0xffff, (cs), 0, 0, (type), 0, (dpl), \
|
||||
1, (uint32_t)(entry) >> 16 }
|
||||
|
||||
typedef struct GateDesc64 {
|
||||
uint32_t off_15_0 : 16;
|
||||
uint32_t cs : 16;
|
||||
uint32_t isv : 3;
|
||||
uint32_t zero1 : 5;
|
||||
uint32_t type : 4;
|
||||
uint32_t zero2 : 1;
|
||||
uint32_t dpl : 2;
|
||||
uint32_t p : 1;
|
||||
uint32_t off_31_16 : 16;
|
||||
uint32_t off_63_32 : 32;
|
||||
uint32_t rsv : 32;
|
||||
} GateDesc64;
|
||||
|
||||
#define GATE64(type, cs, entry, dpl) (GateDesc64) \
|
||||
{ (uint64_t)(entry) & 0xffff, (cs), 0, 0, (type), 0, (dpl), \
|
||||
1, ((uint64_t)(entry) >> 16) & 0xffff, (uint64_t)(entry) >> 32, 0 }
|
||||
|
||||
// Task state segment format
|
||||
typedef struct TSS {
|
||||
|
@ -255,7 +272,7 @@ static inline void pause() {
|
|||
}
|
||||
|
||||
static inline uint32_t get_efl() {
|
||||
volatile uint32_t efl;
|
||||
volatile uintptr_t efl;
|
||||
asm volatile ("pushf; pop %0": "=r"(efl));
|
||||
return efl;
|
||||
}
|
||||
|
@ -303,9 +320,9 @@ typedef struct {
|
|||
} TSS64;
|
||||
#endif
|
||||
|
||||
static inline uint32_t get_cr2() {
|
||||
volatile uint32_t val;
|
||||
asm volatile ("movl %%cr2, %0" : "=r"(val));
|
||||
static inline uintptr_t get_cr2() {
|
||||
volatile uintptr_t val;
|
||||
asm volatile ("mov %%cr2, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
#include "x86_64-qemu.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
void am_on_irq() {
|
||||
printf("%d", _cpu());
|
||||
}
|
||||
|
||||
static _Context* (*user_handler)(_Event, _Context*) = NULL;
|
||||
static GateDesc idt[NR_IRQ];
|
||||
#if __x86_64__
|
||||
static GateDesc64 idt[NR_IRQ];
|
||||
#define GATE GATE64
|
||||
#else
|
||||
static GateDesc32 idt[NR_IRQ];
|
||||
#define GATE GATE32
|
||||
#endif
|
||||
|
||||
|
||||
#define IRQHANDLE_DECL(id, dpl, err) void __am_irq##id();
|
||||
IRQS(IRQHANDLE_DECL)
|
||||
|
@ -13,10 +23,10 @@ int _cte_init(_Context *(*handler)(_Event, _Context *)) {
|
|||
if (_cpu() != 0) panic("init CTE in non-bootstrap CPU");
|
||||
|
||||
for (int i = 0; i < NR_IRQ; i ++) {
|
||||
idt[i] = GATE(STS_TG32, KSEL(SEG_KCODE), __am_irqall, DPL_KERN);
|
||||
idt[i] = GATE(STS_TG, KSEL(SEG_KCODE), __am_irqall, DPL_KERN);
|
||||
}
|
||||
#define IDT_ENTRY(id, dpl, err) \
|
||||
idt[id] = GATE(STS_TG32, KSEL(SEG_KCODE), __am_irq##id, DPL_##dpl);
|
||||
idt[id] = GATE(STS_TG, KSEL(SEG_KCODE), __am_irq##id, DPL_##dpl);
|
||||
IRQS(IDT_ENTRY)
|
||||
|
||||
user_handler = handler;
|
||||
|
@ -43,52 +53,19 @@ void _intr_write(int enable) {
|
|||
}
|
||||
}
|
||||
|
||||
static void panic_on_return() { panic("kernel context returns"); }
|
||||
// static void panic_on_return() { panic("kernel context returns"); }
|
||||
|
||||
_Context *_kcontext(_Area stack, void (*entry)(void *), void *arg) {
|
||||
_Area stk_safe = {
|
||||
(void *)ROUNDUP(stack.start, 64),
|
||||
(void *)ROUNDDOWN(stack.end, 64),
|
||||
};
|
||||
|
||||
_Context *ctx = (_Context *)stk_safe.start;
|
||||
*ctx = (_Context) {
|
||||
.eax = 0, .ebx = 0, .ecx = 0, .edx = 0,
|
||||
.esi = 0, .edi = 0, .ebp = 0, .esp3 = 0,
|
||||
.ss0 = 0, .esp0 = (uint32_t)stk_safe.end,
|
||||
.cs = KSEL(SEG_KCODE), .eip = (uint32_t)entry, .eflags = FL_IF,
|
||||
.ds = KSEL(SEG_KDATA), .es = KSEL(SEG_KDATA), .ss = KSEL(SEG_KDATA),
|
||||
.uvm = NULL,
|
||||
};
|
||||
|
||||
void *values[] = { panic_on_return, arg }; // copy to stack
|
||||
ctx->esp0 -= sizeof(values);
|
||||
for (int i = 0; i < LENGTH(values); i++) {
|
||||
((uintptr_t *)ctx->esp0)[i] = (uintptr_t)values[i];
|
||||
}
|
||||
return ctx;
|
||||
panic("!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define IRQ T_IRQ0 +
|
||||
#define MSG(m) ev.msg = m;
|
||||
|
||||
void __am_irq_handle(TrapFrame *tf) {
|
||||
// saving processor context
|
||||
_Context ctx = {
|
||||
.eax = tf->eax, .ebx = tf->ebx, .ecx = tf->ecx, .edx = tf->edx,
|
||||
.esi = tf->esi, .edi = tf->edi, .ebp = tf->ebp, .esp3 = 0,
|
||||
.eip = tf->eip, .eflags = tf->eflags,
|
||||
.cs = tf->cs, .ds = tf->ds, .es = tf->es, .ss = 0,
|
||||
.ss0 = KSEL(SEG_KDATA), .esp0 = (uint32_t)(tf + 1),
|
||||
.uvm = CPU->uvm,
|
||||
};
|
||||
|
||||
if (tf->cs & DPL_USER) { // interrupt at user code
|
||||
ctx.ss = tf->ss;
|
||||
ctx.esp3 = tf->esp;
|
||||
} else { // interrupt at kernel code
|
||||
// tf (without ss0/esp0) is everything saved on the stack
|
||||
ctx.esp0 -= sizeof(uint32_t) * 2;
|
||||
}
|
||||
|
||||
// sending end-of-interrupt
|
||||
|
@ -143,54 +120,6 @@ void __am_irq_handle(TrapFrame *tf) {
|
|||
ev.cause = tf->err;
|
||||
break;
|
||||
}
|
||||
|
||||
// call user handlers (registered in _cte_init)
|
||||
_Context *ret_ctx = &ctx;
|
||||
if (user_handler) {
|
||||
_Context *next = user_handler(ev, &ctx);
|
||||
if (!next) {
|
||||
panic("return to a null context");
|
||||
}
|
||||
ret_ctx = next;
|
||||
}
|
||||
|
||||
// Return to context @ret_ctx
|
||||
#define REGS_KERNEL(_) \
|
||||
_(eflags) _(cs) _(eip) _(ds) _(es) \
|
||||
_(eax) _(ecx) _(edx) _(ebx) _(esp0) _(ebp) _(esi) _(edi)
|
||||
#define REGS_USER(_) \
|
||||
_(ss) _(esp3) REGS_KERNEL(_)
|
||||
#define push(r) "push %[" #r "];" // -> push %[eax]
|
||||
#define def(r) , [r] "m"(ret_ctx->r) // -> [eax] "m"(ret_ctx->eax)
|
||||
|
||||
CPU->uvm = ret_ctx->uvm;
|
||||
if (ret_ctx->cs & DPL_USER) { // return to user
|
||||
_AddressSpace *uvm = ret_ctx->uvm;
|
||||
if (uvm) {
|
||||
set_cr3(uvm->ptr);
|
||||
}
|
||||
__am_thiscpu_setstk0(ret_ctx->ss0, ret_ctx->esp0);
|
||||
asm volatile goto (
|
||||
"movl %[esp], %%esp;" // move stack
|
||||
REGS_USER(push) // push reg context onto stack
|
||||
"jmp %l[iret]" // goto iret
|
||||
: : [esp] "m"(ret_ctx->esp0)
|
||||
REGS_USER(def) : : iret );
|
||||
} else { // return to kernel
|
||||
asm volatile goto (
|
||||
"movl %[esp], %%esp;" // move stack
|
||||
REGS_KERNEL(push) // push reg context onto stack
|
||||
"jmp %l[iret]" // goto iret
|
||||
: : [esp] "m"(ret_ctx->esp0)
|
||||
REGS_KERNEL(def) : : iret );
|
||||
}
|
||||
iret:
|
||||
asm volatile (
|
||||
"popal;" // restore context
|
||||
"popl %es;"
|
||||
"popl %ds;"
|
||||
"iret;" // interrupt return
|
||||
);
|
||||
}
|
||||
|
||||
void __am_percpu_initirq() {
|
||||
|
@ -199,5 +128,3 @@ void __am_percpu_initirq() {
|
|||
set_idt(idt, sizeof(idt));
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
|
@ -93,11 +93,11 @@ void __am_percpu_initgdt() {
|
|||
gdt[SEG_KDATA] = 0x0000920000000000LL;
|
||||
gdt[SEG_UCODE] = 0x0020F80000000000LL;
|
||||
gdt[SEG_UDATA] = 0x0000F20000000000LL;
|
||||
gdt[SEG_TSS+0] = (0x0067) | ((tss & 0xFFFFFF) << 16) |
|
||||
(0x00E9LL << 40) | (((tss >> 24) & 0xFF) << 56);
|
||||
gdt[SEG_TSS+0] = (0x0067) | ((tss & 0xffffff) << 16) |
|
||||
(0x00e9LL << 40) | (((tss >> 24) & 0xff) << 56);
|
||||
gdt[SEG_TSS+1] = (tss >> 32);
|
||||
set_gdt(gdt, sizeof(SegDesc64) * (NR_SEG + 1));
|
||||
set_tr(KSEL(SEG_TSS));
|
||||
// set_gdt(gdt, sizeof(SegDesc64) * (NR_SEG + 1));
|
||||
// set_tr(KSEL(SEG_TSS));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -7,16 +7,14 @@ _start:
|
|||
#ifndef __x86_64__
|
||||
// 32-bit code
|
||||
pushl $0x7e00
|
||||
call _start_c
|
||||
cli
|
||||
hlt
|
||||
jmp _start_c
|
||||
|
||||
#else
|
||||
// 64-bit code
|
||||
.code32
|
||||
movl $0, %eax
|
||||
cmpl (BOOT_RECORD), %eax
|
||||
jne .x86_64init
|
||||
jne .long_mode_init
|
||||
|
||||
#define PML4 0x1000
|
||||
#define PDPT 0x2000
|
||||
|
@ -46,14 +44,14 @@ _start:
|
|||
cmp %esi, %ecx
|
||||
jne .loop
|
||||
|
||||
.x86_64init:
|
||||
.long_mode_init:
|
||||
movl $PML4, %eax
|
||||
movl %eax, %cr3 // %cr3 = PML4 base
|
||||
movl $0x80000021, %eax
|
||||
movl %eax, %cr4 // %cr4.PAE = 1
|
||||
movl $0xc0000080, %ecx
|
||||
rdmsr
|
||||
or $0x100, %eax
|
||||
orl $0x100, %eax
|
||||
wrmsr // %msr.LME = 1.
|
||||
movl $0x80000011, %eax
|
||||
movl %eax, %cr0 // %cr0.PG = 1; %cr0.PE = 1;
|
||||
|
@ -63,16 +61,16 @@ _start:
|
|||
hlt
|
||||
|
||||
gdt_ptr:
|
||||
.word gdt64_end - gdt64_begin - 1;
|
||||
.word gdt64_end - gdt64_begin - 1
|
||||
.quad gdt64_begin
|
||||
|
||||
gdt64_begin:
|
||||
.long 0xffff0000 # 0: null desc
|
||||
.long 0x00000000 # 0: null desc
|
||||
.long 0x00000000
|
||||
.long 0x00000000 # 1: Code, R/X, Nonconforming
|
||||
.long 0x00209800
|
||||
.long 0x00000000 # 2: Data, R/W, Expand Down
|
||||
.long 0x00009000
|
||||
.long 0x00009800
|
||||
gdt64_end:
|
||||
|
||||
.code64
|
||||
|
@ -81,14 +79,12 @@ _start64:
|
|||
movw $0, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw %ax, %ss
|
||||
|
||||
movq $0x7000, %rsp
|
||||
movq $0x7e00, %rdi
|
||||
call _start_c
|
||||
cli
|
||||
hlt
|
||||
jmp _start_c
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#include <x86.h>
|
||||
|
||||
trap:
|
||||
cli
|
||||
|
||||
#if __x86_64__
|
||||
push %r15
|
||||
push %r14
|
||||
push %r13
|
||||
push %r12
|
||||
push %r11
|
||||
push %r10
|
||||
push %r9
|
||||
push %r8
|
||||
push %rdi
|
||||
push %rsi
|
||||
push %rbp
|
||||
push %rdx
|
||||
push %rcx
|
||||
push %rbx
|
||||
push %rax
|
||||
|
||||
|
||||
call am_on_irq
|
||||
|
||||
pop %rax
|
||||
pop %rbx
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
pop %rbp
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
pop %r8
|
||||
pop %r9
|
||||
pop %r10
|
||||
pop %r11
|
||||
pop %r12
|
||||
pop %r13
|
||||
pop %r14
|
||||
pop %r15
|
||||
addq $16, %rsp
|
||||
iretq
|
||||
|
||||
#else
|
||||
addl $8, %esp
|
||||
iret
|
||||
#endif
|
||||
|
||||
#define NOERR push $0
|
||||
#define ERR
|
||||
#define IRQ_DEF(id, dpl, err) \
|
||||
.globl __am_irq##id; __am_irq##id: cli; err; push $id; jmp trap;
|
||||
IRQS(IRQ_DEF)
|
||||
.globl __am_irqall; __am_irqall: cli; push $0; push $-1; jmp trap;
|
|
@ -10,13 +10,13 @@ void percpu_init();
|
|||
_Area memory_probe();
|
||||
|
||||
struct cpu_local {
|
||||
// _AddressSpace *uvm;
|
||||
#ifndef __x86_64__
|
||||
SegDesc gdt[NR_SEG];
|
||||
TSS tss;
|
||||
#else
|
||||
_AddressSpace *uvm;
|
||||
#if __x86_64__
|
||||
SegDesc64 gdt[NR_SEG + 1];
|
||||
TSS64 tss;
|
||||
#else
|
||||
SegDesc gdt[NR_SEG];
|
||||
TSS tss;
|
||||
#endif
|
||||
uint8_t stack[4096];
|
||||
};
|
||||
|
|
|
@ -5,8 +5,22 @@ void hello() {
|
|||
printf("CPU %d: hello!\n", _cpu());
|
||||
while (1);
|
||||
}
|
||||
|
||||
_Context *on_intr(_Event ev, _Context *ctx) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void foo() {
|
||||
_intr_write(1);
|
||||
while (1) {
|
||||
asm volatile("int $0x80;");
|
||||
}
|
||||
}
|
||||
|
||||
int main(const char *args) {
|
||||
printf("CPU0: hello with args=\"%s\"\n", args);
|
||||
_mpe_init(hello);
|
||||
_cte_init(on_intr);
|
||||
|
||||
_mpe_init(foo);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
target remote localhost:1234
|
||||
layout asm
|
||||
layout regs
|
||||
set pagination off
|
||||
set confirm off
|
||||
file build/hello-x86_32-qemu.o
|
||||
b main
|
||||
c
|
|
@ -4,6 +4,5 @@ layout regs
|
|||
set pagination off
|
||||
set confirm off
|
||||
file build/hello-x86_64-qemu.o
|
||||
# file build/hello-x86_32-qemu.o
|
||||
b __am_percpu_initgdt
|
||||
b _start64
|
||||
c
|
Loading…
Reference in New Issue