From edf9e71e2a7b6b89775c29cf28c19c6b89992c25 Mon Sep 17 00:00:00 2001 From: aqua Date: Mon, 28 Mar 2022 20:03:38 +0300 Subject: Initial commit x86 kernel that prints a hello world message to com1 --- arch/i686/include/gdt.h | 60 +++++++++++++++++++++++++++++++++++ arch/i686/include/paging.h | 59 ++++++++++++++++++++++++++++++++++ arch/i686/include/sys/io.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 arch/i686/include/gdt.h create mode 100644 arch/i686/include/paging.h create mode 100644 arch/i686/include/sys/io.h (limited to 'arch/i686/include') diff --git a/arch/i686/include/gdt.h b/arch/i686/include/gdt.h new file mode 100644 index 0000000..6badf84 --- /dev/null +++ b/arch/i686/include/gdt.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +enum Ring { Ring0 = 0x0, Ring1 = 0x1, Ring2 = 0x2, Ring3 = 0x3 }; + +struct __attribute__((packed)) Access { + bool accessed : 1; // if 0, is set by processor when accessed + bool readwrite : 1; // code seg: read toggle; data seg: write toggle + bool direction : 1; // code seg: conforming bit; data seg: direction bit + bool executable : 1; // executable bit + bool segment : 1; // true for code/data; false for gates/tss + enum Ring privilege : 2; // descriptor privilege level + bool present : 1; // true for every active segment +}; +_Static_assert(sizeof(struct Access) == 1); + +static const struct Access null_access = {}; +static const struct Access ktext_access = {.readwrite = true, .executable = true, .segment = true, .present = true}; +static const struct Access kdata_access = {.readwrite = true, .segment = true, .present = true}; + +// Segment Descriptor +// A memory structure (part of a table) that tells the CPU the attributes of a given segment +// |31| | | | | | |24|23|22|21|20|19| | |16|15| | | | | | | 8| 7| | | | | | | 0| +// | base_31_24 | G|DB| | A| lim_19_16 | access | base_23_16 | +// | base_15_0 | limit_15_0 | +// |31| | | | | | | | | | | | | | |16|15| | | | | | | | | | | | | | | 0| +// limit size of segment - 1, either in bytes or in 4KiB chunks (check flags) +// base address of segment +// access +// flags defines the segment chunks and 16/32 bit +struct __attribute__((packed)) SegmentDescriptor_t { + uint16_t limit_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 access; // access byte + uint8_t limit_19_16 : 4; // high bits of segment limit + // flags + bool a : 1; // unused, available for software use + bool rsv : 1; // reserved + bool db : 1; // false => 16-bit seg; true => 32-bit seg + bool granularity : 1; // limit scaled by 4k when set + uint8_t base_31_24; // high bits of segment address +}; +_Static_assert(sizeof(struct SegmentDescriptor_t) == 8); + +void SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access); + +struct __attribute__((packed)) Pointer { + uint16_t limit; + uint32_t base; +}; + +void gdt_install(); + +enum SegmentIndex { + ktextDescriptor = 2 * sizeof(struct SegmentDescriptor_t), + kdataDescriptor = 3 * sizeof(struct SegmentDescriptor_t), +}; diff --git a/arch/i686/include/paging.h b/arch/i686/include/paging.h new file mode 100644 index 0000000..cff0506 --- /dev/null +++ b/arch/i686/include/paging.h @@ -0,0 +1,59 @@ +#pragma once + +// DirectoryEntry +// |31| | | | | | | | | | | | | | | | | | | |11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +// | page table 4-kb aligned address | avail | G| S| | A| C| W| U| R| P| +struct __attribute__((packed)) DirectoryEntry { + unsigned present : 1; // 0: if set, the page is actually in physical memory + unsigned writeable : 1; // 1: if set, the page is read/write; otherwise the page is read-only + unsigned user : 1; // 2: if set, then page can be access by all; otherwise only the supervisor can access it + unsigned writethrough : 1; // 3: if set, write-through caching is enabled; otherwise write-back is enabled instead + unsigned cachedisable : 1; // 4: if set, the page will not be cached + unsigned accessed : 1; // 5: set by the CPU when the page is read from or written to + unsigned dirty : 1; // 6: used to determine whether a page has been written to + unsigned pagesize : 1; // 7: page size == 0 + unsigned global : 1; + unsigned int __available__ : 3; // available to the OS + unsigned int address : 20; +}; +_Static_assert(sizeof(struct DirectoryEntry) == 4); + +// DirectoryEntry4MB +// |31| | | | | | | | |22|21|20| | | | | | |13|12|11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +// | bits 31-22 of address |RS| bits 39-22 of |AT| avail | G|PS| D| A|CD|WT|US|RW| P| +// | |VD| address +struct __attribute__((packed)) DirectoryEntry4MB { + unsigned present : 1; // 0: if set, the page is actually in physical memory + unsigned writeable : 1; // 1: if set, the page is read/write; otherwise the page is read-only + unsigned useraccess : 1; // 2: if set, then page can be access by all; otherwise only the supervisor can access it + unsigned writethrough : 1; // 3: if set, write-through caching is enabled; otherwise write-back is enabled instead + unsigned cachedisable : 1; // 4: if set, the page will not be cached + unsigned accessed : 1; // 5: set by the CPU when the page is read from or written to + unsigned dirty : 1; // 6: used to determine whether a page has been written to + unsigned pagesize : 1; // 7: page size == 1 + unsigned global : 1; // 8: + unsigned __available__ : 3; // 11..9 available to the OS + unsigned pat : 1; // 12: page attribute table + unsigned int address_high : 8; + unsigned rsvd : 1; // 21 + unsigned int address_low : 10; +}; +_Static_assert(sizeof(struct DirectoryEntry4MB) == 4); + +// TableEntry +// |31| | | | | | | | | | | | | | | | | | | |11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +// | page table 4-kb aligned address | avail | G| | D| A| C| W|US|RW| P| +struct __attribute__((packed)) TableEntry { + unsigned present : 1; // if set, the page is actually in physical memory + unsigned writeable : 1; // if set, the page is read/write; otherwise the page is read-only + unsigned user : 1; // if set, then page can be access by all; otherwise only the supervisor can access it + unsigned writethrough : 1; // if set, write-through caching is enabled; otherwise write-back is enabled instead + unsigned cachedisable : 1; // if set, the page will not be cached + unsigned accessed : 1; // set by the CPU when the page is read from or written to + unsigned dirty : 1; // used to determine whether a page has been written to + unsigned pat : 1; // page attribute table? + unsigned global : 1; + unsigned int __available__ : 3; // available to the OS + unsigned int address : 20; +}; +_Static_assert(sizeof(struct TableEntry) == 4); diff --git a/arch/i686/include/sys/io.h b/arch/i686/include/sys/io.h new file mode 100644 index 0000000..74d4950 --- /dev/null +++ b/arch/i686/include/sys/io.h @@ -0,0 +1,79 @@ +#pragma once + +static inline void +outb(unsigned char val, unsigned short port) +{ + asm volatile("outb %0,%1" : : "a"(val), "dN"(port)); +} + +static inline void +outw(unsigned short val, unsigned short port) +{ + asm volatile("outw %0,%1" : : "a"(val), "dN"(port)); +} + +static inline void +outl(unsigned int val, unsigned short port) +{ + asm volatile("outl %0,%1" : : "a"(val), "dN"(port)); +} + +static inline unsigned char +inb(unsigned short port) +{ + unsigned char val; + asm volatile("inb %1,%0" : "=a"(val) : "dN"(port)); + return val; +} + +static inline unsigned short +inw(unsigned short port) +{ + unsigned short val; + asm volatile("inw %1,%0" : "=a"(val) : "dN"(port)); + return val; +} + +static inline unsigned int +inl(unsigned short port) +{ + unsigned int val; + asm volatile("inl %1,%0" : "=a"(val) : "dN"(port)); + return val; +} + +static inline void +outsb(unsigned short port, const void *__buf, unsigned long __n) +{ + asm volatile("cld; rep; outsb" : "+S"(__buf), "+c"(__n) : "d"(port)); +} + +static inline void +outsw(unsigned short port, const void *__buf, unsigned long __n) +{ + asm volatile("cld; rep; outsw" : "+S"(__buf), "+c"(__n) : "d"(port)); +} + +static inline void +outsl(unsigned short port, const void *__buf, unsigned long __n) +{ + asm volatile("cld; rep; outsl" : "+S"(__buf), "+c"(__n) : "d"(port)); +} + +static inline void +insb(unsigned short port, void *__buf, unsigned long __n) +{ + asm volatile("cld; rep; insb" : "+D"(__buf), "+c"(__n) : "d"(port)); +} + +static inline void +insw(unsigned short port, void *__buf, unsigned long __n) +{ + asm volatile("cld; rep; insw" : "+D"(__buf), "+c"(__n) : "d"(port)); +} + +static inline void +insl(unsigned short port, void *__buf, unsigned long __n) +{ + asm volatile("cld; rep; insl" : "+D"(__buf), "+c"(__n) : "d"(port)); +} -- cgit v1.2.1