WIP: TP1
This commit is contained in:
parent
f3bce787fc
commit
2778dc91fa
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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:
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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:
|
|
@ -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);
|
||||
}
|
|
@ -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... */
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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__
|
|
@ -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]);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
(specifications->manifest
|
||||
(list
|
||||
"bash"
|
||||
"coreutils"
|
||||
"gcc-toolchain"
|
||||
"pkg-config"
|
||||
"valgrind"
|
||||
"findutils"
|
||||
"gdb"
|
||||
"make"
|
||||
"grep"
|
||||
"qemu"
|
||||
"xorriso"
|
||||
"glib"
|
||||
"perl"
|
||||
"grub"
|
||||
)
|
||||
)
|
Binary file not shown.
|
@ -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
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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
|
||||
};
|
|
@ -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.
Loading…
Reference in New Issue