This commit is contained in:
Adrien Bourmault 2023-10-11 19:14:24 +02:00
parent f3bce787fc
commit 2778dc91fa
No known key found for this signature in database
GPG Key ID: 2974E1D5F25DFCC8
54 changed files with 5319 additions and 0 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
Adrien Bourmault
3677850
# [NMV] TP1 : table des pages
## Exercice 1
### Q1
C'est important pour mapper la table des pages elle-même, et la maintenir.
### Q2
On a un seul registre CR3 qui pointe vers une adresse physique de PML4, il y a donc une seule PML4, qui constitue une page. Il y a 512 entrées par page, donc 512 entrées dans la PML4.
Il y a donc 512 pages PML3. Ainsi, on a 262 144 pages PML2, et 134 217 728 pages PML1.
La MMU compare le bit 0 pour savoir si c'est valide.
Pour savoir si elle est terminale, TODO.
### Q3
fait.
## Exercice 2
### Q1
L'index commence au bit 12 et mesure 9 bit pour chaque niveau de table. Ainsi, le premier niveau est masquable avec 1FF000.
On a
$$index = (vaddr & (0x1FF000 << (9 × (lvl-1)))) >> (12 + (9 × (lvl-1)))$$
### Q2

View File

@ -0,0 +1,39 @@
Adrien Bourmault
3677850
# [NMV] TP1 : table des pages
## Exercice 1
### Q1
C'est important pour mapper la table des pages elle-même, et la maintenir.
### Q2
On a un seul registre CR3 qui pointe vers une adresse physique de PML4, il y a donc une seule PML4, qui constitue une page. Il y a 512 entrées par page, donc 512 entrées dans la PML4.
Il y a donc 512 pages PML3. Ainsi, on a 262 144 pages PML2, et 134 217 728 pages PML1.
La MMU compare le bit 0 pour savoir si c'est valide.
Pour savoir si elle est terminale, TODO.
### Q3
fait.
## Exercice 2
### Q1
L'index commence au bit 12 et mesure 9 bit pour chaque niveau de table. Ainsi, le premier niveau est masquable avec 1FF000.
On a
$$index = (vaddr & (0x1FF000 << (9 × (lvl-1)))) >> (12 + (9 × (lvl-1)))$$
### Q2

View File

@ -0,0 +1,152 @@
OBJ := obj/
BIN := bin/
AS := gcc
ASFLAGS := -Wall -Wextra -O2 -nostdlib -nodefaultlibs
CC := gcc
CCFLAGS := -Wall -Wextra -O2 -nostdlib -nodefaultlibs -fno-builtin \
-fno-stack-protector -Wno-implicit-fallthrough -mno-sse -mno-mmx
LD := ld
LDFLAGS := -z max-page-size=0x1000
MAKEFLAGS += --no-print-directory --no-builtin-rules --no-builtin-variables
V ?= 1
ifneq ($(V),2)
Q := @
ISOPREFIX := !
ISOSUFFIX := 2>&1 | grep -E -v \
-e 'xorriso .* libburnia project.' \
-e '(Drive|Media) (current|status|summary) ?:' \
-e 'xorriso : (UPDATE|NOTE)' \
-e 'Added to ISO image:' \
-e 'ISO image produced' \
-e 'Writ(ten|ing) to' \
-e '^[[:space:]]*$$'
endif
ifeq ($(V),1)
define cmd-print
@echo '$(1)'
endef
endif
kernel-obj := $(patsubst %, $(OBJ)kernel/%.o, \
entry idt main memory printk task trap vga \
)
tasks := adversary hash sieve
all: $(BIN)rackdoll.elf
iso: $(BIN)rackdoll.iso
boot: qemu
qemu: $(BIN)rackdoll.iso
$(call cmd-print, BOOT $<)
$(Q)qemu-system-x86_64 -smp 1 -m 4G \
-drive file=$<,format=raw -monitor stdio
bochs: $(BIN)rackdoll.iso
$(call cmd-print, BOOT $<)
$(Q)bochs -q 'boot:cdrom' \
'ata0-master: type=cdrom,path=$<,status=inserted'
# VM rules ====================================================================
$(BIN)rackdoll.iso: $(OBJ)iso | $(BIN)
$(call cmd-print, MKISO $@)
$(Q)$(ISOPREFIX) grub-mkrescue -d ~/.guix-profile/lib/grub/i386-pc -o $@ \
--modules=multiboot2 $< $(ISOSUFFIX)
$(OBJ)iso: grub.cfg $(BIN)rackdoll.elf $(patsubst %, $(BIN)%.elf, $(tasks)) \
| $(OBJ)
$(call cmd-print, BUILD $@)
$(Q)rm -rf $@ 2> /dev/null || true
$(Q)mkdir $@
$(Q)mkdir $@/boot
$(Q)mkdir $@/boot/grub
$(Q)cp $< $@/boot/grub
$(Q)cp $(filter %.elf, $^) $@/boot
# Linkage rules ===============================================================
define cmd-ld
$(call cmd-print, LD $(strip $(1)))
$(Q)$(LD) -o $(1) -T $(2) $(LDFLAGS) $(3)
endef
$(BIN)rackdoll.elf: kernel.ld $(kernel-obj) | $(BIN)
$(call cmd-ld, $@, $<, $(filter %.o, $^))
# Directory rules =============================================================
define cmd-mkdir
$(call cmd-print, MKDIR $(strip $(1)))
$(Q)mkdir $(1)
endef
$(BIN) $(OBJ):
$(call cmd-mkdir, $@)
$(OBJ)kernel: | $(OBJ)
$(call cmd-mkdir, $@)
$(OBJ)task: | $(OBJ)
$(call cmd-mkdir, $@)
# Compilation rules ===========================================================
define cmd-gen
$(call cmd-print, GEN $(strip $(1)))
$(Q)./$(strip $(2)) $(1)
endef
define cmd-as
$(call cmd-print, AS $(strip $(1)))
$(Q)$(AS) $(ASFLAGS) -c $(2) -o $(1) -Iinclude
endef
define cmd-cc
$(call cmd-print, CC $(strip $(1)))
$(Q)$(CC) $(CCFLAGS) -c $(2) -o $(1) -Iinclude
endef
$(OBJ)kernel/trap.S: kernel/trap.pl | $(OBJ)kernel
$(call cmd-gen, $@, $<)
$(OBJ)kernel/trap.o: $(OBJ)kernel/trap.S $(wildcard include/*.h) | $(OBJ)kernel
$(call cmd-as, $@, $<)
$(OBJ)kernel/%.o: kernel/%.S $(wildcard include/*.h) | $(OBJ)kernel
$(call cmd-as, $@, $<)
$(OBJ)kernel/%.o: kernel/%.c $(wildcard include/*.h) | $(OBJ)kernel
$(call cmd-cc, $@, $<)
# Task rules ==================================================================
$(OBJ)task/%.o: task/%.c include/syscall.h | $(OBJ)task
$(call cmd-cc, $@, $< -mcmodel=large)
$(BIN)%.elf: task.ld $(OBJ)task/%.o | $(BIN)
$(call cmd-ld, $@, $<, $(filter %.o, $^))
# Clean rules =================================================================
clean:
$(call cmd-print, CLEAN)
$(Q)rm -rf $(OBJ) $(BIN) 2> /dev/null || true
.SECONDARY:

View File

@ -0,0 +1,10 @@
set timeout=0
set default=0
menuentry 'Rackdoll' {
echo 'Loading Rackdoll OS'
multiboot2 /boot/rackdoll.elf
module2 /boot/hash.elf
module2 /boot/sieve.elf
module2 /boot/adversary.elf
}

View File

@ -0,0 +1,89 @@
#ifndef _INCLUDE_IDT_H_
#define _INCLUDE_IDT_H_
#include <types.h>
#define INTERRUPT_VECTOR_SIZE 256
#define INT_DE 0
#define INT_DB 1
#define INT_NMI 2
#define INT_BP 3
#define INT_OF 4
#define INT_BR 5
#define INT_UD 6
#define INT_NM 7
#define INT_DF 8
#define INT_CO 9
#define INT_TS 10
#define INT_NP 11
#define INT_SS 12
#define INT_GP 13
#define INT_PF 14
#define INT_MF 16
#define INT_AC 17
#define INT_MC 18
#define INT_XF 19
#define INT_SX 30
#define INT_USER_MIN 32
#define INT_USER_TIMER 32
#define INT_USER_SYSCALL 128
#define INT_USER_ENTER_TASKS 129
#define INT_USER_SPURIOUS 130
#define INT_USER_MAX 255
struct interrupt_context
{
uint64_t rbp;
uint64_t rbx;
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rcx;
uint64_t rdx;
uint64_t rsi;
uint64_t rdi;
uint64_t rax;
uint64_t itnum;
uint64_t errcode;
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
} __attribute__((packed));
typedef void (*interrupt_handler_t)(struct interrupt_context *ctx);
extern interrupt_handler_t interrupt_vector[INTERRUPT_VECTOR_SIZE];
void remap_pic(void);
void disable_pic(void);
void setup_apic(void);
void setup_interrupts(void);
static inline void cli(void)
{
asm volatile ("cli");
}
static inline void sti(void)
{
asm volatile ("sti");
}
#endif

View File

@ -0,0 +1,30 @@
#ifndef _INCLUDE_MEMORY_H_
#define _INCLUDE_MEMORY_H_
#include <idt.h>
#include <task.h>
#include <types.h>
paddr_t alloc_page(void); /* Allocate a physical page identity mapped */
void free_page(paddr_t addr); /* Release a page allocated with alloc_page() */
void map_page(struct task *ctx, vaddr_t vaddr, paddr_t paddr);
void load_task(struct task *ctx);
void set_task(struct task *ctx);
void duplicate_task(struct task *ctx);
void mmap(struct task *ctx, vaddr_t vaddr);
void munmap(struct task *ctx, vaddr_t vaddr);
void pgfault(struct interrupt_context *ctx);
#endif

View File

@ -0,0 +1,18 @@
#ifndef _INCLUDE_PRINTK_H_
#define _INCLUDE_PRINTK_H_
#include <stdarg.h>
#include <types.h>
size_t printk(const char *format, ...);
size_t vprintk(const char *format, va_list ap);
size_t snprintk(char *buffer, size_t size, const char *format, ...);
size_t vsnprintk(char *buffer, size_t size, const char *format, va_list ap);
#endif

View File

@ -0,0 +1,14 @@
#ifndef _INCLUDE_STDARG_H_
#define _INCLUDE_STDARG_H_
typedef __builtin_va_list va_list;
#define va_start(value, list) __builtin_va_start(value, list)
#define va_arg(list, type) __builtin_va_arg(list, type)
#define va_end(list) __builtin_va_end(list)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#endif

View File

@ -0,0 +1,35 @@
#ifndef _INCLUDE_STRING_H_
#define _INCLUDE_STRING_H_
#include <types.h>
static inline size_t strlen(const char *str)
{
const char *ptr = str;
while (*ptr != '\0')
ptr++;
return (ptr - str);
}
static inline void memset(void *addr, uint8_t c, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((char *) addr)[i] = c;
}
static inline void memcpy(void *dest, const void *src, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
((uint8_t *) dest)[i] = ((uint8_t *) src)[i];
}
#endif

View File

@ -0,0 +1,89 @@
#ifndef _INCLUDE_KERNEL_H_
#define _INCLUDE_KERNEL_H_
#include <stdarg.h>
#include <types.h>
#define TASK_HEADER_MAGIC 0xff10ADa64bC0DEff
#define SYSCALL_PRINT (0ul)
#define SYSCALL_PRINTNUM (1ul)
#define SYSCALL_MMAP (2ul)
#define SYSCALL_MUNMAP (3ul)
#define SYSCALL_YIELD (4ul)
#define SYSCALL_EXIT (5ul)
#define SYSCALL_FORK (6ul)
struct task_header
{
uint64_t magic;
vaddr_t load_addr;
vaddr_t load_end_addr;
vaddr_t bss_end_addr;
vaddr_t header_addr;
vaddr_t entry_addr;
} __attribute__((packed));
void setup_syscalls(void);
struct syscall_context
{
uint64_t callnum;
uint64_t rflags;
uint64_t rip;
uint64_t rsp;
} __attribute__((packed));
static inline int syscall(size_t callnum, uint64_t arg0)
{
int ret;
asm volatile ("int $0x80\n"
: "=a" (ret)
: "D" (callnum), "S" (arg0));
return ret;
}
static inline void syscall_print(const char *str)
{
syscall(SYSCALL_PRINT, (uint64_t) str);
}
static inline void syscall_printnum(uint64_t num)
{
syscall(SYSCALL_PRINTNUM, num);
}
static inline void syscall_mmap(vaddr_t addr)
{
syscall(SYSCALL_MMAP, addr);
}
static inline void syscall_munmap(vaddr_t addr)
{
syscall(SYSCALL_MUNMAP, addr);
}
static inline void syscall_yield(void)
{
syscall(SYSCALL_YIELD, 0);
}
static inline void syscall_exit(void)
{
syscall(SYSCALL_EXIT, 0);
}
static inline int syscall_fork(void)
{
return syscall(SYSCALL_FORK, 0);
}
#endif

View File

@ -0,0 +1,63 @@
#ifndef _INCLUDE_TASK_H_
#define _INCLUDE_TASK_H_
#include <idt.h>
struct task
{
paddr_t pgt; /* page table paddr */
paddr_t load_paddr; /* paddr of the task code */
paddr_t load_end_paddr; /* paddr following code */
vaddr_t load_vaddr; /* vaddr for load_paddr */
vaddr_t bss_end_vaddr; /* vaddr following bss */
struct interrupt_context context; /* task registers save area */
};
/*
* Documentation for 64-bits Task State Segment can be found in
* AMD64 Architecture Programmer's Manual, Volume 2: System Programming
* Section 12.2: Task-Management Resources
*/
struct task_state_segment
{
uint32_t pad;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t pad1;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t pad2;
uint16_t pad3;
uint16_t iopb_off;
uint64_t iopb;
} __attribute__((packed));
extern struct task_state_segment tss;
void setup_tss(void); /* Setup user mode switch */
void load_tasks(const void *mb2); /* Load tasks from multiboot 2 info */
struct task *current(void); /* Get the current task */
void next_task(struct interrupt_context *ctx); /* Go to the next task */
void exit_task(struct interrupt_context *ctx); /* Exit the current task */
void fork_task(struct interrupt_context *ctx); /* Fork the current task */
void run_tasks(void); /* Start to execute the tasks */
#endif

View File

@ -0,0 +1,26 @@
#ifndef _INCLUDE_TYPES_H_
#define _INCLUDE_TYPES_H_
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
typedef uint8_t bool_t;
typedef uint64_t size_t;
typedef uint64_t paddr_t;
typedef uint64_t vaddr_t;
#define NULL ((void *) 0)
#endif

View File

@ -0,0 +1,15 @@
#ifndef _INCLUDE_VGA_H_
#define _INCLUDE_VGA_H_
#include <types.h>
void clear(void);
void putc(char c);
void puts(const char *str, size_t n);
#endif

View File

@ -0,0 +1,184 @@
#ifndef _INCLUDE_X86_H_
#define _INCLUDE_X86_H_
/*
* The zero, code and data selectors are set in the gdt64 declared in the
* entry.S file.
* Kernel code and data segment descriptors *must* be consecutive in the table
* so we can use syscall and sysret instructions.
* Kernel data and code segment descriptors *must* be consecutive in the table
* so we can use syscall and sysret instructions (note that this time, the
* data segment must be placed before the code segment).
*/
#define ZERO_SELECTOR 0x00
#define KERNEL_CODE_SELECTOR 0x08
#define KERNEL_DATA_SELECTOR 0x10
#define USER_DATA_SELECTOR 0x18
#define USER_CODE_SELECTOR 0x20
#define TSS_SELECTOR 0x28
/*
* Model Sepcific Registers defintions.
* These ones are common to all families of modern Intel and AMD processors.
*/
#define MSR_EFER 0xc0000080
#define MSR_EFER_SCE (1ul << 0)
#define MSR_EFER_LME (1ul << 8)
#define MSR_EFER_LMA (1ul << 10)
#define MSR_EFER_NXE (1ul << 11)
#define MSR_EFER_SVME (1ul << 12)
#define MSR_EFER_LMSLE (1ul << 13)
#define MSR_EFER_FFXSR (1ul << 14)
#define MSR_EFER_TCE (1ul << 15)
/*
* Rflags definitions.
*/
#define RFLAGS_CF (1ul << 0)
#define RFLAGS_PF (1ul << 2)
#define RFLAGS_AF (1ul << 4)
#define RFLAGS_ZF (1ul << 6)
#define RFLAGS_SF (1ul << 7)
#define RFLAGS_TF (1ul << 8)
#define RFLAGS_IF (1ul << 9)
#define RFLAGS_DF (1ul << 10)
#define RFLAGS_OF (1ul << 11)
#define RFLAGS_IOPL (3ul << 12)
#define RFLAGS_NT (1ul << 14)
#define RFLAGS_RF (1ul << 16)
#define RFLAGS_VM (1ul << 17)
#define RFLAGS_AC (1ul << 18)
#define RFLAGS_VIF (1ul << 19)
#define RFLAGS_VIP (1ul << 20)
#define RFLAGS_ID (1ul << 21)
static inline void load_rsp(uint64_t rsp)
{
asm volatile ("movq %0, %%rsp" : : "r" (rsp));
}
static inline uint64_t store_rsp(void)
{
uint64_t rsp;
asm volatile ("movq %%rsp, %0" : "=r" (rsp));
return rsp;
}
static inline void load_cr2(uint64_t cr2)
{
asm volatile ("movq %0, %%cr2" : : "a" (cr2));
}
static inline uint64_t store_cr2(void)
{
uint64_t cr2;
asm volatile ("movq %%cr2, %0" : "=a" (cr2));
return cr2;
}
static inline void load_cr3(uint64_t cr3)
{
asm volatile ("movq %0, %%cr3" : : "a" (cr3));
}
static inline uint64_t store_cr3(void)
{
uint64_t cr3;
asm volatile ("movq %%cr3, %0" : "=a" (cr3));
return cr3;
}
static inline void load_tr(uint16_t tr)
{
asm volatile ("ltr %0" : : "r" (tr));
}
static inline uint16_t store_tr(void)
{
uint16_t tr;
asm volatile ("str %0" : "=r" (tr));
return tr;
}
static inline void invlpg(vaddr_t vaddr)
{
asm volatile ("invlpg (%0)" : : "r" (vaddr) : "memory");
}
typedef uint16_t port_t;
static inline uint8_t in8(port_t port)
{
uint8_t ret;
asm volatile ("inb %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
static inline uint16_t in16(port_t port)
{
uint16_t ret;
asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
static inline uint32_t in32(port_t port)
{
uint32_t ret;
asm volatile ("inl %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
static inline void out8(port_t port, uint8_t val)
{
asm volatile ("outb %0, %1" : : "a" (val), "dN" (port));
}
static inline void out16(port_t port, uint16_t val)
{
asm volatile ("outw %0, %1" : : "a" (val), "dN" (port));
}
static inline void out32(port_t port, uint32_t val)
{
asm volatile ("outl %0, %1" : : "a" (val), "dN" (port));
}
static inline void wrmsr(uint32_t msr, uint64_t val)
{
uint32_t eax, edx;
edx = (val >> 32) & 0xffffffff;
eax = (val >> 0) & 0xffffffff;
asm volatile ("wrmsr" : : "a" (eax), "c" (msr), "d" (edx));
}
static inline uint64_t rdmsr(uint32_t msr)
{
uint32_t eax, edx;
asm volatile ("rdmsr" : "=a" (eax), "=d" (edx) : "c" (msr));
return (((uint64_t) edx) << 32) | eax;
}
#define PGT_VALID_MASK (1 << 0)
#define PGT_WRITABLE_MASK (1 << 1)
#define PGT_USER_MASK (1 << 2)
#define PGT_ADDR_MASK (0xFFFFFFFFFFFFF000)
#define PGT_PML_INDEX(n, vaddr) (vaddr & (0x1FF000 << (9 * (n-1)))) >> (12 + (9 * (n-1)))
#endif

View File

@ -0,0 +1,35 @@
OUTPUT_FORMAT(elf64-x86-64)
/* Kernel Linear (= Physical) Memory Address */
KERNEL_LMA = 0x100000;
SECTIONS
{
/* For what address to compile the code */
. = KERNEL_LMA;
.text : ALIGN(0x1000) {
__kernel_text_start = .;
*(.multiboot2);
*(.text);
__kernel_text_end = .;
}
.data : {
__kernel_data_start = .;
*(.data*);
*(.rodata*);
__kernel_data_end = .;
}
.bss : {
__kernel_bss_start = .;
*(.bss);
*(COMMON);
__kernel_bss_end = .;
}
/DISCARD/ : {
*(.eh_frame .comment);
}
}

View File

@ -0,0 +1,149 @@
# Documentation for multiboot2 can be found in
# The Multiboot Specification version 1.6
# http://nongnu.askapache.com/grub/phcoder/multiboot.pdf
.section ".multiboot2"
.align 64
.header_start:
# The magic field of Multiboot header
.long 0xe85250d6
.long 0
.long (.header_end - .header_start)
.long -(0xe85250d6 + 0 + (.header_end - .header_start))
# The address tag of Multiboot header
.balign 8
.word 2
.word 0
.long 24
.long .header_start
.long __kernel_text_start
.long __kernel_data_end
.long __kernel_bss_end
# The entry address taf of Multiboot header
.balign 8
.word 3
.word 0
.long 12
.long entry_multiboot2
# The terminating tag of Multiboot header
.balign 8
.word 0
.word 0
.long 8
.header_end:
.section ".text"
.balign 8
.code32
entry_multiboot2:
# Setup a valid GDT as multiboot2 does not guarantee it.
# Load the DS segment as a data segment.
# Load the CS segment as the code segment with a long jump.
lgdt gdtr32
movw $0x10, %ax
movw %ax, %ds
ljmp $0x08, $1f
1:
# Load the CR3 with the identity page table pml4
movl $pml4, %eax
movl %eax, %cr3
# Add the PAE and PGE flags to the CR4
movl %cr4, %eax
orl $0xa0, %eax
movl %eax, %cr4
# Set the LME flag in the EFER register
movl $0xc0000080, %ecx
rdmsr
orl $0x100, %eax
wrmsr
# Add the paging with the flags PG and WP in CR0
movl %cr0, %eax
orl $0x80000100, %eax
movl %eax, %cr0
# Setup a 64-bits GDT and load the CS segment with a long jump.
lgdt gdtr64
ljmp $0x08, $1f
.code64
1:
# From this point we are executing in 64-bits mode.
# We can now load the 64-bits data segment.
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
# Setup an initial stack, set %ebp (mb2 info) as first argument, then
# jump to C code.
movq $boot_stack, %rsp
movq $main_multiboot2, %rax
xorq %rdi, %rdi
movl %ebx, %edi
jmpq *%rax
# Documentation for 32-bits Segment Descriptors can be found in
# AMD64 Architecture Programmer's Manual, Volume 2: System Programming
# Section 4.7: Legacy Segment Descriptors
.section ".data"
gdtr32:
.word 3 * 8 - 1
.long gdt32
gdt32:
.word 0, 0, 0, 0 # zero segment
.word 0xffff, 0, 0x9a00, 0x00cf # code segment
.word 0xffff, 0, 0x9200, 0x00cf # data segment
# Documentation for 64-bits Segment Descriptors can be found in
# AMD64 Architecture Programmer's Manual, Volume 2: System Programming
# Section 4.7: Legacy Segment Descriptors
.globl tss64
gdtr64:
.word 7 * 8 - 1
.long gdt64
gdt64:
.word 0, 0, 0, 0 # zero segment
.word 0, 0, 0x9a00, 0x0020 # kernel code segment
.word 0, 0, 0x9200, 0 # kernel data segment
.word 0, 0, 0xf200, 0 # user data segment
.word 0, 0, 0xfa00, 0x0020 # user code segment
tss64:
.word 0, 0, 0x8900, 0 # mandatory tss
.word 0, 0, 0, 0 # tss upper long
# Documentation for 64-bits Page Translation can be found in
# AMD64 Architecture Programmer's Manual, Volume 2: System Programming
# Section 5.3: Long-Mode Page Translation
.align 0x1000
pml4:
.quad pml3 + 0x7 # pml4[0] = pml3 | U | W | P
.space 0xff8, 0 # pml4[n] = empty
pml3:
.quad pml2 + 0x7 # pml3[0] = pml2 | U | W | P
.space 0xff8, 0 # pml3[n] = empty
pml2:
.quad 0x19b # pml2[0] = G | PS | PCD | PWT | W | P
.quad apic + 0x1b # pml2[1] = apic | G | PCD | PWT | W | P
.space 0xff0, 0 # pml2[n] = empty
apic:
.quad 0xfee0011b # apic[0] = 0xfee00000 | G | PCD | PWT | W | P
.space 0xff8, 0
.section ".bss"
.space 0x1000, 0 # initial stack of 4 KiB
boot_stack:
.space 0x1000, 0 # syscall stack of 4 KiB
syscall_stack:

View File

@ -0,0 +1,221 @@
#include <idt.h>
#include <types.h>
#include <printk.h>
#include <x86.h>
#define IO_WAIT_PORT 0x80
#define PIC_MASTER_COMMAND_PORT 0x20
#define PIC_MASTER_DATA_PORT 0x21
#define PIC_SLAVE_COMMAND_PORT 0xa0
#define PIC_SLAVE_DATA_PORT 0xa1
#define PIC_COMMAND_INIT 0x11
#define PIC_DATA_8086 0x01
#define PIC_DATA_DISABLE 0xff
#define PIC_MASTER_REMAP_IRQ 0x20
#define PIC_MASTER_IDENTITY 0x04
#define PIC_SLAVE_REMAP_IRQ 0x28
#define PIC_SLAVE_IDENTITY 0x02
#define LAPIC_BASE_MSR 0x1b
#define LAPIC_BASE_ENABLE (1ul << 11)
#define LAPIC_VADDR 0x200000 /* see memory.c and entry.S */
#define LAPIC_TIMER_PERIODIC (1u << 17)
#define LAPIC_DISABLE (1u << 16)
#define LAPIC_SPURIOUS_ASE (1u << 8)
#define INTERRUPT_GATE_TYPE 0xee00
#define TRAP_GATE_TYPE 0xef00
extern vaddr_t trap_vector[];
static struct {
uint16_t off0;
uint16_t sel;
uint16_t flags;
uint16_t off1;
uint32_t off2;
uint32_t _ign0;
} __attribute__((packed)) idt64[INTERRUPT_VECTOR_SIZE];
struct {
uint16_t limit;
uint64_t base;
} __attribute__((packed)) idtr64;
interrupt_handler_t interrupt_vector[INTERRUPT_VECTOR_SIZE];
static void default_interrupt(struct interrupt_context *ctx)
{
uint64_t cr2;
printk("Interrupt %lu (err = %#lx)\n", ctx->itnum, ctx->errcode);
if (ctx->itnum == INT_PF) {
cr2 = store_cr2();
printk(" CR2 = %p\n", cr2);
}
asm volatile ("hlt");
}
void trap(struct interrupt_context *ctx)
{
interrupt_handler_t handler = interrupt_vector[ctx->itnum];
if (handler == NULL)
default_interrupt(ctx);
else
handler(ctx);
}
static void io_wait(void)
{
out8(IO_WAIT_PORT, 0);
}
void remap_pic(void)
{
uint8_t master_mask, slave_mask;
master_mask = in8(PIC_MASTER_DATA_PORT);
slave_mask = in8(PIC_SLAVE_DATA_PORT);
out8(PIC_MASTER_COMMAND_PORT, PIC_COMMAND_INIT);
io_wait();
out8(PIC_SLAVE_COMMAND_PORT, PIC_COMMAND_INIT);
io_wait();
out8(PIC_MASTER_DATA_PORT, PIC_MASTER_REMAP_IRQ);
io_wait();
out8(PIC_SLAVE_DATA_PORT, PIC_SLAVE_REMAP_IRQ);
io_wait();
out8(PIC_MASTER_DATA_PORT, PIC_MASTER_IDENTITY);
io_wait();
out8(PIC_SLAVE_DATA_PORT, PIC_SLAVE_IDENTITY);
io_wait();
out8(PIC_MASTER_DATA_PORT, PIC_DATA_8086);
io_wait();
out8(PIC_SLAVE_DATA_PORT, PIC_DATA_8086);
io_wait();
out8(PIC_MASTER_DATA_PORT, master_mask);
out8(PIC_SLAVE_DATA_PORT, slave_mask);
}
void disable_pic(void)
{
out8(PIC_MASTER_DATA_PORT, PIC_DATA_DISABLE);
out8(PIC_SLAVE_DATA_PORT, PIC_DATA_DISABLE);
}
void setup_interrupts(void)
{
size_t i;
idtr64.limit = sizeof (idt64) - 1;
idtr64.base = (uint64_t) &idt64;
for (i = 0; i < INTERRUPT_VECTOR_SIZE; i++) {
idt64[i].off0 = ((trap_vector[i] >> 00) & 0xffff);
idt64[i].off1 = ((trap_vector[i] >> 16) & 0xffff);
idt64[i].off2 = ((trap_vector[i] >> 32) & 0xffffffff);
idt64[i].sel = KERNEL_CODE_SELECTOR;
if (i == INT_USER_SYSCALL) {
idt64[i].flags = TRAP_GATE_TYPE;
} else {
idt64[i].flags = INTERRUPT_GATE_TYPE;
}
}
asm volatile ("lidt idtr64");
}
struct lapic_register
{
volatile uint32_t reg;
uint32_t _pad[3];
} __attribute__ ((packed));
struct lapic
{
struct lapic_register _pad0[2];
struct lapic_register id;
struct lapic_register version;
struct lapic_register _pad1[4];
struct lapic_register tpr;
struct lapic_register apr;
struct lapic_register ppr;
struct lapic_register eoi;
struct lapic_register rrr;
struct lapic_register ldr;
struct lapic_register dfr;
struct lapic_register svr;
struct lapic_register isr[8];
struct lapic_register tmr[8];
struct lapic_register irr[8];
struct lapic_register esr;
struct lapic_register _pad2[7];
struct lapic_register icr_low;
struct lapic_register icr_high;
struct lapic_register timer_entry;
struct lapic_register thermal_entry;
struct lapic_register performance_entry;
struct lapic_register local0_entry;
struct lapic_register local1_entry;
struct lapic_register error_entry;
struct lapic_register timer_initial;
struct lapic_register timer_current;
struct lapic_register _pad3[4];
struct lapic_register timer_divide;
struct lapic_register _pad4;
struct lapic_register extended_feature;
struct lapic_register extended_control;
struct lapic_register seoi;
struct lapic_register _pad5[5];
struct lapic_register ier[8];
struct lapic_register extended_vector[3];
} __attribute__ ((packed));
struct lapic *lapic = (struct lapic *) LAPIC_VADDR;
static void timer_interrupt(struct interrupt_context *ctx
__attribute__ ((unused)))
{
lapic->eoi.reg = 0;
}
void setup_apic(void)
{
uint64_t val = rdmsr(LAPIC_BASE_MSR);
interrupt_vector[INT_USER_TIMER] = timer_interrupt;
wrmsr(LAPIC_BASE_MSR, val & ~LAPIC_BASE_ENABLE);
lapic->tpr.reg = 0;
lapic->timer_entry.reg = LAPIC_DISABLE;
lapic->thermal_entry.reg = LAPIC_DISABLE;
lapic->performance_entry.reg = LAPIC_DISABLE;
lapic->local0_entry.reg = LAPIC_DISABLE;
lapic->local1_entry.reg = LAPIC_DISABLE;
lapic->error_entry.reg = LAPIC_DISABLE;
lapic->timer_entry.reg = INT_USER_TIMER | LAPIC_TIMER_PERIODIC;
lapic->timer_divide.reg = 3; /* divide by 16 */
lapic->timer_initial.reg = 0x1000; /* by the power of black magic! */
wrmsr(LAPIC_BASE_MSR, val | LAPIC_BASE_ENABLE);
lapic->svr.reg |= (INT_USER_SPURIOUS | LAPIC_SPURIOUS_ASE);
}

View File

@ -0,0 +1,84 @@
#include <idt.h> /* see there for interrupt names */
#include <memory.h> /* physical page allocator */
#include <printk.h> /* provides printk() and snprintk() */
#include <string.h> /* provides memset() */
#include <syscall.h> /* setup system calls for tasks */
#include <task.h> /* load the task from mb2 info */
#include <types.h> /* provides stdint and general purpose types */
#include <vga.h> /* provides clear() */
#include <x86.h> /* access to cr3 and cr2 */
void print_pgt(paddr_t pml, uint8_t lvl) {
paddr_t *cur = (paddr_t *)(pml & PGT_ADDR_MASK);
if (lvl == 0)
return;
if (lvl == 4)
printk("[print_pgt]\n");
printk("\tPML%d @ 0x%lx exists\n",
lvl,
cur);
while (*cur) {
printk("\t\tPML%d[%lx] -> 0x%lx (FLAGS ",
lvl,
cur,
(uint64_t)(*cur) & PGT_ADDR_MASK);
if (*cur & PGT_USER_MASK)
printk("U");
if (*cur & PGT_WRITABLE_MASK)
printk("W");
if (*cur & PGT_VALID_MASK)
printk("P");
printk(")\n");
if (*cur & PGT_ADDR_MASK)
print_pgt(*cur, lvl - 1);
cur++;
}
}
__attribute__((noreturn))
void die(void)
{
/* Stop fetching instructions and go low power mode */
asm volatile ("hlt");
/* This while loop is dead code, but it makes gcc happy */
while (1)
;
}
__attribute__((noreturn))
void main_multiboot2(void *mb2)
{
struct task fake;
paddr_t new;
clear(); /* clear the VGA screen */
printk("Rackdoll OS\n-----------\n\n"); /* greetings */
setup_interrupts(); /* setup a 64-bits IDT */
setup_tss(); /* setup a 64-bits TSS */
interrupt_vector[INT_PF] = pgfault; /* setup page fault handler */
remap_pic(); /* remap PIC to avoid spurious interrupts */
disable_pic(); /* disable anoying legacy PIC */
sti(); /* enable interrupts */
uint64_t cr3 = store_cr3();
printk("[main] PML4 exists @ 0x%lx\n", cr3);
print_pgt(cr3, 4);
fake.pgt = store_cr3();
new = alloc_page();
map_page(&fake, 0xFF5504000, new);
printk("-----------\n\n");
load_tasks(mb2); /* load the tasks in memory */
run_tasks(); /* run the loaded tasks */
printk("\nGoodbye!\n"); /* fairewell */
die(); /* the work is done, we can die now... */
}

View File

@ -0,0 +1,203 @@
#include <memory.h>
#include <printk.h>
#include <string.h>
#include <x86.h>
#define PHYSICAL_POOL_PAGES 64
#define PHYSICAL_POOL_BYTES (PHYSICAL_POOL_PAGES << 12)
#define BITSET_SIZE (PHYSICAL_POOL_PAGES >> 6)
extern __attribute__((noreturn)) void die(void);
static uint64_t bitset[BITSET_SIZE];
static uint8_t pool[PHYSICAL_POOL_BYTES] __attribute__((aligned(0x1000)));
paddr_t alloc_page(void)
{
size_t i, j;
uint64_t v;
for (i = 0; i < BITSET_SIZE; i++) {
if (bitset[i] == 0xffffffffffffffff)
continue;
for (j = 0; j < 64; j++) {
v = 1ul << j;
if (bitset[i] & v)
continue;
bitset[i] |= v;
return (((64 * i) + j) << 12) + ((paddr_t) &pool);
}
}
printk("[error] Not enough identity free page\n");
return 0;
}
void free_page(paddr_t addr)
{
paddr_t tmp = addr;
size_t i, j;
uint64_t v;
tmp = tmp - ((paddr_t) &pool);
tmp = tmp >> 12;
i = tmp / 64;
j = tmp % 64;
v = 1ul << j;
if ((bitset[i] & v) == 0) {
printk("[error] Invalid page free %p\n", addr);
die();
}
bitset[i] &= ~v;
}
/*
* Memory model for Rackdoll OS
*
* +----------------------+ 0xffffffffffffffff
* | Higher half |
* | (unused) |
* +----------------------+ 0xffff800000000000
* | (impossible address) |
* +----------------------+ 0x00007fffffffffff
* | User |
* | (text + data + heap) |
* +----------------------+ 0x2000000000
* | User |
* | (stack) |
* +----------------------+ 0x40000000
* | Kernel |
* | (valloc) |
* +----------------------+ 0x201000
* | Kernel |
* | (APIC) |
* +----------------------+ 0x200000
* | Kernel |
* | (text + data) |
* +----------------------+ 0x100000
* | Kernel |
* | (BIOS + VGA) |
* +----------------------+ 0x0
*
* This is the memory model for Rackdoll OS: the kernel is located in low
* addresses. The first 2 MiB are identity mapped and not cached.
* Between 2 MiB and 1 GiB, there are kernel addresses which are not mapped
* with an identity table.
* Between 1 GiB and 128 GiB is the stack addresses for user processes growing
* down from 128 GiB.
* The user processes expect these addresses are always available and that
* there is no need to map them explicitely.
* Between 128 GiB and 128 TiB is the heap addresses for user processes.
* The user processes have to explicitely map them in order to use them.
*/
void map_page(struct task *ctx, vaddr_t vaddr, paddr_t paddr)
{
uint64_t *cur_pml = ctx->pgt;
uint64_t cur_entry = 0;
uint64_t *next_addr = NULL;
int n = 4;
printk("[map_page] trying to map 0x%lx -> 0x%lx\n",
vaddr, paddr);
// Exploring each level to the ground
while(n > 1) {
printk("\tEntering PML%d @ 0x%lx\n",
n,
&cur_pml[0]);
// Checking entry validity if level n > 1
// Also checking if ADDR != 0
if (cur_pml[PGT_PML_INDEX(n, vaddr)] & PGT_VALID_MASK
&& cur_pml[PGT_PML_INDEX(n, vaddr)] & PGT_ADDR_MASK) {
printk("\t\tPML%d entry 0x%lx @ 0x%lx is valid (=0x%lx)\n",
n,
cur_pml[PGT_PML_INDEX(n, vaddr)],
&cur_pml[PGT_PML_INDEX(n, vaddr)],
cur_pml[PGT_PML_INDEX(n, vaddr)]
& PGT_VALID_MASK);
} else {
printk("\t\tPML%d entry 0x%lx @ 0x%lx is NOT valid (=0x%lx)\n",
n,
cur_pml[PGT_PML_INDEX(n, vaddr)],
&cur_pml[PGT_PML_INDEX(n, vaddr)],
cur_pml[PGT_PML_INDEX(n, vaddr)]
& PGT_VALID_MASK);
cur_pml[PGT_PML_INDEX(n, vaddr)] = alloc_page();
printk("\t\t\tAllocated at 0x%lx\n",
cur_pml[PGT_PML_INDEX(n, vaddr)]);
cur_pml[PGT_PML_INDEX(n, vaddr)] |= PGT_VALID_MASK
| PGT_WRITABLE_MASK
| PGT_USER_MASK;
}
// Computing the next PML_n entry
cur_pml = cur_pml[PGT_PML_INDEX(n, vaddr)] & PGT_ADDR_MASK;
n--;
}
printk("\tEntering PML%d @ 0x%lx\n",
n,
&cur_pml[0]);
// Mapping, we're n == 1
// Checking validity and addr != 0
if (cur_pml[PGT_PML_INDEX(n, vaddr)] & PGT_VALID_MASK) {
printk("\t\tvaddr 0x%lx WAS ALREADY mapped to 0x%lx !!!\n",
vaddr,
cur_pml[PGT_PML_INDEX(n, vaddr)]
& PGT_ADDR_MASK);
return;
} else {
cur_pml[PGT_PML_INDEX(n, vaddr)] = paddr | PGT_VALID_MASK
| PGT_WRITABLE_MASK
| PGT_USER_MASK;
printk("\t\tvaddr 0x%lx mapped to 0x%lx\n",
vaddr,
cur_pml[PGT_PML_INDEX(n, vaddr)]
& PGT_ADDR_MASK);
return;
}
}
void load_task(struct task *ctx)
{
}
void set_task(struct task *ctx)
{
}
void mmap(struct task *ctx, vaddr_t vaddr)
{
}
void munmap(struct task *ctx, vaddr_t vaddr)
{
}
void pgfault(struct interrupt_context *ctx)
{
printk("Page fault at %p\n", ctx->rip);
printk(" cr2 = %p\n", store_cr2());
asm volatile ("hlt");
}
void duplicate_task(struct task *ctx)
{
}

View File

@ -0,0 +1,409 @@
#include <printk.h>
#include <stdarg.h>
#include <string.h>
#include <vga.h>
struct vsnprintk_state
{
char *buffer;
size_t len;
size_t ptr;
};
static bool_t vsnprintk_handler(void *user, char c)
{
struct vsnprintk_state *st = (struct vsnprintk_state *) user;
if (st->ptr >= st->len)
return 0;
st->buffer[st->ptr] = c;
st->ptr++;
return 1;
}
static bool_t vprintk_handler(void *user __attribute__((unused)), char c)
{
putc(c);
return 1;
}
struct vhprintk_format
{
bool_t alternate_form;
bool_t zero_pad;
bool_t right_pad;
bool_t positive_blank;
bool_t visible_sign;
bool_t long_operand;
size_t minimum_size;
char type;
};
struct vhprintk_state
{
const char *input;
bool_t (*handler)(void *, char);
void *user;
struct vhprintk_format format;
size_t done;
bool_t stop;
};
static size_t number_length(uint64_t number, uint8_t base)
{
size_t len = 0;
do {
number /= base;
len++;
} while (number > 0);
return len;
}
static void vhprintk_read_format(struct vhprintk_state *st)
{
struct vhprintk_format *f = &st->format;
const char *input = st->input;
char c;
memset(f, 0, sizeof (*f));
while ((c = *(input++)) != '\0') {
switch (c) {
case '#':
f->alternate_form = 1;
break;
case '0':
f->zero_pad = 1;
break;
case '-':
f->right_pad = 1;
break;
case ' ':
f->positive_blank = 1;
break;
case '+':
f->visible_sign = 1;
break;
default:
input--;
goto next;
}
}
goto out;
next:
while ((c = *(input++)) != '\0') {
if (c >= '0' && c <= '9') {
f->minimum_size = f->minimum_size * 10 + (c - '0');
} else {
f->type = c;
break;
}
}
out:
if (f->type == 'l') {
f->long_operand = 1;
f->type = *(input++);
}
st->input = input;
}
static bool_t vhprintk_print_one(struct vhprintk_state *st, char c)
{
if (!st->stop) {
if (!st->handler(st->user, c))
st->stop = 1;
else
st->done++;
}
return !(st->stop);
}
static void vhprintk_pad(struct vhprintk_state *st, size_t len, char pad)
{
size_t i;
for (i = 0; i < len; i++)
if (!vhprintk_print_one(st, pad))
return;
}
static void vhprintk_print_radical(struct vhprintk_state *st, uint64_t radical,
uint8_t base, size_t len, char upchar)
{
size_t div = 1;
size_t unit;
char c;
while (len > 1) {
div *= base;
len--;
}
do {
unit = radical / div;
if (unit < 10)
c = '0' + unit;
else
c = upchar + (unit - 10);
if (!vhprintk_print_one(st, c))
return;
radical = radical % div;
div /= base;
} while (div > 0);
}
static void vhprintk_print_number(struct vhprintk_state *st, uint64_t positive,
uint8_t base, const char *prefix,
char upbase)
{
size_t len = number_length(positive, base);
size_t preflen = strlen(prefix);
size_t totlen = len + preflen;
size_t padlen = 0;
size_t i;
if (st->format.minimum_size > totlen)
padlen = st->format.minimum_size - totlen;
if (!st->format.right_pad && !st->format.zero_pad)
vhprintk_pad(st, padlen, ' ');
for (i = 0; i < preflen; i++)
vhprintk_print_one(st, prefix[i]);
if (!st->format.right_pad && st->format.zero_pad)
vhprintk_pad(st, padlen, '0');
vhprintk_print_radical(st, positive, base, len, upbase);
if (st->format.right_pad)
vhprintk_pad(st, padlen, ' ');
}
static void vhprintk_print_signed(struct vhprintk_state *st, uint8_t base,
int64_t arg)
{
const char *prefix = "";
uint64_t positive;
if (arg < 0) {
positive = -arg;
prefix = "-";
} else {
positive = arg;
if (st->format.positive_blank)
prefix = " ";
else if (st->format.visible_sign) {
prefix = "+";
}
}
vhprintk_print_number(st, positive, base, prefix, 0);
}
static void vhprintk_print_unsigned(struct vhprintk_state *st, uint8_t base,
char upbase, uint64_t arg)
{
const char *prefix = "";
if (st->format.type == 'x' || st->format.type == 'X') {
if (st->format.alternate_form)
prefix = "0x";
} else if (st->format.type == 'o') {
if (st->format.alternate_form)
prefix = "0";
} else if (st->format.type == 'b') {
if (st->format.alternate_form)
prefix = "0b";
} else {
if (st->format.positive_blank)
prefix = " ";
else if (st->format.visible_sign) {
prefix = "+";
}
}
vhprintk_print_number(st, arg, base, prefix, upbase);
}
static void vhprintk_print_char(struct vhprintk_state *st, uint32_t arg)
{
size_t padlen = 0;
size_t len = 1;
if (st->format.minimum_size > len)
padlen = st->format.minimum_size - len;
if (!st->format.right_pad)
vhprintk_pad(st, padlen, ' ');
vhprintk_print_one(st, arg);
if (st->format.right_pad)
vhprintk_pad(st, padlen, ' ');
}
static void vhprintk_print_string(struct vhprintk_state *st, const char *arg)
{
size_t padlen = 0;
size_t len, i;
if (arg == NULL)
arg = "(null)";
len = strlen(arg);
if (len == 0 && st->format.positive_blank)
padlen = 1;
if (st->format.minimum_size > len)
padlen = st->format.minimum_size - len;
if (!st->format.right_pad)
vhprintk_pad(st, padlen, ' ');
for (i = 0; i < len; i++)
vhprintk_print_one(st, *arg++);
if (st->format.right_pad)
vhprintk_pad(st, padlen, ' ');
}
static size_t vhprintk(bool_t handler(void *, char), void *user,
const char *input, va_list ap)
{
struct vhprintk_state st;
bool_t fmt = 0;
uint8_t base;
char upbase;
char c;
memset(&st, 0, sizeof (st));
st.input = input;
st.handler = handler;
st.user = user;
while ((c = *(input++)) != '\0') {
if (st.stop)
break;
if (c == '%') {
if (fmt) {
fmt = 0;
} else {
fmt = 1;
continue;
}
}
if (!fmt) {
vhprintk_print_one(&st, c);
continue;
}
st.input = input - 1;
vhprintk_read_format(&st);
base = 0;
upbase = 'a';
if (st.format.type == 'p') {
st.format.type = 'x';
st.format.alternate_form = 1;
st.format.long_operand = 1;
}
switch (st.format.type) {
case 'c':
vhprintk_print_char(&st, va_arg(ap, uint32_t));
break;
case 'd':
case 'i':
if (st.format.long_operand)
vhprintk_print_signed(&st, 10,
va_arg(ap, int64_t));
else
vhprintk_print_signed(&st, 10,
va_arg(ap, int32_t));
break;
case 's':
vhprintk_print_string(&st, va_arg(ap, char *));
break;
case 'X':
upbase = 'A';
case 'x':
base += 6;
case 'u':
base += 2;
case 'o':
base += 6;
case 'b':
base += 2;
if (st.format.long_operand)
vhprintk_print_unsigned(&st, base, upbase,
va_arg(ap, uint64_t));
else
vhprintk_print_unsigned(&st, base, upbase,
va_arg(ap, uint32_t));
break;
}
fmt = 0;
input = st.input;
}
return st.done;
}
size_t printk(const char *format, ...)
{
va_list ap;
size_t ret;
va_start(ap, format);
ret = vprintk(format, ap);
va_end(ap);
return ret;
}
size_t vprintk(const char *format, va_list ap)
{
return vhprintk(vprintk_handler, NULL, format, ap);
}
size_t snprintk(char *buffer, size_t size, const char *format, ...)
{
va_list ap;
size_t ret;
va_start(ap, format);
ret = vsnprintk(buffer, size, format, ap);
va_end(ap);
return ret;
}
size_t vsnprintk(char *buffer, size_t size, const char *format, va_list ap)
{
struct vsnprintk_state st = {
.buffer = buffer,
.len = size,
.ptr = 0
};
return vhprintk(vsnprintk_handler, &st, format, ap);
}

View File

@ -0,0 +1,272 @@
#include <memory.h>
#include <printk.h>
#include <string.h>
#include <syscall.h>
#include <task.h>
#include <types.h>
#include <x86.h>
#define MB2_TAG_END 0
#define MB2_TAG_CMDLINE 1
#define MB2_TAG_NAME 2
#define MB2_TAG_MODULE 3
#define MB2_TAG_MEMORY 4
#define MB2_TAG_BIOS 5
#define MB2_TAG_MMAP 6
#define MB2_TAG_VBE 7
#define MB2_TAG_FRAMEBUF 8
#define MB2_TAG_ELF 9
#define MB2_TAG_APM 10
#define TASK_FIFO_LEN 32
static struct interrupt_context save; /* kernel before running tasks */
static struct task fifo[TASK_FIFO_LEN]; /* fifo of available tasks */
static size_t fifo_size = 0; /* amount of task in the fifo */
static size_t fifo_run = 0; /* current task in the fifo */
struct mb2_info
{
uint32_t total_size;
uint32_t reserved;
} __attribute__((packed));
struct mb2_tag
{
uint32_t type;
uint32_t size;
} __attribute__((packed));
struct mb2_tag_module
{
uint32_t type;
uint32_t size;
uint32_t mod_start;
uint32_t mod_end;
uint8_t string[];
} __attribute__((packed));
struct task_state_segment tss __attribute__((aligned(0x1000)));
/*
* Symbol defined in entry.S
* Points to a slot of the current GDT.
*/
extern uint64_t tss64[2];
/* Util functions to set up the TSS descriptor. */
#define TSS_ADDR_LOW(addr) \
( ((((addr) >> 0) & 0x0000ffff) << 16) \
| ((((addr) >> 16) & 0x000000ff) << 32) \
| ((((addr) >> 16) & 0x0000ff00) << 48) \
)
#define TSS_ADDR_HIGH(addr) \
( ((((addr) >> 32) & 0xffffffff) << 0) \
)
#define TSS_SIZE(size) \
( (((((size) - 1) >> 0) & 0xffff) << 0) \
| (((((size) - 1) >> 16) & 0x000f) << 48) \
)
/* Util functions to set up the TSS. */
#define OFFSETOF(type, field) ((size_t) &(((type *) 0)->field))
void setup_tss(void)
{
paddr_t tss_addr = (paddr_t) &tss;
memset(&tss, 0, sizeof (tss));
tss.rsp0 = store_rsp();
tss.iopb_off = OFFSETOF(struct task_state_segment, iopb);
tss.iopb = 0xffffffffffffffff;
tss64[0] |= TSS_ADDR_LOW(tss_addr);
tss64[0] |= TSS_SIZE(sizeof (tss));
tss64[1] |= TSS_ADDR_HIGH(tss_addr);
load_tr(TSS_SELECTOR);
}
static void parse_task(const struct mb2_tag_module *tag)
{
const uint64_t *ptr = (const uint64_t *) ((uint64_t) tag->mod_start);
const uint64_t *end = (const uint64_t *) ((uint64_t) tag->mod_end);
const struct task_header *header;
struct task *task;
size_t pvdiff;
if (fifo_size == TASK_FIFO_LEN)
return;
while (ptr < end) {
if (*ptr == TASK_HEADER_MAGIC)
break;
ptr++;
}
if (ptr == end)
return;
task = fifo + fifo_size;
memset(task, 0, sizeof (*task));
fifo_size++;
header = (const struct task_header *) ptr;
pvdiff = header->header_addr - ((paddr_t) ptr);
task->load_paddr = header->load_addr - pvdiff;
task->load_end_paddr = header->load_end_addr - pvdiff;
task->load_vaddr = header->load_addr;
task->bss_end_vaddr = header->bss_end_addr;
task->context.rip = header->entry_addr;
task->context.cs = USER_CODE_SELECTOR | 0x3;
task->context.ss = USER_DATA_SELECTOR | 0x3;
task->context.rsp = 0x2000000000;
task->context.rflags = RFLAGS_IF;
load_task(task);
}
static void syscall_handler(struct interrupt_context *ctx)
{
uint64_t arg0 = ctx->rsi;
switch (ctx->rdi) {
case SYSCALL_PRINT:
printk("%s", arg0);
break;
case SYSCALL_PRINTNUM:
printk("%lu", arg0);
break;
case SYSCALL_MMAP:
mmap(fifo + fifo_run, arg0);
break;
case SYSCALL_MUNMAP:
munmap(fifo + fifo_run, arg0);
break;
case SYSCALL_YIELD:
next_task(ctx);
break;
case SYSCALL_EXIT:
exit_task(ctx);
break;
case SYSCALL_FORK:
fork_task(ctx);
break;
}
}
static void enter_handler(struct interrupt_context *ctx)
{
struct task *task = (struct task *) ctx->rdi;
save = *ctx;
set_task(task);
*ctx = task->context;
}
static void enter_task(struct task *task)
{
asm volatile ("int %0" : : "i" (INT_USER_ENTER_TASKS), "D" (task));
}
void load_tasks(const void *mb2)
{
const struct mb2_info *info = (const struct mb2_info *) mb2;
const struct mb2_tag *tag;
vaddr_t ptr = (vaddr_t) mb2;
vaddr_t end = ptr + info->total_size;
ptr += (sizeof (*info) + 7) & ~0x7;
while (ptr < end) {
tag = (const struct mb2_tag *) ptr;
if (tag->type == MB2_TAG_MODULE)
parse_task(((const struct mb2_tag_module *) tag));
ptr = (ptr + tag->size + 7) & ~0x7;
}
interrupt_vector[INT_USER_SYSCALL] = syscall_handler;
interrupt_vector[INT_USER_ENTER_TASKS] = enter_handler;
}
struct task *current(void)
{
if (fifo_run >= fifo_size)
return NULL;
return fifo + fifo_run;
}
void next_task(struct interrupt_context *ctx)
{
fifo[fifo_run].context = *ctx;
fifo_run++;
if (fifo_run >= fifo_size)
fifo_run = 0;
set_task(fifo + fifo_run);
*ctx = fifo[fifo_run].context;
}
void exit_task(struct interrupt_context *ctx)
{
if (fifo_run == (fifo_size - 1)) {
fifo_size--;
fifo_run = 0;
} else {
fifo_size--;
fifo[fifo_run] = fifo[fifo_size];
}
if (fifo_size == 0) {
*ctx = save;
} else {
set_task(fifo + fifo_run);
*ctx = fifo[fifo_run].context;
}
}
void fork_task(struct interrupt_context *ctx)
{
struct task *task;
uint64_t ret = -1;
if (fifo_size == TASK_FIFO_LEN)
goto out;
task = fifo + fifo_size;
fifo_size++;
*task = *current();
task->context = *ctx;
task->context.rax = 1;
duplicate_task(task);
ret = 0;
out:
ctx->rax = ret;
}
void run_tasks(void)
{
if (fifo_size == 0)
return;
fifo_run++;
if (fifo_run >= fifo_size)
fifo_run = 0;
enter_task(fifo + fifo_run);
}

View File

@ -0,0 +1,95 @@
#!/usr/bin/env -S perl
use strict;
use warnings;
sub main
{
my ($output, @err) = @_;
my (@errvec) = qw(8 10 11 12 13 14 17);
my ($vec, $fh);
if (@err) {
printf(STDERR "%s: unexpected operand\n", $0);
printf(STDERR "Usage: %s <output>\n", $0);
return 1;
}
if (!open($fh, '>', $output)) {
printf(STDERR "%s: %s\n", $0, $!);
printf(STDERR "Usage: %s <output>\n", $0);
return 1;
}
printf($fh "%s", <<'EOF');
.section ".text"
_trap:
pushq %rax
pushq %rdi
pushq %rsi
pushq %rdx
pushq %rcx
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
pushq %rbx
pushq %rbp
movq %rsp, %rdi
call trap
popq %rbp
popq %rbx
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rcx
popq %rdx
popq %rsi
popq %rdi
popq %rax
addq $16, %rsp
iretq
EOF
foreach $vec (0 .. 255) {
printf($fh "__trap_vector_%s:\n", $vec);
if (!grep { $vec == $_ } @errvec) {
printf($fh "\tpushq \$0\n");
}
printf($fh "\tpushq \$%s\n", $vec);
printf($fh "\tjmp _trap\n");
}
printf($fh "%s", <<'EOF');
.section ".data"
.globl trap_vector
trap_vector:
EOF
foreach $vec (0 .. 255) {
printf($fh "\t.quad __trap_vector_%s\n", $vec);
}
close($fh);
return 0;
}
exit (main(@ARGV));
__END__

View File

@ -0,0 +1,95 @@
#include <vga.h>
#include <x86.h>
#define VGA_SCREEN_ADDRESS ((uint16_t *) 0xb8000)
#define VGA_SCREEN_LINES 25
#define VGA_SCREEN_COLUMNS 80
#define VGA_CURSOR_ADDRESS_PORT 0x3d4
#define VGA_CURSOR_ADDRESS_LOW 0x0f
#define VGA_CURSOR_ADDRESS_HIGH 0x0e
#define VGA_CURSOR_DATA_PORT 0x3d5
#define VGA_COLOR_DEFAULT 0x700
static uint16_t cursor = 0;
static void update_cursor(uint16_t pos)
{
cursor = pos;
out8(VGA_CURSOR_ADDRESS_PORT, VGA_CURSOR_ADDRESS_LOW);
out8(VGA_CURSOR_DATA_PORT, pos & 0xff);
out8(VGA_CURSOR_ADDRESS_PORT, VGA_CURSOR_ADDRESS_HIGH);
out8(VGA_CURSOR_DATA_PORT, (pos >> 8) & 0xff);
}
static void scroll(void)
{
uint16_t *screen = VGA_SCREEN_ADDRESS;
size_t line, cursor, end;
for (line = 0; line < (VGA_SCREEN_LINES - 1); line++) {
cursor = line * VGA_SCREEN_COLUMNS;
end = cursor + VGA_SCREEN_COLUMNS;
while (cursor < end) {
screen[cursor] = screen[cursor + VGA_SCREEN_COLUMNS];
cursor++;
}
}
cursor = line * VGA_SCREEN_COLUMNS;
end = cursor + VGA_SCREEN_COLUMNS;
while (cursor < end) {
screen[cursor] = VGA_COLOR_DEFAULT;
cursor++;
}
}
void clear(void)
{
size_t i, total = VGA_SCREEN_LINES * VGA_SCREEN_COLUMNS;
uint16_t *screen = VGA_SCREEN_ADDRESS;
for (i = 0; i < total; i++)
screen[i] = VGA_COLOR_DEFAULT;
update_cursor(0);
}
void putc(char c)
{
uint16_t n = cursor;
uint16_t *screen = VGA_SCREEN_ADDRESS;
switch (c) {
case '\n':
n += VGA_SCREEN_COLUMNS;
case '\r':
n = (n / VGA_SCREEN_COLUMNS) * VGA_SCREEN_COLUMNS;
break;
case '\t':
n = ((n + 1) & (~0x7)) + 8;
break;
default:
screen[n++] = VGA_COLOR_DEFAULT | c;
break;
}
if (n >= VGA_SCREEN_LINES * VGA_SCREEN_COLUMNS) {
scroll();
n -= VGA_SCREEN_COLUMNS;
}
update_cursor(n);
}
void puts(const char *str, size_t n)
{
size_t i;
for (i = 0; i < n; i++)
putc(str[i]);
}

View File

@ -0,0 +1,18 @@
(specifications->manifest
(list
"bash"
"coreutils"
"gcc-toolchain"
"pkg-config"
"valgrind"
"findutils"
"gdb"
"make"
"grep"
"qemu"
"xorriso"
"glib"
"perl"
"grub"
)
)

View File

@ -0,0 +1,10 @@
set timeout=0
set default=0
menuentry 'Rackdoll' {
echo 'Loading Rackdoll OS'
multiboot2 /boot/rackdoll.elf
module2 /boot/hash.elf
module2 /boot/sieve.elf
module2 /boot/adversary.elf
}

View File

@ -0,0 +1,35 @@
OUTPUT_FORMAT(elf64-x86-64)
TASK_VMA = 0x2000000000;
SECTIONS
{
. = TASK_VMA;
.header : ALIGN(0x1000) {
__task_start = .;
*(.header);
}
.text : {
*(.text);
}
.data : {
*(.data*);
*(.rodata*);
}
.bss : ALIGN(0x1000) {
__task_end = .;
*(.bss);
*(COMMON);
. = ALIGN(0x1000);
__bss_end = .;
}
/DISCARD/ : {
*(.eh_frame .comment);
}
}

View File

@ -0,0 +1,44 @@
#include <string.h>
#include <syscall.h>
extern char __task_start;
extern char __task_end;
extern char __bss_end;
char zero_variable = 0;
char zero_zone[8000];
void entry(void)
{
size_t i;
char *addr = (char *) 0x1fffff3000;
syscall_print(" ==> Adversary Task\n");
for (i = 0; i < 0x1000; i++)
addr[i] = i & 0xff;
syscall_munmap((vaddr_t) addr);
for (i = 0; i < 0x1000; i++)
if (addr[i] != 0) {
syscall_print(" --> Adversary result: failure\n");
syscall_exit();
}
syscall_yield();
syscall_print(" --> Adversary result: success\n");
syscall_exit();
}
struct task_header header __attribute__((section(".header"))) = {
.magic = TASK_HEADER_MAGIC,
.load_addr = (vaddr_t) &__task_start,
.load_end_addr = (vaddr_t) &__task_end,
.bss_end_addr = (vaddr_t) &__bss_end,
.header_addr = (vaddr_t) &header,
.entry_addr = (vaddr_t) &entry
};

View File

@ -0,0 +1,85 @@
#include <string.h>
#include <syscall.h>
#define HASH_ROUND 512
#define BUFFER_LENGTH 16
extern char __task_start;
extern char __task_end;
extern char __bss_end;
static char expected[] = {126, 64, 218, 208, 114, 16, 110, 33, 198, 241, 22,
210, 117, 211, 243, 161};
static void hash_n(char *out, size_t n)
{
char buffer[BUFFER_LENGTH];
size_t i;
if (n == 0)
return;
for (i = 1; i < BUFFER_LENGTH; i++)
buffer[i] = out[i - 1];
buffer[0] = out[i - 1];
for (i = 0; i < BUFFER_LENGTH; i++)
buffer[i] += buffer[(i + BUFFER_LENGTH / 2) % BUFFER_LENGTH];
syscall_yield();
hash_n(buffer, n - 1);
for (i = 0; i < BUFFER_LENGTH; i++)
buffer[i] += buffer[(i + BUFFER_LENGTH / 4) % BUFFER_LENGTH];
for (i = 0; i < BUFFER_LENGTH; i++)
out[i] = buffer[i];
}
static void hash(char *out, const char *in, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
out[i] = in[i % len];
hash_n(out, HASH_ROUND);
}
void entry(void)
{
char output[BUFFER_LENGTH];
size_t i;
syscall_print(" ==> Hash Task\n");
hash(output, "Keep It Simple and Stupid", 25);
if (output[0] != 126) {
syscall_print(" --> Hash result: failure\n");
} else {
for (i = 0; i < BUFFER_LENGTH; i++)
if (output[i] != expected[i]) {
syscall_print(" --> Hash result: failure\n");
break;
}
if (i == BUFFER_LENGTH)
syscall_print(" --> Hash result: success\n");
}
syscall_exit();
}
struct task_header header __attribute__((section(".header"))) = {
.magic = TASK_HEADER_MAGIC,
.load_addr = (vaddr_t) &__task_start,
.load_end_addr = (vaddr_t) &__task_end,
.bss_end_addr = (vaddr_t) &__bss_end,
.header_addr = (vaddr_t) &header,
.entry_addr = (vaddr_t) &entry
};

View File

@ -0,0 +1,123 @@
#include <string.h>
#include <syscall.h>
#define PAGE_SIZE 4096
#define MAX_SEARCH 4096
extern char __task_start;
extern char __task_end;
extern char __bss_end;
vaddr_t heap = (vaddr_t) &__bss_end;
static unsigned long *number_array(unsigned long max, int init)
{
size_t i, n = max * 8;
unsigned long *ret = (unsigned long *) heap;
if (n & (PAGE_SIZE - 1))
n = (n + PAGE_SIZE) & ~(PAGE_SIZE - 1);
while (n > 0) {
syscall_mmap(heap);
heap += PAGE_SIZE;
n -= PAGE_SIZE;
}
if (init == 0)
return ret;
for (i = 0; i < max; i++)
ret[i] = i;
return ret;
}
static void realloc_array(unsigned long *arr, unsigned long max)
{
size_t n = max * 8;
vaddr_t addr = (vaddr_t) arr;
if (n & (PAGE_SIZE - 1))
n = (n + PAGE_SIZE) & ~(PAGE_SIZE - 1);
while (n > 0) {
syscall_munmap(addr);
syscall_mmap(addr);
addr += PAGE_SIZE;
n -= PAGE_SIZE;
}
}
static size_t filter(unsigned long *to, const unsigned long *from,
size_t index, size_t len)
{
size_t i, j, n;
for (i = 0; i < index; i++)
to[i] = from[i];
n = index;
for (i = index; i < len; i++) {
for (j = 2; j < index; j++)
if ((from[i] % from[j]) == 0)
break;
if (j >= index)
to[n++] = from[i];
}
return n;
}
void entry(void)
{
unsigned long *flip, *flop, *temp;
unsigned long index = 0, len = MAX_SEARCH;
size_t i, num = 0;
syscall_print(" ==> Sieve Task\n");
flip = number_array(MAX_SEARCH, 1);
flop = number_array(MAX_SEARCH, 0);
while (index < len) {
len = filter(flop, flip, index, len);
realloc_array(flip, MAX_SEARCH);
temp = flip;
flip = flop;
flop = temp;
index++;
if ((index % 4) == 0)
syscall_yield();
}
for (i = 0; i < MAX_SEARCH; i++)
if (flip[i] != 0)
num++;
if (num == 565)
syscall_print(" --> Sieve result: success\n");
else
syscall_print(" --> Sieve result: failure\n");
syscall_exit();
}
struct task_header header __attribute__((section(".header"))) = {
.magic = TASK_HEADER_MAGIC,
.load_addr = (vaddr_t) &__task_start,
.load_end_addr = (vaddr_t) &__task_end,
.bss_end_addr = (vaddr_t) &__bss_end,
.header_addr = (vaddr_t) &header,
.entry_addr = (vaddr_t) &entry
};

Binary file not shown.