Fix TSS init.

This commit is contained in:
Alexander Myltsev 2022-12-14 12:28:30 +03:00
parent dd9f5786c2
commit 5f3cbb988d
3 changed files with 67 additions and 54 deletions

View File

@ -1,4 +1,5 @@
#include "gdt.h" #include "gdt.h"
#include "../lib/string.h"
#include <stdint.h> #include <stdint.h>
@ -18,8 +19,6 @@ struct seg_desc_t {
uint8_t base_31_24; // High bits of segment base address uint8_t base_31_24; // High bits of segment base address
} __attribute__((packed)); } __attribute__((packed));
typedef unsigned uint;
#define SEG(type, base, lim, dpl) (struct seg_desc_t) \ #define SEG(type, base, lim, dpl) (struct seg_desc_t) \
{ ((lim) >> 12) & 0xffff, (uint)(base) & 0xffff, \ { ((lim) >> 12) & 0xffff, (uint)(base) & 0xffff, \
((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \
@ -38,66 +37,29 @@ void init_seg_desc() {
seg_desc[SEG_UDATA] = SEG(STA_W, USER_BASE, 0xffffffff - USER_BASE, DPL_USER); seg_desc[SEG_UDATA] = SEG(STA_W, USER_BASE, 0xffffffff - USER_BASE, DPL_USER);
} }
typedef uint16_t ushort;
struct taskstate {
uint link; // Old ts selector
uint esp0; // Stack pointers and segment selectors
ushort ss0; // after an increase in privilege level
ushort padding1;
uint *esp1;
ushort ss1;
ushort padding2;
uint *esp2;
ushort ss2;
ushort padding3;
void *cr3; // Page directory base
uint *eip; // Saved state from last task switch
uint eflags;
uint eax; // More saved state (registers)
uint ecx;
uint edx;
uint ebx;
uint *esp;
uint *ebp;
uint esi;
uint edi;
ushort es; // Even more saved state (segment selectors)
ushort padding4;
ushort cs;
ushort padding5;
ushort ss;
ushort padding6;
ushort ds;
ushort padding7;
ushort fs;
ushort padding8;
ushort gs;
ushort padding9;
ushort ldt;
ushort padding10;
ushort t; // Trap on task switch
ushort iomb; // I/O map base address
} tss;
struct gdt_desc_t { struct gdt_desc_t {
uint16_t size; uint16_t size;
void* ptr; void* ptr;
} __attribute__((packed)); } __attribute__((packed));
void load_gdt() { void load_gdt() {
seg_desc[SEG_TSS] = SEG16(STS_T32A, &tss, sizeof(tss)-1, 0);
seg_desc[SEG_TSS].s = 0;
tss.ss0 = SEG_KDATA << 3;
tss.esp0 = KERN_STACK_BASE;
// setting IOPL=0 in eflags *and* iomb beyond the tss segment limit
// forbids I/O instructions (e.g., inb and outb) from user space
tss.iomb = (ushort) 0xFFFF;
init_seg_desc(); init_seg_desc();
struct gdt_desc_t gdt_desc; struct gdt_desc_t gdt_desc;
gdt_desc.size = sizeof(seg_desc) - 1; gdt_desc.size = sizeof(seg_desc) - 1;
gdt_desc.ptr = seg_desc; gdt_desc.ptr = seg_desc;
asm("lgdt %0": : "m"(gdt_desc)); asm("lgdt %0": : "m"(gdt_desc));
}
void switchuvm(struct taskstate *tss, void* esp) {
memset(tss, 0, sizeof(*tss));
seg_desc[SEG_TSS] = SEG16(STS_T32A, tss, sizeof(*tss)-1, 0);
seg_desc[SEG_TSS].s = 0;
tss->ss0 = SEG_KDATA << 3;
tss->esp0 = (uint)esp;
// setting IOPL=0 in eflags *and* iomb beyond the tss segment limit
// forbids I/O instructions (e.g., inb and outb) from user space
tss->iomb = (ushort) 0xFFFF;
asm("ltr %0": : "r"((ushort)(SEG_TSS << 3))); asm("ltr %0": : "r"((ushort)(SEG_TSS << 3)));
} }

View File

@ -29,5 +29,49 @@
#define KERN_STACK_BASE 0x90000 #define KERN_STACK_BASE 0x90000
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
typedef unsigned uint;
typedef unsigned short ushort;
struct taskstate {
uint link; // Old ts selector
uint esp0; // Stack pointers and segment selectors
ushort ss0; // after an increase in privilege level
ushort padding1;
uint *esp1;
ushort ss1;
ushort padding2;
uint *esp2;
ushort ss2;
ushort padding3;
void *cr3; // Page directory base
uint *eip; // Saved state from last task switch
uint eflags;
uint eax; // More saved state (registers)
uint ecx;
uint edx;
uint ebx;
uint *esp;
uint *ebp;
uint esi;
uint edi;
ushort es; // Even more saved state (segment selectors)
ushort padding4;
ushort cs;
ushort padding5;
ushort ss;
ushort padding6;
ushort ds;
ushort padding7;
ushort fs;
ushort padding8;
ushort gs;
ushort padding9;
ushort ldt;
ushort padding10;
ushort t; // Trap on task switch
ushort iomb; // I/O map base address
};
void load_gdt(); void load_gdt();
void switchuvm(struct taskstate *tss, void* esp);
#endif #endif

13
proc.c
View File

@ -17,12 +17,18 @@ struct kstack {
uint32_t space[400]; uint32_t space[400];
struct context context; struct context context;
registers_t trapframe; registers_t trapframe;
char bottom[];
};
struct task {
struct taskstate tss;
struct kstack stack;
}; };
struct vm { struct vm {
void *kernel_thread; void *kernel_thread;
void *user_thread; void *user_thread;
struct kstack *user_kstack; struct task *user_task;
} *vm; } *vm;
void trapret(); void trapret();
@ -31,7 +37,8 @@ void swtch(void** oldstack, void* newstack);
void run_elf(const char* name) { void run_elf(const char* name) {
if (!vm) { if (!vm) {
vm = kmalloc(sizeof(struct vm)); vm = kmalloc(sizeof(struct vm));
vm->user_kstack = kmalloc(sizeof(struct kstack)); vm->user_task = kmalloc(sizeof(struct task));
switchuvm(&vm->user_task->tss, vm->user_task->stack.bottom);
} }
if (read_file(name, (void*)USER_BASE, 100 << 20) <= 0) { if (read_file(name, (void*)USER_BASE, 100 << 20) <= 0) {
printk(name); printk(name);
@ -40,7 +47,7 @@ void run_elf(const char* name) {
} }
Elf32_Ehdr *hdr = (void*)USER_BASE; Elf32_Ehdr *hdr = (void*)USER_BASE;
struct kstack *u = vm->user_kstack; struct kstack *u = &vm->user_task->stack;
memset(u, 0, sizeof(*u)); memset(u, 0, sizeof(*u));
u->context.eip = (uint32_t)trapret; u->context.eip = (uint32_t)trapret;