From c4fcc92183c55db868d0d6ae53e6009fb2e53ee5 Mon Sep 17 00:00:00 2001 From: aqua Date: Sat, 29 Oct 2022 11:26:44 +0300 Subject: makefile: add i686/arch.a target --- Makefile | 26 ++++++------ arch/i686/boot.S | 89 ----------------------------------------- arch/i686/gdt.c | 20 --------- arch/i686/include/gdt.h | 55 ------------------------- arch/i686/include/idt.h | 18 --------- arch/i686/include/paging.h | 59 --------------------------- arch/i686/include/sys/control.h | 9 ----- arch/i686/include/sys/cpuid.h | 35 ---------------- arch/i686/include/sys/io.h | 79 ------------------------------------ arch/i686/init.s | 42 ------------------- arch/i686/lgdt.c | 35 ---------------- arch/i686/lidt.c | 46 --------------------- arch/i686/linker.ld | 54 ------------------------- arch/i686/macros.s | 25 ------------ arch/i686/meson.build | 9 ----- arch/i686/test/gdt.c | 20 --------- arch/i686/toolchain.ini | 18 --------- i686/Makefile | 17 ++++++++ i686/boot.S | 89 +++++++++++++++++++++++++++++++++++++++++ i686/gdt.c | 20 +++++++++ i686/gdt.h | 55 +++++++++++++++++++++++++ i686/idt.h | 18 +++++++++ i686/init.s | 42 +++++++++++++++++++ i686/lgdt.c | 35 ++++++++++++++++ i686/lidt.c | 46 +++++++++++++++++++++ i686/linker.ld | 54 +++++++++++++++++++++++++ i686/macros.s | 25 ++++++++++++ i686/meson.build | 9 +++++ i686/paging.h | 59 +++++++++++++++++++++++++++ i686/sys/control.h | 9 +++++ i686/sys/cpuid.h | 35 ++++++++++++++++ i686/sys/io.h | 79 ++++++++++++++++++++++++++++++++++++ i686/test/gdt.c | 20 +++++++++ i686/toolchain.ini | 18 +++++++++ i686/toolchain.mk | 2 + lib/Makefile | 13 ++++++ lib/targets.mk | 6 --- rules.mk | 13 ++++++ 38 files changed, 670 insertions(+), 633 deletions(-) delete mode 100644 arch/i686/boot.S delete mode 100644 arch/i686/gdt.c delete mode 100644 arch/i686/include/gdt.h delete mode 100644 arch/i686/include/idt.h delete mode 100644 arch/i686/include/paging.h delete mode 100644 arch/i686/include/sys/control.h delete mode 100644 arch/i686/include/sys/cpuid.h delete mode 100644 arch/i686/include/sys/io.h delete mode 100644 arch/i686/init.s delete mode 100644 arch/i686/lgdt.c delete mode 100644 arch/i686/lidt.c delete mode 100644 arch/i686/linker.ld delete mode 100644 arch/i686/macros.s delete mode 100644 arch/i686/meson.build delete mode 100644 arch/i686/test/gdt.c delete mode 100644 arch/i686/toolchain.ini create mode 100644 i686/Makefile create mode 100644 i686/boot.S create mode 100644 i686/gdt.c create mode 100644 i686/gdt.h create mode 100644 i686/idt.h create mode 100644 i686/init.s create mode 100644 i686/lgdt.c create mode 100644 i686/lidt.c create mode 100644 i686/linker.ld create mode 100644 i686/macros.s create mode 100644 i686/meson.build create mode 100644 i686/paging.h create mode 100644 i686/sys/control.h create mode 100644 i686/sys/cpuid.h create mode 100644 i686/sys/io.h create mode 100644 i686/test/gdt.c create mode 100644 i686/toolchain.ini create mode 100644 lib/Makefile delete mode 100644 lib/targets.mk create mode 100644 rules.mk diff --git a/Makefile b/Makefile index d7caeea..ebc8d64 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,10 @@ MAKE = make -TARGET = i686 -include ${TARGET}/toolchain.mk - -CCFLAGS += -Ilib -I. - -all: libk.a +ARCH = i686 +include ${ARCH}/toolchain.mk info: @echo "this is the all target" - @echo "TARGET ${TARGET}" + @echo "ARCH ${ARCH}" @echo "BUILD ${BUILD}" @echo " MAKE ${MAKE}" @${MAKE} --version | head -n1 @@ -17,12 +13,14 @@ info: @echo " LD ${LD} ${LDFLAGS}" @${LD} --version | head -n1 -clean: - @rm -rf ${libk,OBJS} +all: lib/libk.a ${ARCH}/arch.a -.SUFFIXES: .c .o -.c.o: - @echo ' CC $^' - @$(CC) $(CCFLAGS) -c -o $@ $^ +lib/libk.a: + ${MAKE} ARCH=${ARCH} -C lib libk.a +i686/arch.a: + ${MAKE} ARCH=${ARCH} -C i686 arch.a + +clean: + ${MAKE} ARCH=${ARCH} -C lib clean + ${MAKE} ARCH=${ARCH} -C ${ARCH} clean -include lib/targets.mk diff --git a/arch/i686/boot.S b/arch/i686/boot.S deleted file mode 100644 index 1eea9a3..0000000 --- a/arch/i686/boot.S +++ /dev/null @@ -1,89 +0,0 @@ -#define ASM_FILE -#include -#include "macros.s" - -/* Declare a multiboot header that marks this program as a kernel */ -.section .multiboot.header, "a" -header_begin: -.align 8 - .int MULTIBOOT2_HEADER_MAGIC - .int MULTIBOOT_ARCHITECTURE_I386 - .int header_end - header_begin - .int -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (header_end - header_begin)) - -.align 8 -header_info_begin: - .short MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST - .short 0 # flags - .int header_info_end - header_info_begin - .int MULTIBOOT_TAG_TYPE_MMAP -header_info_end: - -.align 8 - .short MULTIBOOT_HEADER_TAG_END - .short 0 - .int 8 -header_end: - -.section .multiboot.pages, "aw", @nobits -.align 4096 -bootstrap_page0: - .skip 1024 * 4 - -.section .multiboot.text, "ax" -.extern k_pagedir -.extern k_stack -.extern k_init - -#.global __vaddr_base -#.set __vaddr_base, 0xc0000000 -#.global __vaddr_offset -.set __vaddr_offset, 0xc0000000 - 0x2000 - -.global _start -.type _start, @function -_start: - cli - - # check multiboot header - cmp $MULTIBOOT2_BOOTLOADER_MAGIC, %eax - jz c - hlt - -c: mov $k_stack - __vaddr_offset, %esp - - push %ebx # pointer to multiboot structure - call __multiboot2 - - # mmap multiboot section into bootstrap page - movl $bootstrap_page0, %edi - movl $1024, %ecx - mmap_section __multiboot_begin, __multiboot_end, PAGE_RW - mmap_section (__text_begin - __vaddr_offset), (__text_end - __vaddr_offset), PAGE_RO - mmap_section (__rodata_begin - __vaddr_offset), (__rodata_end - __vaddr_offset), PAGE_RO - mmap_section (__bss_begin - __vaddr_offset), (__bss_end - __vaddr_offset), PAGE_RW - mmap_section (__data_begin - __vaddr_offset), (__data_end - __vaddr_offset), PAGE_RW - - # mmap all the other section into k_ptable0x300 - movl $(k_ptable0x300 - __vaddr_offset), %edi - movl $1024, %ecx - mmap_section (__text_begin - __vaddr_offset), (__text_end - __vaddr_offset), PAGE_RO - mmap_section (__rodata_begin - __vaddr_offset), (__rodata_end - __vaddr_offset), PAGE_RO - mmap_section (__bss_begin - __vaddr_offset), (__bss_end - __vaddr_offset), PAGE_RW - mmap_section (__data_begin - __vaddr_offset), (__data_end - __vaddr_offset), PAGE_RW - - movl $(bootstrap_page0 + PAGE_RW), k_pagedir - __vaddr_offset + 0 * 4 - movl $(k_ptable0x300 - __vaddr_offset + PAGE_RW), k_pagedir - __vaddr_offset + 768 * 4 - - movl $(k_pagedir - __vaddr_offset), %ecx - movl %ecx, %cr3 - - # enable paging and the write-protect bit - movl %cr0, %ecx - orl $0x80010000, %ecx - movl %ecx, %cr0 - - # jump to higher half with an absolute jump - lea (k_init), %ecx - jmp *%ecx - diff --git a/arch/i686/gdt.c b/arch/i686/gdt.c deleted file mode 100644 index fe0bfc9..0000000 --- a/arch/i686/gdt.c +++ /dev/null @@ -1,20 +0,0 @@ -#include - -void -SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access) -{ - self->base_15_0 = base & 0xffff; - self->base_23_16 = (base >> 16) & 0xff; - self->base_31_24 = (base >> 24) & 0xff; - - self->limit_15_0 = (limit <= 0xffff) ? (limit & 0xffff) : ((limit >> 12) & 0xffff); - self->limit_19_16 = (limit <= 0xffff) ? 0 : ((limit >> 28) & 0xf); - - self->access = access; - - self->a = 0; - self->rsv = 0; - self->db = (limit > 0xffff) ? 1 : 0; - self->granularity = (limit > 0) ? 1 : 0; -} - diff --git a/arch/i686/include/gdt.h b/arch/i686/include/gdt.h deleted file mode 100644 index 9148c3d..0000000 --- a/arch/i686/include/gdt.h +++ /dev/null @@ -1,55 +0,0 @@ -#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); - -void gdt_install(); - -enum SegmentIndex { - ktextDescriptor = 2 * sizeof(struct SegmentDescriptor_t), - kdataDescriptor = 3 * sizeof(struct SegmentDescriptor_t), -}; diff --git a/arch/i686/include/idt.h b/arch/i686/include/idt.h deleted file mode 100644 index 22dc6de..0000000 --- a/arch/i686/include/idt.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -struct interrupt_frame { - uint32_t ip; - uint32_t cs; - uint32_t flags; - uint32_t sp; - uint32_t ss; -}; - -void abort_handler(struct interrupt_frame *frame); -void interrupt_handler(struct interrupt_frame *frame); -void interrupt_handler_e(struct interrupt_frame *frame, uint32_t error); -void syscall_handler(struct interrupt_frame *frame); - -void idt_install(); diff --git a/arch/i686/include/paging.h b/arch/i686/include/paging.h deleted file mode 100644 index cff0506..0000000 --- a/arch/i686/include/paging.h +++ /dev/null @@ -1,59 +0,0 @@ -#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/control.h b/arch/i686/include/sys/control.h deleted file mode 100644 index a40a67f..0000000 --- a/arch/i686/include/sys/control.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -static void -abort() -{ - asm volatile(R"(cli -h: hlt -jmp h)"); -} diff --git a/arch/i686/include/sys/cpuid.h b/arch/i686/include/sys/cpuid.h deleted file mode 100644 index f2ffe37..0000000 --- a/arch/i686/include/sys/cpuid.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -struct CPUVersion { - unsigned int stepping : 4; - unsigned int model : 4; - unsigned int family : 4; - unsigned int type : 2; - unsigned int __unused_1 : 2; - unsigned int model_ex : 4; - unsigned int family_ex : 8; - unsigned int __unused_2 : 4; -} __attribute__((packed, aligned(__alignof__(unsigned int)))); -_Static_assert(sizeof(struct CPUVersion) == sizeof(unsigned int)); - -unsigned int -family(const struct CPUVersion v) -{ - if (v.family == 0x0f) return v.family + v.family_ex; - else - return v.family; -} - -unsigned int -model(const struct CPUVersion v) -{ - switch (v.family) { - case 0x06: - case 0x0f: - return ((unsigned int)v.model_ex << 4) | v.model; - default: - return v.model; - } -} diff --git a/arch/i686/include/sys/io.h b/arch/i686/include/sys/io.h deleted file mode 100644 index 74d4950..0000000 --- a/arch/i686/include/sys/io.h +++ /dev/null @@ -1,79 +0,0 @@ -#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)); -} diff --git a/arch/i686/init.s b/arch/i686/init.s deleted file mode 100644 index 92710df..0000000 --- a/arch/i686/init.s +++ /dev/null @@ -1,42 +0,0 @@ -.section .stack, "aw", @nobits -.global k_stack -.align 16 /* Stack on x86 must be 16-byte aligned according to System V ABI */ -k_stack_bottom: - .skip 16 * 1024 /* 16 kByte */ -k_stack: - -.section .pages, "aw", @nobits -.align 4096 -.global k_pagedir -k_pagedir: .skip 1024 * 4 -.global k_ptable0x300 -k_ptable0x300: .skip 1024 * 4 - -.section .text -.global k_init -.extern kmain -k_init: - # kernel entry point, higher half - - # unmap the identity mapping as its no longer necessary - movl $0, k_pagedir + 0 * 4 - mov %cr3, %ecx # reload cr3 to force a TLB flush - mov %ecx, %cr3 - - # zero out the stack - mov $4096, %ecx # loop counter - mov $k_stack_bottom, %edi # start from the bottom - xor %edx, %edx # clear %edx -1: movl %edx, (%edi) # store %edx into address in %edi - addl $4, %edi # point to next address - loop 1b # loop according to %ecx - - mov $k_stack, %esp # point stack pointer to the stack - - call kmain - - /* If the system has nothing more to do, put it in an infinite loop */ - cli # disable interrupts -h: hlt # wait for interrupt - jmp h # continue waiting for interrupt - diff --git a/arch/i686/lgdt.c b/arch/i686/lgdt.c deleted file mode 100644 index 2be5d30..0000000 --- a/arch/i686/lgdt.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -struct __attribute__((packed)) Pointer { - uint16_t limit; - uint32_t base; -}; - -static struct SegmentDescriptor_t segments[8] __attribute__((aligned(32))); - -void -gdt_install() -{ - SegmentDescriptor(&segments[0], 0, 0, 0); // null segment - SegmentDescriptor(&segments[2], 0, 0xffffffff, 0x9a); // ktext - SegmentDescriptor(&segments[3], 0, 0xffffffff, 0x92); // kdata - - const struct Pointer ptr = {.limit = sizeof(segments) - 1, .base = (unsigned)&segments}; - asm volatile("lgdt (%0)" : : "a"(&ptr)); - - // load the kernel data segment - asm volatile(R"(mov %0, %%ds - mov %0, %%es - mov %0, %%fs - mov %0, %%gs - mov %0, %%ss -)" - : - : "ax"(kdataDescriptor)); - - // load the kernel code segment - asm volatile(R"(ljmp %0, $1f - 1:)" - : - : "i"(ktextDescriptor)); -} diff --git a/arch/i686/lidt.c b/arch/i686/lidt.c deleted file mode 100644 index efbade3..0000000 --- a/arch/i686/lidt.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -struct __attribute__((packed)) Pointer { - uint16_t limit; - uint32_t base; -}; - -enum Type { - Null = 0, - Intr = 0b10001110, // 32-bit interrupt -}; - -struct __attribute__((packed)) Gate_t { - uint16_t offset_15_0; // segment offset low - uint16_t selector; // code segment selector - uint8_t __unused; // unused in protected mode - uint8_t type; // interrupt type - uint16_t offset_31_16; // segment offset high -}; -_Static_assert(sizeof(struct Gate_t) == 8); - -void -Gate(struct Gate_t *entry, void *f, uint16_t selector) -{ - uint32_t f_addr = (uint32_t)f; - entry->offset_15_0 = f_addr & 0xffff; - entry->offset_31_16 = (f_addr >> 16) & 0xffff; - entry->selector = selector; - entry->__unused = 0; - entry->type = Intr; -} - -static struct Gate_t interrupt_table[256] __attribute((aligned(4096))); - -void -idt_install() -{ - for (int i = 0; i <= 0x2f; ++i) Gate(&interrupt_table[i], &interrupt_handler, 0x10); - Gate(&interrupt_table[0x80], &abort_handler, 0x10); - - const struct Pointer ptr = {.limit = sizeof(interrupt_table) - 1, .base = (unsigned)&interrupt_table}; - asm volatile("lidt (%0)" : : "a"(&ptr)); - - asm volatile("sti"); -} diff --git a/arch/i686/linker.ld b/arch/i686/linker.ld deleted file mode 100644 index 61a3be9..0000000 --- a/arch/i686/linker.ld +++ /dev/null @@ -1,54 +0,0 @@ -ENTRY(_start) -OUTPUT_FORMAT(elf32-i386) - -MULTIBOOT_SIZE = 0x2000; -VADDR_BASE = 0xc0000000; - -SECTIONS -{ - /* First put the multiboot header, as it is required to be put very early in the image or the bootloader won't * - * recognize the file format. * - * Once the MMU is set up, this section is no longer needed and should be unmapped. */ - . = 0; - .bootstrap : { - . = ALIGN(8); - __multiboot_begin = .; - KEEP(*(.multiboot.header)) - KEEP(*(.multiboot.text)) - KEEP(*(.multiboot.pages)) - __multiboot_end = .; - } - - . = VADDR_BASE; - - .text ALIGN(4K) : AT(ADDR(.text) - VADDR_BASE + MULTIBOOT_SIZE) { - __text_begin = .; - *(.text*) - __text_end = .; - } - - /* Read-only data. */ - .rodata ALIGN(4K) : AT(ADDR(.rodata) - VADDR_BASE + MULTIBOOT_SIZE) { - __rodata_begin = .; - *(.constinit) - *(.rodata*) - __rodata_end = .; - } - - /* Read-write data (uninitialized) and stack */ - .bss ALIGN(4K) : AT(ADDR(.bss) - VADDR_BASE + MULTIBOOT_SIZE) { - __bss_begin = .; - *(.stack) - *(.pages) - *(.bss*) - __bss_end = .; - } - - /* Read-write data (initialized) */ - .data ALIGN(4K) : AT(ADDR(.data) - VADDR_BASE + MULTIBOOT_SIZE) { - __data_begin = .; - *(.init) - *(.data) - __data_end = .; - } -} diff --git a/arch/i686/macros.s b/arch/i686/macros.s deleted file mode 100644 index a9b8b4d..0000000 --- a/arch/i686/macros.s +++ /dev/null @@ -1,25 +0,0 @@ -.set PAGE_RO, 0x001 -.set PAGE_RW, 0x003 -/* write section to page table macro - * - * Registers used: - * %ecx: loop counter [ set to $1024 ] - * %edx: temporary - * %esi: current page being mapped - * %edi: page entry [ set to $page_addr ] - */ -.macro mmap_section begin, end, access - mov $\begin, %esi # from $begin -1: cmpl $\end, %esi # until $end - jge 2f - - movl %esi, %edx - orl $\access, %edx - movl %edx, (%edi) - - addl $4096, %esi # move to next page - addl $4, %edi # size of page entry is 4 bytes - loop 1b # loop according to %ecx -2: -.endm - diff --git a/arch/i686/meson.build b/arch/i686/meson.build deleted file mode 100644 index f6bed8e..0000000 --- a/arch/i686/meson.build +++ /dev/null @@ -1,9 +0,0 @@ -arch = declare_dependency( - sources: ['boot.S', 'init.s', - 'gdt.c', 'lgdt.c', 'lidt.c' - ], - include_directories: 'include', - compile_args: '-mgeneral-regs-only' -) - -test('GDT', executable('gdt', ['test/gdt.c', 'gdt.c'], include_directories: 'include', native: true)) diff --git a/arch/i686/test/gdt.c b/arch/i686/test/gdt.c deleted file mode 100644 index 2947b42..0000000 --- a/arch/i686/test/gdt.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "gdt.h" -#include -#include - -int -main() -{ - assert(*(uint8_t *)&null_access == 0x00); - assert(*(uint8_t *)&ktext_access == 0x9a); - assert(*(uint8_t *)&kdata_access == 0x92); - - struct SegmentDescriptor_t d; - SegmentDescriptor(&d, 0, 0, 0); - assert(*(uint64_t *)&d == 0); - - assert(ktextDescriptor == 0x10); - assert(kdataDescriptor == 0x18); - - return EXIT_SUCCESS; -} diff --git a/arch/i686/toolchain.ini b/arch/i686/toolchain.ini deleted file mode 100644 index 5114cfe..0000000 --- a/arch/i686/toolchain.ini +++ /dev/null @@ -1,18 +0,0 @@ -[constants] -arch = 'i686' - -[host_machine] -system = 'none' -cpu_family = 'x86' -cpu = 'i686' -endian = 'little' - -[binaries] -c = 'i686-elf-gcc' -ar = 'i686-elf-ar' -strip = 'i686-elf-strip' - -[built-in options] -c_args = ['-ffreestanding'] -c_link_args = ['-nostdlib'] - diff --git a/i686/Makefile b/i686/Makefile new file mode 100644 index 0000000..52295a8 --- /dev/null +++ b/i686/Makefile @@ -0,0 +1,17 @@ +include ../${ARCH}/toolchain.mk +include ../rules.mk + +CCFLAGS += -I../grub/include + +all: arch.a + +arch,SRCS = boot.S init.s \ + gdt.c lgdt.c \ + lidt.c +arch,OBJS = $(filter %.o,$(arch,SRCS:%.S=%.o) $(arch,SRCS:%.s=%.o) $(arch,SRCS:%.c=%.o)) +arch.a: ${arch,OBJS} + @echo ' AR $@' + @${AR} ${ARFLAGS} $@ $^ + +clean: + @rm -rf ${arch,OBJS} diff --git a/i686/boot.S b/i686/boot.S new file mode 100644 index 0000000..1eea9a3 --- /dev/null +++ b/i686/boot.S @@ -0,0 +1,89 @@ +#define ASM_FILE +#include +#include "macros.s" + +/* Declare a multiboot header that marks this program as a kernel */ +.section .multiboot.header, "a" +header_begin: +.align 8 + .int MULTIBOOT2_HEADER_MAGIC + .int MULTIBOOT_ARCHITECTURE_I386 + .int header_end - header_begin + .int -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (header_end - header_begin)) + +.align 8 +header_info_begin: + .short MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST + .short 0 # flags + .int header_info_end - header_info_begin + .int MULTIBOOT_TAG_TYPE_MMAP +header_info_end: + +.align 8 + .short MULTIBOOT_HEADER_TAG_END + .short 0 + .int 8 +header_end: + +.section .multiboot.pages, "aw", @nobits +.align 4096 +bootstrap_page0: + .skip 1024 * 4 + +.section .multiboot.text, "ax" +.extern k_pagedir +.extern k_stack +.extern k_init + +#.global __vaddr_base +#.set __vaddr_base, 0xc0000000 +#.global __vaddr_offset +.set __vaddr_offset, 0xc0000000 - 0x2000 + +.global _start +.type _start, @function +_start: + cli + + # check multiboot header + cmp $MULTIBOOT2_BOOTLOADER_MAGIC, %eax + jz c + hlt + +c: mov $k_stack - __vaddr_offset, %esp + + push %ebx # pointer to multiboot structure + call __multiboot2 + + # mmap multiboot section into bootstrap page + movl $bootstrap_page0, %edi + movl $1024, %ecx + mmap_section __multiboot_begin, __multiboot_end, PAGE_RW + mmap_section (__text_begin - __vaddr_offset), (__text_end - __vaddr_offset), PAGE_RO + mmap_section (__rodata_begin - __vaddr_offset), (__rodata_end - __vaddr_offset), PAGE_RO + mmap_section (__bss_begin - __vaddr_offset), (__bss_end - __vaddr_offset), PAGE_RW + mmap_section (__data_begin - __vaddr_offset), (__data_end - __vaddr_offset), PAGE_RW + + # mmap all the other section into k_ptable0x300 + movl $(k_ptable0x300 - __vaddr_offset), %edi + movl $1024, %ecx + mmap_section (__text_begin - __vaddr_offset), (__text_end - __vaddr_offset), PAGE_RO + mmap_section (__rodata_begin - __vaddr_offset), (__rodata_end - __vaddr_offset), PAGE_RO + mmap_section (__bss_begin - __vaddr_offset), (__bss_end - __vaddr_offset), PAGE_RW + mmap_section (__data_begin - __vaddr_offset), (__data_end - __vaddr_offset), PAGE_RW + + movl $(bootstrap_page0 + PAGE_RW), k_pagedir - __vaddr_offset + 0 * 4 + movl $(k_ptable0x300 - __vaddr_offset + PAGE_RW), k_pagedir - __vaddr_offset + 768 * 4 + + movl $(k_pagedir - __vaddr_offset), %ecx + movl %ecx, %cr3 + + # enable paging and the write-protect bit + movl %cr0, %ecx + orl $0x80010000, %ecx + movl %ecx, %cr0 + + # jump to higher half with an absolute jump + lea (k_init), %ecx + jmp *%ecx + diff --git a/i686/gdt.c b/i686/gdt.c new file mode 100644 index 0000000..c0898f3 --- /dev/null +++ b/i686/gdt.c @@ -0,0 +1,20 @@ +#include "gdt.h" + +void +SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access) +{ + self->base_15_0 = base & 0xffff; + self->base_23_16 = (base >> 16) & 0xff; + self->base_31_24 = (base >> 24) & 0xff; + + self->limit_15_0 = (limit <= 0xffff) ? (limit & 0xffff) : ((limit >> 12) & 0xffff); + self->limit_19_16 = (limit <= 0xffff) ? 0 : ((limit >> 28) & 0xf); + + self->access = access; + + self->a = 0; + self->rsv = 0; + self->db = (limit > 0xffff) ? 1 : 0; + self->granularity = (limit > 0) ? 1 : 0; +} + diff --git a/i686/gdt.h b/i686/gdt.h new file mode 100644 index 0000000..9148c3d --- /dev/null +++ b/i686/gdt.h @@ -0,0 +1,55 @@ +#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); + +void gdt_install(); + +enum SegmentIndex { + ktextDescriptor = 2 * sizeof(struct SegmentDescriptor_t), + kdataDescriptor = 3 * sizeof(struct SegmentDescriptor_t), +}; diff --git a/i686/idt.h b/i686/idt.h new file mode 100644 index 0000000..22dc6de --- /dev/null +++ b/i686/idt.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +struct interrupt_frame { + uint32_t ip; + uint32_t cs; + uint32_t flags; + uint32_t sp; + uint32_t ss; +}; + +void abort_handler(struct interrupt_frame *frame); +void interrupt_handler(struct interrupt_frame *frame); +void interrupt_handler_e(struct interrupt_frame *frame, uint32_t error); +void syscall_handler(struct interrupt_frame *frame); + +void idt_install(); diff --git a/i686/init.s b/i686/init.s new file mode 100644 index 0000000..92710df --- /dev/null +++ b/i686/init.s @@ -0,0 +1,42 @@ +.section .stack, "aw", @nobits +.global k_stack +.align 16 /* Stack on x86 must be 16-byte aligned according to System V ABI */ +k_stack_bottom: + .skip 16 * 1024 /* 16 kByte */ +k_stack: + +.section .pages, "aw", @nobits +.align 4096 +.global k_pagedir +k_pagedir: .skip 1024 * 4 +.global k_ptable0x300 +k_ptable0x300: .skip 1024 * 4 + +.section .text +.global k_init +.extern kmain +k_init: + # kernel entry point, higher half + + # unmap the identity mapping as its no longer necessary + movl $0, k_pagedir + 0 * 4 + mov %cr3, %ecx # reload cr3 to force a TLB flush + mov %ecx, %cr3 + + # zero out the stack + mov $4096, %ecx # loop counter + mov $k_stack_bottom, %edi # start from the bottom + xor %edx, %edx # clear %edx +1: movl %edx, (%edi) # store %edx into address in %edi + addl $4, %edi # point to next address + loop 1b # loop according to %ecx + + mov $k_stack, %esp # point stack pointer to the stack + + call kmain + + /* If the system has nothing more to do, put it in an infinite loop */ + cli # disable interrupts +h: hlt # wait for interrupt + jmp h # continue waiting for interrupt + diff --git a/i686/lgdt.c b/i686/lgdt.c new file mode 100644 index 0000000..10781db --- /dev/null +++ b/i686/lgdt.c @@ -0,0 +1,35 @@ +#include "gdt.h" + +struct __attribute__((packed)) Pointer { + uint16_t limit; + uint32_t base; +}; + +static struct SegmentDescriptor_t segments[8] __attribute__((aligned(32))); + +void +gdt_install() +{ + SegmentDescriptor(&segments[0], 0, 0, 0); // null segment + SegmentDescriptor(&segments[2], 0, 0xffffffff, 0x9a); // ktext + SegmentDescriptor(&segments[3], 0, 0xffffffff, 0x92); // kdata + + const struct Pointer ptr = {.limit = sizeof(segments) - 1, .base = (unsigned)&segments}; + asm volatile("lgdt (%0)" : : "a"(&ptr)); + + // load the kernel data segment + asm volatile(R"(mov %0, %%ds + mov %0, %%es + mov %0, %%fs + mov %0, %%gs + mov %0, %%ss +)" + : + : "ax"(kdataDescriptor)); + + // load the kernel code segment + asm volatile(R"(ljmp %0, $1f + 1:)" + : + : "i"(ktextDescriptor)); +} diff --git a/i686/lidt.c b/i686/lidt.c new file mode 100644 index 0000000..3e261ac --- /dev/null +++ b/i686/lidt.c @@ -0,0 +1,46 @@ +#include "idt.h" +#include + +struct __attribute__((packed)) Pointer { + uint16_t limit; + uint32_t base; +}; + +enum Type { + Null = 0, + Intr = 0b10001110, // 32-bit interrupt +}; + +struct __attribute__((packed)) Gate_t { + uint16_t offset_15_0; // segment offset low + uint16_t selector; // code segment selector + uint8_t __unused; // unused in protected mode + uint8_t type; // interrupt type + uint16_t offset_31_16; // segment offset high +}; +_Static_assert(sizeof(struct Gate_t) == 8); + +void +Gate(struct Gate_t *entry, void *f, uint16_t selector) +{ + uint32_t f_addr = (uint32_t)f; + entry->offset_15_0 = f_addr & 0xffff; + entry->offset_31_16 = (f_addr >> 16) & 0xffff; + entry->selector = selector; + entry->__unused = 0; + entry->type = Intr; +} + +static struct Gate_t interrupt_table[256] __attribute((aligned(4096))); + +void +idt_install() +{ + for (int i = 0; i <= 0x2f; ++i) Gate(&interrupt_table[i], &interrupt_handler, 0x10); + Gate(&interrupt_table[0x80], &abort_handler, 0x10); + + const struct Pointer ptr = {.limit = sizeof(interrupt_table) - 1, .base = (unsigned)&interrupt_table}; + asm volatile("lidt (%0)" : : "a"(&ptr)); + + asm volatile("sti"); +} diff --git a/i686/linker.ld b/i686/linker.ld new file mode 100644 index 0000000..61a3be9 --- /dev/null +++ b/i686/linker.ld @@ -0,0 +1,54 @@ +ENTRY(_start) +OUTPUT_FORMAT(elf32-i386) + +MULTIBOOT_SIZE = 0x2000; +VADDR_BASE = 0xc0000000; + +SECTIONS +{ + /* First put the multiboot header, as it is required to be put very early in the image or the bootloader won't * + * recognize the file format. * + * Once the MMU is set up, this section is no longer needed and should be unmapped. */ + . = 0; + .bootstrap : { + . = ALIGN(8); + __multiboot_begin = .; + KEEP(*(.multiboot.header)) + KEEP(*(.multiboot.text)) + KEEP(*(.multiboot.pages)) + __multiboot_end = .; + } + + . = VADDR_BASE; + + .text ALIGN(4K) : AT(ADDR(.text) - VADDR_BASE + MULTIBOOT_SIZE) { + __text_begin = .; + *(.text*) + __text_end = .; + } + + /* Read-only data. */ + .rodata ALIGN(4K) : AT(ADDR(.rodata) - VADDR_BASE + MULTIBOOT_SIZE) { + __rodata_begin = .; + *(.constinit) + *(.rodata*) + __rodata_end = .; + } + + /* Read-write data (uninitialized) and stack */ + .bss ALIGN(4K) : AT(ADDR(.bss) - VADDR_BASE + MULTIBOOT_SIZE) { + __bss_begin = .; + *(.stack) + *(.pages) + *(.bss*) + __bss_end = .; + } + + /* Read-write data (initialized) */ + .data ALIGN(4K) : AT(ADDR(.data) - VADDR_BASE + MULTIBOOT_SIZE) { + __data_begin = .; + *(.init) + *(.data) + __data_end = .; + } +} diff --git a/i686/macros.s b/i686/macros.s new file mode 100644 index 0000000..a9b8b4d --- /dev/null +++ b/i686/macros.s @@ -0,0 +1,25 @@ +.set PAGE_RO, 0x001 +.set PAGE_RW, 0x003 +/* write section to page table macro + * + * Registers used: + * %ecx: loop counter [ set to $1024 ] + * %edx: temporary + * %esi: current page being mapped + * %edi: page entry [ set to $page_addr ] + */ +.macro mmap_section begin, end, access + mov $\begin, %esi # from $begin +1: cmpl $\end, %esi # until $end + jge 2f + + movl %esi, %edx + orl $\access, %edx + movl %edx, (%edi) + + addl $4096, %esi # move to next page + addl $4, %edi # size of page entry is 4 bytes + loop 1b # loop according to %ecx +2: +.endm + diff --git a/i686/meson.build b/i686/meson.build new file mode 100644 index 0000000..f6bed8e --- /dev/null +++ b/i686/meson.build @@ -0,0 +1,9 @@ +arch = declare_dependency( + sources: ['boot.S', 'init.s', + 'gdt.c', 'lgdt.c', 'lidt.c' + ], + include_directories: 'include', + compile_args: '-mgeneral-regs-only' +) + +test('GDT', executable('gdt', ['test/gdt.c', 'gdt.c'], include_directories: 'include', native: true)) diff --git a/i686/paging.h b/i686/paging.h new file mode 100644 index 0000000..cff0506 --- /dev/null +++ b/i686/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/i686/sys/control.h b/i686/sys/control.h new file mode 100644 index 0000000..a40a67f --- /dev/null +++ b/i686/sys/control.h @@ -0,0 +1,9 @@ +#pragma once + +static void +abort() +{ + asm volatile(R"(cli +h: hlt +jmp h)"); +} diff --git a/i686/sys/cpuid.h b/i686/sys/cpuid.h new file mode 100644 index 0000000..f2ffe37 --- /dev/null +++ b/i686/sys/cpuid.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +struct CPUVersion { + unsigned int stepping : 4; + unsigned int model : 4; + unsigned int family : 4; + unsigned int type : 2; + unsigned int __unused_1 : 2; + unsigned int model_ex : 4; + unsigned int family_ex : 8; + unsigned int __unused_2 : 4; +} __attribute__((packed, aligned(__alignof__(unsigned int)))); +_Static_assert(sizeof(struct CPUVersion) == sizeof(unsigned int)); + +unsigned int +family(const struct CPUVersion v) +{ + if (v.family == 0x0f) return v.family + v.family_ex; + else + return v.family; +} + +unsigned int +model(const struct CPUVersion v) +{ + switch (v.family) { + case 0x06: + case 0x0f: + return ((unsigned int)v.model_ex << 4) | v.model; + default: + return v.model; + } +} diff --git a/i686/sys/io.h b/i686/sys/io.h new file mode 100644 index 0000000..74d4950 --- /dev/null +++ b/i686/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)); +} diff --git a/i686/test/gdt.c b/i686/test/gdt.c new file mode 100644 index 0000000..2947b42 --- /dev/null +++ b/i686/test/gdt.c @@ -0,0 +1,20 @@ +#include "gdt.h" +#include +#include + +int +main() +{ + assert(*(uint8_t *)&null_access == 0x00); + assert(*(uint8_t *)&ktext_access == 0x9a); + assert(*(uint8_t *)&kdata_access == 0x92); + + struct SegmentDescriptor_t d; + SegmentDescriptor(&d, 0, 0, 0); + assert(*(uint64_t *)&d == 0); + + assert(ktextDescriptor == 0x10); + assert(kdataDescriptor == 0x18); + + return EXIT_SUCCESS; +} diff --git a/i686/toolchain.ini b/i686/toolchain.ini new file mode 100644 index 0000000..5114cfe --- /dev/null +++ b/i686/toolchain.ini @@ -0,0 +1,18 @@ +[constants] +arch = 'i686' + +[host_machine] +system = 'none' +cpu_family = 'x86' +cpu = 'i686' +endian = 'little' + +[binaries] +c = 'i686-elf-gcc' +ar = 'i686-elf-ar' +strip = 'i686-elf-strip' + +[built-in options] +c_args = ['-ffreestanding'] +c_link_args = ['-nostdlib'] + diff --git a/i686/toolchain.mk b/i686/toolchain.mk index 884369c..c41c784 100644 --- a/i686/toolchain.mk +++ b/i686/toolchain.mk @@ -1,10 +1,12 @@ # define compiler, linker, archiver and strip and their flags # +AS = i686-elf-as CC = i686-elf-gcc CCFLAGS = -Wall -Wextra -Wpedantic -fanalyzer -ffreestanding LD = i686-elf-ld LDFLAGS = -nostdlib AR = i686-elf-ar +ARFLAGS = r STRIP = i686-elf-strip diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..3a5fff9 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,13 @@ +include ../${ARCH}/toolchain.mk +include ../rules.mk + +CCFLAGS += -I. -I.. + +libk,SRCS = memcpy.c memset.c stdio/printf.c string/itoa.c +libk,OBJS = $(libk,SRCS:%.c=%.o) +libk.a: ${libk,OBJS} + @echo ' AR $@' + @${AR} ${ARFLAGS} $@ $^ + +clean: + @rm -rf ${libk,OBJS} diff --git a/lib/targets.mk b/lib/targets.mk deleted file mode 100644 index cbf9da8..0000000 --- a/lib/targets.mk +++ /dev/null @@ -1,6 +0,0 @@ -libk,SRCS = lib/memcpy.c lib/memset.c lib/stdio/printf.c lib/string/itoa.c -libk,OBJS = $(libk,SRCS:%.c=%.o) -libk.a: ${libk,OBJS} - @echo ' AR $@' - @${AR} ${ARFLAGS} $@ $^ - diff --git a/rules.mk b/rules.mk new file mode 100644 index 0000000..113794b --- /dev/null +++ b/rules.mk @@ -0,0 +1,13 @@ +.SUFFIXES: .s .S .c .o +.s.o: + @echo ' CC $^' + @$(AS) $(ASFLAGS) -c -o $@ $^ + +.S.o: + @echo ' CC $^' + @$(CC) $(CCFLAGS) -c -o $@ $^ + +.c.o: + @echo ' CC $^' + @$(CC) $(CCFLAGS) -c -o $@ $^ + -- cgit v1.2.1