299 lines
8.8 KiB
C
299 lines
8.8 KiB
C
/* x86_desc.h - Defines for various x86 descriptors, descriptor tables,
|
|
* and selectors
|
|
* vim:ts=4 noexpandtab
|
|
*/
|
|
|
|
#ifndef _X86_DESC_H
|
|
#define _X86_DESC_H
|
|
|
|
#include "lib/types.h"
|
|
|
|
/* Segment selector values */
|
|
#define KERNEL_CS 0x0010
|
|
#define KERNEL_DS 0x0018
|
|
#define USER_CS 0x0023
|
|
#define USER_DS 0x002B
|
|
#define KERNEL_TSS 0x0030
|
|
#define KERNEL_LDT 0x0038
|
|
|
|
// Some constants
|
|
// Number of Page Directory pd_entries
|
|
#define NUM_PDE 1024
|
|
#define NUM_PTE 1024
|
|
#define PAGE_SIZE_4KB 0x1000
|
|
#define MAX_PROGRAMS_NUM 8
|
|
|
|
/* Size of the task state segment (TSS) */
|
|
#define TSS_SIZE 104
|
|
|
|
/* Number of vectors in the interrupt descriptor table (IDT) */
|
|
#define NUM_VEC 256
|
|
|
|
#ifndef ASM
|
|
|
|
/* This structure is used to load descriptor base registers
|
|
* like the GDTR and IDTR */
|
|
typedef struct x86_desc {
|
|
uint16_t padding;
|
|
uint16_t size;
|
|
uint32_t addr;
|
|
} x86_desc_t;
|
|
|
|
/* This is a segment descriptor. It goes in the GDT. */
|
|
typedef struct seg_desc {
|
|
union {
|
|
uint32_t val[2];
|
|
struct {
|
|
uint16_t seg_lim_15_00;
|
|
uint16_t base_15_00;
|
|
uint8_t base_23_16;
|
|
uint32_t type : 4;
|
|
uint32_t sys : 1;
|
|
uint32_t dpl : 2;
|
|
uint32_t present : 1;
|
|
uint32_t seg_lim_19_16 : 4;
|
|
uint32_t avail : 1;
|
|
uint32_t reserved : 1;
|
|
uint32_t opsize : 1;
|
|
uint32_t granularity : 1;
|
|
uint8_t base_31_24;
|
|
} __attribute__ ((packed));
|
|
};
|
|
} seg_desc_t;
|
|
|
|
/* TSS structure */
|
|
typedef struct __attribute__((packed)) tss_t {
|
|
uint16_t prev_task_link;
|
|
uint16_t prev_task_link_pad;
|
|
|
|
uint32_t esp0;
|
|
uint16_t ss0;
|
|
uint16_t ss0_pad;
|
|
|
|
uint32_t esp1;
|
|
uint16_t ss1;
|
|
uint16_t ss1_pad;
|
|
|
|
uint32_t esp2;
|
|
uint16_t ss2;
|
|
uint16_t ss2_pad;
|
|
|
|
uint32_t cr3;
|
|
|
|
uint32_t eip;
|
|
uint32_t eflags;
|
|
|
|
uint32_t eax;
|
|
uint32_t ecx;
|
|
uint32_t edx;
|
|
uint32_t ebx;
|
|
uint32_t esp;
|
|
uint32_t ebp;
|
|
uint32_t esi;
|
|
uint32_t edi;
|
|
|
|
uint16_t es;
|
|
uint16_t es_pad;
|
|
|
|
uint16_t cs;
|
|
uint16_t cs_pad;
|
|
|
|
uint16_t ss;
|
|
uint16_t ss_pad;
|
|
|
|
uint16_t ds;
|
|
uint16_t ds_pad;
|
|
|
|
uint16_t fs;
|
|
uint16_t fs_pad;
|
|
|
|
uint16_t gs;
|
|
uint16_t gs_pad;
|
|
|
|
uint16_t ldt_segment_selector;
|
|
uint16_t ldt_pad;
|
|
|
|
uint16_t debug_trap : 1;
|
|
uint16_t io_pad : 15;
|
|
uint16_t io_base_addr;
|
|
} tss_t;
|
|
|
|
/* Some external descriptors declared in .S files */
|
|
extern x86_desc_t gdt_desc;
|
|
extern uint32_t gdt;
|
|
|
|
extern uint16_t ldt_desc;
|
|
extern uint32_t ldt_size;
|
|
extern seg_desc_t ldt_desc_ptr;
|
|
extern seg_desc_t gdt_ptr;
|
|
extern seg_desc_t gdt_desc_ptr;
|
|
extern uint32_t ldt;
|
|
|
|
extern uint32_t tss_size;
|
|
extern seg_desc_t tss_desc_ptr;
|
|
extern tss_t tss;
|
|
|
|
// Page Directory Entry for 4 KB Page Table (goes into the PD)
|
|
typedef union pde_4KB_t {
|
|
uint32_t val;
|
|
struct {
|
|
uint32_t present :1;
|
|
uint32_t read_write :1;
|
|
uint32_t user_supervisor :1;
|
|
uint32_t write_through :1;
|
|
uint32_t cache_disabled :1;
|
|
uint32_t accessed :1;
|
|
uint32_t reserved :1;
|
|
uint32_t page_size :1;
|
|
uint32_t global :1;
|
|
uint32_t avail :3;
|
|
uint32_t PTB_addr :20;
|
|
} __attribute__ ((packed));
|
|
} pde_4KB_t;
|
|
|
|
// Page Directory Entry for 4 MB Page (goes into the PD)
|
|
typedef union pde_4MB_t {
|
|
uint32_t val;
|
|
struct {
|
|
uint32_t present :1;
|
|
uint32_t read_write :1;
|
|
uint32_t user_supervisor :1;
|
|
uint32_t write_through :1;
|
|
uint32_t cache_disabled :1;
|
|
uint32_t accessed :1;
|
|
uint32_t dirty :1;
|
|
uint32_t page_size :1;
|
|
uint32_t global :1;
|
|
uint32_t avail :3;
|
|
uint32_t pat :1;
|
|
uint32_t reserved :9;
|
|
uint32_t PB_addr :10;
|
|
} __attribute__ ((packed));
|
|
} pde_4MB_t;
|
|
|
|
// General Page Directory Entry
|
|
typedef union pde_t {
|
|
pde_4KB_t pde_KB;
|
|
pde_4MB_t pde_MB;
|
|
} pde_t;
|
|
|
|
// Page Table Entry for 4 KB Page(goes into the PD)
|
|
typedef union pte_4KB_t {
|
|
uint32_t val;
|
|
struct {
|
|
uint32_t present :1;
|
|
uint32_t read_write :1;
|
|
uint32_t user_supervisor :1;
|
|
uint32_t write_through :1;
|
|
uint32_t cache_disabled :1;
|
|
uint32_t accessed :1;
|
|
uint32_t dirty :1;
|
|
uint32_t pat :1;
|
|
uint32_t global :1;
|
|
uint32_t avail :3;
|
|
uint32_t PB_addr :20;
|
|
} __attribute__ ((packed));
|
|
} pte_4KB_t;
|
|
|
|
// Variables for Page Directory and Page Table, aligned on 4kB boundaries
|
|
extern pde_t page_directory[NUM_PDE] __attribute__((aligned (PAGE_SIZE_4KB)));
|
|
extern pte_4KB_t page_table[NUM_PTE] __attribute__((aligned (PAGE_SIZE_4KB)));
|
|
extern pte_4KB_t page_table_usermap[NUM_PTE] __attribute__((aligned (PAGE_SIZE_4KB)));
|
|
|
|
/* Sets runtime-settable parameters in the GDT entry for the LDT */
|
|
#define SET_LDT_PARAMS(str, addr, lim) \
|
|
do { \
|
|
str.base_31_24 = ((uint32_t)(addr) & 0xFF000000) >> 24; \
|
|
str.base_23_16 = ((uint32_t)(addr) & 0x00FF0000) >> 16; \
|
|
str.base_15_00 = (uint32_t)(addr) & 0x0000FFFF; \
|
|
str.seg_lim_19_16 = ((lim) & 0x000F0000) >> 16; \
|
|
str.seg_lim_15_00 = (lim) & 0x0000FFFF; \
|
|
} while (0)
|
|
|
|
/* Sets runtime parameters for the TSS */
|
|
#define SET_TSS_PARAMS(str, addr, lim) \
|
|
do { \
|
|
str.base_31_24 = ((uint32_t)(addr) & 0xFF000000) >> 24; \
|
|
str.base_23_16 = ((uint32_t)(addr) & 0x00FF0000) >> 16; \
|
|
str.base_15_00 = (uint32_t)(addr) & 0x0000FFFF; \
|
|
str.seg_lim_19_16 = ((lim) & 0x000F0000) >> 16; \
|
|
str.seg_lim_15_00 = (lim) & 0x0000FFFF; \
|
|
} while (0)
|
|
|
|
/* An interrupt descriptor entry (goes into the IDT) */
|
|
typedef union idt_desc_t {
|
|
uint32_t val[2];
|
|
struct {
|
|
uint16_t offset_15_00;
|
|
uint16_t seg_selector;
|
|
uint8_t reserved4;
|
|
uint32_t reserved3 : 1;
|
|
uint32_t reserved2 : 1;
|
|
uint32_t reserved1 : 1;
|
|
uint32_t size : 1;
|
|
uint32_t reserved0 : 1;
|
|
uint32_t dpl : 2;
|
|
uint32_t present : 1;
|
|
uint16_t offset_31_16;
|
|
} __attribute__ ((packed));
|
|
} idt_desc_t;
|
|
|
|
/* The IDT itself (declared in x86_desc.S */
|
|
extern idt_desc_t idt[NUM_VEC];
|
|
/* The descriptor used to load the IDTR */
|
|
extern x86_desc_t idt_desc_ptr;
|
|
|
|
/* Sets runtime parameters for an IDT entry
|
|
* I changed this to only set IDT entry as present when offset is set
|
|
*/
|
|
#define SET_IDT_ENTRY(str, handler) \
|
|
do { \
|
|
str.present = 1; \
|
|
str.offset_31_16 = ((uint32_t)(handler) & 0xFFFF0000) >> 16; \
|
|
str.offset_15_00 = ((uint32_t)(handler) & 0xFFFF); \
|
|
} while (0)
|
|
|
|
/* Load task register. This macro takes a 16-bit index into the GDT,
|
|
* which points to the TSS entry. x86 then reads the GDT's TSS
|
|
* descriptor and loads the base address specified in that descriptor
|
|
* into the task register */
|
|
#define ltr(desc) \
|
|
do { \
|
|
asm volatile ("ltr %w0" \
|
|
: \
|
|
: "r" (desc) \
|
|
: "memory", "cc" \
|
|
); \
|
|
} while (0)
|
|
|
|
/* Load the interrupt descriptor table (IDT). This macro takes a 32-bit
|
|
* address which points to a 6-byte structure. The 6-byte structure
|
|
* (defined as "struct x86_desc" above) contains a 2-byte size field
|
|
* specifying the size of the IDT, and a 4-byte address field specifying
|
|
* the base address of the IDT. */
|
|
#define lidt(desc) \
|
|
do { \
|
|
asm volatile ("lidt (%0)" \
|
|
: \
|
|
: "g" (desc) \
|
|
: "memory" \
|
|
); \
|
|
} while (0)
|
|
|
|
/* Load the local descriptor table (LDT) register. This macro takes a
|
|
* 16-bit index into the GDT, which points to the LDT entry. x86 then
|
|
* reads the GDT's LDT descriptor and loads the base address specified
|
|
* in that descriptor into the LDT register */
|
|
#define lldt(desc) \
|
|
do { \
|
|
asm volatile ("lldt %%ax" \
|
|
: \
|
|
: "a" (desc) \
|
|
: "memory" \
|
|
); \
|
|
} while (0)
|
|
|
|
#endif /* ASM */
|
|
|
|
#endif /* _x86_DESC_H */
|