From c62f52342f6938bfdbbb511324f0393150e6832e Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Jun 2018 01:00:25 +0200 Subject: [PATCH] Add gdt (from SOS) --- gdt.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdt.h | 39 +++++++++++++++ main.c | 2 + types.h | 1 + 4 files changed, 189 insertions(+) create mode 100644 gdt.c create mode 100644 gdt.h diff --git a/gdt.c b/gdt.c new file mode 100644 index 0000000..ff0df71 --- /dev/null +++ b/gdt.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "segment.h" + +#include "gdt.h" + +/** + * The sructure of a segment descriptor. + * + * @see Intel x86 doc, Vol 3, section 3.4.3, figure 3-8. For segment + * types, see section 3.5 + */ +struct x86_segment_descriptor { + /* Lowest dword */ + uint16_t limit_15_0; /* Segment limit, bits 15..0 */ + uint16_t base_paged_addr_15_0; /* Base address, bits 15..0 */ + + /* Highest dword */ + uint8_t base_paged_addr_23_16; /* Base address bits 23..16 */ + uint8_t segment_type : 4; /* Section 3.4.3.1 (code/data) + and 3.5 (system) of Intel x86 vol 3 */ + uint8_t descriptor_type : 1; /* 0=system, 1=Code/Data */ + uint8_t dpl : 2; + uint8_t present : 1; + + uint8_t limit_19_16 : 4; /* Segment limit, bits 19..16 */ + uint8_t custom : 1; + uint8_t zero : 1; + uint8_t op_size : 1; /* 0=16bits instructions, 1=32bits */ + uint8_t granularity : 1; /* 0=limit in bytes, 1=limit in pages */ + + uint8_t base_paged_addr_31_24; /* Base address bits 31..24 */ +} __attribute__((packed, aligned(8))); + +/** + * The GDT register, which stores the address and size of the + * GDT. + * + * @see Intel x86 doc vol 3, section 2.4, figure 2-4; and section + * 3.5.1 + */ +struct x86_gdt_register { + /* The maximum GDT offset allowed to access an entry in the GDT */ + uint16_t limit; + + /* This is not exactly a "virtual" address, ie an adddress such as + those of instructions and data; this is a "linear" address, ie an + address in the paged memory. However, in SOS we configure the + segmented memory as a "flat" space: the 0-4GB segment-based (ie + "virtual") addresses directly map to the 0-4GB paged memory (ie + "linear"), so that the "linear" addresses are numerically equal + to the "virtual" addresses: this base_addr will thus be the same + as the address of the gdt array */ + uint32_t base_addr; +} __attribute__((packed, aligned(8))); + +/** + * Helper macro that builds a Segment descriptor for the virtual + * 0..4GB addresses to be mapped to the linear 0..4GB linear + * addresses. + */ +#define BUILD_GDTE(descr_privilege_level, is_code) \ + ((struct x86_segment_descriptor){ \ + .limit_15_0 = 0xffff, \ + .base_paged_addr_15_0 = 0, \ + .base_paged_addr_23_16 = 0, \ + .segment_type = \ + ((is_code) ? 0xb : 0x3), /* With descriptor_type (below) = 1 (code/data), \ + * see Figure 3-1 of section 3.4.3.1 in Intel \ + * x86 vol 3: \ + * - Code (bit 3 = 1): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Readable \ + * bit 2: 0=Non-Conforming \ + * - Data (bit 3 = 0): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Writable \ + * bit 2: 0=Expand up (stack-related) \ + * For Conforming/non conforming segments, see \ + * Intel x86 Vol 3 section 4.8.1.1 \ + */ \ + .descriptor_type = 1, /* 1=Code/Data */ \ + .dpl = ((descr_privilege_level)&0x3), \ + .present = 1, \ + .limit_19_16 = 0xf, \ + .custom = 0, \ + .op_size = 1, /* 32 bits instr/data */ \ + .granularity = 1 /* limit is in 4kB Pages */ \ + }) + +/** The actual GDT */ +static struct x86_segment_descriptor gdt[] = { + [SOS_SEG_NULL] = + (struct x86_segment_descriptor){ + 0, + }, + [SOS_SEG_KCODE] = BUILD_GDTE(0, 1), + [SOS_SEG_KDATA] = BUILD_GDTE(0, 0), +}; + +int gdtSetup(void) +{ + struct x86_gdt_register gdtr; + + /* Address of the GDT */ + gdtr.base_addr = (uint32_t)gdt; + + /* The limit is the maximum offset in bytes from the base address of + the GDT */ + gdtr.limit = sizeof(gdt) - 1; + + /* Commit the GDT into the CPU, and update the segment + registers. The CS register may only be updated with a long jump + to an absolute address in the given segment (see Intel x86 doc + vol 3, section 4.8.1). */ + asm volatile("lgdt %0 \n\ + ljmp %1,$1f \n\ + 1: \n\ + movw %2, %%ax \n\ + movw %%ax, %%ss \n\ + movw %%ax, %%ds \n\ + movw %%ax, %%es \n\ + movw %%ax, %%fs \n\ + movw %%ax, %%gs" + : + : "m"(gdtr), "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE)), + "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA)) + : "memory", "eax"); + + return 0; +} diff --git a/gdt.h b/gdt.h new file mode 100644 index 0000000..8957891 --- /dev/null +++ b/gdt.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_GDT_H_ +#define _SOS_GDT_H_ + +/** + * @file gdt.h + * + * The routines that manage the GDT, the table that maps the virtual + * addresses (data/instructions, segment-relative), to "linear" + * addresses (ie paged-memory). In SOS/x86, we use a "flat" virtual + * space, ie the virtual and linear spaces are equivalent. + * + * @see Intel x86 doc vol 3, chapter 3 + */ + +/** + * Configure the virtual space as a direct mapping to the linear + * address space (ie "flat" virtual space). + */ +int gdtSetup(void); + +#endif /* _SOS_GDT_H_ */ diff --git a/main.c b/main.c index 478839d..3850668 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,4 @@ +#include "gdt.h" #include "idt.h" #include "io.h" #include "irq.h" @@ -36,6 +37,7 @@ void kmain() const short color = GREEN; clearScreen(BLACK); printString("Setting up IDT", color, BLACK, 0, 0); + gdtSetup(); idtSetup(); printString("Setting up IRQ", color, BLACK, 0, 1); irqSetup(); diff --git a/types.h b/types.h index 5601972..5f664c5 100644 --- a/types.h +++ b/types.h @@ -35,4 +35,5 @@ typedef __u64 uint64_t; typedef __u64 u_int64_t; typedef __s64 int64_t; +typedef enum { FALSE=0, TRUE } bool_t; #define NULL ((void*)0)