#include "gdt.h" #include "../lib/string.h" #include "kernel/mem.h" #include struct seg_desc_t { uint16_t lim_15_0; // Low bits of segment limit uint16_t base_15_0; // Low bits of segment base address uint8_t base_23_16; // Middle bits of segment base address uint8_t type : 4; // Segment type (see STA_ constants) uint8_t s : 1; // 0 = system, 1 = application uint8_t dpl : 2; // Descriptor Privilege Level uint8_t p : 1; // Present uint8_t lim_19_16 : 4; // High bits of segment limit uint8_t avl : 1; // Unused (available for software use) uint8_t rsv1 : 1; // Reserved uint8_t db : 1; // 0 = 16-bit segment, 1 = 32-bit segment uint8_t g : 1; // Granularity: limit scaled by 4K when set uint8_t base_31_24; // High bits of segment base address } __attribute__((packed)); #define SEG(type, base, lim, dpl) (struct seg_desc_t) \ { ((lim) >> 12) & 0xffff, (uint)(base) & 0xffff, \ ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ (uint)(lim) >> 28, 0, 0, 1, 1, (uint)(base) >> 24 } #define SEG16(type, base, lim, dpl) (struct seg_desc_t) \ { (lim) & 0xffff, (uint)(base) & 0xffff, \ ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ (uint)(lim) >> 16, 0, 0, 1, 0, (uint)(base) >> 24 } struct seg_desc_t seg_desc[6]; void init_seg_desc() { seg_desc[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0); seg_desc[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); seg_desc[SEG_UCODE] = SEG(STA_X|STA_R, USER_BASE, 0xffffffff - USER_BASE, DPL_USER); seg_desc[SEG_UDATA] = SEG(STA_W, USER_BASE, 0xffffffff - USER_BASE, DPL_USER); } struct gdt_desc_t { uint16_t size; void* ptr; } __attribute__((packed)); void load_gdt() { init_seg_desc(); struct gdt_desc_t gdt_desc; gdt_desc.size = sizeof(seg_desc) - 1; gdt_desc.ptr = seg_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))); }