x86-64 single-core simple cte

This commit is contained in:
Yanyan Jiang 2020-01-25 23:52:51 +08:00
parent 61fe0809dd
commit b339c0acf7
11 changed files with 147 additions and 130 deletions

View File

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

View File

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

View File

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

View File

@ -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));
}
}
*/

View File

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

View File

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

54
am/src/x86_64/qemu/trap.S Normal file
View File

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

View File

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

View File

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

8
tests/hello/x32.gdb Normal file
View File

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

View File

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