diff --git a/.bochsrc b/.bochsrc index 10c2e4f..4808a27 100644 --- a/.bochsrc +++ b/.bochsrc @@ -11,6 +11,7 @@ clock: sync=realtime ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0-master: type=cdrom, path="k.iso", status=inserted boot: cdrom +magic_break: enabled=1 # write serial logs to stdout com1: enabled=1, mode=file, dev=/dev/stdout diff --git a/k/Makefile b/k/Makefile index 52aacbd..02ba1c9 100644 --- a/k/Makefile +++ b/k/Makefile @@ -30,7 +30,8 @@ OBJS = \ libvga.o \ list.o \ memory.o \ - serial.o + serial.o \ + gdt.o DEPS = $(OBJS:.o=.d) diff --git a/k/gdt.c b/k/gdt.c new file mode 100644 index 0000000..c8e0182 --- /dev/null +++ b/k/gdt.c @@ -0,0 +1,122 @@ +#include "gdt.h" + +static struct gdt gdt = { 0 }; + +static void create_kernel_ds() +{ + struct gdt_entry *entry = gdt.entries + KERNEL_DS_INDEX; + + uint32_t limit = 0xfffff; + uint32_t base = 0x0; + + entry->granularity = 1; + entry->db = 1; + entry->l = 0; + entry->available = 0; + + entry->present = 1; + entry->desc_priv = 0; + entry->desc_type = 1; + entry->ex = 0; + entry->dc = 0; + entry->rw = 1; + entry->accessed = 0; + + entry->limit_1 = limit & 0xffff; + entry->limit_2 = (limit >> 16) & 0xf; + + entry->base_1 = base & 0xffff; + entry->base_2 = (base >> 16) & 0xff; + entry->base_3 = (base >> 24) & 0xff; +} + +static void create_kernel_cs() +{ + struct gdt_entry *entry = gdt.entries + KERNEL_CS_INDEX; + + uint32_t limit = 0xfffff; + uint32_t base = 0x0; + + entry->granularity = 1; + entry->db = 1; + entry->l = 0; + entry->available = 0; + + entry->present = 1; + entry->desc_priv = 0; + entry->desc_type = 1; + entry->ex = 1; + entry->dc = 0; + entry->rw = 1; + entry->accessed = 0; + + entry->limit_1 = limit & 0xffff; + entry->limit_2 = (limit >> 16) & 0xf; + + entry->base_1 = base & 0xffff; + entry->base_2 = (base >> 16) & 0xff; + entry->base_3 = (base >> 24) & 0xff; +} + +static void create_gdt() +{ + create_kernel_ds(); + create_kernel_cs(); +} + +static void load_gdt() +{ + struct gdt_r gdtr; + gdtr.addr = (uint32_t)&gdt; + gdtr.limit = GDT_SIZE - 1; + + asm volatile("lgdt %0\n" + : + : "m" (gdtr) + : "memory"); +} + +static void load_ds() +{ + struct segment_selector selector; + selector.index = KERNEL_DS_INDEX; + selector.table_indicator = 0; + selector.rpl = 0; + + asm volatile("movw %0, %%ax\n" + "movw %%ax, %%ds\n" + "movw %%ax, %%fs\n" + "movw %%ax, %%gs\n" + "movw %%ax, %%ss\n" + : + : "m" (selector) + : "ax"); +} + +static void load_cs() +{ + struct segment_selector selector; + selector.index = KERNEL_CS_INDEX; + selector.table_indicator = 0; + selector.rpl = 0; + + asm volatile("pushl %0\n" + "pushl $1f\n" + "lret\n" + "1:\n" + : + : "m" (selector)); +} + +static void reload_segment_selectors() +{ + load_ds(); + load_cs(); +} + +void init_gdt() +{ + create_gdt(); + load_gdt(); + reload_segment_selectors(); +} diff --git a/k/gdt.h b/k/gdt.h new file mode 100644 index 0000000..95028f7 --- /dev/null +++ b/k/gdt.h @@ -0,0 +1,52 @@ +#ifndef GDT_H +#define GDT_H + +#include + +#define GDT_NB_ENTRIES 3 +#define GDT_SIZE (GDT_NB_ENTRIES * sizeof(struct gdt_entry)) + +#define KERNEL_CS_INDEX 1 +#define KERNEL_DS_INDEX 2 + +struct gdt_entry +{ + uint16_t limit_1 : 16; + uint16_t base_1 : 16; + uint8_t base_2 : 8; + uint8_t accessed : 1; + uint8_t rw : 1; + uint8_t dc : 1; + uint8_t ex : 1; + uint8_t desc_type : 1; + uint8_t desc_priv : 2; + uint8_t present : 1; + uint8_t limit_2 : 4; + uint8_t available : 1; + uint8_t l : 1; + uint8_t db : 1; + uint8_t granularity : 1; + uint8_t base_3 : 8; +} __attribute__ ((packed)); + +struct gdt +{ + struct gdt_entry entries[GDT_NB_ENTRIES]; +}; + +struct gdt_r +{ + uint16_t limit; + uint32_t addr; +} __attribute__ ((packed)); + +struct segment_selector +{ + uint8_t rpl : 2; + uint8_t table_indicator : 1; + uint16_t index : 13; +} __attribute__ ((packed)); + +void init_gdt(); + +#endif /* !GDT_H */ diff --git a/k/k.c b/k/k.c index 3fce470..a66b1e0 100644 --- a/k/k.c +++ b/k/k.c @@ -30,6 +30,7 @@ static void k_init(void) { init_serial(); + init_gdt(); } void k_main(unsigned long magic, multiboot_info_t *info) diff --git a/k/serial.c b/k/serial.c index d18469c..570b7fe 100644 --- a/k/serial.c +++ b/k/serial.c @@ -24,12 +24,12 @@ void init_serial(void) int write(const char *buf, size_t count) { - int sent; + size_t sent; for(sent = 0; sent < count; ++sent) { u8 line_status = inb(COM1 + 5); - if (!line_status & EMPTY_TRANSMITTER) + if (!(line_status & EMPTY_TRANSMITTER)) break; outb(COM1, buf[sent]); }