Lecture 2: Isolation and exceptions

Memory and isolation

Registers

Memory (aka primary memory)

Process isolation

Safe sharing

Hardware virtualization

Dangerous registers, dangerous instructions

Wait a minute!

Memory protection

Time protection

Where are the cops?

Exceptions

Exceptions and virtual computers

Processor configuration

Registers saved by hardware during an exception

// end of struct regstate:
    uint64_t reg_rip;        // instruction pointer
    uint64_t reg_cs;         // CPL
    uint64_t reg_rflags;     // flags (including privilege flags)
    uint64_t reg_rsp;        // stack pointer
    uint64_t reg_ss;
// k-exception.S:
exception_entry_3:
    pushq $0
    pushq $3
    jmp exception_entry
exception_entry:
    ...
    push %gs
    push %fs
    pushq %r15
    pushq %r14
    ...
    pushq %rdx
    pushq %rcx
    pushq %rax

Example from WeensyOS

// Top of the kernel stack
#define KERNEL_STACK_TOP        0x80000
static uint64_t gdt_segments[7];
static x86_64_taskstate taskstate;
...

    // IDT
    for (int i = 0; i < 256; ++i) {
        uintptr_t handler_function = interrupt_descriptors[i].gd_low;
        set_gate(&interrupt_descriptors[i], handler_function,
                 X86GATE_INTERRUPT, i == INT_BP ? 3 : 0, 0);
    }
    x86_64_pseudodescriptor idt;
    idt.limit = sizeof(interrupt_descriptors) - 1;
    idt.base = (uint64_t) interrupt_descriptors;

    // GDT, TSS
    memset(&taskstate, 0, sizeof(taskstate));
    taskstate.ts_rsp[0] = KERNEL_STACK_TOP; // address to store exception-time registers

    set_app_segment(&gdt_segments[0], X86SEG_X | X86SEG_L, 0); ...
    set_sys_segment(&gdt_segments[0x28 >> 3], (uintptr_t) &taskstate, sizeof(taskstate), X86SEG_TSS, 0);
    x86_64_pseudodescriptor gdt;
    gdt.limit = sizeof(gdt_segments) - 1;
    gdt.base = (uint64_t) gdt_segments;

    // install
    asm volatile("lgdt [&gdt.limit]; ltr $0x28; lidt [&idt.limit]");

Multiprocessor exceptions

struct cpustate

struct __attribute__((aligned(4096))) cpustate {
    ...
    uint64_t gdt_segments_[7];
    x86_64_taskstate taskstate_;
};

    // GDT, TSS
    memset(&taskstate_, 0, sizeof(taskstate_)); // was global
    taskstate_.ts_rsp[0] = (uintptr_t) this + CPUSTACK_SIZE; // was KERNEL_STACK_TOP

    set_app_segment(&gdt_segments_[0], X86SEG_X | X86SEG_L, 0); ...
    set_sys_segment(&gdt_segments_[0x28 >> 3], (uintptr_t) &taskstate_, sizeof(taskstate_), X86SEG_TSS, 0);
    x86_64_pseudodescriptor gdt;
    gdt.limit = sizeof(gdt_segments_) - 1;
    gdt.base = (uint64_t) gdt_segments_;

    // install
    asm volatile("lgdt [&gdt.limit]; ltr $0x28; lidt [&idt.limit]");

How can code tell which CPU took the exception??