This commit is contained in:
op52 2018-12-04 01:29:45 -05:00
commit a9d4aa30ae
51 changed files with 4853 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.idea/
cmake-build-debug/
out/
user/out/
.vscode/
CMakeLists.txt

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Op52
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

14
README.md Normal file
View File

@ -0,0 +1,14 @@
# CurrOS
CurrOS is a simple x86-64 kernel that supports interrupt, memory management, processes and threads, userspace and system calls.
## Toolchain
clang, lld, xorriso, grub-pc-bin, nasm
## Build
Run make inside "user" directory to build the test user program.
Run make in root dir and boot from out/curros.iso
## Clean
make clean
cd user
make clean

7
grub.cfg Normal file
View File

@ -0,0 +1,7 @@
set timeout=0
set default=0
menuentry "curros" {
multiboot2 /kernel.elf
module2 /hello.elf
}

47
inc/asm.inc Normal file
View File

@ -0,0 +1,47 @@
%macro PUSH_REGS 0
push rax ;save current rax
push rbx ;save current rbx
push rcx ;save current rcx
push rdx ;save current rdx
push rbp ;save current rbp
push rdi ;save current rdi
push rsi ;save current rsi
push r8 ;save current r8
push r9 ;save current r9
push r10 ;save current r10
push r11 ;save current r11
push r12 ;save current r12
push r13 ;save current r13
push r14 ;save current r14
push r15 ;save current r15
mov rax, ds
push rax
mov rax, es
push rax
push fs
push gs
%endmacro
%macro POP_REGS 0
pop gs
pop fs
pop rax
mov es, rax
pop rax
mov ds, rax
pop r15 ;restore current r15
pop r14 ;restore current r14
pop r13 ;restore current r13
pop r12 ;restore current r12
pop r11 ;restore current r11
pop r10 ;restore current r10
pop r9 ;restore current r9
pop r8 ;restore current r8
pop rsi ;restore current rsi
pop rdi ;restore current rdi
pop rbp ;restore current rbp
pop rdx ;restore current rdx
pop rcx ;restore current rcx
pop rbx ;restore current rbx
pop rax ;restore current rax
%endmacro

31
inc/cdef.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
typedef uint32_t uint32;
typedef int32_t int32;
typedef uint64_t uint64;
typedef int64_t int64;
typedef uintptr_t uintptr;
typedef uint16_t uint16;
typedef int16_t int16;
typedef uint8_t uint8;
typedef int8_t int8;
typedef size_t usize;
typedef _Bool bool;
#define TRUE (1)
#define FALSE (0)
#define ASM_F __attribute__((cdecl))
#define PACKED __attribute__((packed))
#define PRAGMA_PACKED __attribute__((packed))
#define ALIGN(type, num, align) (((type)(num) + ((type)align - 1)) & ~((type)align - 1))
#define UNREFERENCED(x) {(x) = (x);}

46
inc/clib.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include "cdef.h"
/**
* Common macros, etc
*/
#define OBTAIN_STRUCT_ADDR(member_addr, struct_name, member_name) ((struct_name*)((uintptr)(member_addr) - (uintptr)(&(((struct_name*)0)->member_name))))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define SWAP(a, b, T) do { T temp = *(a); *(a) = *(b); *(b) = temp; } while(0);
uint64
str_len(char const *str);
uint64
str_cmp(char const *str1, char const *str2);
void
mem_cpy(void *src, void *dst, uint64 size);
void
mem_mv(void *src, void *dst, uint64 size);
#define KASSERT(expr) kassert_ex(#expr, __FILE__, __LINE__, expr)
void
kassert_ex(const char *expr_str, const char *file, int32 line, int32 expr);
void
mem_set(void *src, uint8 val, uint64 size);
static inline uint64
bit_field_mask(uint32 low, uint32 high)
{
return ~((uint64)-1 << (high - low + 1)) << low;
}
void
poor_sleep(uint32 dat);

44
inc/cpu.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include "cdef.h"
void ASM_F out_8(uint16 port, uint8 data);
void ASM_F out_16(uint16 port, uint16 data);
void ASM_F out_32(uint16 port, uint32 data);
int32 ASM_F cmpxchg_32(int32 *dst, int32 old_val, int32 new_val);
int32 ASM_F xinc_32(int32* dst, int32 val);
uint8 ASM_F in_8(uint16 port);
uint16 ASM_F in_16(uint16 port);
uint32 ASM_F in_32(uint16 port);
void ASM_F flush_gdt(void *gdt_ptr, uint16 code_slct, uint16 data_slct);
void ASM_F flush_idt(void *idt_ptr);
void ASM_F flush_tss(uint16 tss_slct);
void ASM_F cpuid(uint32 *eax, uint32 *ebx, uint32 *ecx, uint32 *edx);
void ASM_F read_msr(uint32 *ecx, uint32 *edx, uint32 *eax);
void ASM_F write_msr(uint32 *ecx, uint32 *edx, uint32 *eax);
void ASM_F sti();
void ASM_F cli();
void ASM_F hlt();
uint64 ASM_F read_cr8();
void ASM_F write_cr8(uint64 val);
uint64 ASM_F read_cr3();
void ASM_F write_cr3(uint64 val);
void ASM_F flush_tlb();
#define BOCHS_BREAK __asm__("xchg %bx,%bx");

129
inc/elf64.h Normal file
View File

@ -0,0 +1,129 @@
/* ELF64 Object representation and parsing header. */
#include "cdef.h"
#include "proc.h"
typedef uint64 Elf64_Addr;
typedef uint64 Elf64_Off;
typedef uint16 Elf64_Half;
typedef uint32 Elf64_Word;
typedef uint32 Elf64_Sword;
typedef uint64 Elf64_Xword;
typedef uint64 Elf64_Sxword;
// This is custom
typedef uint8 uchar;
/* HEADER */
typedef struct
{
uchar e_ident[16];
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} elf64_hdr;
#define EI_MAG0 0 // should be \x7f
#define EI_MAG1 1 // E
#define EI_MAG2 2 // L
#define EI_MAG3 3 // F
#define ELFMAG0 '\x7f'
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_OSABI 7
#define EI_ABIVERSION 8
#define EI_PAD 9
#define EI_NIDENT 16
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
#define ELFOSABI_SYSV 0
#define ELFOSABI_HPUX 1
#define ELFOSABI_STANDALONE 255
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
#define ET_CORE 4
#define ET_LOOS 0xFE00
#define ET_HIOS 0XFEFF
#define ET_LOPROC 0XFF00
#define ET_HIPROC 0XFFFF
#define EV_CURRENT 1
typedef struct
{
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} elf64_phdr;
/* Special value for e_phnum. This indicates that the real number of
program headers is too large to fit into e_phnum. Instead the real
value is in the field sh_info of section 0. */
#define PN_XNUM 0xffff
/* Legal values for p_type (segment type). */
#define PT_NULL 0 /* Program header table entry unused */
#define PT_LOAD 1 /* Loadable program segment */
#define PT_DYNAMIC 2 /* Dynamic linking information */
#define PT_INTERP 3 /* Program interpreter */
#define PT_NOTE 4 /* Auxiliary information */
#define PT_SHLIB 5 /* Reserved */
#define PT_PHDR 6 /* Entry for header table itself */
#define PT_TLS 7 /* Thread-local storage segment */
#define PT_NUM 8 /* Number of defined types */
#define PT_LOOS 0x60000000 /* Start of OS-specific */
#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
#define PT_LOSUNW 0x6ffffffa
#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
#define PT_HISUNW 0x6fffffff
#define PT_HIOS 0x6fffffff /* End of OS-specific */
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
#define PT_HIPROC 0x7fffffff /* End of processor-specific */
/* Legal values for p_flags (segment flags). */
#define PF_X (1 << 0) /* Segment is executable */
#define PF_W (1 << 1) /* Segment is writable */
#define PF_R (1 << 2) /* Segment is readable */
#define PF_MASKOS 0x0ff00000 /* OS-specific */
#define PF_MASKPROC 0xf0000000 /* Processor-specific */
int32 elf_load_file(struct pcb *proc, void *file, void **entry);

11
inc/error.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "cdef.h"
enum
{
ESUCCESS = 0,
ENOSUPPORT = -1,
ENOMEM = -2,
EINVARG = -3,
};

113
inc/intr.h Normal file
View File

@ -0,0 +1,113 @@
#pragma once
#include "cdef.h"
#include "cpu.h"
#define READ_IRQ() read_cr8()
#define WRITE_IRQ(x) write_cr8(x)
#define NUM_IDT_DESC (256)
#define NUM_GDT_DESC (7)
#define IDT_DESC_SIZE (16)
#define GDT_DESC_SIZE (8)
// + 8 because TSS descriptor is 16 bytes instead
#define GDT_SIZE ((NUM_GDT_DESC) * (GDT_DESC_SIZE))
#define IDT_SIZE ((NUM_IDT_DESC) * (IDT_DESC_SIZE))
#define GDT_K_CODE (1)
#define GDT_NULL (0)
#define GDT_K_DATA (2)
#define GDT_U_CODE (3)
#define GDT_U_DATA (4)
#define GDT_U_TSS (5)
#define SEL(idx, TI, RPL) ((((uint16)idx) << 3) | (((uint16) TI) << 2) | ((uint16) RPL))
struct PACKED gdtr
{
uint16 size;
uint64 offset;
};
struct PACKED idtr
{
uint16 size;
uint64 offset;
};
struct PACKED gdt_desc
{
uint16 seg_l;
uint16 base_l;
uint8 base_m;
uint8 attr1;
uint8 attr2;
uint8 base_h;
};
struct PACKED idt_desc
{
uint16 offset_l;
uint16 seg_sel;
uint16 attr;
uint16 offset_m;
uint32 offset_h;
uint32 reserved;
};
struct PACKED intr_frame
{
uint64 gs;
uint64 fs;
uint64 es;
uint64 ds;
uint64 r15;
uint64 r14;
uint64 r13;
uint64 r12;
uint64 r11;
uint64 r10;
uint64 r9;
uint64 r8;
uint64 rsi;
uint64 rdi;
uint64 rbp;
uint64 rdx;
uint64 rcx;
uint64 rbx;
uint64 rax;
uint64 error_code;
uint64 rip;
uint64 cs;
uint64 rflags;
uint64 rsp;
uint64 ss;
};
struct PACKED tss
{
uint32 unused0;
uint64 rsp0;
uint64 rsp1;
uint64 rsp2;
uint32 unused1[19];
};
#define INTR_VEC_TIMER (50)
#define INTR_VEC_SPURIOUS (255)
#define INTR_VEC_SYSCALL (51)
#define INTR_LIMIT_INTEL (31)
// returns the new exception frame pointer
// interrupt handlers should EOI
typedef void* (*intr_handler)(struct intr_frame *frame);
int32 intr_init();
void* ASM_F intr_dispatcher(uint32 vec, struct intr_frame *frame);
void set_intr_handler(uint32 vec, intr_handler handler);
void send_ipi(uint32 vec);
void stop_cpu();

70
inc/llist.h Normal file
View File

@ -0,0 +1,70 @@
#pragma once
#include "cdef.h"
struct llist_node
{
struct llist_node *prev;
struct llist_node *next;
void * data;
};
struct llist
{
struct llist_node *head;
struct llist_node *tail;
uint32 size;
};
void
lb_llist_init(struct llist *list);
uint32
lb_llist_size(struct llist *list);
void
lb_llist_push_front(struct llist *list, struct llist_node *node);
void
lb_llist_push_back(struct llist *list, struct llist_node *node);
struct llist_node *
lb_llist_pop_front(struct llist *list);
struct llist_node *
lb_llist_pop_back(struct llist *list);
void
lb_llist_insert_by_idx(struct llist *list, uint32 index, struct llist_node *node);
struct llist_node *
lb_llist_remove_by_idx(struct llist *list, uint32 index);
struct llist_node *
lb_llist_get(struct llist *list, uint32 index);
void
lb_llist_insert_by_ref(struct llist *list, struct llist_node *cur_node, struct llist_node *new_node);
struct llist_node *
lb_llist_remove_by_ref(struct llist *list, struct llist_node *node);
struct llist_node *
lb_llist_next(struct llist_node *node);
struct llist_node *
lb_llist_prev(struct llist_node *node);
struct llist_node *
lb_llist_first(struct llist *list);
struct llist_node *
lb_llist_last(struct llist *list);

18
inc/memory_layout.h Normal file
View File

@ -0,0 +1,18 @@
/* System memory layout */
#pragma once
#define U_STACK_VADDR 0x90000000
#define K_START 0xFFFF800000000000
#define K_PMAP_VADDR 0xFFFF800000000000
#define K_DYNAMIC 0xFFFFFFFF00000000
#define K_DYN_END 0xFFFFFFFF70000000
#define K_IMAGE 0xFFFFFFFF80000000
#define PAGE_SIZE (0x1000)
#define K_IMAGE_PADDR (0x1000000)
// reserve 16MB
#define K_IMAGE_PRESRV (16 * 1024 * 1024)
#define R_PADDR(paddr) (void*)((paddr) + K_PMAP_VADDR)
#define IS_KERN_SPACE(vaddr) (((uintptr)vaddr) >= K_START)

434
inc/multiboot2.h Normal file
View File

@ -0,0 +1,434 @@
/* multiboot2.h - Multiboot 2 header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 32768
#define MULTIBOOT_HEADER_ALIGN 8
/* The magic field should contain this. */
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
/* This should be in %eax. */
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000008
/* Flags set in the 'flags' member of the multiboot header. */
#define MULTIBOOT_TAG_ALIGN 8
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
#define MULTIBOOT_TAG_TYPE_MODULE 3
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
#define MULTIBOOT_TAG_TYPE_MMAP 6
#define MULTIBOOT_TAG_TYPE_VBE 7
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
#define MULTIBOOT_TAG_TYPE_APM 10
#define MULTIBOOT_TAG_TYPE_EFI32 11
#define MULTIBOOT_TAG_TYPE_EFI64 12
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
#define MULTIBOOT_TAG_TYPE_NETWORK 16
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
#define MULTIBOOT_HEADER_TAG_END 0
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
#define MULTIBOOT_ARCHITECTURE_I386 0
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
#ifndef ASM_FILE
/* CurrOS */
#include "cdef.h"
/* CurrOS */
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* ISA */
multiboot_uint32_t architecture;
/* Total header length. */
multiboot_uint32_t header_length;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
};
struct multiboot_header_tag
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_information_request
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t requests[0];
};
struct multiboot_header_tag_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
};
struct multiboot_header_tag_entry_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t entry_addr;
};
struct multiboot_header_tag_console_flags
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t console_flags;
};
struct multiboot_header_tag_framebuffer
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
struct multiboot_header_tag_module_align
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_relocatable
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t min_addr;
multiboot_uint32_t max_addr;
multiboot_uint32_t align;
multiboot_uint32_t preference;
};
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
multiboot_uint32_t zero;
};
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_tag
{
multiboot_uint32_t type;
multiboot_uint32_t size;
};
struct multiboot_tag_string
{
multiboot_uint32_t type;
multiboot_uint32_t size;
char string[0];
};
struct multiboot_tag_module
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
char cmdline[0];
};
struct multiboot_tag_basic_meminfo
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
};
struct multiboot_tag_bootdev
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t biosdev;
multiboot_uint32_t slice;
multiboot_uint32_t part;
};
struct multiboot_tag_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t entry_size;
multiboot_uint32_t entry_version;
struct multiboot_mmap_entry entries[0];
};
struct multiboot_vbe_info_block
{
multiboot_uint8_t external_specification[512];
};
struct multiboot_vbe_mode_info_block
{
multiboot_uint8_t external_specification[256];
};
struct multiboot_tag_vbe
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
struct multiboot_vbe_info_block vbe_control_info;
struct multiboot_vbe_mode_info_block vbe_mode_info;
};
struct multiboot_tag_framebuffer_common
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
multiboot_uint16_t reserved;
};
struct multiboot_tag_framebuffer
{
struct multiboot_tag_framebuffer_common common;
union
{
struct
{
multiboot_uint16_t framebuffer_palette_num_colors;
struct multiboot_color framebuffer_palette[0];
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
struct multiboot_tag_elf_sections
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t num;
multiboot_uint32_t entsize;
multiboot_uint32_t shndx;
char sections[0];
};
struct multiboot_tag_apm
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
struct multiboot_tag_efi32
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_smbios
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t major;
multiboot_uint8_t minor;
multiboot_uint8_t reserved[6];
multiboot_uint8_t tables[0];
};
struct multiboot_tag_old_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_new_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_network
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t dhcpack[0];
};
struct multiboot_tag_efi_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t descr_size;
multiboot_uint32_t descr_vers;
multiboot_uint8_t efi_mmap[0];
};
struct multiboot_tag_efi32_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_load_base_addr
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t load_base_addr;
};
/* CurrOS */
typedef struct multiboot2_entry
{
uint32 total_size;
uint32 reserved;
} mbentry;
typedef struct multiboot_header mheader;
typedef struct multiboot_header_tag htag;
typedef struct multiboot_tag_module mod_tag;
void parse_mb2(mbentry * mb, void ** module, char ** ld_name, uint64*, uint64*);
/* CurrOS */
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */

43
inc/multiboot2.inc Normal file
View File

@ -0,0 +1,43 @@
MULTIBOOT_SEARCH equ 32768
MULTIBOOT_HEADER_ALIGN equ 8
MULTIBOOT2_HEADER_MAGIC equ 0xe85250d6
MULTIBOOT2_BOOTLOADER_MAGIC equ 0x36d76289
MULTIBOOT_MOD_ALIGN equ 0x00001000
MULTIBOOT_INFO_ALIGN equ 0x00000008
MULTIBOOT_TAG_ALIGN equ 8
MULTIBOOT_TAG_TYPE_END equ 0
MULTIBOOT_TAG_TYPE_CMDLINE equ 1
MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME equ 2
MULTIBOOT_TAG_TYPE_MODULE equ 3
MULTIBOOT_TAG_TYPE_BASIC_MEMINFO equ 4
MULTIBOOT_TAG_TYPE_BOOTDEV equ 5
MULTIBOOT_TAG_TYPE_MMAP equ 6
MULTIBOOT_TAG_TYPE_VBE equ 7
MULTIBOOT_TAG_TYPE_FRAMEBUFFER equ 8
MULTIBOOT_TAG_TYPE_ELF_SECTIONS equ 9
MULTIBOOT_TAG_TYPE_APM equ 10
MULTIBOOT_TAG_TYPE_EFI32 equ 11
MULTIBOOT_TAG_TYPE_EFI64 equ 12
MULTIBOOT_TAG_TYPE_SMBIOS equ 13
MULTIBOOT_TAG_TYPE_ACPI_OLD equ 14
MULTIBOOT_TAG_TYPE_ACPI_NEW equ 15
MULTIBOOT_TAG_TYPE_NETWORK equ 16
MULTIBOOT_TAG_TYPE_EFI_MMAP equ 17
MULTIBOOT_TAG_TYPE_EFI_BS equ 18
MULTIBOOT_HEADER_TAG_END equ 0
MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST equ 1
MULTIBOOT_HEADER_TAG_ADDRESS equ 2
MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS equ 3
MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS equ 4
MULTIBOOT_HEADER_TAG_FRAMEBUFFER equ 5
MULTIBOOT_HEADER_TAG_MODULE_ALIGN equ 6
MULTIBOOT_HEADER_TAG_EFI_BS equ 7
MULTIBOOT_ARCHITECTURE_I386 equ 0
MULTIBOOT_ARCHITECTURE_MIPS32 equ 4
MULTIBOOT_HEADER_TAG_OPTIONAL equ 1
MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED equ 1
MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED equ 2

15
inc/paging.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "cdef.h"
#include "memory_layout.h"
#define PML4_ENTRY(vaddr) ((vaddr >> 39) & 0x1FF)
#define PDPT_ENTRY(vaddr) ((vaddr >> 30) & 0x1FF)
#define PD_ENTRY(vaddr) ((vaddr >> 21) & 0x1FF)
#define PT_ENTRY(vaddr) ((vaddr >> 12) & 0x1FF)
#define KERNEL_PAGE_SIZE (PAGE_SIZE)
uintptr get_paddr(uint64 cr3, uintptr vaddr);
int32 map_vmem(uint64 cr3, uintptr virt_addr, uintptr phys_addr);

28
inc/pmm.h Normal file
View File

@ -0,0 +1,28 @@
/* Header file for physical memory management */
#pragma once
#include "cdef.h"
#include "llist.h"
#include "spin_lock.h"
typedef uintptr paddr;
typedef struct llist memlist;
typedef struct llist_node memnode;
typedef struct allocation_unit {
paddr head;
uint64 size;
uint8 status;
} allocu;
void * pmalloc(uint32 size); // Allocate a physical page
void pfree(paddr p); // Free physical page
// TODO : Setup methods
void pmm_init(uint64 low, uint64 high);
uint8 get_mem_phase();
void set_mmap_low(uint64 low, uint64 size);
void set_mmap_high(uint64 high, uint64 size);

9
inc/print.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include "cdef.h"
void clear_screen(void);
void kprintf(char const *format, ...);
void print_init();

22
inc/proc.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "cdef.h"
#include "llist.h"
#include "spin_lock.h"
struct pcb
{
uint64 cr3;
uint32 proc_id;
struct llist threads;
struct llist_node list_node;
struct spin_lock lock;
};
// procs now are simply cr3 holders
int32 proc_create(void* elf64, uint32* proc_id);
// proc init also makes the current address space process 0
// and creates a thread to run k_routine
int32 proc_init(void* k_routine);

18
inc/spin_lock.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "cdef.h"
struct spin_lock
{
int32 val;
};
void spin_init(struct spin_lock *lock);
void spin_lock(struct spin_lock *lock);
void spin_unlock(struct spin_lock *lock);
uint64 spin_lock_irq_save(struct spin_lock* lock);
void spin_unlock_irq_restore(struct spin_lock* lock, uint64 irq);

5
inc/syscall.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "cdef.h"
void syscall_init();

42
inc/thread.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include "proc.h"
struct tcb
{
struct pcb *proc;
uint32 tid;
int32 exit_code;
uint32 state;
uintptr ustack;
usize ustack_sz;
void* kstack;
usize kstack_sz;
uint64 rsp0; // kernel stack pointer for the stack, has context information
struct spin_lock lock;
struct llist_node list_node;
};
struct tcb* get_cur_thread();
int32 thread_stop(uint32 tid, int32 code);
void list_threads();
int32 thread_create(struct pcb* proc, void* entry, void* args, uint32* tid);
void thread_init();
void thread_schedule();
int32 thread_get_exit_code(uint32 tid, int32* exit_code);
void thread_yield();
int32 thread_resume(uint32 tid);
void thread_exit(int32 code);
int32 thread_block(uint32 tid);

64
inc/vmm.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
/* Virtual memory management header */
#include "cdef.h"
#include "memory_layout.h"
#include "llist.h"
#include "pmm.h"
#include "spin_lock.h"
typedef uintptr vaddr;
typedef struct llist vmll;
typedef struct llist_node vm_node;
typedef struct virtual_page
{
vaddr address; // Init to 0x0
vaddr table_ptr;
vmll allocs; // Linked list of vm_atom
uint64 free;
uint8 status;
} vm_object;
typedef struct allocation
{
usize offset;
usize size;
vm_object *page_ptr;
} vm_atom;
typedef struct page_table
{
uint64 id;
usize size;
usize free;
vm_atom *map;
} vm_unit;
typedef struct allocation_sector
{
uint64 start;
uint64 end;
vm_object **actbck;
vm_object **resbck;
vm_object *largest_free;
uint16 dirty;
} vm_sector;
typedef struct page_table_entries
{
vm_unit *groups;
vm_sector sectors[3];
vm_object *pages;
vmll *global_alloc;
usize free_frames;
} vmem;
void init_vm();
void vm_issue_unit(uint64 id, usize size);
void *kalloc(usize size);
void kfree(void *ptr);

32
linker.ld Normal file
View File

@ -0,0 +1,32 @@
ENTRY(sys_entry)
KERNEL_IMAGE_VADDR = 0xFFFFFFFF80000000;
KERNEL_IMAGE_PADDR = 0x1000000;
KERNEL_PAGE_SIZE = 0x1000;
SECTIONS
{
. = KERNEL_IMAGE_VADDR + KERNEL_IMAGE_PADDR;
.multiboot_header ALIGN(KERNEL_PAGE_SIZE) : AT(ADDR(.multiboot_header) - KERNEL_IMAGE_VADDR)
{
*(.multiboot_header)
}
.text ALIGN(KERNEL_PAGE_SIZE) : AT(ADDR(.text) - KERNEL_IMAGE_VADDR)
{
*(.text)
}
.data ALIGN(KERNEL_PAGE_SIZE) : AT(ADDR(.data) - KERNEL_IMAGE_VADDR)
{
*(.data)
*(.rodata*)
}
.bss ALIGN(KERNEL_PAGE_SIZE) : AT(ADDR(.bss) - KERNEL_IMAGE_VADDR)
{
*(.bss)
*(COMMON)
}
}

137
makefile Normal file
View File

@ -0,0 +1,137 @@
AS := nasm
CC := clang-6.0
LD := lld-6.0
DAS := llvm-objdump-6.0
.DEFAULT_GOAL := all
C_FLAGS_ARCH_X86_64 := -mcmodel=kernel \
-target x86_64-pc-none-elf \
-mno-red-zone \
-mno-mmx \
-mno-sse \
-mno-sse2 \
-mno-sse3 \
-mno-3dnow
C_FLAGS = -x c \
-g \
-c \
-O0 \
-std=c17 \
-Wall \
-Werror \
-Wextra \
-Wpedantic \
-ffreestanding \
-fno-pic \
-fno-stack-protector \
-Wno-int-to-pointer-cast \
-Wno-zero-length-array \
$(C_FLAGS_ARCH_X86_64) \
-I$(INC)/ \
$(C_EFLAGS)
AS_FLAGS = -w+all \
-w+error \
-f elf64 \
-F dwarf \
-g \
-I$(INC)/ \
$(AS_FLAGS_$(MOD))
DUMP_FLAGS = -x86-asm-syntax=intel \
-disassemble \
-r \
-t \
-triple=x86_64-pc-none-elf \
-print-imm-hex
LD_FLAGS = -fuse-ld=$(LD) \
-nostdlib \
-Wl,-T,$(LD_SCRIPT) \
-Wl,--fatal-warnings
# ===============================
# HERE COMES file definitions
# ===============================
SRC := src
INC := inc
OUT := out
LD_SCRIPT := linker.ld
GRUB_CFG := grub.cfg
TGT := $(OUT)/kernel.elf
ISO := $(OUT)/curros.iso
DMP := $(OUT)/kernel.dmp
# ===============================
# Add additional c source files here
# ===============================
C_SRC := kmain.c \
llist.c \
intr.c \
clib.c \
print.c \
multiboot2.c \
pmm.c \
elf64.c \
vmm.c \
spin_lock.c \
thread.c \
proc.c \
paging.c \
syscall.c
# ===============================
# Add additional ASM source files here
# ===============================
ASM_SRC := boot.asm \
cpu.asm \
intr.asm
# ===============================
# Compilation rules
# ===============================
C_OBJ := $(addsuffix .o, $(addprefix $(OUT)/,$(C_SRC)))
ASM_OBJ := $(addsuffix .o, $(addprefix $(OUT)/,$(ASM_SRC)))
$(C_OBJ): $(OUT)/%.c.o : $(SRC)/%.c
$(CC) $(C_FLAGS) -o $@ $<
$(ASM_OBJ): $(OUT)/%.asm.o : $(SRC)/%.asm
$(AS) $(AS_FLAGS) -o $@ $<
$(TGT): $(C_OBJ) $(ASM_OBJ) $(LD_SCRIPT)
$(CC) $(LD_FLAGS) -o $@ $^
$(DMP): $(TGT)
$(DAS) $(DUMP_FLAGS) $< > $@
$(ISO): $(TGT) $(GRUB_CFG)
mkdir -p $(OUT)/temp/boot/grub
cp $(GRUB_CFG) $(OUT)/temp/boot/grub/
cp $(TGT) $(OUT)/temp/
cp ./user/out/hello.elf $(OUT)/temp/
grub-mkrescue -d /usr/lib/grub/i386-pc -o $(ISO) $(OUT)/temp
.PHONY: mkdir
mkdir:
mkdir -p out
.PHONY: clean
clean:
rm -rf $(OUT)
.PHONY: all
all: mkdir $(TGT) $(DMP) $(ISO)
.PHONY: debug
debug:
qemu-system-x86_64 -boot d -cdrom $(ISO)

14
paper/curros.tex Normal file
View File

@ -0,0 +1,14 @@
\title{CurrOS: A Work In Progress}
\author{
Mohammad Yazdani
}
\date{\today}
\documentclass[12pt]{article}
\begin{document}
\maketitle
\end{document}

269
src/boot.asm Normal file
View File

@ -0,0 +1,269 @@
%include "multiboot2.inc"
KERNEL_PAGE_SIZE equ 0x1000
KERNEL_IMAGE_VADDR equ 0xFFFFFFFF80000000
KERNEL_PMAP_VADDR equ 0xFFFF800000000000
%define GET_PADDR(x) ((x) - KERNEL_IMAGE_VADDR)
%define GET_PML4(vaddr) (((vaddr) >> 39 ) & 0x1FF)
%define GET_PDPT(vaddr) (((vaddr) >> 30 ) & 0x1FF)
global sys_entry
extern kmain
section .multiboot_header
ASM_MULTIBOOT_CHECK_SUM equ (0xFFFFFFFF - (MULTIBOOT2_HEADER_MAGIC + ASM_MULTIBOOT_HEADER_SIZE + MULTIBOOT_ARCHITECTURE_I386) + 1)
section .multiboot_header
bits 32
align KERNEL_PAGE_SIZE
;====================
align MULTIBOOT_HEADER_ALIGN
start_hdr:
dd MULTIBOOT2_HEADER_MAGIC
dd MULTIBOOT_ARCHITECTURE_I386
dd ASM_MULTIBOOT_HEADER_SIZE
dd ASM_MULTIBOOT_CHECK_SUM
;====================
align MULTIBOOT_INFO_ALIGN
dw MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST
dw 0 ; flag
dd (8+4*3) ; size
dd MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME
dd MULTIBOOT_TAG_TYPE_MMAP
dd MULTIBOOT_TAG_TYPE_ACPI_NEW
;====================
align MULTIBOOT_INFO_ALIGN
dw MULTIBOOT_HEADER_TAG_MODULE_ALIGN; type=6
dw 0 ; flag
dd 8 ; size
;====================
align MULTIBOOT_INFO_ALIGN
dw MULTIBOOT_HEADER_TAG_END
dw 0 ; flag
dd 8 ; size
;====================
ASM_MULTIBOOT_HEADER_SIZE equ ($ - start_hdr)
section .text
bits 32
sys_entry:
cli
cld
cmp eax, MULTIBOOT2_BOOTLOADER_MAGIC
jne .end
; save multiboot info
mov dword [GET_PADDR(multiboot_info_ptr)], ebx
; setup stack
call check_long_mode ; check support for long mode
cmp eax, 1
jne .end
; disable paging first
mov eax, cr0 ; Set the A-register to control register 0.
and eax, ~(1 << 31) & 0xFFFFFFFF ; Clear the PG-bit, which is bit 31, and hack to get rid of warning
mov cr0, eax ; Set control register 0 to the A-register.
; point the first PML4 entry to the identity pdpt
mov eax, GET_PADDR(init_pml4)
mov dword [eax], GET_PADDR(init_pdpt_iden) + 11b ; write the lower bits, higher = 0
; point the nth PML4 entry to the kernel pdpt
mov eax, GET_PADDR(init_pml4) + GET_PML4(KERNEL_IMAGE_VADDR) * 8
mov dword [eax], GET_PADDR(init_pdpt_kern) + 11b
; point the nth PML4 entry to the kernel pmap pdpt
mov eax, GET_PADDR(init_pml4) + GET_PML4(KERNEL_PMAP_VADDR) * 8
mov dword [eax], GET_PADDR(init_pdpt_pmap) + 11b
; identity map the first 4GB and to kernel pmap region
mov eax, GET_PADDR(init_pdpt_iden)
mov edx, GET_PADDR(init_pdpt_pmap)
mov ebx, 10000011b ; R/W + SU + 1G page
mov ecx, 4 ; loop 4 times
.l0:
mov dword [eax], ebx
mov dword [edx], ebx
add ebx, 1*1024*1024*1024 ; 1G
add eax, 8
add edx, 8
loop .l0
; map the first 1 GB, which contains the kernel, to KERNEL_BASE_VADDR
mov eax, GET_PADDR(init_pdpt_kern)
; extract the PML4 entry
add eax, GET_PDPT(KERNEL_IMAGE_VADDR) * 8
mov ebx, 10000011b ; R/W + SU + 1G page
mov dword [eax], ebx
; enable PAE
mov eax, cr4 ; Set the A-register to control register 4.
or eax, 1 << 5 ; Set the PAE-bit, which is the 6th bit (bit 5).
mov cr4, eax ; Set control register 4 to the A-register.
; enable long mode
mov ecx, 0xC0000080 ; Set the C-register to 0xC0000080, which is the EFER MSR.
rdmsr ; Read from the model-specific register.
or eax, 1 << 8 ; Set the LM-bit which is the 9th bit (bit 8).
wrmsr ; Write to the model-specific register.
; let cr3 point at page table
mov eax, GET_PADDR(init_pml4)
mov cr3, eax
; enable paging, enter compatibility mode
mov eax, cr0 ; Set the A-register to control register 0.
or eax, 1 << 31 ; Set the PG-bit, which is bit 31.
mov cr0, eax ; Set control register 0 to the A-register.
; now we are in compat mode
; load the long mode GDT
lgdt [GET_PADDR(init_gdt.ptr)]
; switch to long mode
jmp init_gdt.code:GET_PADDR(sys_entry_64)
.end:
hlt
check_long_mode:
push ebp
mov ebp,esp
pushfd
pop eax
mov ecx, eax
xor eax, 1 << 21
push eax
popfd
pushfd
pop eax
push ecx
popfd
xor eax, ecx
jz .not_supported
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb .not_supported ; It is less, there is no long mode.
mov eax, 0x80000001 ; Set the A-register to 0x80000001.
cpuid ; CPU identification.
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
jz .not_supported ; They arent, there is no long mode.
mov eax,1
jmp .end
.not_supported:
xor eax,eax
.end:
mov esp,ebp
pop ebp
ret
section .data
bits 32
multiboot_info_ptr:
dd 0
section .text
bits 64
sys_entry_64:
; note that we are in long mode but rip is still lower
; switch to high address
mov rax, .high
jmp rax
.high:
; set ds segment
mov rax,init_gdt.data
mov ds, rax
; map GDT into virtual address space
mov qword [init_gdt.ptr + 2], init_gdt
lgdt [init_gdt.ptr]
;reload cs
push qword init_gdt.data ; ss
push qword init_stack ; rsp
pushfq
push qword init_gdt.code ; cs
push qword .reload ; rip
iretq
.reload:
mov rax, ss
mov ds, rax
mov es, rax
mov fs, rax
mov gs, rax
; unmap the first 4GB because we don't need them anymore
mov rax, GET_PADDR(init_pml4)
mov qword [rax], 0 ;
; flush TLB
mov rax, cr3
mov cr3, rax
; kernel is now in only -2GB mode
xor rdi, rdi
mov edi, dword [multiboot_info_ptr]
mov rax, KERNEL_PMAP_VADDR
add rdi, rax
call kmain
.end:
hlt
section .data
bits 64
align KERNEL_PAGE_SIZE
times KERNEL_PAGE_SIZE db 0
init_stack:
init_pml4:
align KERNEL_PAGE_SIZE
times KERNEL_PAGE_SIZE db 0
init_pdpt_iden:
align KERNEL_PAGE_SIZE
times KERNEL_PAGE_SIZE db 0
init_pdpt_pmap:
align KERNEL_PAGE_SIZE
times KERNEL_PAGE_SIZE db 0
init_pdpt_kern:
align KERNEL_PAGE_SIZE
times KERNEL_PAGE_SIZE db 0
init_gdt: ; Global Descriptor Table (long mode).
.null: equ $ - init_gdt ; The null descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 0 ; Access.
db 0 ; Granularity.
db 0 ; Base (high).
.code: equ $ - init_gdt ; The code descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011010b ; Access (exec/read).
db 00100000b ; Granularity.
db 0 ; Base (high).
.data: equ $ - init_gdt ; The data descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010010b ; Access (read/write).
db 00100000b ; Granularity.
db 0 ; Base (high).
.ptr:
; GDT PTR
dw $ - init_gdt - 1 ; Limit.
dq GET_PADDR(init_gdt) ; Base.

89
src/clib.c Normal file
View File

@ -0,0 +1,89 @@
#include "clib.h"
#include "print.h"
#include "intr.h"
void
mem_cpy(void *src, void *dst, uint64 size)
{
char *cSrc = (char *) src;
char *cDst = (char *) dst;
while (size--)
{
*(cDst++) = *(cSrc++);
}
}
void
mem_set(void *src, uint8 val, uint64 size)
{
while (size--)
{
*(uint8 *) src = val;
src = (void *) ((uintptr) src + 1);
}
}
void
mem_mv(void *src, void *dst, uint64 size)
{
if (src >= dst)
{
mem_cpy(src, dst, size);
return;
}
src = (void *) ((uintptr) src + size - 1);
dst = (void *) ((uintptr) dst + size - 1);
while (size--)
{
*(char *) dst = *(char *) src;
dst = (void *) ((uintptr) dst - 1);
src = (void *) ((uintptr) src - 1);
}
}
uint64
str_len(char const *str)
{
uint64 length = 0;
while (*str != 0)
{
str++;
length++;
}
return length;
}
uint64
str_cmp(char const *str1, char const *str2)
{
uint64 length = str_len(str1);
if (length != str_len(str2))
{
return 0;
}
while (length--)
{
if (*(str1 + length) != *(str2 + length))
{
return 0;
}
}
return 1;
}
void
poor_sleep(uint32 dat)
{
for(uint32 i = 0; i < dat; i++)
{
}
}
void kassert_ex(const char *expr_str, const char *file, int32 line, int32 expr)
{
if (!expr)
{
kprintf("Assertion \"%s\" failed at %s:%d.\n", expr_str, file, line);
stop_cpu();
}
}

201
src/cpu.asm Normal file
View File

@ -0,0 +1,201 @@
section .text
bits 64
global out_8
global out_16
global out_32
global in_8
global in_16
global in_32
global read_msr
global read_cr8
global write_cr8
global write_msr
global cpuid
global flush_gdt
global flush_idt
global cmpxchg_32
global xinc_32
global cli
global sti
global read_cr3
global write_cr3
global flush_tlb
global hlt
global flush_tss
flush_tss:
mov ax, di
ltr ax
ret
hlt:
hlt
ret
flush_tlb:
mov rax, cr3
mov cr3, rax
ret
read_cr3:
mov rax, cr3
ret
write_cr3:
mov cr3, rdi
ret
read_cr8:
mov rax, cr8
ret
write_cr8:
mov cr8, rdi
ret
cli:
cli
ret
sti:
sti
ret
out_32:
mov rdx,rdi
mov rax,rsi
out dx,eax
nop
nop
nop
ret
out_16:
mov rdx,rdi
mov rax,rsi
out dx,ax
nop
nop
nop
ret
out_8:
mov rdx,rdi
mov rax,rsi
out dx,al
nop
nop
nop
ret
in_8:
mov rdx,rdi
xor rax,rax
in al,dx
nop
nop
nop
ret
in_16:
mov rdx,rdi
xor rax,rax
in ax,dx
nop
nop
nop
ret
in_32:
mov rdx,rdi
xor rax,rax
in eax,dx
nop
nop
nop
ret
read_msr:
; preserve rdx
push rdx
mov ecx, dword [rdi]
rdmsr
mov dword [rdi], ecx
mov dword [rsi], edx
pop r11
mov dword [r11], eax
ret
write_msr:
mov ecx, dword [rdi]
mov eax, dword [rdx]
mov edx, dword [rsi]
wrmsr
ret
cpuid:
push rbp
mov rbp,rsp
; preserve rbx,rcx,rdx
push rbx
push rcx
push rdx
; cpuid parameters eax,ecx
mov eax, dword [rdi]
mov ecx, dword [rdx]
cpuid
; write results back to memory
mov dword [rdi], eax
mov dword [rsi], ebx
pop r11
mov dword [r11], ecx
pop r11
mov dword [r11], edx
pop rbx
mov rsp,rbp
pop rbp
ret
flush_gdt:
push rbp
mov rbp, rsp
lgdt [rdi]
;reload cs
push rdx ; data_slct : ss
push rbp ; rsp
pushfq
push rsi ; cs
mov rax, .reload
push rax ;rip
iretq
.reload:
mov es,rdx
mov fs,rdx
mov gs,rdx
mov ds,rdx
pop rbp
ret
flush_idt:
lidt [rdi]
ret
; ============================
cmpxchg_32:
mov eax, esi; eax = test_node_compare
lock cmpxchg dword [rdi], edx ; edx = val, rdi = ptr to dst
ret
; ============================
xinc_32:
lock xadd dword [rdi], esi ; [rdi] = [rdi] + esi, esi = old [rdi]
xor rax, rax
mov eax, esi
ret

145
src/elf64.c Normal file
View File

@ -0,0 +1,145 @@
#include <elf64.h>
#include <cdef.h>
#include <error.h>
#include <paging.h>
#include <pmm.h>
#include <print.h>
#include <clib.h>
bool
elf_check_file(elf64_hdr *hdr)
{
if (!hdr)
{ return 0; }
if (hdr->e_ident[EI_MAG0] != ELFMAG0)
{ return 0; }
if (hdr->e_ident[EI_MAG1] != ELFMAG1)
{ return 0; }
if (hdr->e_ident[EI_MAG2] != ELFMAG2)
{ return 0; }
if (hdr->e_ident[EI_MAG3] != ELFMAG3)
{ return 0; }
return 1;
}
bool
elf_check_supported(elf64_hdr *hdr)
{
if (!elf_check_file(hdr))
{ return 0; }
if (hdr->e_ident[EI_CLASS] != ELFCLASS64)
{ return 0; }
if (hdr->e_ident[EI_DATA] != ELFDATA2LSB)
{ return 0; } // TODO : May not be true
//if (hdr->e_machine != EM_386) return 0; // TODO : CHECK
if (hdr->e_ident[EI_VERSION] != EV_CURRENT)
{ return 0; }
if (hdr->e_type != ET_EXEC)
{ return 0; }
return 1;
}
static int32 elf_load_seg(struct pcb *proc, void* file, elf64_phdr* hdr)
{
void *seg_start = (void*)((uintptr)file + hdr->p_offset);
void *vaddr = (void*)hdr->p_vaddr;
usize file_size = hdr->p_filesz;
usize mem_size = hdr->p_memsz;
int32 ret = ESUCCESS;
if (((uintptr) vaddr & 0xfff) != 0)
{
// alignment
ret = EINVARG;
}
if (ret == ESUCCESS)
{
uint32 num_pages = ((uint32)mem_size + KERNEL_PAGE_SIZE - 1) / KERNEL_PAGE_SIZE;
// allocate memory
for (uint32 i = 0; i < num_pages; i++)
{
// map pages
uintptr page = (uintptr) pmalloc(KERNEL_PAGE_SIZE);
if (page == (uintptr) NULL)
{
ret = ENOMEM;
}
if (ret == ESUCCESS)
{
ret = map_vmem(proc->cr3, (uintptr) vaddr, page);
}
if (ret == ESUCCESS)
{
usize cpy_size = file_size > KERNEL_PAGE_SIZE ? KERNEL_PAGE_SIZE : (file_size % KERNEL_PAGE_SIZE);
// copy the current segment
mem_cpy(seg_start, R_PADDR(page), cpy_size);
}
if (ret != ESUCCESS)
{
break;
}
vaddr = (void *) ((uintptr) vaddr + KERNEL_PAGE_SIZE);
seg_start = (void *) ((uintptr) seg_start + KERNEL_PAGE_SIZE);
}
}
if (ret != ESUCCESS)
{
// cleanup
}
return ret;
}
int32
elf_load_file(struct pcb *proc, void *file, void **entry)
{
int32 ret = ESUCCESS;
elf64_hdr *hdr = (elf64_hdr *) file;
if (!elf_check_supported(hdr))
{
ret = EINVARG;
}
if (ret == ESUCCESS)
{
elf64_phdr *phdr_start = (elf64_phdr *) ((uintptr) file + hdr->e_phoff);
// load program segments
for (int i = 0; i < hdr->e_phnum; i++)
{
elf64_phdr *each_seg = (elf64_phdr *) ((uintptr) phdr_start + i * hdr->e_phentsize);
if (each_seg->p_type == PT_LOAD)
{
// load segment
ret = elf_load_seg(proc, file, each_seg);
#ifdef KDBG
if (ret == ESUCCESS)
{
kprintf("Loaded segment offset 0x%x to vaddr 0x%x, fs: %d, ms: %d\n", (uint64) each_seg->p_offset,
(uint64) each_seg->p_vaddr, (uint64) each_seg->p_filesz, (uint64) each_seg->p_memsz);
}
#endif
}
if (ret != ESUCCESS)
{
break;
}
}
}
if (ret == ESUCCESS)
{
// write back entry
*entry = (void *) hdr->e_entry;
}
return ret;
}

566
src/intr.asm Normal file
View File

@ -0,0 +1,566 @@
%include "asm.inc"
extern intr_dispatcher
global intr_stub_array
section .data
bits 64
intr_stub_array:
dq intr_stub_0
dq intr_stub_1
dq intr_stub_2
dq intr_stub_3
dq intr_stub_4
dq intr_stub_5
dq intr_stub_6
dq intr_stub_7
dq intr_stub_8
dq intr_stub_9
dq intr_stub_10
dq intr_stub_11
dq intr_stub_12
dq intr_stub_13
dq intr_stub_14
dq intr_stub_15
dq intr_stub_16
dq intr_stub_17
dq intr_stub_18
dq intr_stub_19
dq intr_stub_20
dq intr_stub_21
dq intr_stub_22
dq intr_stub_23
dq intr_stub_24
dq intr_stub_25
dq intr_stub_26
dq intr_stub_27
dq intr_stub_28
dq intr_stub_29
dq intr_stub_30
dq intr_stub_31
dq intr_stub_32
dq intr_stub_33
dq intr_stub_34
dq intr_stub_35
dq intr_stub_36
dq intr_stub_37
dq intr_stub_38
dq intr_stub_39
dq intr_stub_40
dq intr_stub_41
dq intr_stub_42
dq intr_stub_43
dq intr_stub_44
dq intr_stub_45
dq intr_stub_46
dq intr_stub_47
dq intr_stub_48
dq intr_stub_49
dq intr_stub_50
dq intr_stub_51
dq intr_stub_52
dq intr_stub_53
dq intr_stub_54
dq intr_stub_55
dq intr_stub_56
dq intr_stub_57
dq intr_stub_58
dq intr_stub_59
dq intr_stub_60
dq intr_stub_61
dq intr_stub_62
dq intr_stub_63
dq intr_stub_64
dq intr_stub_65
dq intr_stub_66
dq intr_stub_67
dq intr_stub_68
dq intr_stub_69
dq intr_stub_70
dq intr_stub_71
dq intr_stub_72
dq intr_stub_73
dq intr_stub_74
dq intr_stub_75
dq intr_stub_76
dq intr_stub_77
dq intr_stub_78
dq intr_stub_79
dq intr_stub_80
dq intr_stub_81
dq intr_stub_82
dq intr_stub_83
dq intr_stub_84
dq intr_stub_85
dq intr_stub_86
dq intr_stub_87
dq intr_stub_88
dq intr_stub_89
dq intr_stub_90
dq intr_stub_91
dq intr_stub_92
dq intr_stub_93
dq intr_stub_94
dq intr_stub_95
dq intr_stub_96
dq intr_stub_97
dq intr_stub_98
dq intr_stub_99
dq intr_stub_100
dq intr_stub_101
dq intr_stub_102
dq intr_stub_103
dq intr_stub_104
dq intr_stub_105
dq intr_stub_106
dq intr_stub_107
dq intr_stub_108
dq intr_stub_109
dq intr_stub_110
dq intr_stub_111
dq intr_stub_112
dq intr_stub_113
dq intr_stub_114
dq intr_stub_115
dq intr_stub_116
dq intr_stub_117
dq intr_stub_118
dq intr_stub_119
dq intr_stub_120
dq intr_stub_121
dq intr_stub_122
dq intr_stub_123
dq intr_stub_124
dq intr_stub_125
dq intr_stub_126
dq intr_stub_127
dq intr_stub_128
dq intr_stub_129
dq intr_stub_130
dq intr_stub_131
dq intr_stub_132
dq intr_stub_133
dq intr_stub_134
dq intr_stub_135
dq intr_stub_136
dq intr_stub_137
dq intr_stub_138
dq intr_stub_139
dq intr_stub_140
dq intr_stub_141
dq intr_stub_142
dq intr_stub_143
dq intr_stub_144
dq intr_stub_145
dq intr_stub_146
dq intr_stub_147
dq intr_stub_148
dq intr_stub_149
dq intr_stub_150
dq intr_stub_151
dq intr_stub_152
dq intr_stub_153
dq intr_stub_154
dq intr_stub_155
dq intr_stub_156
dq intr_stub_157
dq intr_stub_158
dq intr_stub_159
dq intr_stub_160
dq intr_stub_161
dq intr_stub_162
dq intr_stub_163
dq intr_stub_164
dq intr_stub_165
dq intr_stub_166
dq intr_stub_167
dq intr_stub_168
dq intr_stub_169
dq intr_stub_170
dq intr_stub_171
dq intr_stub_172
dq intr_stub_173
dq intr_stub_174
dq intr_stub_175
dq intr_stub_176
dq intr_stub_177
dq intr_stub_178
dq intr_stub_179
dq intr_stub_180
dq intr_stub_181
dq intr_stub_182
dq intr_stub_183
dq intr_stub_184
dq intr_stub_185
dq intr_stub_186
dq intr_stub_187
dq intr_stub_188
dq intr_stub_189
dq intr_stub_190
dq intr_stub_191
dq intr_stub_192
dq intr_stub_193
dq intr_stub_194
dq intr_stub_195
dq intr_stub_196
dq intr_stub_197
dq intr_stub_198
dq intr_stub_199
dq intr_stub_200
dq intr_stub_201
dq intr_stub_202
dq intr_stub_203
dq intr_stub_204
dq intr_stub_205
dq intr_stub_206
dq intr_stub_207
dq intr_stub_208
dq intr_stub_209
dq intr_stub_210
dq intr_stub_211
dq intr_stub_212
dq intr_stub_213
dq intr_stub_214
dq intr_stub_215
dq intr_stub_216
dq intr_stub_217
dq intr_stub_218
dq intr_stub_219
dq intr_stub_220
dq intr_stub_221
dq intr_stub_222
dq intr_stub_223
dq intr_stub_224
dq intr_stub_225
dq intr_stub_226
dq intr_stub_227
dq intr_stub_228
dq intr_stub_229
dq intr_stub_230
dq intr_stub_231
dq intr_stub_232
dq intr_stub_233
dq intr_stub_234
dq intr_stub_235
dq intr_stub_236
dq intr_stub_237
dq intr_stub_238
dq intr_stub_239
dq intr_stub_240
dq intr_stub_241
dq intr_stub_242
dq intr_stub_243
dq intr_stub_244
dq intr_stub_245
dq intr_stub_246
dq intr_stub_247
dq intr_stub_248
dq intr_stub_249
dq intr_stub_250
dq intr_stub_251
dq intr_stub_252
dq intr_stub_253
dq intr_stub_254
dq intr_stub_255
section .text
bits 64
%macro decl_err_intr_stub 1
intr_stub_%1:
; save context
PUSH_REGS
push qword %1
jmp intr_stub
%endmacro
%macro decl_intr_stub 1
intr_stub_%1:
; push dummy error code to have consistent frame
push qword 0
PUSH_REGS
push qword %1
jmp intr_stub
%endmacro
intr_stub:
pop rdi
mov rsi, rsp
call intr_dispatcher
; restore registers
POP_REGS
; skip error code
add rsp, 8
iretq
intr_stub_start:
decl_intr_stub 0
decl_intr_stub 1
decl_intr_stub 2
decl_intr_stub 3
decl_intr_stub 4
decl_intr_stub 5
decl_intr_stub 6
decl_intr_stub 7
decl_err_intr_stub 8
decl_intr_stub 9
decl_err_intr_stub 10
decl_err_intr_stub 11
decl_err_intr_stub 12
decl_err_intr_stub 13
decl_err_intr_stub 14
decl_intr_stub 15
decl_intr_stub 16
decl_err_intr_stub 17
decl_intr_stub 18
decl_intr_stub 19
decl_intr_stub 20
decl_intr_stub 21
decl_intr_stub 22
decl_intr_stub 23
decl_intr_stub 24
decl_intr_stub 25
decl_intr_stub 26
decl_intr_stub 27
decl_intr_stub 28
decl_intr_stub 29
decl_intr_stub 30
decl_intr_stub 31
decl_intr_stub 32
decl_intr_stub 33
decl_intr_stub 34
decl_intr_stub 35
decl_intr_stub 36
decl_intr_stub 37
decl_intr_stub 38
decl_intr_stub 39
decl_intr_stub 40
decl_intr_stub 41
decl_intr_stub 42
decl_intr_stub 43
decl_intr_stub 44
decl_intr_stub 45
decl_intr_stub 46
decl_intr_stub 47
decl_intr_stub 48
decl_intr_stub 49
intr_stub_50:
; push dummy error code to have consistent frame
push qword 0
PUSH_REGS
mov rdi, 50
mov rsi, rsp
call intr_dispatcher
xchg bx,bx
; now rax hows the next thread's rsp0
mov rsp, rax ; switch stack
POP_REGS ; restore registers
add rsp, 8 ; skip error code
iretq
decl_intr_stub 51
decl_intr_stub 52
decl_intr_stub 53
decl_intr_stub 54
decl_intr_stub 55
decl_intr_stub 56
decl_intr_stub 57
decl_intr_stub 58
decl_intr_stub 59
decl_intr_stub 60
decl_intr_stub 61
decl_intr_stub 62
decl_intr_stub 63
decl_intr_stub 64
decl_intr_stub 65
decl_intr_stub 66
decl_intr_stub 67
decl_intr_stub 68
decl_intr_stub 69
decl_intr_stub 70
decl_intr_stub 71
decl_intr_stub 72
decl_intr_stub 73
decl_intr_stub 74
decl_intr_stub 75
decl_intr_stub 76
decl_intr_stub 77
decl_intr_stub 78
decl_intr_stub 79
decl_intr_stub 80
decl_intr_stub 81
decl_intr_stub 82
decl_intr_stub 83
decl_intr_stub 84
decl_intr_stub 85
decl_intr_stub 86
decl_intr_stub 87
decl_intr_stub 88
decl_intr_stub 89
decl_intr_stub 90
decl_intr_stub 91
decl_intr_stub 92
decl_intr_stub 93
decl_intr_stub 94
decl_intr_stub 95
decl_intr_stub 96
decl_intr_stub 97
decl_intr_stub 98
decl_intr_stub 99
decl_intr_stub 100
decl_intr_stub 101
decl_intr_stub 102
decl_intr_stub 103
decl_intr_stub 104
decl_intr_stub 105
decl_intr_stub 106
decl_intr_stub 107
decl_intr_stub 108
decl_intr_stub 109
decl_intr_stub 110
decl_intr_stub 111
decl_intr_stub 112
decl_intr_stub 113
decl_intr_stub 114
decl_intr_stub 115
decl_intr_stub 116
decl_intr_stub 117
decl_intr_stub 118
decl_intr_stub 119
decl_intr_stub 120
decl_intr_stub 121
decl_intr_stub 122
decl_intr_stub 123
decl_intr_stub 124
decl_intr_stub 125
decl_intr_stub 126
decl_intr_stub 127
decl_intr_stub 128
decl_intr_stub 129
decl_intr_stub 130
decl_intr_stub 131
decl_intr_stub 132
decl_intr_stub 133
decl_intr_stub 134
decl_intr_stub 135
decl_intr_stub 136
decl_intr_stub 137
decl_intr_stub 138
decl_intr_stub 139
decl_intr_stub 140
decl_intr_stub 141
decl_intr_stub 142
decl_intr_stub 143
decl_intr_stub 144
decl_intr_stub 145
decl_intr_stub 146
decl_intr_stub 147
decl_intr_stub 148
decl_intr_stub 149
decl_intr_stub 150
decl_intr_stub 151
decl_intr_stub 152
decl_intr_stub 153
decl_intr_stub 154
decl_intr_stub 155
decl_intr_stub 156
decl_intr_stub 157
decl_intr_stub 158
decl_intr_stub 159
decl_intr_stub 160
decl_intr_stub 161
decl_intr_stub 162
decl_intr_stub 163
decl_intr_stub 164
decl_intr_stub 165
decl_intr_stub 166
decl_intr_stub 167
decl_intr_stub 168
decl_intr_stub 169
decl_intr_stub 170
decl_intr_stub 171
decl_intr_stub 172
decl_intr_stub 173
decl_intr_stub 174
decl_intr_stub 175
decl_intr_stub 176
decl_intr_stub 177
decl_intr_stub 178
decl_intr_stub 179
decl_intr_stub 180
decl_intr_stub 181
decl_intr_stub 182
decl_intr_stub 183
decl_intr_stub 184
decl_intr_stub 185
decl_intr_stub 186
decl_intr_stub 187
decl_intr_stub 188
decl_intr_stub 189
decl_intr_stub 190
decl_intr_stub 191
decl_intr_stub 192
decl_intr_stub 193
decl_intr_stub 194
decl_intr_stub 195
decl_intr_stub 196
decl_intr_stub 197
decl_intr_stub 198
decl_intr_stub 199
decl_intr_stub 200
decl_intr_stub 201
decl_intr_stub 202
decl_intr_stub 203
decl_intr_stub 204
decl_intr_stub 205
decl_intr_stub 206
decl_intr_stub 207
decl_intr_stub 208
decl_intr_stub 209
decl_intr_stub 210
decl_intr_stub 211
decl_intr_stub 212
decl_intr_stub 213
decl_intr_stub 214
decl_intr_stub 215
decl_intr_stub 216
decl_intr_stub 217
decl_intr_stub 218
decl_intr_stub 219
decl_intr_stub 220
decl_intr_stub 221
decl_intr_stub 222
decl_intr_stub 223
decl_intr_stub 224
decl_intr_stub 225
decl_intr_stub 226
decl_intr_stub 227
decl_intr_stub 228
decl_intr_stub 229
decl_intr_stub 230
decl_intr_stub 231
decl_intr_stub 232
decl_intr_stub 233
decl_intr_stub 234
decl_intr_stub 235
decl_intr_stub 236
decl_intr_stub 237
decl_intr_stub 238
decl_intr_stub 239
decl_intr_stub 240
decl_intr_stub 241
decl_intr_stub 242
decl_intr_stub 243
decl_intr_stub 244
decl_intr_stub 245
decl_intr_stub 246
decl_intr_stub 247
decl_intr_stub 248
decl_intr_stub 249
decl_intr_stub 250
decl_intr_stub 251
decl_intr_stub 252
decl_intr_stub 253
decl_intr_stub 254
decl_intr_stub 255

353
src/intr.c Normal file
View File

@ -0,0 +1,353 @@
#include "intr.h"
#include "cpu.h"
#include "clib.h"
#include "memory_layout.h"
#include "print.h"
#include "paging.h"
#include "thread.h"
#include "error.h"
/**
* IDT Defns
*/
#define GATE_DPL_0 (0ull << 13)
#define GATE_DPL_1 (1ull << 13)
#define GATE_DPL_2 (2ull << 13)
#define GATE_DPL_3 (3ull << 13)
#define GATE_PRESENT (1ull << 15)
#define GATE_TYPE_CALL (12ull << 8)
#define GATE_TYPE_INTERRUPT (14ull << 8)
#define GATE_TYPE_TRAP (15ull << 8)
/**
GDT Defns
**/
#define SEG_GRANULARITY (1ull << 55)
#define SEG_LONG (1ull << 53)
#define SEG_DPL_0 (0ull << 45)
#define SEG_DPL_1 (1ull << 45)
#define SEG_DPL_2 (2ull << 45)
#define SEG_DPL_3 (3ull << 45)
#define SEG_PRESENT (1ull << 47)
#define SEG_CODE_DATA (1ull << 44)
#define SEG_TYPE_DATA_RW (2ull << 40)
#define SEG_TYPE_DATA_R (0ull << 40)
#define SEG_TYPE_CODE_X (8ull << 40)
#define SEG_TYPE_CODE_XR (10ull << 40)
#define SEG_TYPE_CODE_XC (12ull << 40)
#define SEG_TYPE_CODE_XRC (14ull << 40)
#define SEG_AVAILABLE (1ull << 52)
#define SEG_32_BITS (1ull << 54)
// APIC Interrupt vectors
#define EDX_MASK_APIC (1 << 9)
#define MSR_APIC_BASE (0x1b)
#define MSR_MASK_APIC (1 << 11)
// PIC defs
#define PIC1_COMMAND (0x20)
#define PIC1_DATA (PIC1_COMMAND+1)
#define PIC2_COMMAND (0xa0)
#define PIC2_DATA (PIC2_COMMAND+1)
#define APIC_REG_SPURIOUS (0xF0)
#define APIC_REG_TIMER (0x320)
#define APIC_REG_EOI (0xB0)
#define APIC_REG_TIMER_DIV (0x3E0)
#define APIC_REG_TIMER_INIT_CNT (0x380)
#define APIC_REG_TIMER_CUR_CNT (0x390)
#define APIC_REG_ID (0x20)
#define APIC_REG_LINT0 (0x350)
#define APIC_REG_LINT1 (0x360)
#define APIC_REG_ICR_L (0x300)
#define APIC_REG_ICR_H (0x310)
#define IPI_DLM_FIXED (0 << 8)
#define IPI_DLM_START_UP (6 << 8)
#define IPI_DSM_PHYS (0 << 11)
#define IPI_DSM_LOGI (1 << 11)
#define IPI_STATUS_MASK (1 << 12)
#define IPI_LVL_ASS (1 << 15)
#define IPI_LVL_DEA (0 << 15)
// base on 1Ghz CPU
#define APIC_TIMER_INIT_CNT (10000000)
#define REG_SPURIOUS_APIC_ENABLE (1 << 8)
extern void *intr_stub_array[NUM_IDT_DESC];
static void *apic_base;
static struct tss utss;
static struct gdtr gdtptr;
static struct idtr idtptr;
static struct gdt_desc gdt[NUM_GDT_DESC];
static struct idt_desc idt[NUM_IDT_DESC];
static intr_handler intr_disp_tbl[NUM_IDT_DESC];
static void write_idt_desc(void *gate, uint64 offset, uint32 selector, uint32 attr)
{
((uint8 *) gate)[0] = (uint8) (offset & 0xFF);
((uint8 *) gate)[1] = (uint8) ((offset >> 8) & 0xFF);
((uint8 *) gate)[2] = (uint8) (selector & 0xFF);
((uint8 *) gate)[3] = (uint8) ((selector >> 8) & 0xFF);
((uint8 *) gate)[4] = (uint8) (attr & 0xFF);
((uint8 *) gate)[5] = (uint8) ((attr >> 8) & 0xFF);
((uint8 *) gate)[6] = (uint8) ((offset >> 16) & 0xFF);
((uint8 *) gate)[7] = (uint8) ((offset >> 24) & 0xFF);
((uint8 *) gate)[8] = (uint8) ((offset >> 32) & 0xFF);
((uint8 *) gate)[9] = (uint8) ((offset >> 40) & 0xFF);
((uint8 *) gate)[10] = (uint8) ((offset >> 48) & 0xFF);
((uint8 *) gate)[11] = (uint8) ((offset >> 56) & 0xFF);
((uint8 *) gate)[12] = 0;
((uint8 *) gate)[13] = 0;
((uint8 *) gate)[14] = 0;
((uint8 *) gate)[15] = 0;
}
static void write_gdt_desc(void *gdt, uint32 base, uint32 limit, uint64 attr)
{
uint64 seg_desc = (((uint64) base & 0xFFFF) << 16) | ((((uint64) base >> 16) & 0xFF) << 32) |
((((uint64) base >> 24) & 0xFF) << 56) | ((uint64) limit & 0xFFFF) |
((((uint64) limit >> 16) & 0xF) << 48) | attr;
((uint8 *) gdt)[0] = (uint8) (seg_desc & 0xFF);
((uint8 *) gdt)[1] = (uint8) ((seg_desc >> 8) & 0xFF);
((uint8 *) gdt)[2] = (uint8) ((seg_desc >> 16) & 0xFF);
((uint8 *) gdt)[3] = (uint8) ((seg_desc >> 24) & 0xFF);
((uint8 *) gdt)[4] = (uint8) ((seg_desc >> 32) & 0xFF);
((uint8 *) gdt)[5] = (uint8) ((seg_desc >> 40) & 0xFF);
((uint8 *) gdt)[6] = (uint8) ((seg_desc >> 48) & 0xFF);
((uint8 *) gdt)[7] = (uint8) ((seg_desc >> 56) & 0xFF);
}
static void disable_pic()
{
out_8(PIC1_COMMAND, 0x11); // starts the initialization sequence (in cascade mode)
out_8(PIC2_COMMAND, 0x11);
out_8(PIC1_DATA, 32); // ICW2: Master PIC vector offset
out_8(PIC2_DATA, 40); // ICW2: Slave PIC vector offset
out_8(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
out_8(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
out_8(PIC1_DATA, 0x1); // set their modes to 8086
out_8(PIC2_DATA, 0x1);
out_8(PIC1_DATA, 0xff);
out_8(PIC2_DATA, 0xff);
}
static void write_apic_reg(uint32 reg, uint32 val)
{
*(uint32 *) ((uintptr) apic_base + reg) = val;
}
static uint32 read_apic_reg(uint32 reg)
{
return *(uint32 *) ((uintptr) apic_base + reg);
}
static int32 init_apic()
{
uint32 eax = 1, ebx, ecx, edx;
cpuid(&eax, &ebx, &ecx, &edx);
if (!(edx & EDX_MASK_APIC))
{
return ENOSUPPORT;
}
disable_pic();
// hardware enable APIC
ecx = MSR_APIC_BASE;
read_msr(&ecx, &edx, &eax);
apic_base = R_PADDR(eax & 0xFFFF0000);
eax |= MSR_MASK_APIC;
write_msr(&ecx, &edx, &eax);
#ifdef KDBG
kprintf("APIC base address: 0x%x\n", (uint64) apic_base);
#endif
// map spurious interrupt and software enable APIC
uint32 reg = read_apic_reg(APIC_REG_SPURIOUS);
write_apic_reg(APIC_REG_SPURIOUS, reg | REG_SPURIOUS_APIC_ENABLE);
// Mask LINT0 LINT1
reg = read_apic_reg(APIC_REG_LINT0);
write_apic_reg(APIC_REG_LINT0, reg | (1 << 16));
reg = read_apic_reg(APIC_REG_LINT1);
write_apic_reg(APIC_REG_LINT1, reg | (1 << 16));
// configure APIC timer
write_apic_reg(APIC_REG_TIMER_DIV, 0xB); // 0x1011, divide by 1
write_apic_reg(APIC_REG_TIMER_INIT_CNT, APIC_TIMER_INIT_CNT);
write_apic_reg(APIC_REG_TIMER_CUR_CNT, APIC_REG_TIMER_INIT_CNT);
write_apic_reg(APIC_REG_TIMER, 0xFF020000 | INTR_VEC_TIMER); // periodic
// unblock all interrupts
write_cr8(0);
return ESUCCESS;
}
static void *timer_intr_handler(struct intr_frame *frame)
{
struct tcb *cur = get_cur_thread();
if (cur != NULL)
{
// hack to get away first scheduling 1st time
// save the stack pointer of the current thread
cur->rsp0 = (uint64) frame;
}
// run the scheduler
thread_schedule();
cur = get_cur_thread();
// now cur is the next thread to run
// swap address space
// which shouldn't page fault as we are in kernel
write_cr3(cur->proc->cr3);
flush_tlb();
// write tss segment
utss.rsp0 = (uint64)((uintptr)cur->kstack + cur->kstack_sz);
// now we are in the target address space
// the only thing to do is to switch stack, which will be done in ASM handler
return (void *) cur->rsp0;
}
extern char init_stack[];
int32 intr_init()
{
int32 ret;
// init GDT
write_gdt_desc(&gdt[GDT_NULL], 0, 0, 0); // empty desc
write_gdt_desc(&gdt[GDT_K_CODE], 0, 0xFFFFFFFF,
SEG_LONG | SEG_DPL_0 | SEG_PRESENT | SEG_GRANULARITY | SEG_CODE_DATA |
SEG_TYPE_CODE_XR); // kernel code
write_gdt_desc(&gdt[GDT_K_DATA], 0, 0xFFFFFFFF,
SEG_LONG | SEG_DPL_0 | SEG_PRESENT | SEG_GRANULARITY | SEG_CODE_DATA |
SEG_TYPE_DATA_RW); // kernel data
write_gdt_desc(&gdt[GDT_U_CODE], 0, 0xFFFFFFFF,
SEG_LONG | SEG_DPL_3 | SEG_PRESENT | SEG_GRANULARITY | SEG_CODE_DATA |
SEG_TYPE_CODE_XR); // user code
write_gdt_desc(&gdt[GDT_U_DATA], 0, 0xFFFFFFFF,
SEG_LONG | SEG_DPL_3 | SEG_PRESENT | SEG_GRANULARITY | SEG_CODE_DATA |
SEG_TYPE_DATA_RW); // user data
// write tss
write_gdt_desc(&gdt[GDT_U_TSS], (uint32) &utss, sizeof(struct tss),
SEG_PRESENT | SEG_DPL_3 | ((uint64)9 << 40));
// write high bits
*(uint64 *) &gdt[GDT_U_TSS + 1] = ((uintptr)&utss) >> 32;
// init tss
mem_set(&utss, 0, sizeof(struct tss));
gdtptr.size = GDT_SIZE - 1;
gdtptr.offset = (uintptr) gdt;
flush_gdt(&gdtptr, SEL(GDT_K_CODE, 0, 0), SEL(GDT_K_DATA, 0, 0));
flush_tss(SEL(GDT_U_TSS, 0, 3));
idtptr.offset = (uintptr) idt;
idtptr.size = IDT_SIZE - 1;
for (int i = 0; i < NUM_IDT_DESC; i++)
{
write_idt_desc(&idt[i], (uintptr) intr_stub_array[i],
SEL(GDT_K_CODE, 0, 0),
GATE_DPL_3 | GATE_TYPE_INTERRUPT | GATE_PRESENT);
}
mem_set(intr_disp_tbl, 0, sizeof(intr_disp_tbl));
flush_idt(&idtptr);
ret = init_apic();
if (ret == ESUCCESS)
{
// enable interrupt flag but mask all external interrupts
WRITE_IRQ(0xf);
sti();
set_intr_handler(INTR_VEC_TIMER, timer_intr_handler);
}
return ret;
}
void set_intr_handler(uint32 vec, intr_handler handler)
{
intr_disp_tbl[vec] = handler;
}
void stop_cpu()
{
// stop interrupt and halt
cli();
hlt();
}
// this returns info returned by intr_disp_tbl
// in case the assembly stub needs them (e.g. ctx swap)
void *intr_dispatcher(uint32 vec, struct intr_frame *frame)
{
void *ret = NULL;
if (intr_disp_tbl[vec] != NULL)
{
ret = intr_disp_tbl[vec](frame);
}
else
{
if (vec <= INTR_LIMIT_INTEL)
{
kprintf("[PANIC] Exception %d has no handler. RIP: 0x%x ERR:0x%x\n", (uint64) vec, (uint64) frame->rip,
(uint64) frame->error_code);
stop_cpu();
}
else
{
kprintf("[WARN] Interrupt %d has no handler. RIP: 0x%x\n", (uint64) vec, (uint64) frame->rip);
}
}
if (vec >= INTR_VEC_TIMER && vec != INTR_VEC_SPURIOUS)
{
// if it's delivered by local APIC, signal EOI
write_apic_reg(APIC_REG_EOI, 0);
}
return ret;
}
static uint32 get_core()
{
return read_apic_reg(APIC_REG_ID) >> 24;
}
void send_ipi(uint32 vec)
{
// we decide to not support multicore for now. So hardcode to the current core
// used to emulate IO stuff
uint64 reg = ((uint64) get_core() << 56) | IPI_DLM_FIXED | IPI_DSM_PHYS | IPI_LVL_ASS | (vec & 0xff);
// block all interrupts because there is no context
uint64 irq = READ_IRQ();
WRITE_IRQ(0xf);
write_apic_reg(APIC_REG_ICR_L, (uint32)reg);
write_apic_reg(APIC_REG_ICR_H, (uint32)(reg >> 32));
// block until successfully delivered
while (reg & IPI_STATUS_MASK)
{
reg = read_apic_reg(APIC_REG_ICR_L);
}
WRITE_IRQ(irq);
}

138
src/kmain.c Normal file
View File

@ -0,0 +1,138 @@
#include "multiboot2.h"
#include "intr.h"
#include "print.h"
#include "clib.h"
#include "cpu.h"
#include "thread.h"
#include "proc.h"
#include "pmm.h"
#include "syscall.h"
#include "error.h"
#include "vmm.h"
#include "elf64.h"
void kthread1(void *arg);
void kthread2(void *arg);
void kproc(void *arg);
void *_module;
void kmain(mbentry *mb)
{
char *ld_name = 0x0;
mod_tag *module = 0x0;
uint64 mem_low;
uint64 mem_high;
int32 status;
print_init();
parse_mb2(mb, (void **) &module, &ld_name, &mem_low, &mem_high);
kprintf("Bootloader: %s\n", ld_name);
kprintf("User executable loaded at 0x%x size %d.\n", (uint64) R_PADDR(module->mod_start), (uint64) (module->mod_end - module->mod_start));
kprintf("Initializing interrupt...\n");
status = intr_init();
kprintf("Initializing system call...\n");
syscall_init();
KASSERT(status == ESUCCESS);
_module = R_PADDR(module->mod_start);
kprintf("Initializing PMM...\n");
pmm_init(mem_low, mem_high);
kprintf("Initializing VMM...\n");
init_vm();
kprintf("Initializing threads...\n");
thread_init();
kprintf("Initializing processes...\n");
status = proc_init((void *) kproc);
KASSERT(status == ESUCCESS);
// unmask all interrupts
WRITE_IRQ(0x0);
send_ipi(INTR_VEC_TIMER);
KASSERT(FALSE);
}
#define THREAD_DELAY (5000000*4)
static uint32 kt1id;
static uint32 kt2id;
void kthread1(void *arg)
{
UNREFERENCED(arg);
uint64 i = 0;
while (i != 0xFFFFFFFFFF)
{
poor_sleep(THREAD_DELAY);
kprintf("[KThread1] %d\n", i);
if (i == 10)
{
kprintf("[KThread1] Blocking KThread 2... \n", i);
thread_block(kt2id);
}
if (i == 20)
{
kprintf("[KThread1] Resuming KThread 2... \n", i);
thread_resume(kt2id);
}
i++;
}
}
void kthread2(void *arg)
{
UNREFERENCED(arg);
bool thread1exited = FALSE;
uint64 i = 0;
int32 ex;
while (i != 0xFFFFFFFFFF)
{
poor_sleep(THREAD_DELAY);
kprintf("[KThread2] %d\n", i);
if (i == 40)
{
kprintf("[KThread2] Stopping KThread1 with exit code 0xdeadbeef\n", i);
thread_stop(kt1id, 0xDEADBEEF);
}
if (!thread1exited && thread_get_exit_code(kt1id, &ex) == ESUCCESS)
{
kprintf("[KThread2] KThread1 exited with 0x%x\n", (uint64) ex);
thread1exited = TRUE;
}
i++;
}
}
void kproc(void *arg)
{
// the idle thread
UNREFERENCED(arg);
int32 status;
status = thread_create(get_cur_thread()->proc, (void *) kthread1, NULL, &kt1id);
kprintf("[KIdle] Created KThread1... 0x%x\n", (uint64) status);
status = thread_create(get_cur_thread()->proc, (void *) kthread2, NULL, &kt2id);
kprintf("[KIdle] Created KThread2... 0x%x\n", (uint64) status);
uint32 id;
status = proc_create(_module, &id);
kprintf("[KIdle] Created process from module... 0x%x\n", (uint64) status);
while (1)
{
#ifdef KDBG
kprintf("[KIdle] Yielding...\n");
#endif
thread_yield();
}
}

250
src/llist.c Normal file
View File

@ -0,0 +1,250 @@
#include "llist.h"
static void
llist_node_init(struct llist_node *node)
{
node->next = NULL;
node->prev = NULL;
}
void
lb_llist_init(struct llist *list)
{
list->head = NULL;
list->tail = NULL;
list->size = 0;
}
uint32
lb_llist_size(struct llist *list)
{
return list->size;
}
void
lb_llist_push_front(struct llist *list, struct llist_node *node)
{
llist_node_init(node);
lb_llist_insert_by_ref(list, NULL, node);
}
void
lb_llist_push_back(struct llist *list, struct llist_node *node)
{
llist_node_init(node);
lb_llist_insert_by_ref(list, list->tail, node);
}
struct llist_node *
lb_llist_pop_front(struct llist *list)
{
struct llist_node *ret;
ret = list->head;
lb_llist_remove_by_ref(list, list->head);
return ret;
}
struct llist_node *
lb_llist_pop_back(struct llist *list)
{
struct llist_node *ret;
ret = list->tail;
lb_llist_remove_by_ref(list, list->tail);
return ret;
}
void
lb_llist_insert_by_ref(struct llist *list, struct llist_node *cur_node, struct llist_node *new_node)
{
struct llist_node *left_node;
struct llist_node *right_node;
if (list == NULL || new_node == NULL)
{
return;
}
llist_node_init(new_node);
/*
* adjust the current node
*/
if (cur_node == NULL)
{
new_node->next = list->head;
new_node->prev = NULL;
}
else
{
new_node->prev = cur_node;
new_node->next = cur_node->next;
}
/*
* assign left and treenode node
*/
if (cur_node == NULL)
{
left_node = NULL;
right_node = list->head == NULL ? NULL : list->head;
}
else
{
left_node = cur_node;
right_node = cur_node->next;
}
/*
* adjust left and treenode node accordingly
*/
if (left_node != NULL)
{
left_node->next = new_node;
}
else
{
list->head = new_node;
}
if (right_node != NULL)
{
right_node->prev = new_node;
}
else
{
list->tail = new_node;
}
list->size++;
}
void
lb_llist_insert_by_idx(struct llist *list, uint32 index, struct llist_node *node)
{
struct llist_node *prev_node;
prev_node = lb_llist_get(list, index - 1);
llist_node_init(node);
if (prev_node == NULL)
{
if (index == 0)
{
lb_llist_insert_by_ref(list, NULL, node);
}
}
else
{
lb_llist_insert_by_ref(list, prev_node, node);
}
}
struct llist_node *
lb_llist_remove_by_idx(struct llist *list, uint32 index)
{
struct llist_node *cur_node;
cur_node = lb_llist_get(list, index);
if (cur_node == NULL)
{
return NULL;
}
return lb_llist_remove_by_ref(list, cur_node);
}
/**
* returns the next node
*/
struct llist_node *
lb_llist_remove_by_ref(struct llist *list, struct llist_node *node)
{
struct llist_node *ret;
/*
* Adjust the left and treenode node
*/
if (node->prev != NULL)
{
node->prev->next = node->next;
}
else
{
list->head = node->next;
}
if (node->next != NULL)
{
node->next->prev = node->prev;
}
else
{
list->tail = node->prev;
}
ret = node->next;
llist_node_init(node);
list->size--;
return ret;
}
struct llist_node *
lb_llist_get(struct llist *list, uint32 index)
{
if (list->head == NULL)
{
return NULL;
}
struct llist_node *cur_node = list->head;
while (index-- && (cur_node = cur_node->next) != NULL)
{}
return cur_node;
}
struct llist_node *
lb_llist_next(struct llist_node *node)
{
return node->next;
}
struct llist_node *
lb_llist_prev(struct llist_node *node)
{
return node->prev;
}
struct llist_node *
lb_llist_first(struct llist *list)
{
return list->head;
}
struct llist_node *
lb_llist_last(struct llist *list)
{
return list->tail;
}

96
src/multiboot2.c Normal file
View File

@ -0,0 +1,96 @@
#include <multiboot2.h>
#include <pmm.h>
#include <cdef.h>
#include <print.h>
#include <memory_layout.h>
// Putting multiboot device info here
static char *loader_name = 0x0;
static void *file_mod = 0x0;
// OH BOY DON"T I FUCKING LOVE THIS SHIT
static uint64 _low = 0;
static uint64 _high = 0;
void
process_mmap(struct multiboot_tag_mmap *mmap)
{
struct multiboot_mmap_entry entry;
uint16 num_entries = (mmap->size - sizeof(*mmap)) / mmap->entry_size;
for (uint16 i = 0; i < num_entries; i++)
{
entry = mmap->entries[i];
if ((entry.type == 1) && (entry.len > _high - _low))
{
#ifdef KDBG
kprintf("Update low: 0x%x high: 0x%x\n", (uint64) entry.addr, (uint64) (entry.addr + entry.len));
#endif
_high = entry.addr + entry.len;
_low = entry.addr;
}
}
}
void
process_tag(htag *tag)
{
struct multiboot_tag_mmap *mmap_tag;
struct multiboot_tag_string *strtag;
struct multiboot_tag_module *modtag;
while(1)
{
if(tag->type == MULTIBOOT_HEADER_TAG_END)
{
break;
}
switch (tag->type)
{
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
strtag = (struct multiboot_tag_string *) tag;
loader_name = &strtag->string[0];
tag = (void*)ALIGN(uintptr, (uintptr)tag + tag->size, MULTIBOOT_TAG_ALIGN);
break;
case MULTIBOOT_TAG_TYPE_MMAP:
mmap_tag = (struct multiboot_tag_mmap *) tag;
process_mmap(mmap_tag);
tag = (void*)ALIGN(uintptr, (uintptr)tag + tag->size, MULTIBOOT_TAG_ALIGN);
break;
case MULTIBOOT_TAG_TYPE_MODULE:
modtag = (struct multiboot_tag_module *)tag;
file_mod = modtag;
tag = (void*)ALIGN(uintptr, (uintptr)tag + tag->size, MULTIBOOT_TAG_ALIGN);
break;
default:
tag = (void*)ALIGN(uintptr, (uintptr)tag + tag->size, MULTIBOOT_TAG_ALIGN);
break;
}
}
}
void parse_mb2(mbentry *mb, void **module, char **ld_name, uint64 *low, uint64 *high)
{
uint64 tag_base0 = (uint64) mb;
uint64 next_entry;
uint64 last_entry;
next_entry = tag_base0 + 8;
last_entry = tag_base0 + mb->total_size - 8;
htag *last_tag = (htag *) last_entry;
if (!(last_tag->type == 0 && last_tag->size == 8))
{ return; }
htag *tag = (htag *) next_entry;
process_tag(tag);
*module = file_mod;
*ld_name = loader_name;
*low = _low;
*high = _high;
}

159
src/paging.c Normal file
View File

@ -0,0 +1,159 @@
#include <memory_layout.h>
#include <print.h>
#include "paging.h"
#include "pmm.h"
#include "cpu.h"
#include "clib.h"
#include "error.h"
#define ENTRY_SIZE (8)
#define NEXT_LEVEL_MASK bit_field_mask(12,51)
#define BIT_PRESENT (1ull)
#define BIT_WRITEABLE (1ull << 1)
#define BIT_USER (1ull << 2)
#define BIT_WRITE_THROUGH (1ull << 3)
#define BIT_CACHE_DISABLED (1ull << 4)
#define BIT_ACCESSED (1ull << 5)
#define BIT_PS (1ull << 7)
#define BIT_EXECUTION_DISABLED (1ull << 63)
static void
write_page_table(void *const base, uintptr const p_addr, uint64 const attr)
{
uint64 entry = (p_addr & 0xFFFFFFFFFF000) | attr;
((uint8 *) base)[0] = (uint8) (entry & 0xFF);
((uint8 *) base)[1] = (uint8) ((entry >> 8) & 0xFF);
((uint8 *) base)[2] = (uint8) ((entry >> 16) & 0xFF);
((uint8 *) base)[3] = (uint8) ((entry >> 24) & 0xFF);
((uint8 *) base)[4] = (uint8) ((entry >> 32) & 0xFF);
((uint8 *) base)[5] = (uint8) ((entry >> 40) & 0xFF);
((uint8 *) base)[6] = (uint8) ((entry >> 48) & 0xFF);
((uint8 *) base)[7] = (uint8) ((entry >> 56) & 0xFF);
}
static int32 ensure_present(uint64 *entry, uint64 attr, uintptr *alloc)
{
uint32 ret = ESUCCESS;
uintptr p_alloc = (uintptr) NULL;
if (!(*entry & BIT_PRESENT))
{
p_alloc = (uintptr) pmalloc(KERNEL_PAGE_SIZE);
if (p_alloc == (uintptr) NULL)
{
ret = ENOMEM;
}
else
{
mem_set(R_PADDR(p_alloc), 0, KERNEL_PAGE_SIZE);
write_page_table(entry, p_alloc, attr);
}
}
if (ret == ESUCCESS)
{
*alloc = p_alloc;
}
return ret;
}
int32 map_vmem(uint64 cr3, uintptr vaddr, uintptr paddr)
{
int32 ret;
vaddr &= ~(uintptr)0xfff;
paddr &= ~(uintptr)0xfff;
uint64 *pml4_e = R_PADDR(cr3 + ENTRY_SIZE * PML4_ENTRY(vaddr));
uintptr pdpt_alloc = (uintptr) NULL;
ret = ensure_present(pml4_e, BIT_PRESENT | BIT_WRITEABLE | (IS_KERN_SPACE(vaddr) ? 0 : BIT_USER), &pdpt_alloc);
uint64 *pdpt_e = NULL;
uintptr pd_alloc = (uintptr) NULL;
if (ret == ESUCCESS)
{
pdpt_e = R_PADDR((*pml4_e & NEXT_LEVEL_MASK) + ENTRY_SIZE * PDPT_ENTRY(vaddr));
ret = ensure_present(pdpt_e, BIT_PRESENT | BIT_WRITEABLE | (IS_KERN_SPACE(vaddr) ? 0 : BIT_USER), &pd_alloc);
}
uint64 *pd_e = NULL;
uintptr pt_alloc = (uintptr) NULL;
if (ret == ESUCCESS)
{
pd_e = R_PADDR((*pdpt_e & NEXT_LEVEL_MASK) + ENTRY_SIZE * PD_ENTRY(vaddr));
ret = ensure_present(pd_e, BIT_PRESENT | BIT_WRITEABLE | (IS_KERN_SPACE(vaddr) ? 0 : BIT_USER), &pt_alloc);
}
if (ret == ESUCCESS)
{
uint64 *pt_e = R_PADDR((*pd_e & NEXT_LEVEL_MASK) + ENTRY_SIZE * PT_ENTRY(vaddr));
write_page_table(pt_e, paddr, BIT_PRESENT | BIT_WRITEABLE | (IS_KERN_SPACE(vaddr) ? 0 : BIT_USER));
#ifdef KDBG
kprintf("Mapped 0x%x to 0x%x\n", vaddr, paddr);
#endif
}
if (ret != ESUCCESS)
{
if (pdpt_alloc != (uintptr) NULL)
{
pfree(pdpt_alloc);
}
if (pd_alloc != (uintptr) NULL)
{
pfree(pd_alloc);
}
if (pt_alloc != (uintptr) NULL)
{
pfree(pt_alloc);
}
}
return ret;
}
uintptr get_paddr(uint64 cr3, uintptr vaddr)
{
uint64 pml4_e = *(uint64 *) R_PADDR(cr3 + ENTRY_SIZE * PML4_ENTRY(vaddr));
if (!(pml4_e & BIT_PRESENT))
{
// not present in PML4
return (uintptr) NULL;
}
uint64 pdpt_e = *(uint64 *) R_PADDR((pml4_e & NEXT_LEVEL_MASK) + ENTRY_SIZE * PDPT_ENTRY((uintptr)vaddr));
if (!(pdpt_e & BIT_PRESENT))
{
return (uintptr) NULL;
}
if (pdpt_e & BIT_PS)
{
// 1GB page
return (pdpt_e & bit_field_mask(30, 51)) + ((uintptr)vaddr & (0x3FFFFFFF));
}
uint64 pd_e = *(uint64 *) R_PADDR((pdpt_e & NEXT_LEVEL_MASK) + ENTRY_SIZE * PD_ENTRY((uintptr)vaddr));
if (!(pdpt_e & BIT_PRESENT) || (pdpt_e & BIT_PS))
{
// don't support 2MB pages yet
return (uintptr) NULL;
}
uint64 pt_e = *(uint64 *) R_PADDR((pd_e & NEXT_LEVEL_MASK) + ENTRY_SIZE * PT_ENTRY(vaddr));
if (!(pt_e & BIT_PRESENT))
{
return (uintptr) NULL;
}
return (pt_e & bit_field_mask(12, 51)) + (uintptr)vaddr & 0xFFF;
}

48
src/pmm.c Normal file
View File

@ -0,0 +1,48 @@
#include <print.h>
#include <paging.h>
#include "memory_layout.h"
#include "pmm.h"
#include "clib.h"
static uint64 mem_low;
static uint64 mem_high;
static uint64 ptr;
static struct spin_lock pm_global_lock;
void
pfree(paddr p)
{
UNREFERENCED(p);
}
void* pmalloc(uint32 size)
{
void* ret = NULL;
spin_lock(&pm_global_lock);
if((size > KERNEL_PAGE_SIZE) || (ptr >= mem_high))
{
ret = NULL;
}
else
{
ret = (void *) ptr;
ptr = ptr + KERNEL_PAGE_SIZE;
}
spin_unlock(&pm_global_lock);
#ifdef KDBG
kprintf("Allocated physical: 0x%x, size: %d\n", (uint64)ptr, (uint64)size);
#endif
return ret;
}
void pmm_init(uint64 low, uint64 high)
{
mem_low = MAX(K_IMAGE_PADDR + K_IMAGE_PRESRV, low);
ptr = mem_low;
mem_high = high;
spin_init(&pm_global_lock);
}

212
src/print.c Normal file
View File

@ -0,0 +1,212 @@
#include "print.h"
#include "clib.h"
#include "memory_layout.h"
#include "spin_lock.h"
#define FBUF (uintptr)R_PADDR(0xb8000)
#define GET_ROW(pos) ((pos) / 80)
#define GET_POS(row, col) ((row) * 80 + (col))
static struct spin_lock lock;
static uint64 text_pos;
void print_init()
{
spin_init(&lock);
text_pos = 0;
clear_screen();
}
static void
print_scroll(void)
{
mem_mv((void*)(FBUF + GET_POS(1, 0) * 2), (void *) (FBUF + GET_POS(0, 0) * 2), (80 * 24) * 2);
}
static void
print_str(char const *str)
{
if (str == NULL)
{
return;
}
while (*str != 0)
{
if (*str == '\n')
{
text_pos = 80 * (GET_ROW(text_pos) + 1);
if (text_pos > 80 * 25 - 1)
{
//can't hold
print_scroll();
mem_set((void *) (FBUF + 80 * 24 * 2), 0, 80 * 2); // clear last row
text_pos = 80 * 24;
}
str++;
}
else
{
if (text_pos > 80 * 25 - 1)
{
//can't hold
print_scroll();
text_pos = 80 * 24;
}
*((char *) (FBUF) + text_pos * 2) = *str;
*((char *) (FBUF) + text_pos * 2 + 1) = 7;
str++;
text_pos++;
}
}
}
static void
print_uint(uint64 number)
{
char arr[21]; // do not need to initialize
arr[20] = 0; //zero-terminated
uint32 index = 19;
uint32 const div = 10;
while (1)
{
uint64 quo = number / div;
uint64 rmd = number % div;
number = quo;
arr[index--] = (char) ('0' + rmd);
if (number == 0)
{
break;
}
}
print_str(&(arr[index + 1]));
}
static void
print_int(int64 number)
{
char arr[21]; // do not need to initialize
arr[20] = 0; //zero-terminated
uint32 index = 19;
uint32 isNegative = 0;
uint32 const div = 10;
if (number < 0)
{
isNegative = 1;
number *= -1;
}
while (1)
{
int64 quo = number / div;
int64 rmd = number % div;
number = quo;
arr[index--] = (char) ('0' + rmd);
if (number == 0)
{
break;
}
}
if (isNegative)
{
arr[index--] = '-';
}
print_str(&(arr[index + 1]));
}
static void
print_hex(uint64 number, uint64 capital)
{
char const lookup_table_cap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char const lookup_table[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
char const *const look_up = capital == 1 ? &lookup_table_cap[0] : &lookup_table[0];
char arr[17];
arr[16] = 0; //zero-terminated
uint32 index = 15;
uint32 const div = 16;
while (1)
{
uint64 quo = number / div;
uint64 rmd = number % div;
number = quo;
arr[index--] = look_up[rmd];
if (number == 0)
{
break;
}
}
print_str(&(arr[index + 1]));
}
void
clear_screen(void)
{
uint64 irq;
irq = spin_lock_irq_save(&lock);
text_pos = 0; // reset text_pos
mem_set((void *) FBUF, 0, 25 * 80 * 2);
spin_unlock_irq_restore(&lock, irq);
}
static void
kvprintf(char const *format, va_list args)
{
char buf[2];
int64 d;
uint64 u;
char *s;
buf[1] = '\0';
for (; *format != '\0'; format++)
{
if (*format != '%')
{
buf[0] = *format;
print_str(buf);
continue;
}
format++;
switch (*format)
{
case 'd':
d = va_arg(args, int64);
print_int(d);
break;
case 'u':
u = va_arg(args, uint64);
print_uint(u);
break;
case 's':
s = va_arg(args, char *);
print_str(s);
break;
case 'x':
u = va_arg(args, uint64);
print_hex(u, 0);
break;
case 'X':
u = va_arg(args, uint64);
print_hex(u, 1);
break;
case '%':
buf[0] = '%';
print_str(buf);
break;
default:
buf[0] = '%';
print_str(buf);
format--;
break;
}
}
}
void
kprintf(char const *format, ...)
{
va_list args;
va_start(args, format);
uint64 irq;
irq = spin_lock_irq_save(&lock);
kvprintf(format, args);
spin_unlock_irq_restore(&lock, irq);
va_end(args);
}

132
src/proc.c Normal file
View File

@ -0,0 +1,132 @@
#include "error.h"
#include "proc.h"
#include "pmm.h"
#include "vmm.h"
#include "thread.h"
#include "elf64.h"
#include "cpu.h"
#include "paging.h"
#include "memory_layout.h"
static struct spin_lock proc_list_lock;
static struct llist proc_list;
static uint32 proc_id;
int32 proc_init(void* k_routine)
{
uint32 tid;
int32 ret = ESUCCESS;
spin_init(&proc_list_lock);
lb_llist_init(&proc_list);
proc_id = 0;
// hack to make the first process
struct pcb *pcb = kalloc(sizeof(struct pcb));
if (pcb == NULL)
{
ret = ENOMEM;
}
if (ret == ESUCCESS)
{
pcb->cr3 = read_cr3();
pcb->proc_id = (uint32) xinc_32((int32 *) &proc_id, 1);
spin_init(&pcb->lock);
lb_llist_init(&pcb->threads);
ret = thread_create(pcb, k_routine, NULL, &tid);
}
if (ret != ESUCCESS)
{
kfree(pcb);
}
return ret;
}
int32 proc_create(void* elf64, uint32 *pid)
{
int32 ret = ESUCCESS;
// allocate struct pcb
struct pcb *pcb = kalloc(sizeof(struct pcb));
if (pcb == NULL)
{
ret = ENOMEM;
}
// allocate pml4
uintptr cr3 = (uintptr) NULL;
if (ret == ESUCCESS)
{
cr3 = (uintptr) pmalloc(PAGE_SIZE);
if (cr3 == (uintptr) NULL)
{
ret = ENOMEM;
}
}
void* entry = NULL;
bool pushed = FALSE;
if (ret == ESUCCESS)
{
// init pcb
pcb->cr3 = cr3;
pcb->proc_id = (uint32) xinc_32((int32 *) &proc_id, 1);
spin_init(&pcb->lock);
lb_llist_init(&pcb->threads);
// write page tables
uintptr cur_cr3 = read_cr3();
uint64 *cur_pml4 = R_PADDR(cur_cr3);
uint64 *pml4 = R_PADDR(cr3);
// identity map the kernel space
for (uint32 i = PML4_ENTRY(K_START); i < 512; i++)
{
pml4[i] = cur_pml4[i];
}
// register the process
spin_lock(&proc_list_lock);
lb_llist_push_front(&proc_list, &pcb->list_node);
spin_unlock(&proc_list_lock);
pushed = TRUE;
ret = elf_load_file(pcb, elf64, &entry);
}
if (ret == ESUCCESS)
{
// create the thread
uint32 tid;
ret = thread_create(pcb, entry, (void*)0x13141516, &tid);
}
if (ret == ESUCCESS)
{
*pid = pcb->proc_id;
}
else
{
if (pcb != NULL)
{
if (pushed)
{
spin_lock(&proc_list_lock);
lb_llist_remove_by_ref(&proc_list, &pcb->list_node);
spin_unlock(&proc_list_lock);
}
kfree(pcb);
}
// need to properly unmap everything
if (cr3 != (uintptr) NULL)
{
pfree(cr3);
}
}
return ret;
}

47
src/spin_lock.c Normal file
View File

@ -0,0 +1,47 @@
#include "spin_lock.h"
#include "cpu.h"
#include "intr.h"
void
spin_init(struct spin_lock *lock)
{
if (lock != NULL)
{
lock->val = 0;
}
}
void
spin_lock(struct spin_lock *lock)
{
if (lock != NULL)
{
while (cmpxchg_32(&lock->val, 0, 1) != 0)
{}
}
}
void
spin_unlock(struct spin_lock *lock)
{
if (lock != NULL)
{
lock->val = 0;
}
}
uint64 spin_lock_irq_save(struct spin_lock* lock)
{
uint64 ret = READ_IRQ();
WRITE_IRQ(0xf);
spin_lock(lock);
return ret;
}
void spin_unlock_irq_restore(struct spin_lock* lock, uint64 irq)
{
spin_unlock(lock);
WRITE_IRQ(irq);
}

28
src/syscall.c Normal file
View File

@ -0,0 +1,28 @@
#include <print.h>
#include "syscall.h"
#include "thread.h"
#include "intr.h"
void *syscall_handler(struct intr_frame *frame)
{
uint64 vec = (uint32)frame->rdi;
if (vec == 0)
{
// print
kprintf("%s", (char*)frame->rsi);
}
else
{
kprintf("[WARN] Unrecognized syscall from proc %d, thread %d, function %d\n", (uint64) get_cur_thread()->proc->proc_id,
(uint64) get_cur_thread()->tid,
vec);
}
// nothing for the handler
return NULL;
}
void syscall_init()
{
set_intr_handler(INTR_VEC_SYSCALL, syscall_handler);
}

420
src/thread.c Normal file
View File

@ -0,0 +1,420 @@
#include <print.h>
#include <paging.h>
#include "thread.h"
#include "error.h"
#include "proc.h"
#include "clib.h"
#include "vmm.h"
#include "cpu.h"
#include "intr.h"
#include "memory_layout.h"
#define THREAD_STACK_SIZE (PAGE_SIZE)
enum
{
THREAD_STATE_RDY = 0,
THREAD_STATE_BLK = 1,
THREAD_STATE_ZOM = 2,
};
static uint32 thread_id;
static struct tcb *cur_thread;
static struct llist thread_list;
static struct spin_lock thread_list_lock;
void list_threads()
{
struct llist_node *node = lb_llist_first(&thread_list);
struct tcb *tcb = NULL;
while (node != NULL)
{
tcb = OBTAIN_STRUCT_ADDR(node, struct tcb, list_node);
// reading no need to lock thread lock
kprintf("Thread %d\n", (uint64) tcb->tid);
node = lb_llist_next(node);
}
}
static struct tcb *get_tcb_by_id(uint32 tid)
{
// the thread list lock must be held
struct llist_node *node = lb_llist_first(&thread_list);
struct tcb *tcb = NULL;
while (node != NULL)
{
tcb = OBTAIN_STRUCT_ADDR(node, struct tcb, list_node);
// reading no need to lock thread lock
if (tcb->tid == tid)
{
break;
}
node = lb_llist_next(node);
}
return tcb;
}
int32 thread_get_exit_code(uint32 tid, int32 *exit_code)
{
int32 ret = ESUCCESS;
struct tcb *tcb;
uint64 irq = spin_lock_irq_save(&thread_list_lock);
tcb = get_tcb_by_id(tid);
spin_unlock_irq_restore(&thread_list_lock, irq);
if (tcb == NULL)
{
ret = EINVARG;
}
if (ret == ESUCCESS)
{
if (tcb->state == THREAD_STATE_ZOM)
{
*exit_code = tcb->exit_code;
// this is unfair but do it for now
thread_yield();
}
else
{
ret = EINVARG;
}
}
return ret;
}
int32 thread_stop(uint32 tid, int32 code)
{
int32 ret = ESUCCESS;
struct tcb *tcb;
uint64 irq = spin_lock_irq_save(&thread_list_lock);
tcb = get_tcb_by_id(tid);
spin_unlock_irq_restore(&thread_list_lock, irq);
if (tcb == NULL)
{
ret = EINVARG;
}
if (ret == ESUCCESS)
{
spin_lock(&tcb->lock);
if (tcb->state != THREAD_STATE_ZOM)
{
tcb->state = THREAD_STATE_ZOM;
tcb->exit_code = code;
}
else
{
ret = EINVARG;
}
spin_unlock(&tcb->lock);
}
if (ret == ESUCCESS)
{
// well this is unfair
// but do this for now
thread_yield();
}
return ret;
}
void set_cur_thread(struct tcb *t)
{
// first time setting
KASSERT(cur_thread == NULL);
cur_thread = t;
}
// this guy picks the next thread to run
// by updating cur_thread
// timer interrupt always
// the actual context swap is done elsewhere
void thread_schedule()
{
// only timer interrupt context
spin_lock(&thread_list_lock);
if (cur_thread == NULL)
{
// first thread hack
cur_thread = OBTAIN_STRUCT_ADDR(lb_llist_first(&thread_list), struct tcb, list_node);
}
KASSERT(cur_thread != NULL);
struct llist_node *next_node = &cur_thread->list_node;
// since there must be a null thread, node cannot be null
while (1)
{
// get the next tcb in a round robbin fashion
next_node = lb_llist_next(next_node);
if (next_node == NULL)
{
next_node = lb_llist_first(&thread_list);
}
struct tcb *next = OBTAIN_STRUCT_ADDR(next_node, struct tcb, list_node);
// we are only checking states here so no need to worry
// since thread_block always fires an timer interrupt, which will be served immediately after this returns
// so even if someone else from another core blocks this thread during this window
// this thread will get descheduled right after the current timer interrupt deasserts
// the worst case is someone unblocked a thread right after we checked it, but it doesn't break integrity
if (next->state == THREAD_STATE_RDY)
{
cur_thread = next;
// stop looping, scheduler runs fast, although o(n)
break;
}
else if (next->state == THREAD_STATE_ZOM)
{
// zombie thread, should use ref count to properly deallocate stuff
// TODO: clean up zombie threads
}
}
spin_unlock(&thread_list_lock);
#ifdef KDBG
kprintf("[Scheduler] Next Proc: %d. Next Thread: %d\n", (uint64)cur_thread->proc->proc_id, (uint64)cur_thread->tid);
#endif
}
void thread_exit(int32 code)
{
spin_lock(&cur_thread->lock);
KASSERT(cur_thread->state == THREAD_STATE_RDY);
cur_thread->exit_code = code;
cur_thread->state = THREAD_STATE_ZOM;
spin_unlock(&cur_thread->lock);
thread_yield();
// shouldn't get here
KASSERT(FALSE);
}
int32 thread_resume(uint32 tid)
{
int32 ret = ESUCCESS;
struct tcb *tcb;
uint64 irq = spin_lock_irq_save(&thread_list_lock);
tcb = get_tcb_by_id(tid);
spin_unlock_irq_restore(&thread_list_lock, irq);
if (tcb == NULL)
{
ret = EINVARG;
}
if (ret == ESUCCESS)
{
spin_lock(&tcb->lock);
if (tcb->state == THREAD_STATE_BLK)
{
tcb->state = THREAD_STATE_RDY;
}
else
{
ret = EINVARG;
}
spin_unlock(&tcb->lock);
}
return ret;
}
int32 thread_block(uint32 tid)
{
int32 ret = ESUCCESS;
struct tcb *tcb;
uint64 irq = spin_lock_irq_save(&thread_list_lock);
tcb = get_tcb_by_id(tid);
spin_unlock_irq_restore(&thread_list_lock, irq);
if (tcb == NULL)
{
ret = EINVARG;
}
if (ret == ESUCCESS)
{
spin_lock(&tcb->lock);
if (tcb->state == THREAD_STATE_RDY)
{
tcb->state = THREAD_STATE_BLK;
}
else
{
ret = EINVARG;
}
spin_unlock(&tcb->lock);
}
if (ret == ESUCCESS)
{
// this is unfair but do it for now
thread_yield();
}
return ret;
}
void thread_yield()
{
// emulate a timer interrupt on target core
send_ipi(INTR_VEC_TIMER);
}
#define MODE_K (0)
#define MODE_U (1)
static void write_intr_frame(struct intr_frame *frame, uint32 mode, uint64 iret_addr, uint64 iret_stack, uint64 arg)
{
uint64 dsel = mode == MODE_K ? SEL(GDT_K_DATA, 0, 0) : SEL(GDT_U_DATA, 0, 3);
uint64 csel = mode == MODE_K ? SEL(GDT_K_CODE, 0, 0) : SEL(GDT_U_CODE, 0, 3);
frame->ss = dsel;
frame->ds = dsel;
frame->es = dsel;
frame->fs = dsel;
frame->gs = dsel;
frame->cs = csel;
frame->rip = (uint64) iret_addr;
frame->rdi = arg;
frame->rsp = iret_stack;
// only set interrupt enable flag
frame->rflags = (0x200);
}
int32 thread_create(struct pcb *proc, void *entry, void *args, uint32 *tid)
{
int32 ret = ESUCCESS;
struct tcb *tcb = kalloc(sizeof(struct tcb));
if (tcb == NULL)
{
ret = ENOMEM;
}
// allocate thread kernel stack
// 4k stack for now
// no stack overflow
uintptr ustack = (uintptr) NULL;
uint64 *kstack = NULL;
uint64 *kstack_top = NULL;
if (ret == ESUCCESS)
{
kstack = kalloc(THREAD_STACK_SIZE);
if (kstack == NULL)
{
ret = ENOMEM;
}
else
{
kstack_top = (uint64 *) ((uintptr) kstack + THREAD_STACK_SIZE);
}
}
// allocate ustack always
if (ret == ESUCCESS)
{
ustack = (uintptr) pmalloc(THREAD_STACK_SIZE);
if (ustack == (uintptr) NULL)
{
ret = ENOMEM;
}
}
struct intr_frame *frame = NULL;
if (ret == ESUCCESS)
{
tcb->tid = (uint32) xinc_32((int32 *) &thread_id, 1);
spin_init(&tcb->lock);
tcb->exit_code = 0;
tcb->state = THREAD_STATE_RDY;
tcb->proc = proc;
tcb->kstack = kstack;
tcb->kstack_sz = THREAD_STACK_SIZE;
tcb->ustack_sz = THREAD_STACK_SIZE;
tcb->ustack = ustack;
// write initial context information on the kernel stack
frame = (struct intr_frame *) ((uintptr) kstack_top - sizeof(struct intr_frame));
mem_set(frame, 0, sizeof(struct intr_frame));
// here we wanna check if the entrance is user mode
if (IS_KERN_SPACE(entry))
{
write_intr_frame(frame, MODE_K, (uint64) entry, (uint64) kstack_top, (uint64) args);
}
else
{
// map ustack to the user address space
ret = map_vmem(proc->cr3, U_STACK_VADDR, ustack);
if (ret == ESUCCESS)
{
write_intr_frame(frame, MODE_U, (uint64) entry, (uint64) (U_STACK_VADDR + THREAD_STACK_SIZE),
(uint64) args);
}
}
}
if (ret == ESUCCESS)
{
// update interrupt stack pointer
tcb->rsp0 = (uint64) frame;
// add to thread list
uint64 irq;
irq = spin_lock_irq_save(&thread_list_lock);
lb_llist_push_back(&thread_list, &tcb->list_node);
spin_unlock_irq_restore(&thread_list_lock, irq);
*tid = tcb->tid;
}
if (ret != ESUCCESS)
{
// clean up
if (tcb != NULL)
{
kfree(tcb);
}
if (ustack != (uintptr) NULL)
{
pfree(ustack);
}
if (kstack != NULL)
{
kfree(kstack);
}
}
return ret;
}
void thread_init()
{
cur_thread = NULL;
lb_llist_init(&thread_list);
spin_init(&thread_list_lock);
thread_id = 0;
}
struct tcb *get_cur_thread()
{
return cur_thread;
}

69
src/vmm.c Normal file
View File

@ -0,0 +1,69 @@
#include <cdef.h>
#include <vmm.h>
#include <pmm.h>
#include <paging.h>
#include <memory_layout.h>
#include <error.h>
#include <cpu.h>
#include <print.h>
static void *pointer;
static struct spin_lock lock;
void *kalloc(usize size)
{
spin_lock(&lock);
void *ret;
if ((size > KERNEL_PAGE_SIZE) || ((uintptr) pointer + size >= K_DYN_END))
{
ret = NULL;
}
else
{
ret = pointer;
pointer = (void *) ((uintptr) pointer + KERNEL_PAGE_SIZE);
}
spin_unlock(&lock);
/* Hack */
int32 status = ESUCCESS;
if (ret != NULL)
{
// check if the target page is already mapped
// ret val does not cross page boundries
if (get_paddr(read_cr3(), (uintptr) ret) == (uintptr) NULL)
{
uintptr frame = (uintptr) pmalloc(PAGE_SIZE);
status = (frame != (uintptr) NULL) && (map_vmem(read_cr3(), (uintptr) ret, frame) != ESUCCESS);
}
}
if (status != ESUCCESS)
{
ret = NULL;
}
else
{
flush_tlb();
}
#ifdef KDBG
kprintf("Allocated Virtual: 0x%x Size: %d\n", ret, (uint64) size);
#endif
return ret;
}
void init_vm()
{
pointer = (void *) K_DYNAMIC;
spin_init(&lock);
}
void
kfree(void *ptr)
{
UNREFERENCED(ptr);
}

6
test/bochsrc Normal file
View File

@ -0,0 +1,6 @@
display_library: x, options="gui_debug"
cpuid: 1g_pages=1
ata0-master: type=cdrom, path="out/curros.iso", status=inserted
boot: cdrom
magic_break: enabled=1
memory: guest=512, host=512

4
test/qemu.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
qemu-system-x86_64 -m 128 -monitor stdio -cdrom out/curros.iso -s -S -d cpu_reset

12
user/curros.asm Normal file
View File

@ -0,0 +1,12 @@
SYSCALL_VEC equ 51
SECTION .text
BITS 64
GLOBAL syscall
syscall:
; rdi = function number
; rsi = args
int SYSCALL_VEC
ret

36
user/hello.c Normal file
View File

@ -0,0 +1,36 @@
#include <stdint.h>
#include <cdef.h>
#include <curros.h>
#define THREAD_DELAY (5000000*4)
void
main(void *dat)
{
char *msg_ok = "[UThread3] Magic number OK.\n";
char *msg_bad = "[UThread3] Magic number FAILED.\n";
char msg[] = "[UThread3] \n";
uint32 success = 0;
uint32 magic = 0x13141516;
if ((uint32) dat == magic)
{
syscall(SYSCALL_FUNC_PRINT, msg_ok);
success = 1;
}
else
{
syscall(SYSCALL_FUNC_PRINT, msg_bad);
success = 0;
}
int i = 0;
while (1)
{
poor_sleep(THREAD_DELAY);
i = i % 10;
msg[11] = i + 48;
syscall(SYSCALL_FUNC_PRINT, msg);
i++;
}
// don't return here, need to call thread exit
}

22
user/inc/cdef.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
typedef uint32_t uint32;
typedef int32_t int32;
typedef uint64_t uint64;
typedef int64_t int64;
typedef uintptr_t uintptr;
typedef uint16_t uint16;
typedef int16_t int16;
typedef uint8_t uint8;
typedef int8_t int8;
typedef size_t usize;
typedef _Bool bool;
#define TRUE (1)
#define FALSE (0)

14
user/inc/curros.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "cdef.h"
#define SYSCALL_FUNC_PRINT (0)
void syscall(uint32 func, void* args);
static inline void poor_sleep(uint32 dat)
{
for(uint32 i = 0; i < dat; i++)
{
}
}

26
user/linker.ld Normal file
View File

@ -0,0 +1,26 @@
ENTRY(main)
KERNEL_PAGE_SIZE = 0x1000;
USER_APPLICATION_VADDR = 0x1000000;
SECTIONS
{
. = USER_APPLICATION_VADDR;
.text ALIGN(KERNEL_PAGE_SIZE):
{
*(.text)
}
.data ALIGN(KERNEL_PAGE_SIZE):
{
*(.data)
*(.rodata*)
}
.bss ALIGN(KERNEL_PAGE_SIZE):
{
*(.bss)
*(COMMON)
}
}

91
user/makefile Normal file
View File

@ -0,0 +1,91 @@
AS := nasm
CC := clang-6.0
LD := lld-6.0
DAS := llvm-objdump-6.0
.DEFAULT_GOAL := all
C_FLAGS_ARCH_X86_64 := -target x86_64-pc-none-elf \
-mno-red-zone \
-mno-mmx \
-mno-sse \
-mno-sse2 \
-mno-sse3 \
-mno-3dnow
C_FLAGS = -x c \
-g \
-c \
-O0 \
-std=c17 \
-Wall \
-Werror \
-Wextra \
-Wpedantic \
-ffreestanding \
-fno-pic \
-fno-stack-protector \
-Wno-error=int-to-pointer-cast \
-Wno-error=zero-length-array \
$(C_FLAGS_ARCH_X86_64) \
-I$(INC)/
AS_FLAGS = -w+all \
-w+error \
-f elf64 \
-F dwarf \
-g \
-I$(INC)/ \
LD_FLAGS = -fuse-ld=$(LD) \
-nostdlib \
-Wl, linker.ld \
-Wl,--fatal-warnings
# ===============================
# HERE COMES file definitions
# ===============================
INC := inc
SRC := .
OUT := out
TGT := $(OUT)/hello.elf
# ===============================
# Add additional c source files here
# ===============================
C_SRC := hello.c
# ===============================
# Add additional ASM source files here
# ===============================
ASM_SRC := curros.asm
# ===============================
# Compilation rules
# ===============================
C_OBJ := $(addsuffix .o, $(addprefix $(OUT)/,$(C_SRC)))
ASM_OBJ := $(addsuffix .o, $(addprefix $(OUT)/,$(ASM_SRC)))
$(C_OBJ): $(OUT)/%.c.o : %.c
$(CC) $(C_FLAGS) -o $@ $<
$(ASM_OBJ): $(OUT)/%.asm.o : %.asm
$(AS) $(AS_FLAGS) -o $@ $<
$(TGT): $(C_OBJ) $(ASM_OBJ)
$(CC) $(LD_FLAGS) -o $@ $^
.PHONY: mkdir
mkdir:
mkdir -p out
.PHONY: clean
clean:
rm -rf $(OUT)
.PHONY: all
all: mkdir $(TGT)