Compare commits
70 Commits
attribut_f
...
master
Author | SHA1 | Date | |
---|---|---|---|
778999c8f4 | |||
d6ab0da231 | |||
|
dea0eba83d | ||
86a0138d9c | |||
|
dc4c465e94 | ||
|
1047400be2 | ||
e0c392c16e | |||
4204087bd1 | |||
454f0875f5 | |||
9713f527a8 | |||
70366fa7be | |||
a38a674a53 | |||
0688afa76d | |||
90436a4f46 | |||
f9ce88e7a3 | |||
|
1c2cd75c72 | ||
|
758017a8e7 | ||
|
f8b1b2c5a7 | ||
|
cb5e408525 | ||
|
a78aa420fd | ||
|
fe6dfbc1c6 | ||
|
7b953e625e | ||
|
026618a730 | ||
607fcc7121 | |||
|
c3f3eb435e | ||
|
3339f8b059 | ||
|
88b9c3160b | ||
|
b352eab798 | ||
|
b8c4c782de | ||
|
1895781213 | ||
|
cca78b269d | ||
|
bf7008fc98 | ||
|
ccfafe4a04 | ||
|
62a1c1cefb | ||
|
f751835115 | ||
|
5a2042e577 | ||
|
9fa9bd0411 | ||
|
a4873a7d30 | ||
|
205d174c8a | ||
|
d9051ea59c | ||
|
b9d741060f | ||
|
1bb81fd57e | ||
|
44c5551655 | ||
|
b6fd550e7f | ||
|
8af3ba0762 | ||
|
1e3be650f2 | ||
|
bd25bb8478 | ||
|
946c47a988 | ||
a45dd96dc8 | |||
|
2b324ac62d | ||
|
edbbaec930 | ||
|
45ec3c1a7b | ||
|
2359cf2744 | ||
|
ee42ba1350 | ||
|
01f5b872f2 | ||
|
8a4e0ff10f | ||
|
f110f85498 | ||
|
f05e017d45 | ||
|
60e71f6521 | ||
|
6a00aa4762 | ||
|
63757b1e0c | ||
|
01d54dea85 | ||
|
107bcedf90 | ||
|
cf3c2f10fd | ||
|
a4f5a367ab | ||
|
bee58d9642 | ||
|
1120b40655 | ||
|
b0a192ce7c | ||
|
d6dc298d35 | ||
1e6614308a |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
serialOut
|
||||
disk.img
|
||||
kernel
|
||||
kernel.sym
|
||||
kernel.debug
|
||||
userspace/user
|
||||
docs/*.html
|
||||
|
18
Makefile
18
Makefile
@ -3,7 +3,7 @@ CPPFLAGS = -MMD
|
||||
AS=nasm
|
||||
ASFLAGS += -f elf32
|
||||
LDFLAGS += -m elf_i386
|
||||
CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector -fno-tree-vectorize -D__KERNEL__
|
||||
CFLAGS += -m32 -pipe -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector -fno-tree-vectorize -D__KERNEL__
|
||||
#keep .i and .s
|
||||
#CFLAGS += -save-temps
|
||||
#CFLAGS += -fanalyzer -Wno-analyzer-malloc-leak -Wno-analyzer-out-of-bounds
|
||||
@ -38,7 +38,7 @@ kernel kernel.debug &: $(asmobj) $(gasmobj) $(cobj) linker.ld
|
||||
fd.iso: kernel
|
||||
mkdir -p isodir/boot/grub
|
||||
cp $< isodir/boot/
|
||||
@printf "menuentry \"myos\" {\n\tmultiboot /boot/kernel\n}" > isodir/boot/grub/grub.cfg
|
||||
@printf "set timeout=0\nset default=0\nmenuentry \"matos\" {\n\tmultiboot /boot/kernel\n}" > isodir/boot/grub/grub.cfg
|
||||
grub-mkrescue -o $@ isodir
|
||||
|
||||
userspace: FORCE
|
||||
@ -47,7 +47,7 @@ userspace: FORCE
|
||||
FORCE:
|
||||
@
|
||||
|
||||
doc: $(docobj)
|
||||
doc: $(docobj) ## generate documentation
|
||||
|
||||
help: ## show this help
|
||||
# regex for general help
|
||||
@ -65,7 +65,7 @@ disk.img: disk.sfdisk userspace
|
||||
# Before having filesystem support, just dump the user prog into the first partition
|
||||
strip userspace/user -o userspace/user.strip
|
||||
$(eval file_size:=$(shell du -b userspace/user.strip|awk '{print $$1}' | xargs printf "%016d" )) \
|
||||
sed '1s/^/$(file_size)/' userspace/user.strip | dd of=disk.img seek=2048 bs=512
|
||||
sed '1s/^/$(file_size)/' userspace/user.strip | dd of=disk.img seek=34816 bs=512
|
||||
|
||||
# NASM without preprocessing
|
||||
%.o:%.asm
|
||||
@ -88,20 +88,26 @@ test: clean kernel disk.img
|
||||
run:kernel disk.img ## Run the OS on qemu
|
||||
qemu-system-x86_64 -kernel $< -serial stdio $(QEMU_OPT)
|
||||
|
||||
debug: CFLAGS += $(DEBUG_FLAGS) ## Run the OS on qemu and attach a debugger to it (may need a clean befor to have the debug symbols)
|
||||
debug: CFLAGS += $(DEBUG_FLAGS) ## Run the OS on qemu and attach a debugger to it (may need a clean before to have the debug symbols)
|
||||
debug: CXXFLAGS += $(DEBUG_FLAGS)
|
||||
debug:kernel kernel.debug disk.img
|
||||
gdb -q -x debug.gdb
|
||||
|
||||
isodebug: CFLAGS += $(DEBUG_FLAGS) ## Same than previous but kernel is loaded by grub. So, for example, we can access the elf debug info
|
||||
isodebug: CXXFLAGS += $(DEBUG_FLAGS)
|
||||
isodebug:fd.iso disk.img
|
||||
gdb -q -x debug.iso.gdb
|
||||
|
||||
debug_test: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST
|
||||
debug_test: debug
|
||||
|
||||
screenshot:
|
||||
screenshot: ## Take a screenshot of the qemu window
|
||||
shutter --window=qemu -o screenshot_1.png -e && zopflipng screenshot_1.png screenshot_1.png
|
||||
|
||||
clean:
|
||||
$(RM) kernel $(asmobj) $(gasmobj) $(cobj) $(deps) $(cinc) fd.iso kernel.debug kernel.map $(docobj)
|
||||
$(RM) -r isodir
|
||||
$(MAKE) -C userspace clean
|
||||
|
||||
.PHONY:
|
||||
userspace screenshot
|
||||
|
12
README.md
12
README.md
@ -11,7 +11,7 @@ It's targetting x86 and inspirated by http://sos.enix.org/fr/PagePrincipale
|
||||
To generate iso image
|
||||
|
||||
* `mtools xorriso (which is libisoburn on ArchLinux)`
|
||||
* gcc >= 6
|
||||
* gcc for 32bits (e.g. gcc-multilib for ubuntu) >= 11
|
||||
* sfdisk (util-linux)
|
||||
|
||||
# Run it
|
||||
@ -49,6 +49,16 @@ modify the disk image with your favorit tool (e.g. gparted) and re-generate disk
|
||||
|
||||
sfdisk -d > disk.sfdisk
|
||||
|
||||
# Multiboot
|
||||
|
||||
In arch/x86/boot, you can choose the assembly used to start the C part by removing the .opt extension
|
||||
|
||||
* boot.asm: intel syntax with multiboot support
|
||||
* boot.S: GNU As syntax with multiboot support
|
||||
* boot_multiboot2.S: GNU As syntax with multiboot2 support
|
||||
|
||||
/!\ multiboot2 is not supported by qemu for -kernel option (https://gitlab.com/qemu-project/qemu/-/issues/389).
|
||||
So you may have to use the fd.iso image and modify the grub configuration from `multiboot /boot/kernel` to `multiboot2 /boot/kernel`
|
||||
|
||||
# Features
|
||||
|
||||
|
@ -118,6 +118,8 @@ This is useful when debugging or when you implement call tracing.
|
||||
*/
|
||||
.size _start, . - _start
|
||||
.global _stack_bottom
|
||||
_stack_bottom: stack_bottom
|
||||
.global _stack_stop
|
||||
_stack_stop: stack_top
|
||||
_stack_bottom:
|
||||
.long stack_bottom
|
||||
.global _stack_top
|
||||
_stack_top:
|
||||
.long stack_top
|
||||
|
125
arch/x86/boot/boot_multiboot2.S.opt
Normal file
125
arch/x86/boot/boot_multiboot2.S.opt
Normal file
@ -0,0 +1,125 @@
|
||||
/* Inspired by from https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#boot_002eS */
|
||||
|
||||
/* boot.S - bootstrap the kernel */
|
||||
/* Copyright (C) 1999, 2001, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define ASM_FILE 1
|
||||
#include <multiboot2.h>
|
||||
|
||||
.section .multiboot
|
||||
.align 4
|
||||
/* Multiboot header. */
|
||||
multiboot_header:
|
||||
/* magic */
|
||||
.long MULTIBOOT2_HEADER_MAGIC
|
||||
/* ISA: i386 */
|
||||
.long MULTIBOOT_ARCHITECTURE_I386
|
||||
/* Header length. */
|
||||
.long multiboot_header_end - multiboot_header
|
||||
/* checksum */
|
||||
.long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header))
|
||||
multiboot_header_end:
|
||||
|
||||
.section .bss
|
||||
.align 4096
|
||||
stack_bottom:
|
||||
.skip 16384 # 16 KiB
|
||||
stack_top:
|
||||
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
/*
|
||||
The bootloader has loaded us into 32-bit protected mode on a x86
|
||||
machine. Interrupts are disabled. Paging is disabled. The processor
|
||||
state is as defined in the multiboot standard. The kernel has full
|
||||
control of the CPU. The kernel can only make use of hardware features
|
||||
and any code it provides as part of itself. There's no printf
|
||||
function, unless the kernel provides its own <stdio.h> header and a
|
||||
printf implementation. There are no security restrictions, no
|
||||
safeguards, no debugging mechanisms, only what the kernel provides
|
||||
itself. It has absolute and complete power over the
|
||||
machine.
|
||||
*/
|
||||
|
||||
/*
|
||||
To set up a stack, we set the esp register to point to the top of our
|
||||
stack (as it grows downwards on x86 systems). This is necessarily done
|
||||
in assembly as languages such as C cannot function without a stack.
|
||||
*/
|
||||
mov $stack_top, %esp
|
||||
mov $stack_bottom, %ebp
|
||||
|
||||
/*
|
||||
This is a good place to initialize crucial processor state before the
|
||||
high-level kernel is entered. It's best to minimize the early
|
||||
environment where crucial features are offline. Note that the
|
||||
processor is not fully initialized yet: Features such as floating
|
||||
point instructions and instruction set extensions are not initialized
|
||||
yet. The GDT should be loaded here. Paging should be enabled here.
|
||||
C++ features such as global constructors and exceptions will require
|
||||
runtime support to work as well.
|
||||
*/
|
||||
|
||||
/* Reset EFLAGS. */
|
||||
pushl $0
|
||||
popf
|
||||
|
||||
|
||||
/*
|
||||
Enter the high-level kernel. The ABI requires the stack is 16-byte
|
||||
aligned at the time of the call instruction (which afterwards pushes
|
||||
the return pointer of size 4 bytes). The stack was originally 16-byte
|
||||
aligned above and we've since pushed a multiple of 16 bytes to the
|
||||
stack since (pushed 0 bytes so far) and the alignment is thus
|
||||
preserved and the call is well defined.
|
||||
*/
|
||||
/* Push the pointer to the Multiboot information structure. */
|
||||
pushl %ebx
|
||||
/* Push the magic value. */
|
||||
pushl %eax
|
||||
call kmain
|
||||
|
||||
/*
|
||||
If the system has nothing more to do, put the computer into an
|
||||
infinite loop. To do that:
|
||||
1) Disable interrupts with cli (clear interrupt enable in eflags).
|
||||
They are already disabled by the bootloader, so this is not needed.
|
||||
Mind that you might later enable interrupts and return from
|
||||
kernel_main (which is sort of nonsensical to do).
|
||||
2) Wait for the next interrupt to arrive with hlt (halt instruction).
|
||||
Since they are disabled, this will lock up the computer.
|
||||
3) Jump to the hlt instruction if it ever wakes up due to a
|
||||
non-maskable interrupt occurring or due to system management mode.
|
||||
*/
|
||||
cli
|
||||
1: hlt
|
||||
jmp 1b
|
||||
|
||||
/*
|
||||
Set the size of the _start symbol to the current location '.' minus its start.
|
||||
This is useful when debugging or when you implement call tracing.
|
||||
*/
|
||||
.size _start, . - _start
|
||||
.global _stack_bottom
|
||||
_stack_bottom:
|
||||
.long stack_bottom
|
||||
.global _stack_top
|
||||
_stack_top:
|
||||
.long stack_top
|
@ -45,30 +45,53 @@ int exceptionSetRoutine(int exception, exception_handler handler)
|
||||
|
||||
void print_handler(struct cpu_state *frame, ulong intr)
|
||||
{
|
||||
int intNbInt = intr;
|
||||
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d", intNbInt);
|
||||
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %lu", intr);
|
||||
printf("Exception %lu at 0x%p\n", intr, (void *)cpu_context_get_PC(frame));
|
||||
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
void pagefault_handler(struct cpu_state *frame, ulong intr)
|
||||
{
|
||||
|
||||
// PAGE_FAULT is a interrupt with an error code (see exception_wrapper.S)
|
||||
uint32_t error_code = cpu_context_get_EX_err(frame);
|
||||
struct thread *current = getCurrentThread();
|
||||
|
||||
if (cpu_context_is_in_user_mode(current->cpuState)) {
|
||||
assert(frame == current->cpuState); // pagefault in kernel not supported ATM
|
||||
|
||||
struct uAddrSpace *as = processGetAddrSpace(current->process);
|
||||
vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame);
|
||||
int needMMUSetup =
|
||||
(uAddrSpaceGetMMUContext(as) != getCurrentThread()->squattedContext);
|
||||
|
||||
if(!uAddrSpaceCheckNAlloc(as, faultAddr))
|
||||
return;
|
||||
if (needMMUSetup) {
|
||||
threadChangeCurrentContext(uAddrSpaceGetMMUContext(as));
|
||||
}
|
||||
|
||||
printf("page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x\n", current->name,
|
||||
(void *)cpu_context_get_PC(frame), (void *)faultAddr, cpu_context_get_EX_err(frame));
|
||||
if (cpu_context_is_in_user_mode(frame)) {
|
||||
if (!uAddrSpaceHeapCheckNAlloc(as, faultAddr))
|
||||
goto release_context;
|
||||
|
||||
int ret = uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2);
|
||||
|
||||
if (!ret)
|
||||
goto release_context;
|
||||
|
||||
printf(
|
||||
"page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x ressource ret %d\n",
|
||||
current->name, (void *)cpu_context_get_PC(frame), (void *)faultAddr, error_code,
|
||||
ret);
|
||||
printf("Killing User Thread\n");
|
||||
threadExit();
|
||||
|
||||
release_context:
|
||||
if (needMMUSetup)
|
||||
threadChangeCurrentContext(NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr);
|
||||
(void)intr;
|
||||
for (;;)
|
||||
continue;
|
||||
}
|
||||
@ -79,5 +102,6 @@ int exceptionSetup()
|
||||
exceptionSetRoutine(i, print_handler);
|
||||
}
|
||||
exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@
|
||||
iret
|
||||
.endm
|
||||
|
||||
/*List of exception w or w/o err codehttps://wiki.osdev.org/Exceptions*/
|
||||
/* List of exception w or w/o err code https://wiki.osdev.org/Exceptions */
|
||||
.irp exception_id, 8, 10, 11, 12, 13, 14, 17, 30
|
||||
exception_mac_with_errcode exception_id
|
||||
.endr
|
||||
|
@ -19,6 +19,8 @@
|
||||
*/
|
||||
#include "segment.h"
|
||||
#include "gdt.h"
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
|
||||
/**
|
||||
* The sructure of a segment descriptor.
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "idt.h"
|
||||
#include "stddef.h"
|
||||
|
||||
static struct idtEntry idt[IDT_NUM];
|
||||
|
||||
int idtSetup()
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
|
||||
#define IDT_NUM 256
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define PAGING_MEM_USER (1U << 0)
|
||||
#define PAGING_MEM_READ (1U << 1)
|
||||
#define PAGING_MEM_WRITE (1U << 2)
|
||||
#define PAGING_MEM_EXEC (1U << 3)
|
||||
|
||||
int pagingSetup(paddr_t lowerKernelAddr, paddr_t upperKernelAddr);
|
||||
|
||||
|
@ -1,12 +1,19 @@
|
||||
#pragma once
|
||||
#include "paging.h"
|
||||
#include "stdarg.h"
|
||||
#include "stddef.h"
|
||||
#include "types.h"
|
||||
|
||||
/** Arbitrary size allocator **/
|
||||
|
||||
/*
|
||||
* Initialize malloc system
|
||||
*/
|
||||
int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *entryAddr);
|
||||
|
||||
/*
|
||||
* Add Slice for some simple/commun size
|
||||
*/
|
||||
|
||||
int allocPopulate();
|
||||
/*
|
||||
* Allow malloc to allocate elements of this precise size.
|
||||
|
@ -7,6 +7,14 @@
|
||||
#include "mem.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
struct memArea {
|
||||
vaddr_t startAddr;
|
||||
uint nbPages;
|
||||
|
||||
struct memArea *next;
|
||||
struct memArea *prev;
|
||||
};
|
||||
|
||||
static struct memArea *freeArea;
|
||||
static struct memArea *usedArea;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "paging.h"
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
|
||||
/* Pure Virtual Memory Allocation */
|
||||
|
||||
@ -8,19 +9,29 @@
|
||||
#define AREA_PHY_MAP (1<<0)
|
||||
#define AREA_MEM_TOP PAGING_MIRROR_VADDR
|
||||
|
||||
struct memArea {
|
||||
vaddr_t startAddr;
|
||||
uint nbPages;
|
||||
|
||||
struct memArea *next;
|
||||
struct memArea *prev;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the Area subsystem
|
||||
**/
|
||||
void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stack_bottom, vaddr_t stack_top);
|
||||
|
||||
/**
|
||||
* Request a virtual memory area of @param nbPages
|
||||
**/
|
||||
vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags);
|
||||
// Remove an area from the free ones but do not add it into used ones.
|
||||
// This area should be latter added woth areaAdd.
|
||||
// Used by malloc to avoid recursivity issue
|
||||
vaddr_t areaBook(unsigned int nbPages, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Free a virtual area
|
||||
**/
|
||||
int areaFree(vaddr_t addr);
|
||||
|
||||
/**
|
||||
* Remove an area from the "free" ones but do not add it into used ones.
|
||||
* This area should be latter added with areaAdd.
|
||||
* Used by malloc to avoid recursivity issue
|
||||
**/
|
||||
vaddr_t areaBook(unsigned int nbPages, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Declare a virtual region to be managed by the subsytem
|
||||
*/
|
||||
int areaAdd(vaddr_t begin, vaddr_t end, int isFree);
|
||||
|
@ -27,7 +27,8 @@
|
||||
*/
|
||||
|
||||
#include "errno.h"
|
||||
#include "stdarg.h"
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#include "types.h"
|
||||
|
||||
/**
|
||||
|
49
core/elf.c
49
core/elf.c
@ -5,6 +5,7 @@
|
||||
#include "paging.h"
|
||||
#include "thread.h"
|
||||
#include "types.h"
|
||||
#include "zero.h"
|
||||
|
||||
/**
|
||||
* Make sure the program is in a valid ELF format, map it into memory,
|
||||
@ -13,40 +14,11 @@
|
||||
* @return 0 when the program is not a valid ELF
|
||||
*/
|
||||
|
||||
uaddr_t loadElfProg(const char *prog, struct process * proc)
|
||||
uaddr_t loadElfProg(const char *prog, struct process *proc)
|
||||
{
|
||||
int i;
|
||||
uaddr_t lastUserAddr = 0;
|
||||
|
||||
/**
|
||||
* Typedefs, constants and structure definitions as given by the ELF
|
||||
* standard specifications.
|
||||
*/
|
||||
typedef unsigned long Elf32_Addr;
|
||||
typedef unsigned long Elf32_Word;
|
||||
typedef unsigned short Elf32_Half;
|
||||
typedef unsigned long Elf32_Off;
|
||||
// typedef signed long Elf32_Sword;
|
||||
|
||||
/* Elf identification */
|
||||
|
||||
#define EI_NIDENT 16
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
} __attribute__((packed)) Elf32_Ehdr_t;
|
||||
struct uAddrSpace *as = processGetAddrSpace(proc);
|
||||
|
||||
/* e_ident value */
|
||||
#define ELFMAG0 0x7f
|
||||
@ -97,16 +69,6 @@ uaddr_t loadElfProg(const char *prog, struct process * proc)
|
||||
#define EV_NONE 0 /* invalid version */
|
||||
#define EV_CURRENT 1 /* current version */
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
} __attribute__((packed)) Elf32_Phdr_t;
|
||||
|
||||
/* Reserved segment types p_type */
|
||||
#define PT_NULL 0
|
||||
@ -182,6 +144,11 @@ uaddr_t loadElfProg(const char *prog, struct process * proc)
|
||||
if (lastUserAddr < uaddr) {
|
||||
lastUserAddr = uaddr;
|
||||
}
|
||||
|
||||
// Hack: Even if already allocated mark the adresse space as managed by a ressource
|
||||
// So this address space is not used by another ressource.
|
||||
uaddr = elf_phdrs[i].p_vaddr;
|
||||
assert(zeroMmap(as, &uaddr, elf_phdrs[i].p_memsz, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ, 0) == 0);
|
||||
}
|
||||
|
||||
processInitHeap(proc, lastUserAddr);
|
||||
|
93
core/elf.h
93
core/elf.h
@ -3,4 +3,97 @@
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
#include "types.h"
|
||||
|
||||
/**
|
||||
* Typedefs, constants and structure definitions as given by the ELF
|
||||
* standard specifications.
|
||||
*/
|
||||
typedef unsigned long Elf32_Addr;
|
||||
typedef unsigned long Elf32_Word;
|
||||
typedef unsigned short Elf32_Half;
|
||||
typedef unsigned long Elf32_Off;
|
||||
// typedef signed long Elf32_Sword;
|
||||
|
||||
/**
|
||||
* ELF 32-bit format related structures.
|
||||
* See http://www.cs.cmu.edu/afs/cs/academic/class/15213-f00/docs/elf.pdf
|
||||
*/
|
||||
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
#define SHT_LOPROC 0x70000000
|
||||
#define SHT_HIPROC 0x7fffffff
|
||||
#define SHT_LOUSER 0x80000000
|
||||
#define SHT_HIUSER 0xffffffff
|
||||
|
||||
|
||||
/** ELF Header **/
|
||||
#define EI_NIDENT 16
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
} __attribute__((packed)) Elf32_Ehdr_t;
|
||||
|
||||
/** ELF Section header */
|
||||
typedef struct {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
} __attribute__((packed)) Elf32_Shdr_t;
|
||||
|
||||
/** ELF Symbol **/
|
||||
typedef struct {
|
||||
Elf32_Word st_name;
|
||||
Elf32_Addr st_value;
|
||||
Elf32_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32_Half st_shndx;
|
||||
} __attribute__((packed)) Elf32_Sym_t;
|
||||
|
||||
/** ELF Program header **/
|
||||
typedef struct {
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
} __attribute__((packed)) Elf32_Phdr_t;
|
||||
|
||||
#define ELF_SYM_TYPE(info) ((info) & 0xf)
|
||||
#define ELF_SYM_TYPE_FUNC 0x2
|
||||
|
||||
|
||||
uaddr_t loadElfProg(const char *prog, struct process *proc);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
|
||||
// NIH http://wiki.osdev.org/Inline_Assembly/Examples#I.2FO_access
|
||||
static inline void outb(uint16_t port, uint8_t val)
|
||||
|
@ -425,7 +425,8 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
case 'x': {
|
||||
char val[sizeof(long long int) * 2];
|
||||
unsigned int valIdx = 0;
|
||||
long long int d = va_arg(ap, long long int);
|
||||
unsigned long long int d =
|
||||
va_arg(ap, unsigned long long int);
|
||||
itoa(d, val, 16);
|
||||
if (str) {
|
||||
while (val[valIdx]) {
|
||||
@ -453,7 +454,7 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
case 'x': {
|
||||
char val[sizeof(int) * 2];
|
||||
unsigned int valIdx = 0;
|
||||
long int d = va_arg(ap, long int);
|
||||
unsigned long int d = va_arg(ap, unsigned long int);
|
||||
itoa(d, val, 16);
|
||||
if (str) {
|
||||
while (val[valIdx]) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "assert.h"
|
||||
#include "stdarg.h"
|
||||
#include "stddef.h"
|
||||
#include "minmax.h"
|
||||
|
||||
#define islower(c) (('a' <= (c)) && ((c) <= 'z'))
|
||||
@ -36,8 +37,8 @@ int vprintf(const char *format, va_list ap) __attribute__ ((__format__ (printf,
|
||||
int printf(const char *format, ...) __attribute__ ((__format__ (printf, 1, 2)));
|
||||
|
||||
// Could be used after malloc is available
|
||||
int asprintf(char **strp, const char *fmt, ...);
|
||||
int vasprintf(char **strp, const char *fmt, va_list ap);
|
||||
int asprintf(char **strp, const char *fmt, ...) __attribute__ ((__format__ (printf, 2, 3)));
|
||||
int vasprintf(char **strp, const char *fmt, va_list ap) __attribute__ ((__format__ (printf, 2, 0)));
|
||||
|
||||
/*
|
||||
* Dummy printk for disabled debugging statements to use whilst maintaining
|
||||
|
29
core/main.c
29
core/main.c
@ -28,6 +28,7 @@
|
||||
#include "time.h"
|
||||
#include "types.h"
|
||||
#include "vga.h"
|
||||
#include "zero.h"
|
||||
|
||||
#define CHECK_FLAG(flags, bit) ((flags) & (1 << (bit)))
|
||||
|
||||
@ -35,7 +36,7 @@ void idleThread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
while (1) {
|
||||
VGAPrintf(GREEN, BLACK, 0, VGA_HEIGHT - 1, "%d", (jiffies / HZ));
|
||||
VGAPrintf(GREEN, BLACK, 0, VGA_HEIGHT - 1, "%d allocated %d, mapped %d", (jiffies / HZ), getNbAllocatedPage(), getNbMappedPage());
|
||||
threadYield();
|
||||
}
|
||||
}
|
||||
@ -45,7 +46,7 @@ void idleThread(void *arg)
|
||||
#define FILE_MAX_SIZE 64 // In nb of sectors
|
||||
void loadUserSpace()
|
||||
{
|
||||
struct ata_partition *part = ATAGetPartition(0);
|
||||
struct ata_partition *part = ATAGetPartitionByType(PART_TYPE_LINUX);
|
||||
|
||||
if (part == NULL) {
|
||||
printf("No user partition found\n");
|
||||
@ -72,8 +73,8 @@ void loadUserSpace()
|
||||
sectorToRead = DIV_ROUND_UP(sizeInt, DISK_SECTOR_SIZE) - 1;
|
||||
}
|
||||
|
||||
if (sectorToRead > FILE_MAX_SIZE - 1) {
|
||||
printf("File too long");
|
||||
if (sectorToRead > FILE_MAX_SIZE - 1 || sectorToRead <= 0) {
|
||||
printf("Invalid file size: %d (sector)\n", sectorToRead);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -83,7 +84,9 @@ void loadUserSpace()
|
||||
return;
|
||||
}
|
||||
|
||||
struct process *proc = processCreate("UserSpace");
|
||||
{
|
||||
struct process *proc = processCreate("init");
|
||||
struct uAddrSpace *as = processGetAddrSpace(proc);
|
||||
|
||||
threadChangeCurrentContext(processGetMMUContext(proc));
|
||||
uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE, proc);
|
||||
@ -93,16 +96,15 @@ void loadUserSpace()
|
||||
}
|
||||
|
||||
// Alloc user stack
|
||||
uaddr_t stackTop = 0xfffffffc;
|
||||
uaddr_t stackBottom = ALIGN_DOWN(stackTop, PAGE_SIZE);
|
||||
paddr_t stackPhy = allocPhyPage(1);
|
||||
assert(pageMap(stackBottom, stackPhy,
|
||||
PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0);
|
||||
unrefPhyPage(stackPhy);
|
||||
size_t stackSize = PAGE_SIZE * 2;
|
||||
uaddr_t stack = PAGING_TOP_USER_ADDRESS - stackSize + 1;
|
||||
zeroMmap(as, &stack, stackSize, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ,
|
||||
0);
|
||||
|
||||
threadCreateUser("UserProg", proc, prog, 0, 0, stackTop);
|
||||
threadCreateUser("init", proc, prog, 0, 0, stack + stackSize - 4);
|
||||
processUnref(proc);
|
||||
threadChangeCurrentContext(NULL);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
@ -159,6 +161,9 @@ void kmain(unsigned long magic, unsigned long addr)
|
||||
}
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(mbi->flags, 5)) {
|
||||
stackSymbolSetup(mbi);
|
||||
}
|
||||
if (CHECK_FLAG(mbi->flags, 6)) {
|
||||
memMapAvailable = 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
#include "types.h"
|
||||
|
||||
uint32_t log2(uint32_t x);
|
||||
|
32
core/mem.h
32
core/mem.h
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
#include "types.h"
|
||||
|
||||
/** Physical Page related function
|
||||
/**
|
||||
* Physical Page management
|
||||
*/
|
||||
|
||||
#define PAGE_SHIFT 12U
|
||||
@ -11,8 +12,8 @@
|
||||
|
||||
|
||||
// Defined in linker.ld script
|
||||
extern uint32_t __ld_kernel_begin;
|
||||
extern uint32_t __ld_kernel_end;
|
||||
extern char __ld_kernel_begin;
|
||||
extern char __ld_kernel_end;
|
||||
|
||||
struct phyMemDesc {
|
||||
paddr_t phy_addr;
|
||||
@ -20,10 +21,33 @@ struct phyMemDesc {
|
||||
struct phyMemDesc *next, *prev;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initi Physical Page management subsystem
|
||||
**/
|
||||
int memSetup(paddr_t upperMem, paddr_t * firstUsed, paddr_t *lastUsed);
|
||||
|
||||
/**
|
||||
* Declare a physical region to be managed by the physica page subsystem
|
||||
**/
|
||||
int memAddBank(paddr_t bottomMem, paddr_t topMem, int isFree);
|
||||
|
||||
/**
|
||||
* Request @params nbPage free physical pages
|
||||
**/
|
||||
paddr_t allocPhyPage(uint nbPage);
|
||||
|
||||
/**
|
||||
* Decrement the nb of user of a given physical page
|
||||
**/
|
||||
int unrefPhyPage(paddr_t addr);
|
||||
|
||||
/**
|
||||
* Increment the nb of user of a given physical page
|
||||
**/
|
||||
int refPhyPage(paddr_t addr);
|
||||
|
||||
/**
|
||||
* Return the number of physical allocated pages
|
||||
**/
|
||||
unsigned long getNbAllocatedPage(void);
|
||||
void memGetStat(uint *free, uint *used);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "stdarg.h"
|
||||
#include "stddef.h"
|
||||
|
||||
struct mmu_context;
|
||||
|
||||
|
418
core/multiboot2.h
Normal file
418
core/multiboot2.h
Normal file
@ -0,0 +1,418 @@
|
||||
/* Taken from https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#multiboot2_002eh */
|
||||
/* multiboot2.h - Multiboot 2 header file. */
|
||||
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
|
||||
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MULTIBOOT_HEADER
|
||||
#define MULTIBOOT_HEADER 1
|
||||
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
#define MULTIBOOT_SEARCH 32768
|
||||
#define MULTIBOOT_HEADER_ALIGN 8
|
||||
|
||||
/* The magic field should contain this. */
|
||||
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
||||
|
||||
/* This should be in %eax. */
|
||||
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
|
||||
|
||||
/* Alignment of multiboot modules. */
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
|
||||
/* Alignment of the multiboot info structure. */
|
||||
#define MULTIBOOT_INFO_ALIGN 0x00000008
|
||||
|
||||
/* Flags set in the ’flags’ member of the multiboot header. */
|
||||
|
||||
#define MULTIBOOT_TAG_ALIGN 8
|
||||
#define MULTIBOOT_TAG_TYPE_END 0
|
||||
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
|
||||
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
|
||||
#define MULTIBOOT_TAG_TYPE_MODULE 3
|
||||
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
|
||||
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
|
||||
#define MULTIBOOT_TAG_TYPE_MMAP 6
|
||||
#define MULTIBOOT_TAG_TYPE_VBE 7
|
||||
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
|
||||
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
|
||||
#define MULTIBOOT_TAG_TYPE_APM 10
|
||||
#define MULTIBOOT_TAG_TYPE_EFI32 11
|
||||
#define MULTIBOOT_TAG_TYPE_EFI64 12
|
||||
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
|
||||
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
|
||||
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
|
||||
#define MULTIBOOT_TAG_TYPE_NETWORK 16
|
||||
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
|
||||
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
|
||||
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
|
||||
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
|
||||
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
|
||||
|
||||
#define MULTIBOOT_HEADER_TAG_END 0
|
||||
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
|
||||
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
|
||||
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
|
||||
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
|
||||
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
|
||||
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
|
||||
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
|
||||
|
||||
#define MULTIBOOT_ARCHITECTURE_I386 0
|
||||
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
|
||||
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
||||
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
|
||||
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||
|
||||
#ifndef ASM_FILE
|
||||
|
||||
typedef unsigned char multiboot_uint8_t;
|
||||
typedef unsigned short multiboot_uint16_t;
|
||||
typedef unsigned int multiboot_uint32_t;
|
||||
typedef unsigned long long multiboot_uint64_t;
|
||||
|
||||
struct multiboot_header
|
||||
{
|
||||
/* Must be MULTIBOOT_MAGIC - see above. */
|
||||
multiboot_uint32_t magic;
|
||||
|
||||
/* ISA */
|
||||
multiboot_uint32_t architecture;
|
||||
|
||||
/* Total header length. */
|
||||
multiboot_uint32_t header_length;
|
||||
|
||||
/* The above fields plus this one must equal 0 mod 2^32. */
|
||||
multiboot_uint32_t checksum;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_information_request
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t requests[0];
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_address
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t header_addr;
|
||||
multiboot_uint32_t load_addr;
|
||||
multiboot_uint32_t load_end_addr;
|
||||
multiboot_uint32_t bss_end_addr;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_entry_address
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t entry_addr;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_console_flags
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t console_flags;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_framebuffer
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t width;
|
||||
multiboot_uint32_t height;
|
||||
multiboot_uint32_t depth;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_module_align
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
};
|
||||
|
||||
struct multiboot_header_tag_relocatable
|
||||
{
|
||||
multiboot_uint16_t type;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t min_addr;
|
||||
multiboot_uint32_t max_addr;
|
||||
multiboot_uint32_t align;
|
||||
multiboot_uint32_t preference;
|
||||
};
|
||||
|
||||
struct multiboot_color
|
||||
{
|
||||
multiboot_uint8_t red;
|
||||
multiboot_uint8_t green;
|
||||
multiboot_uint8_t blue;
|
||||
};
|
||||
|
||||
struct multiboot_mmap_entry
|
||||
{
|
||||
multiboot_uint64_t addr;
|
||||
multiboot_uint64_t len;
|
||||
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
|
||||
#define MULTIBOOT_MEMORY_NVS 4
|
||||
#define MULTIBOOT_MEMORY_BADRAM 5
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t zero;
|
||||
};
|
||||
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
|
||||
|
||||
struct multiboot_tag
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
};
|
||||
|
||||
struct multiboot_tag_string
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
char string[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_module
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t mod_start;
|
||||
multiboot_uint32_t mod_end;
|
||||
char cmdline[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_basic_meminfo
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t mem_lower;
|
||||
multiboot_uint32_t mem_upper;
|
||||
};
|
||||
|
||||
struct multiboot_tag_bootdev
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t biosdev;
|
||||
multiboot_uint32_t slice;
|
||||
multiboot_uint32_t part;
|
||||
};
|
||||
|
||||
struct multiboot_tag_mmap
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t entry_size;
|
||||
multiboot_uint32_t entry_version;
|
||||
struct multiboot_mmap_entry entries[0];
|
||||
};
|
||||
|
||||
struct multiboot_vbe_info_block
|
||||
{
|
||||
multiboot_uint8_t external_specification[512];
|
||||
};
|
||||
|
||||
struct multiboot_vbe_mode_info_block
|
||||
{
|
||||
multiboot_uint8_t external_specification[256];
|
||||
};
|
||||
|
||||
struct multiboot_tag_vbe
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
|
||||
multiboot_uint16_t vbe_mode;
|
||||
multiboot_uint16_t vbe_interface_seg;
|
||||
multiboot_uint16_t vbe_interface_off;
|
||||
multiboot_uint16_t vbe_interface_len;
|
||||
|
||||
struct multiboot_vbe_info_block vbe_control_info;
|
||||
struct multiboot_vbe_mode_info_block vbe_mode_info;
|
||||
};
|
||||
|
||||
struct multiboot_tag_framebuffer_common
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
|
||||
multiboot_uint64_t framebuffer_addr;
|
||||
multiboot_uint32_t framebuffer_pitch;
|
||||
multiboot_uint32_t framebuffer_width;
|
||||
multiboot_uint32_t framebuffer_height;
|
||||
multiboot_uint8_t framebuffer_bpp;
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
|
||||
multiboot_uint8_t framebuffer_type;
|
||||
multiboot_uint16_t reserved;
|
||||
};
|
||||
|
||||
struct multiboot_tag_framebuffer
|
||||
{
|
||||
struct multiboot_tag_framebuffer_common common;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
multiboot_uint16_t framebuffer_palette_num_colors;
|
||||
struct multiboot_color framebuffer_palette[0];
|
||||
};
|
||||
struct
|
||||
{
|
||||
multiboot_uint8_t framebuffer_red_field_position;
|
||||
multiboot_uint8_t framebuffer_red_mask_size;
|
||||
multiboot_uint8_t framebuffer_green_field_position;
|
||||
multiboot_uint8_t framebuffer_green_mask_size;
|
||||
multiboot_uint8_t framebuffer_blue_field_position;
|
||||
multiboot_uint8_t framebuffer_blue_mask_size;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct multiboot_tag_elf_sections
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t num;
|
||||
multiboot_uint32_t entsize;
|
||||
multiboot_uint32_t shndx;
|
||||
char sections[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_apm
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint16_t version;
|
||||
multiboot_uint16_t cseg;
|
||||
multiboot_uint32_t offset;
|
||||
multiboot_uint16_t cseg_16;
|
||||
multiboot_uint16_t dseg;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint16_t cseg_len;
|
||||
multiboot_uint16_t cseg_16_len;
|
||||
multiboot_uint16_t dseg_len;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi32
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi64
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint64_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_smbios
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint8_t major;
|
||||
multiboot_uint8_t minor;
|
||||
multiboot_uint8_t reserved[6];
|
||||
multiboot_uint8_t tables[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_old_acpi
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint8_t rsdp[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_new_acpi
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint8_t rsdp[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_network
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint8_t dhcpack[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi_mmap
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t descr_size;
|
||||
multiboot_uint32_t descr_vers;
|
||||
multiboot_uint8_t efi_mmap[0];
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi32_ih
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_efi64_ih
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint64_t pointer;
|
||||
};
|
||||
|
||||
struct multiboot_tag_load_base_addr
|
||||
{
|
||||
multiboot_uint32_t type;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t load_base_addr;
|
||||
};
|
||||
|
||||
#endif /* ! ASM_FILE */
|
||||
|
||||
#endif /* ! MULTIBOOT_HEADER */
|
@ -5,12 +5,14 @@
|
||||
#include "list.h"
|
||||
#include "mmuContext.h"
|
||||
#include "types.h"
|
||||
#include "thread.h"
|
||||
#include "uaddrspace.h"
|
||||
|
||||
struct process {
|
||||
char name[PROCESS_NAME_MAX_LENGTH];
|
||||
int ref;
|
||||
int pid;
|
||||
pid_t pid;
|
||||
pid_t nextTid;
|
||||
struct uAddrSpace *addrSpace;
|
||||
struct thread *thList;
|
||||
|
||||
@ -48,6 +50,7 @@ struct process *processCreate(char *name)
|
||||
|
||||
disable_IRQs(flags);
|
||||
new->pid = nextPid++;
|
||||
new->nextTid = new->pid;
|
||||
list_add_tail(processList, new);
|
||||
restore_IRQs(flags);
|
||||
|
||||
@ -66,7 +69,7 @@ void processListPrint()
|
||||
struct thread *th;
|
||||
int nbTh;
|
||||
|
||||
printf("%d %s %d %d\n", proc->pid, proc->name, processCountThread(proc), proc->ref);
|
||||
printf("%lu %s %d %d\n", proc->pid, proc->name, processCountThread(proc), proc->ref);
|
||||
list_foreach_named(proc->thList, th, nbTh, prevInProcess, nextInProcess)
|
||||
{
|
||||
if (th == cur) {
|
||||
@ -164,6 +167,10 @@ int processSetName(struct process *proc, char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *processGetName(struct process *proc){
|
||||
return proc->name;
|
||||
}
|
||||
|
||||
struct mmu_context *processGetMMUContext(struct process *proc)
|
||||
{
|
||||
return uAddrSpaceGetMMUContext(proc->addrSpace);
|
||||
@ -176,3 +183,47 @@ struct uAddrSpace *processGetAddrSpace(struct process *proc){
|
||||
int processInitHeap(struct process *proc, uaddr_t lastUserAddr){
|
||||
return uAddrSpaceSetHeap(proc->addrSpace, lastUserAddr, 0);
|
||||
}
|
||||
|
||||
pid_t processGetId(struct process *proc){
|
||||
return proc->pid;
|
||||
}
|
||||
|
||||
pid_t processGetNextTid(struct process *proc){
|
||||
return proc->nextTid++;
|
||||
}
|
||||
|
||||
//Should be called with IRQ disabled
|
||||
struct thread *processGetThread(struct process *proc, pid_t tid)
|
||||
{
|
||||
int count;
|
||||
struct thread *th;
|
||||
struct thread *thFound = NULL;
|
||||
|
||||
list_foreach_named(proc->thList, th, count, prevInProcess, nextInProcess)
|
||||
{
|
||||
if (th->tid == tid) {
|
||||
thFound = th;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return thFound;
|
||||
}
|
||||
|
||||
int processJoinThread(struct process *proc, pid_t tid)
|
||||
{
|
||||
uint32_t flags;
|
||||
struct thread *th;
|
||||
int ret = -1;
|
||||
|
||||
disable_IRQs(flags);
|
||||
|
||||
th = processGetThread(proc, tid);
|
||||
if (th && th->wqExit) {
|
||||
wait(th->wqExit);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
restore_IRQs(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
#include "thread.h"
|
||||
#include "types.h"
|
||||
|
||||
#define PROCESS_NAME_MAX_LENGTH 32
|
||||
typedef unsigned long int pid_t;
|
||||
|
||||
struct process;
|
||||
struct thread;
|
||||
|
||||
int processSetup();
|
||||
struct process *processCreate(char *name);
|
||||
@ -12,8 +14,12 @@ void processListPrint();
|
||||
int processRef(struct process *proc);
|
||||
int processUnref(struct process *proc);
|
||||
int processSetName(struct process *proc, char *name);
|
||||
char *processGetName(struct process *proc);
|
||||
int processAddThread(struct process *proc, struct thread *th);
|
||||
int processRemoveThread(struct thread *th);
|
||||
struct mmu_context *processGetMMUContext(struct process *th);
|
||||
struct uAddrSpace *processGetAddrSpace(struct process *proc);
|
||||
int processInitHeap(struct process *proc, uaddr_t lastUserAddr);
|
||||
pid_t processGetId(struct process *proc);
|
||||
pid_t processGetNextTid(struct process *proc);
|
||||
int processJoinThread(struct process *proc, pid_t tid);
|
||||
|
92
core/stack.c
92
core/stack.c
@ -1,7 +1,94 @@
|
||||
#include "stack.h"
|
||||
#include "elf.h"
|
||||
#include "klibc.h"
|
||||
#include "paging.h"
|
||||
#include "types.h"
|
||||
|
||||
/** Defined in linker.ld script **/
|
||||
extern char __multiboot_data_start;
|
||||
extern char __multiboot_data_end;
|
||||
static size_t multibootDataSize;
|
||||
static size_t multibootUsage;
|
||||
|
||||
/** Initialized at 'StackSymbolSetup'. */
|
||||
static Elf32_Sym_t *elfSymtab;
|
||||
static size_t elfSymtabSize;
|
||||
|
||||
static const char *elfStrtab;
|
||||
static size_t elfStrtabSize;
|
||||
|
||||
static void *stackSaveSection(const void *addr, size_t size, const char *sectionName)
|
||||
{
|
||||
if (size > (multibootDataSize - multibootUsage)) {
|
||||
printf("No enough room to store %s (%d/%d). Increase multiboot_data section size",
|
||||
sectionName, size, (multibootDataSize - multibootUsage));
|
||||
return NULL;
|
||||
}
|
||||
void *destAddr = (void *)&__multiboot_data_start + multibootUsage;
|
||||
|
||||
memcpy((void *)destAddr, addr, size);
|
||||
multibootUsage += size;
|
||||
|
||||
return destAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the symbols table and string table from a multiboot information.
|
||||
* We need to copy them as they are loaded by the bootloader and could be override as soon
|
||||
* as we play with memory around our loaded kernel.
|
||||
* As special ELF section is allocated for this purpose.
|
||||
*/
|
||||
void stackSymbolSetup(multiboot_info_t *mbi)
|
||||
{
|
||||
/** Get the section header table as an array of section headers. */
|
||||
Elf32_Shdr_t *sht = (Elf32_Shdr_t *)mbi->u.elf_sec.addr;
|
||||
size_t sec_len = (size_t)mbi->u.elf_sec.num;
|
||||
assert(mbi->u.elf_sec.size == sizeof(Elf32_Shdr_t));
|
||||
multibootDataSize = &__multiboot_data_end - &__multiboot_data_start;
|
||||
multibootUsage = 0;
|
||||
|
||||
/**
|
||||
* The section header at index 'shndx' in the table is a meta section
|
||||
* header. It contains a list of section header names in the table. We
|
||||
* should look for section header names ".symtab" & ".strtab".
|
||||
*/
|
||||
const char *sh_names = (const char *)sht[mbi->u.elf_sec.shndx].sh_addr;
|
||||
|
||||
/** Loop through the table and look for ".symtab" & ".strtab". */
|
||||
for (size_t i = 0; i < sec_len; ++i) {
|
||||
const char *name = sh_names + sht[i].sh_name;
|
||||
|
||||
if (strcmp(name, ".symtab") == 0) {
|
||||
assert(sht[i].sh_type == SHT_SYMTAB);
|
||||
elfSymtab = stackSaveSection((void *)sht[i].sh_addr, sht[i].sh_size, name);
|
||||
if (elfSymtab)
|
||||
elfSymtabSize = sht[i].sh_size;
|
||||
|
||||
} else if (strcmp(name, ".strtab") == 0) {
|
||||
assert(sht[i].sh_type == SHT_STRTAB);
|
||||
elfStrtab = stackSaveSection((void *)sht[i].sh_addr, sht[i].sh_size, name);
|
||||
if (elfStrtab)
|
||||
elfStrtabSize = sht[i].sh_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Look up an address in symbols map and return its function name or NULL. */
|
||||
const char *lookupSymbolName(uint32_t addr)
|
||||
{
|
||||
size_t symtab_len = elfSymtabSize / sizeof(Elf32_Sym_t);
|
||||
|
||||
for (size_t i = 0; i < symtab_len; ++i) {
|
||||
if ((ELF_SYM_TYPE(elfSymtab[i].st_info) == ELF_SYM_TYPE_FUNC) &&
|
||||
(addr >= elfSymtab[i].st_value) &&
|
||||
(addr <= elfSymtab[i].st_value + elfSymtab[i].st_size)) {
|
||||
return elfStrtab + elfSymtab[i].st_name;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void printStackTrace(unsigned int maxFrames)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -21,7 +108,12 @@ void printStackTrace(unsigned int maxFrames)
|
||||
break;
|
||||
}
|
||||
unsigned int *arguments = ebp + 2;
|
||||
const char *functionName = lookupSymbolName(eip);
|
||||
if (functionName != NULL) {
|
||||
printf("[%d] %s (", frame, functionName);
|
||||
} else {
|
||||
printf("[%d] 0x%x (", frame, eip);
|
||||
}
|
||||
int nbArg = 0;
|
||||
do {
|
||||
if ((_stack_bottom <= (vaddr_t)arguments) && ((vaddr_t)arguments <= _stack_top)) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "multiboot.h"
|
||||
|
||||
#include "types.h"
|
||||
extern vaddr_t _stack_bottom;
|
||||
extern vaddr_t _stack_top;
|
||||
void printStackTrace(unsigned int maxFrame);
|
||||
void stackSymbolSetup(multiboot_info_t *mbi);
|
||||
|
@ -1,53 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__extension__ typedef __signed__ long long __s64;
|
||||
__extension__ typedef unsigned long long __u64;
|
||||
#else
|
||||
typedef __signed__ long long __s64;
|
||||
typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
/* sysv */
|
||||
typedef unsigned char unchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef __s8 int8_t;
|
||||
typedef __s16 int16_t;
|
||||
typedef __s32 int32_t;
|
||||
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u16 uint16_t;
|
||||
typedef __u32 uint32_t;
|
||||
|
||||
typedef __u64 uint64_t;
|
||||
typedef __u64 u_int64_t;
|
||||
typedef __s64 int64_t;
|
||||
|
||||
typedef enum { FALSE = 0, TRUE } bool_t;
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#if __x86_64__
|
||||
typedef unsigned long size_t;
|
||||
typedef long ssize_t;
|
||||
typedef unsigned long int uintptr_t;
|
||||
#else
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
#endif
|
||||
|
||||
//__builtin_va_list could be used instead
|
||||
typedef char *va_list;
|
||||
#define va_start(v, l) ((v) = (va_list) & (l) + sizeof(l))
|
||||
|
29
core/stddef.h
Normal file
29
core/stddef.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum { FALSE = 0, TRUE } bool_t;
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#if __x86_64__
|
||||
typedef unsigned long size_t;
|
||||
typedef long ssize_t;
|
||||
typedef unsigned long int uintptr_t;
|
||||
typedef long int intptr_t;
|
||||
#else
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef int intptr_t;
|
||||
#endif
|
||||
#if __x86_64__
|
||||
typedef unsigned long size_t;
|
||||
typedef long ssize_t;
|
||||
typedef unsigned long int uintptr_t;
|
||||
typedef long int intptr_t;
|
||||
#else
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef int intptr_t;
|
||||
#endif
|
||||
|
||||
typedef int wchar_t;
|
64
core/stdint.h
Normal file
64
core/stdint.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__extension__ typedef __signed__ long long __s64;
|
||||
__extension__ typedef unsigned long long __u64;
|
||||
#else
|
||||
typedef __signed__ long long __s64;
|
||||
typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
/* sysv */
|
||||
typedef unsigned char unchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef __s8 int8_t;
|
||||
typedef __s16 int16_t;
|
||||
typedef __s32 int32_t;
|
||||
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u16 uint16_t;
|
||||
typedef __u32 uint32_t;
|
||||
|
||||
typedef __u64 uint64_t;
|
||||
typedef __u64 u_int64_t;
|
||||
typedef __s64 int64_t;
|
||||
|
||||
#define USHRT_MAX ((u16)(~0U))
|
||||
#define SHRT_MAX ((s16)(USHRT_MAX >> 1))
|
||||
#define SHRT_MIN ((s16)(-SHRT_MAX - 1))
|
||||
#define INT_MAX ((int)(~0U >> 1))
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#define UINT_MAX (~0U)
|
||||
#define LONG_MAX ((long)(~0UL >> 1))
|
||||
#define LONG_MIN (-LONG_MAX - 1)
|
||||
#define ULONG_MAX (~0UL)
|
||||
#define LLONG_MAX ((long long)(~0ULL >> 1))
|
||||
#define LLONG_MIN (-LLONG_MAX - 1)
|
||||
#define ULLONG_MAX (~0ULL)
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#define PHYS_ADDR_MAX (~(phys_addr_t)0)
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
#define S8_MAX ((s8)(U8_MAX >> 1))
|
||||
#define S8_MIN ((s8)(-S8_MAX - 1))
|
||||
#define U16_MAX ((u16)~0U)
|
||||
#define S16_MAX ((s16)(U16_MAX >> 1))
|
||||
#define S16_MIN ((s16)(-S16_MAX - 1))
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#define S32_MAX ((s32)(U32_MAX >> 1))
|
||||
#define S32_MIN ((s32)(-S32_MAX - 1))
|
||||
#define U64_MAX ((u64)~0ULL)
|
||||
#define S64_MAX ((s64)(U64_MAX >> 1))
|
||||
#define S64_MIN ((s64)(-S64_MAX - 1))
|
141
core/syscall.c
141
core/syscall.c
@ -1,11 +1,15 @@
|
||||
#include "syscall.h"
|
||||
#include "kernel.h"
|
||||
#include "keyboard.h"
|
||||
#include "klibc.h"
|
||||
#include "paging.h"
|
||||
#include "process.h"
|
||||
#include "stdarg.h"
|
||||
#include "thread.h"
|
||||
#include "types.h"
|
||||
#include "uaccess.h"
|
||||
#include "uaddrspace.h"
|
||||
#include "zero.h"
|
||||
|
||||
int syscallExecute(int syscallId, const struct cpu_state *userCtx)
|
||||
{
|
||||
@ -22,8 +26,8 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx)
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_YOLO:
|
||||
ret = printf("YOLO FROM USERSPACE\n");
|
||||
case SYSCALL_ID_HELO:
|
||||
ret = printf("HELLO FROM USERSPACE\n");
|
||||
break;
|
||||
case SYSCALL_ID_PUTC: {
|
||||
unsigned int c;
|
||||
@ -40,7 +44,7 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx)
|
||||
printf("Got 5args from userspace %d %d %d %d %d\n", arg1, arg2, arg3, arg4, arg5);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_BRK:{
|
||||
case SYSCALL_ID_BRK: {
|
||||
|
||||
struct uAddrSpace *as;
|
||||
uaddr_t newHeapTop;
|
||||
@ -50,11 +54,140 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx)
|
||||
if (ret != 0)
|
||||
break;
|
||||
threadChangeCurrentContext(uAddrSpaceGetMMUContext(as));
|
||||
//TODO : what if *newHeapTop raise page fault?
|
||||
// TODO : what if *newHeapTop raise page fault?
|
||||
ret = sysBrk(as, newHeapTop);
|
||||
threadChangeCurrentContext(NULL);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_MMAP: {
|
||||
struct uAddrSpace *as;
|
||||
uaddr_t uaddr;
|
||||
uaddr_t uaddr_ptr;
|
||||
size_t size;
|
||||
uint32_t rights;
|
||||
uint32_t flags;
|
||||
uaddr_t userPath;
|
||||
|
||||
char path[256];
|
||||
|
||||
as = processGetAddrSpace(getCurrentThread()->process);
|
||||
ret = syscallGet5args(userCtx, (unsigned int *)&uaddr_ptr, (unsigned int *)&size,
|
||||
(unsigned int *)&rights, (unsigned int *)&flags,
|
||||
(unsigned int *)&userPath);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (memcpyFromUser((vaddr_t)&uaddr, uaddr_ptr, sizeof(uaddr)) != sizeof(uaddr)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
strzcpyFromUser((vaddr_t *)path, (uaddr_t *)userPath, sizeof(path));
|
||||
|
||||
printf("Trying mmap for device %s at %lu\n", path, (vaddr_t)uaddr);
|
||||
if (strcmp(path, "/dev/zero") == 0) {
|
||||
ret = zeroMmap(as, &uaddr, size, rights, flags);
|
||||
}
|
||||
if (!ret) {
|
||||
if (memcpyToUser(uaddr_ptr, (vaddr_t)&uaddr, sizeof(uaddr)) != sizeof(uaddr)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_MUNMAP: {
|
||||
struct uAddrSpace *as;
|
||||
uaddr_t uaddr;
|
||||
size_t size;
|
||||
|
||||
ret = syscallGet2args(userCtx, (unsigned int *)&uaddr, (unsigned int *)&size);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
as = processGetAddrSpace(getCurrentThread()->process);
|
||||
ret = uAddrSpaceUnmap(as, uaddr, size);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_NEW_THREAD: {
|
||||
struct uAddrSpace *as;
|
||||
thread_id_t threadIdPtr;
|
||||
thread_id_t threadId;
|
||||
uaddr_t funcAddr;
|
||||
uint32_t arg1, arg2;
|
||||
size_t stackSize;
|
||||
|
||||
ret = syscallGet5args(userCtx, (unsigned int *)&threadIdPtr,
|
||||
(unsigned int *)&funcAddr, (unsigned int *)&arg1,
|
||||
(unsigned int *)&arg2, (unsigned int *)&stackSize);
|
||||
if (ret)
|
||||
break;
|
||||
if (stackSize <= 0) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (memcpyFromUser((vaddr_t)&threadId, threadIdPtr, sizeof(threadId)) !=
|
||||
sizeof(threadId)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
as = processGetAddrSpace(getCurrentThread()->process);
|
||||
stackSize = ALIGN(stackSize, PAGE_SIZE);
|
||||
|
||||
uaddr_t stackAddr = 0;
|
||||
ret = zeroMmap(as, &stackAddr, stackSize, PAGING_MEM_READ | PAGING_MEM_WRITE, 0);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
struct thread *th = threadCreateUser(NULL, getCurrentThread()->process, funcAddr,
|
||||
arg1, arg2, stackAddr + stackSize);
|
||||
|
||||
if (th == NULL) {
|
||||
ret = -ENOMEM;
|
||||
uAddrSpaceUnmap(as, stackAddr, stackSize);
|
||||
}
|
||||
threadId = threadGetId(th);
|
||||
|
||||
if (memcpyToUser(threadIdPtr, (vaddr_t)&threadId, sizeof(threadId)) !=
|
||||
sizeof(threadId)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_USLEEP: {
|
||||
unsigned int sleep;
|
||||
|
||||
ret = syscallGet1arg(userCtx, &sleep);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = threadUsleep(sleep);
|
||||
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_GETPID: {
|
||||
ret = processGetId(getCurrentThread()->process);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_GETTID: {
|
||||
ret = threadGetId(getCurrentThread());
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ID_THREAD_JOIN: {
|
||||
thread_id_t tid;
|
||||
|
||||
ret = syscallGet1arg(userCtx, (unsigned int *)&tid);
|
||||
if (ret)
|
||||
break;
|
||||
ret = processJoinThread(getCurrentThread()->process, tid);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Unknon syscall id %d\n", syscallId);
|
||||
ret = -ENOENT;
|
||||
|
@ -4,11 +4,18 @@
|
||||
#endif
|
||||
|
||||
#define SYSCALL_ID_EXIT 1
|
||||
#define SYSCALL_ID_YOLO 2
|
||||
#define SYSCALL_ID_HELO 2
|
||||
#define SYSCALL_ID_PUTC 3
|
||||
#define SYSCALL_ID_READ 4
|
||||
#define SYSCALL_ID_TEST 5
|
||||
#define SYSCALL_ID_BRK 6
|
||||
#define SYSCALL_ID_MMAP 7
|
||||
#define SYSCALL_ID_MUNMAP 8
|
||||
#define SYSCALL_ID_NEW_THREAD 9
|
||||
#define SYSCALL_ID_USLEEP 10
|
||||
#define SYSCALL_ID_GETPID 11
|
||||
#define SYSCALL_ID_GETTID 12
|
||||
#define SYSCALL_ID_THREAD_JOIN 13
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int syscallExecute(int syscallId, const struct cpu_state *user_ctx);
|
||||
|
@ -12,6 +12,12 @@
|
||||
|
||||
static struct thread *currentThread;
|
||||
static struct thread *threadWithTimeout;
|
||||
static thread_id_t nextTid; // This is the TID for kernel thread ONLY
|
||||
|
||||
pid_t threadGetId(struct thread *th)
|
||||
{
|
||||
return th->tid;
|
||||
}
|
||||
|
||||
static void threadPrepareContext(struct thread *th);
|
||||
|
||||
@ -84,6 +90,8 @@ struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, v
|
||||
goto free_mem;
|
||||
|
||||
thread->state = READY;
|
||||
thread->tid = nextTid++;
|
||||
thread->wqExit = NULL;
|
||||
uint32_t flags;
|
||||
disable_IRQs(flags);
|
||||
list_add_tail(currentThread, thread);
|
||||
@ -110,6 +118,14 @@ struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t
|
||||
}
|
||||
thread->stackSize = THREAD_DEFAULT_STACK_SIZE;
|
||||
|
||||
thread->wqExit = (struct wait_queue * )malloc(sizeof(struct wait_queue));
|
||||
if (!thread->wqExit) {
|
||||
free((void *)thread->stackAddr);
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
waitQueueInit(thread->wqExit);
|
||||
|
||||
if (name)
|
||||
strzcpy(thread->name, name, THREAD_NAME_MAX_LENGTH);
|
||||
else
|
||||
@ -124,6 +140,7 @@ struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t
|
||||
goto free_mem;
|
||||
|
||||
thread->state = READY;
|
||||
thread->tid = processGetNextTid(proc);
|
||||
uint32_t flags;
|
||||
disable_IRQs(flags);
|
||||
list_add_tail(currentThread, thread);
|
||||
@ -143,9 +160,14 @@ void threadDelete(struct thread *thread)
|
||||
restore_IRQs(flags);
|
||||
assert(thread->state == EXITING);
|
||||
|
||||
if (thread->squattedContext) {
|
||||
threadChangeCurrentContext(NULL);
|
||||
if (thread->wqExit) {
|
||||
waitUp(thread->wqExit);
|
||||
}
|
||||
|
||||
if (thread->squattedContext) {
|
||||
mmuContextUnref(thread->squattedContext);
|
||||
}
|
||||
|
||||
if (thread->process)
|
||||
processRemoveThread(thread);
|
||||
|
||||
@ -210,16 +232,17 @@ int threadOnJieffiesTick()
|
||||
disable_IRQs(flags);
|
||||
list_foreach(currentThread, nextThread, idx)
|
||||
{
|
||||
if (nextThread->state == SLEEPING && nextThread->jiffiesSleeping) {
|
||||
if (nextThread->state == SLEEPING) {
|
||||
if (nextThread->jiffiesSleeping)
|
||||
nextThread->jiffiesSleeping--;
|
||||
if (!nextThread->jiffiesSleeping) {
|
||||
if (!nextThread->jiffiesSleeping)
|
||||
nextThread->state = READY;
|
||||
}
|
||||
}
|
||||
}
|
||||
list_foreach_named(threadWithTimeout, nextThread, idx, timePrev, timeNext)
|
||||
{
|
||||
if (nextThread->state == WAITING && nextThread->jiffiesSleeping) {
|
||||
if (nextThread->state == WAITING) {
|
||||
if (nextThread->jiffiesSleeping)
|
||||
nextThread->jiffiesSleeping--;
|
||||
if (!nextThread->jiffiesSleeping) {
|
||||
nextThread->sleepHaveTimeouted = 1;
|
||||
@ -292,6 +315,11 @@ int threadYield()
|
||||
}
|
||||
|
||||
int threadMsleep(unsigned long msec)
|
||||
{
|
||||
return threadUsleep(msec*1000);
|
||||
}
|
||||
|
||||
int threadUsleep(unsigned long usec)
|
||||
{
|
||||
uint32_t flags;
|
||||
struct thread *next, *current;
|
||||
@ -299,12 +327,12 @@ int threadMsleep(unsigned long msec)
|
||||
disable_IRQs(flags);
|
||||
|
||||
current = currentThread;
|
||||
assertmsg(current->state == RUNNING, "thread %s is in state %d for %lu\n", current->name,
|
||||
current->state, msec);
|
||||
assertmsg(current->state == RUNNING, "thread %s is in state %d for %lu us\n", current->name,
|
||||
current->state, usec);
|
||||
|
||||
current->state = SLEEPING;
|
||||
current->sleepHaveTimeouted = 0;
|
||||
current->jiffiesSleeping = msecs_to_jiffies(msec);
|
||||
current->jiffiesSleeping = usecs_to_jiffies(usec);
|
||||
next = threadSelectNext();
|
||||
|
||||
assert(next != current);
|
||||
|
@ -4,6 +4,7 @@ struct thread;
|
||||
#include "cpu_context.h"
|
||||
#include "mem.h"
|
||||
#include "process.h"
|
||||
#include "wait.h"
|
||||
|
||||
#define THREAD_NAME_MAX_LENGTH 32
|
||||
#define THREAD_DEFAULT_STACK_SIZE PAGE_SIZE
|
||||
@ -17,8 +18,11 @@ typedef enum {
|
||||
EXITING
|
||||
} thread_state;
|
||||
|
||||
typedef unsigned long int thread_id_t;
|
||||
|
||||
struct thread {
|
||||
char name[THREAD_NAME_MAX_LENGTH];
|
||||
thread_id_t tid;
|
||||
struct cpu_state *cpuState;
|
||||
thread_state state;
|
||||
vaddr_t stackAddr;
|
||||
@ -32,6 +36,7 @@ struct thread {
|
||||
// For User thread only
|
||||
struct thread *nextInProcess, *prevInProcess;
|
||||
struct process *process;
|
||||
struct wait_queue *wqExit; // This will be signaled at thread exit (user only)
|
||||
|
||||
/**
|
||||
* Address space currently "squatted" by the thread, or used to be
|
||||
@ -83,8 +88,10 @@ int threadYield();
|
||||
int threadWait(struct thread *current, struct thread *next, unsigned long msec);
|
||||
int threadUnsched(struct thread *th);
|
||||
int threadMsleep(unsigned long msec);
|
||||
int threadUsleep(unsigned long usec);
|
||||
int threadOnJieffiesTick();
|
||||
struct thread *getCurrentThread();
|
||||
int threadAddThread(struct thread *th);
|
||||
int threadChangeCurrentContext(struct mmu_context *ctx);
|
||||
int threadCount();
|
||||
thread_id_t threadGetId(struct thread *th);
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "time.h"
|
||||
#include "stddef.h"
|
||||
#include <stdint.h>
|
||||
|
||||
unsigned long volatile jiffies = INITIAL_JIFFIES;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "stdint.h"
|
||||
|
||||
#define HZ 100
|
||||
/*
|
||||
|
27
core/types.h
27
core/types.h
@ -1,32 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define USHRT_MAX ((u16)(~0U))
|
||||
#define SHRT_MAX ((s16)(USHRT_MAX >> 1))
|
||||
#define SHRT_MIN ((s16)(-SHRT_MAX - 1))
|
||||
#define INT_MAX ((int)(~0U >> 1))
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#define UINT_MAX (~0U)
|
||||
#define LONG_MAX ((long)(~0UL >> 1))
|
||||
#define LONG_MIN (-LONG_MAX - 1)
|
||||
#define ULONG_MAX (~0UL)
|
||||
#define LLONG_MAX ((long long)(~0ULL >> 1))
|
||||
#define LLONG_MIN (-LLONG_MAX - 1)
|
||||
#define ULLONG_MAX (~0ULL)
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#define PHYS_ADDR_MAX (~(phys_addr_t)0)
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
#define S8_MAX ((s8)(U8_MAX >> 1))
|
||||
#define S8_MIN ((s8)(-S8_MAX - 1))
|
||||
#define U16_MAX ((u16)~0U)
|
||||
#define S16_MAX ((s16)(U16_MAX >> 1))
|
||||
#define S16_MIN ((s16)(-S16_MAX - 1))
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#define S32_MAX ((s32)(U32_MAX >> 1))
|
||||
#define S32_MIN ((s32)(-S32_MAX - 1))
|
||||
#define U64_MAX ((u64)~0ULL)
|
||||
#define S64_MAX ((s64)(U64_MAX >> 1))
|
||||
#define S64_MIN ((s64)(-S64_MAX - 1))
|
||||
|
||||
// Virtual address
|
||||
typedef unsigned long vaddr_t;
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include "uaccess.h"
|
||||
#include "assert.h"
|
||||
#include "errno.h"
|
||||
#include "minmax.h"
|
||||
#include "mmuContext.h"
|
||||
#include "paging.h"
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
#include "uaccess.h"
|
||||
#include "types.h"
|
||||
|
||||
static int bindtoUserContext()
|
||||
{
|
||||
@ -42,6 +44,17 @@ static int memcpyUserMemNoCheck(vaddr_t dest, vaddr_t src, size_t size)
|
||||
return size;
|
||||
}
|
||||
|
||||
int memcpyToUser(uaddr_t to, vaddr_t from, size_t size)
|
||||
{
|
||||
|
||||
if ((uint)to < PAGING_BASE_USER_ADDRESS)
|
||||
return -EPERM;
|
||||
if ((uint)to > PAGING_TOP_USER_ADDRESS - size)
|
||||
return -EPERM;
|
||||
|
||||
return memcpyUserMemNoCheck(to, from, size);
|
||||
}
|
||||
|
||||
int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size)
|
||||
{
|
||||
|
||||
@ -52,3 +65,37 @@ int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size)
|
||||
|
||||
return memcpyUserMemNoCheck(to, from, size);
|
||||
}
|
||||
|
||||
static int strzcpyFromUserNoCheck(char *to, char *from, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bindtoUserContext();
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
to[i] = from[i];
|
||||
if (from[i] == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
to[size - 1] = '\0';
|
||||
|
||||
ret = unbindUserContext();
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int strzcpyFromUser(vaddr_t *to, uaddr_t *from, size_t size)
|
||||
{
|
||||
if ((uint)from < PAGING_BASE_USER_ADDRESS)
|
||||
return -EPERM;
|
||||
if ((uint)from > PAGING_TOP_USER_ADDRESS - size)
|
||||
return -EPERM;
|
||||
|
||||
return strzcpyFromUserNoCheck((char *)to, (char *)from, size);
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "stddef.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size);
|
||||
int memcpyToUser(uaddr_t to, vaddr_t from, size_t size);
|
||||
int strzcpyFromUser(vaddr_t *to, uaddr_t *from, size_t size);
|
||||
|
@ -1,9 +1,12 @@
|
||||
#include "uaddrspace.h"
|
||||
#include "alloc.h"
|
||||
#include "errno.h"
|
||||
#include "kernel.h"
|
||||
#include "klibc.h"
|
||||
#include "list.h"
|
||||
#include "mem.h"
|
||||
#include "mmuContext.h"
|
||||
#include "paging.h"
|
||||
#include "process.h"
|
||||
#include "stdarg.h"
|
||||
#include "thread.h"
|
||||
@ -12,18 +15,6 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct uAddrVirtualReg {
|
||||
uaddr_t addr;
|
||||
size_t size;
|
||||
int right; // PAGING_MEM_*
|
||||
uint32_t offset; // in the mappedRessource
|
||||
uint flags;
|
||||
|
||||
struct mappedRessource *res;
|
||||
struct uAddrVirtualReg *nextInAddrSpace, *prevInAddrSpace;
|
||||
struct uAddrVirtualReg *nextInMappedRes, *prevInMappedRes;
|
||||
};
|
||||
|
||||
struct uAddrSpace {
|
||||
struct process *process; // The process that is represented by this AS
|
||||
struct mmu_context *ctx; // The corresponding MMU configuration
|
||||
@ -31,26 +22,89 @@ struct uAddrSpace {
|
||||
struct uAddrVirtualReg *listVirtualReg; // List of Virtual Region used by this process
|
||||
|
||||
uaddr_t heapStart; // Start of the Head
|
||||
size_t heapSize; // Hep size -> modified by brk()
|
||||
size_t heapSize; // Heap size -> modified by brk()
|
||||
};
|
||||
|
||||
struct mappedRessourceOps {
|
||||
int (*open)(struct uAddrVirtualReg *vreg);
|
||||
int (*close)(struct uAddrVirtualReg *vreg);
|
||||
int (*unmap)(struct uAddrVirtualReg *vregi, uaddr_t addr, size_t size);
|
||||
int (*nopage)(struct uAddrVirtualReg *vregi, uaddr_t addr,
|
||||
int right); // Called by the pageflt handler when the page is missing
|
||||
};
|
||||
static int hasOverlap(uaddr_t addr1, size_t size1, uaddr_t addr2, size_t size2)
|
||||
{
|
||||
return max(addr1, addr2) < min(addr1 + size1, addr2 + size2);
|
||||
}
|
||||
|
||||
struct mappedRessource {
|
||||
int right; // PAGING_MEM_*
|
||||
struct mappedRessourceOps *ops;
|
||||
struct uAddrVirtualReg *listVirtualReg;
|
||||
};
|
||||
static struct uAddrVirtualReg *findVirtualRegionFromAddr(struct uAddrSpace *as, uaddr_t uaddr, size_t size)
|
||||
{
|
||||
struct uAddrVirtualReg *reg;
|
||||
int idx;
|
||||
|
||||
list_foreach_named(as->listVirtualReg, reg, idx, prevInAddrSpace, nextInAddrSpace)
|
||||
{
|
||||
if (hasOverlap(reg->addr, reg->size, uaddr, size))
|
||||
return reg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct uAddrVirtualReg *findVirtualRegionBeforeAddr(struct uAddrSpace *as,
|
||||
uaddr_t uaddr)
|
||||
{
|
||||
struct uAddrVirtualReg *reg, *prev = NULL;
|
||||
int idx;
|
||||
|
||||
list_foreach_named(as->listVirtualReg, reg, idx, prevInAddrSpace, nextInAddrSpace)
|
||||
{
|
||||
if (uaddr < reg->addr)
|
||||
break;
|
||||
prev = reg;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a address not alreay used in the virtual region of the AS.
|
||||
* This address will be equals to uaddr if possible and could take size
|
||||
*/
|
||||
static uaddr_t findFreeAddrInVirtualRegion(struct uAddrSpace *as, uaddr_t uaddr, size_t size)
|
||||
{
|
||||
struct uAddrVirtualReg *reg, *regNext, *regOver;
|
||||
|
||||
if (uaddr < PAGING_BASE_USER_ADDRESS)
|
||||
uaddr = PAGING_BASE_USER_ADDRESS;
|
||||
if(uaddr > PAGING_TOP_USER_ADDRESS - size)
|
||||
uaddr = PAGING_TOP_USER_ADDRESS - size;
|
||||
|
||||
reg = findVirtualRegionFromAddr(as, uaddr, size);
|
||||
|
||||
if (!reg)
|
||||
return uaddr;
|
||||
|
||||
int idx;
|
||||
|
||||
regOver = reg;
|
||||
|
||||
//Find last region that overlap
|
||||
list_foreach_named(reg->nextInAddrSpace, regNext, idx, prevInAddrSpace, nextInAddrSpace){
|
||||
if(!hasOverlap(uaddr, size, regNext->addr, regNext->size))
|
||||
break;
|
||||
regOver = regNext;
|
||||
}
|
||||
|
||||
uaddr = regOver->addr + regOver->size;
|
||||
list_foreach_named(regOver->nextInAddrSpace, regNext, idx, prevInAddrSpace,
|
||||
nextInAddrSpace)
|
||||
{
|
||||
if (!hasOverlap(uaddr, size, regNext->addr, regNext->size) &&
|
||||
uaddr <= (PAGING_TOP_USER_ADDRESS - size)) {
|
||||
return uaddr;
|
||||
}
|
||||
if (reg == regNext) // Already checked region
|
||||
break;
|
||||
uaddr = regNext->addr + regNext->size;
|
||||
}
|
||||
return (uaddr_t)NULL;
|
||||
}
|
||||
|
||||
struct uAddrSpace *uAddrSpaceCreate(struct process *proc)
|
||||
{
|
||||
struct uAddrSpace *addr = (struct uAddrSpace *)malloc(sizeof(struct uAddrSpace));
|
||||
struct uAddrSpace *addr = (struct uAddrSpace *)zalloc(sizeof(struct uAddrSpace));
|
||||
|
||||
if (addr == NULL)
|
||||
return NULL;
|
||||
@ -64,16 +118,130 @@ struct uAddrSpace *uAddrSpaceCreate(struct process *proc)
|
||||
}
|
||||
|
||||
addr->process = proc;
|
||||
list_init(addr->listVirtualReg);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
int uAddrSpaceDelete(struct uAddrSpace *addr)
|
||||
{
|
||||
// TODO Work on Virtual Region
|
||||
struct uAddrVirtualReg *reg;
|
||||
|
||||
list_collapse_named(addr->listVirtualReg, reg, nextInAddrSpace, prevInAddrSpace) {
|
||||
if (reg->res == NULL) {
|
||||
// This is memory allocated for the heap just unmap it to free it
|
||||
pr_devel("Freeing heap 0x%lx for process %s\n", reg->addr,
|
||||
processGetName(addr->process));
|
||||
pageUnmap(reg->addr);
|
||||
free(reg);
|
||||
} else {
|
||||
if(reg->res->ops){
|
||||
if(reg->res->ops->unmap)
|
||||
reg->res->ops->unmap(reg, reg->addr, reg->size);
|
||||
if(reg->res->ops->close)
|
||||
reg->res->ops->close(reg);
|
||||
}
|
||||
free(reg);
|
||||
}
|
||||
}
|
||||
return mmuContextUnref(addr->ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the associated uAddrVirtualReg associated to the unmap space and free them;
|
||||
*/
|
||||
int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size)
|
||||
{
|
||||
if (uaddr < PAGING_BASE_USER_ADDRESS || uaddr > PAGING_TOP_USER_ADDRESS - size)
|
||||
return -EINVAL;
|
||||
if (!IS_ALIGNED(uaddr, PAGE_SIZE) || size <= 0)
|
||||
return -EINVAL;
|
||||
if(!as)
|
||||
return -EINVAL;
|
||||
|
||||
size = ALIGN(size, PAGE_SIZE);
|
||||
struct uAddrVirtualReg *reg = as->listVirtualReg;
|
||||
struct uAddrVirtualReg *lastReg = reg ? reg->prevInAddrSpace : NULL;
|
||||
|
||||
while (reg != NULL) {
|
||||
if (reg->addr > uaddr + size)
|
||||
break;
|
||||
struct uAddrVirtualReg *next = reg->nextInAddrSpace;
|
||||
// The Virtual Region is completly inside the unmaped space
|
||||
if (reg->addr >= uaddr && (reg->addr + reg->size <= uaddr + size)) {
|
||||
list_delete_named(as->listVirtualReg, reg, prevInAddrSpace, nextInAddrSpace);
|
||||
list_delete_named(reg->res->listVirtualReg, reg, prevInMappedRes, nextInMappedRes);
|
||||
|
||||
if (reg->res->ops && reg->res->ops->unmap)
|
||||
reg->res->ops->unmap(reg, uaddr, size);
|
||||
|
||||
if (reg->res->ops && reg->res->ops->close)
|
||||
reg->res->ops->close(reg);
|
||||
|
||||
if (reg == next)//singleton
|
||||
next = NULL;
|
||||
|
||||
free(reg);
|
||||
// Unmaped space is inside and smaller than the VR
|
||||
// VR should be splitted
|
||||
} else if (reg->addr > uaddr && (reg->addr + reg->size < uaddr + size)) {
|
||||
struct uAddrVirtualReg *new =
|
||||
(struct uAddrVirtualReg *)zalloc(sizeof(struct uAddrSpace));
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
new->addr = uaddr + size;
|
||||
new->size = reg->addr + reg->size - (uaddr + size);
|
||||
new->right = reg->right;
|
||||
new->offset = uaddr + size - reg->addr;
|
||||
|
||||
reg->size = uaddr - reg->addr;
|
||||
|
||||
list_insert_after_named(as->listVirtualReg, reg, new, prevInAddrSpace,
|
||||
nextInAddrSpace);
|
||||
list_insert_after_named(reg->res->listVirtualReg, reg, new, prevInMappedRes,
|
||||
nextInMappedRes);
|
||||
if (reg->res->ops && reg->res->ops->unmap)
|
||||
reg->res->ops->unmap(reg, uaddr, size);
|
||||
if (new->res->ops && new->res->ops->open)
|
||||
new->res->ops->open(new);
|
||||
break;
|
||||
// Only affect the beginning
|
||||
} else if (uaddr <= reg->addr && uaddr + size > reg->addr) {
|
||||
size_t offset = uaddr + size - reg->addr;
|
||||
reg->size -= offset;
|
||||
reg->offset += offset;
|
||||
reg->addr += offset;
|
||||
if (reg->res->ops && reg->res->ops->unmap)
|
||||
reg->res->ops->unmap(reg, uaddr, size);
|
||||
break;
|
||||
// Only affect the end
|
||||
} else if (uaddr > reg->addr && uaddr < reg->addr + size &&
|
||||
uaddr + size > reg->addr + reg->size) {
|
||||
size_t unmapSize = reg->addr + reg->size - uaddr;
|
||||
reg->size = uaddr - reg->addr;
|
||||
|
||||
if (reg->res->ops && reg->res->ops->unmap)
|
||||
reg->res->ops->unmap(reg, uaddr, unmapSize);
|
||||
}
|
||||
reg = next;
|
||||
if (reg == lastReg)
|
||||
break;
|
||||
}
|
||||
|
||||
int needMMUSetup = as->ctx != getCurrentThread()->squattedContext;
|
||||
|
||||
if (needMMUSetup)
|
||||
threadChangeCurrentContext(as->ctx);
|
||||
for (vaddr_t addr = uaddr; addr < uaddr + size; addr += PAGE_SIZE) {
|
||||
pageUnmap(addr);
|
||||
}
|
||||
if (needMMUSetup)
|
||||
threadChangeCurrentContext(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mmu_context *uAddrSpaceGetMMUContext(struct uAddrSpace *addr)
|
||||
{
|
||||
return addr->ctx;
|
||||
@ -102,30 +270,190 @@ uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop)
|
||||
incSize = ALIGN(newHeapTop - (as->heapStart + as->heapSize), PAGE_SIZE);
|
||||
|
||||
if (incSize < 0){
|
||||
//FIXME
|
||||
return as->heapStart + as->heapSize;
|
||||
}
|
||||
|
||||
as->heapSize += incSize;
|
||||
|
||||
return 0;
|
||||
return as->heapStart + as->heapSize;
|
||||
}
|
||||
|
||||
int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr)
|
||||
int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr)
|
||||
{
|
||||
pr_devel("Checking %lx inside %lx and %lx\n", addr, as->heapStart, as->heapStart +as->heapSize);
|
||||
struct uAddrVirtualReg *newReg;
|
||||
int right = PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ;
|
||||
|
||||
pr_devel("Heap check: 0x%lx inside 0x%lx and 0x%lx\n", addr, as->heapStart,
|
||||
as->heapStart + as->heapSize);
|
||||
|
||||
if (addr < as->heapStart || addr >= as->heapStart + as->heapSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_devel("Alloc heap for process %s\n", processGetName(as->process));
|
||||
|
||||
vaddr_t addrAlign = ALIGN_DOWN(addr, PAGE_SIZE);
|
||||
paddr_t ppage = allocPhyPage(1);
|
||||
|
||||
if (0 != pageMap(addrAlign, ppage, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ)) {
|
||||
return -1;
|
||||
}
|
||||
if (0 != pageMap(addrAlign, ppage, right))
|
||||
goto free_ppage;
|
||||
|
||||
newReg = zalloc(sizeof(struct uAddrVirtualReg));
|
||||
|
||||
if (newReg == NULL)
|
||||
goto free_ppage;
|
||||
|
||||
newReg->addr = addrAlign;
|
||||
newReg->size = PAGE_SIZE;
|
||||
newReg->right = right;
|
||||
|
||||
// keep the AS list sorted
|
||||
struct uAddrVirtualReg *prev = findVirtualRegionBeforeAddr(as, addrAlign);
|
||||
if (prev)
|
||||
list_insert_after_named(as->listVirtualReg, prev, newReg, prevInAddrSpace,
|
||||
nextInAddrSpace);
|
||||
else
|
||||
list_add_tail_named(as->listVirtualReg, newReg, nextInAddrSpace, prevInAddrSpace);
|
||||
|
||||
unrefPhyPage(ppage);
|
||||
|
||||
return 0;
|
||||
free_ppage:
|
||||
unrefPhyPage(ppage);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct uAddrVirtualReg *uAddrSpaceMergeVr(struct uAddrVirtualReg *prev,
|
||||
struct uAddrVirtualReg *next)
|
||||
{
|
||||
if (prev && next && prev->addr + prev->size == next->addr && prev->right == next->right &&
|
||||
prev->res == next->res && prev->flags == next->flags && prev->offset == next->offset) {
|
||||
prev->size += next->size;
|
||||
return next;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights,
|
||||
uint32_t flags, struct mappedRessource *res, uint32_t offset )
|
||||
{
|
||||
int ret = 0;
|
||||
uaddr_t hint_uaddr = *uaddr;
|
||||
|
||||
if (res == NULL || res->ops == NULL || res->ops->nopage == NULL)
|
||||
return -ENOENT;
|
||||
if (!IS_ALIGNED(hint_uaddr, PAGE_SIZE) || size <= 0)
|
||||
return -EINVAL;
|
||||
if (flags & UA_MAP_SHARED) {
|
||||
if (((rights & PAGING_MEM_READ) && !(res->allowedRight & PAGING_MEM_READ)) ||
|
||||
((rights & PAGING_MEM_WRITE) && !(res->allowedRight & PAGING_MEM_WRITE)) ||
|
||||
((rights & PAGING_MEM_EXEC) && !(res->allowedRight & PAGING_MEM_EXEC)))
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
size = ALIGN(size, PAGE_SIZE);
|
||||
struct uAddrVirtualReg *reg =
|
||||
(struct uAddrVirtualReg *)malloc(sizeof(struct uAddrVirtualReg));
|
||||
if (!reg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (flags & UA_MAP_FIXED) {
|
||||
if (hint_uaddr < PAGING_BASE_USER_ADDRESS ||
|
||||
hint_uaddr > PAGING_TOP_USER_ADDRESS - size) {
|
||||
ret = -EINVAL;
|
||||
goto free_reg;
|
||||
}
|
||||
ret = uAddrSpaceUnmap(as, hint_uaddr, size);
|
||||
if (ret)
|
||||
goto free_reg;
|
||||
|
||||
} else {
|
||||
hint_uaddr = findFreeAddrInVirtualRegion(as, hint_uaddr, size);
|
||||
if (!hint_uaddr) {
|
||||
ret = -ENOMEM;
|
||||
goto free_reg;
|
||||
}
|
||||
}
|
||||
|
||||
reg->addr = hint_uaddr;
|
||||
reg->size = size;
|
||||
reg->right = rights;
|
||||
reg->res = res;
|
||||
reg->offset = offset;
|
||||
|
||||
// keep the AddrSpace list sorted
|
||||
struct uAddrVirtualReg *prev = findVirtualRegionBeforeAddr(as, hint_uaddr);
|
||||
bool_t regIsNew = TRUE;
|
||||
if (prev) {
|
||||
struct uAddrVirtualReg *toFree = uAddrSpaceMergeVr(prev, reg);
|
||||
if (toFree) {
|
||||
pr_devel("Merge VR with prev\n");
|
||||
reg = prev;
|
||||
regIsNew = FALSE;
|
||||
free(toFree);
|
||||
}
|
||||
toFree = uAddrSpaceMergeVr(reg, prev->nextInAddrSpace);
|
||||
if (toFree) {
|
||||
pr_devel("Merge VR with next\n");
|
||||
regIsNew = FALSE;
|
||||
if (toFree->res && toFree->res->ops && toFree->res->ops->close)
|
||||
toFree->res->ops->close(toFree);
|
||||
list_delete_named(as->listVirtualReg, toFree, prevInAddrSpace, nextInAddrSpace);
|
||||
list_delete_named(toFree->res->listVirtualReg, toFree, prevInMappedRes,
|
||||
nextInMappedRes);
|
||||
free(toFree);
|
||||
}
|
||||
if (regIsNew)
|
||||
list_insert_after_named(as->listVirtualReg, prev, reg, prevInAddrSpace,
|
||||
nextInAddrSpace);
|
||||
} else
|
||||
list_add_tail_named(as->listVirtualReg, reg, prevInAddrSpace, nextInAddrSpace);
|
||||
|
||||
if (regIsNew) {
|
||||
list_add_tail_named(reg->res->listVirtualReg, reg, prevInMappedRes, nextInMappedRes);
|
||||
if (res->onResMapped) {
|
||||
int cbret = res->onResMapped(reg);
|
||||
if (cbret) {
|
||||
pr_devel("Call back failed on ressource mmaped\n");
|
||||
ret = uAddrSpaceUnmap(as, reg->addr, reg->size);
|
||||
}
|
||||
}
|
||||
|
||||
if (res->ops->open)
|
||||
res->ops->open(reg);
|
||||
}
|
||||
|
||||
*uaddr = hint_uaddr;
|
||||
|
||||
return ret;
|
||||
free_reg:
|
||||
free(reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if @param faultAddr could be managed by the uAddrVirtualReg from @param as
|
||||
**/
|
||||
int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWriteAccess)
|
||||
{
|
||||
struct uAddrVirtualReg *reg;
|
||||
int rights = PAGING_MEM_READ | PAGING_MEM_USER;
|
||||
|
||||
reg = findVirtualRegionFromAddr(as, faultAddr, 1);
|
||||
|
||||
if (reg == NULL)
|
||||
return -EFAULT;
|
||||
|
||||
pr_devel("Virtual Region for pageflt found\n");
|
||||
|
||||
if (isWriteAccess && !(reg->right & PAGING_MEM_WRITE))
|
||||
return -EACCES;
|
||||
|
||||
if (isWriteAccess || (reg->right & PAGING_MEM_WRITE))
|
||||
rights |= PAGING_MEM_WRITE;
|
||||
|
||||
if (reg->res->ops->nopage(reg, faultAddr, rights))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,15 +1,54 @@
|
||||
#pragma once
|
||||
#include "mmuContext.h"
|
||||
#include "process.h"
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#include "types.h"
|
||||
#include <stddef.h>
|
||||
|
||||
struct uAddrSpace;
|
||||
struct uAddrVirtualReg;
|
||||
|
||||
struct uAddrSpace * uAddrSpaceCreate(struct process *proc);
|
||||
#define UA_MAP_SHARED (1 << 0)
|
||||
#define UA_MAP_PRIVATE (1 << 1)
|
||||
#define UA_MAP_FIXED (1 << 2)
|
||||
|
||||
// TODO : move this struct to .c and add accessors
|
||||
struct uAddrVirtualReg {
|
||||
uaddr_t addr;
|
||||
size_t size;
|
||||
int right; // PAGING_MEM_*
|
||||
uint32_t offset; // in the mappedRessource
|
||||
uint flags;
|
||||
|
||||
struct mappedRessource *res;
|
||||
struct uAddrVirtualReg *nextInAddrSpace, *prevInAddrSpace;
|
||||
struct uAddrVirtualReg *nextInMappedRes, *prevInMappedRes;
|
||||
};
|
||||
|
||||
struct mappedRessourceOps {
|
||||
int (*open)(struct uAddrVirtualReg *vreg);
|
||||
int (*close)(struct uAddrVirtualReg *vreg);
|
||||
int (*unmap)(struct uAddrVirtualReg *vreg, uaddr_t addr, size_t size);
|
||||
int (*nopage)(struct uAddrVirtualReg *vreg, uaddr_t addr,
|
||||
int right); // Called by the pageflt handler when the page is missing
|
||||
};
|
||||
|
||||
struct mappedRessource {
|
||||
int allowedRight; // PAGING_MEM_*
|
||||
struct mappedRessourceOps *ops;
|
||||
struct uAddrVirtualReg *listVirtualReg;
|
||||
void *customData;
|
||||
int (*onResMapped)(struct uAddrVirtualReg *reg); // Callabck for when the ressourced get mapped
|
||||
};
|
||||
|
||||
struct uAddrSpace *uAddrSpaceCreate(struct process *proc);
|
||||
int uAddrSpaceDelete(struct uAddrSpace *addr);
|
||||
struct mmu_context * uAddrSpaceGetMMUContext(struct uAddrSpace *addr);
|
||||
struct mmu_context *uAddrSpaceGetMMUContext(struct uAddrSpace *addr);
|
||||
int uAddrSpaceSetHeap(struct uAddrSpace *as, uaddr_t addr, size_t size);
|
||||
int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr);
|
||||
int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr);
|
||||
uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop);
|
||||
|
||||
int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights,
|
||||
uint32_t flags, struct mappedRessource *res, uint32_t offset);
|
||||
int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size);
|
||||
int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWriteAccess);
|
||||
|
@ -184,18 +184,19 @@ class ListDumpCmd(gdb.Command):
|
||||
"list_dump", gdb.COMMAND_USER
|
||||
)
|
||||
|
||||
def _print_list(self, val):
|
||||
def _print_list(self, val, next_name):
|
||||
"""Walk through the linked list.
|
||||
|
||||
We will simply follow the 'next' pointers until we encounter the HEAD again
|
||||
"""
|
||||
idx = 0
|
||||
head = val
|
||||
thread_ptr = val
|
||||
result = ""
|
||||
|
||||
while thread_ptr != 0 and (idx == 0 or thread_ptr != head):
|
||||
result += gdb.execute('p *({}){}'.format(str(thread_ptr.type),thread_ptr), to_string=True)
|
||||
thread_ptr = thread_ptr["next"]
|
||||
result += gdb.execute('p *({}){}'.format(str(thread_ptr.type),
|
||||
thread_ptr), to_string=True)
|
||||
thread_ptr = thread_ptr[next_name]
|
||||
idx += 1
|
||||
result = ("Found a Linked List with %d items:" % idx) + "\n" + result
|
||||
return result
|
||||
@ -209,17 +210,21 @@ class ListDumpCmd(gdb.Command):
|
||||
# We can pass args here and use Python CLI utilities like argparse
|
||||
# to do argument parsing
|
||||
print("Args Passed: %s" % args)
|
||||
if args:
|
||||
ptr_val = gdb.parse_and_eval(args)
|
||||
else:
|
||||
ptr_val = gdb.parse_and_eval("currentThread")
|
||||
thread_name = "currentThread"
|
||||
next_name = "next"
|
||||
if(args):
|
||||
args_arr = args.split()
|
||||
thread_name = args_arr[0]
|
||||
if(len(args_arr) >= 2):
|
||||
next_name = args_arr[1]
|
||||
ptr_val = gdb.parse_and_eval(thread_name)
|
||||
try:
|
||||
ptr_val["next"]
|
||||
ptr_val[next_name]
|
||||
except:
|
||||
print("Expected pointer argument with a next field")
|
||||
print("Expected pointer argument with a %s field" % next_name)
|
||||
return
|
||||
|
||||
print(self._print_list(ptr_val))
|
||||
print(self._print_list(ptr_val, next_name))
|
||||
|
||||
|
||||
register_pretty_printer(None, CustomPrettyPrinterLocator(), replace=True)
|
||||
|
10
debug.iso.gdb
Normal file
10
debug.iso.gdb
Normal file
@ -0,0 +1,10 @@
|
||||
add-symbol-file userspace/user
|
||||
# Thx to add-gnu-debuglink gdb should know that symbols are in kernel.debug.
|
||||
# And by default, it should be looking at executable.debug
|
||||
# But we still have to give him the executable he is suppose to debug (See https://sourceware.org/gdb/current/onlinedocs/gdb.html/Separate-Debug-Files.html)
|
||||
#add-symbol-file kernel.debug
|
||||
file kernel
|
||||
source custom_gdb_extension.py
|
||||
#For ASM sources
|
||||
directory arch/x86/:core
|
||||
target remote | qemu-system-i386 -S -gdb stdio -m 16M -serial file:serialOut -hda fd.iso -hdb disk.img
|
@ -2,8 +2,6 @@ label: dos
|
||||
label-id: 0x9ec19bcc
|
||||
device: disk.img
|
||||
unit: sectors
|
||||
sector-size: 512
|
||||
|
||||
disk.img1 : start= 2048, size= 10240, type=83
|
||||
disk.img2 : start= 12288, size= 10240, type=b
|
||||
disk.img3 : start= 22528, size= 43008, type=e
|
||||
disk.img1 : start= 2048, size= 32768, type=6, bootable
|
||||
disk.img2 : start= 34816, size= 30720, type=83
|
||||
|
@ -418,6 +418,10 @@ int ATADetectDevice(struct ata_device *dev)
|
||||
struct ata_controller *ctl = dev->ctl;
|
||||
outb(ctl->base + ATA_PIO_DRIVE,
|
||||
ATA_PIO_DRIVE_IBM | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER));
|
||||
outb(ctl->base + ATA_PIO_SEC_COUNT, 0);
|
||||
outb(ctl->base + ATA_PIO_LBALO, 0);
|
||||
outb(ctl->base + ATA_PIO_LBAMID, 0);
|
||||
outb(ctl->base + ATA_PIO_LBAHI, 0);
|
||||
unsigned st = inb(ctl->base + ATA_PIO_STATUS);
|
||||
if (st & ATA_PIO_STATUS_DRIVE_BUSY)
|
||||
goto no_disk;
|
||||
@ -451,6 +455,10 @@ int ATAGetDeviceInfo(struct ata_device *dev)
|
||||
|
||||
outb(ctl->base + ATA_PIO_DRIVE,
|
||||
ATA_PIO_DRIVE_IBM | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER));
|
||||
outb(ctl->base + ATA_PIO_SEC_COUNT, 0);
|
||||
outb(ctl->base + ATA_PIO_LBALO, 0);
|
||||
outb(ctl->base + ATA_PIO_LBAMID, 0);
|
||||
outb(ctl->base + ATA_PIO_LBAHI, 0);
|
||||
outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY);
|
||||
|
||||
/* Wait for command completion (wait while busy bit is set) */
|
||||
@ -513,6 +521,19 @@ struct ata_partition *ATAGetPartition(int id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ata_partition *ATAGetPartitionByType(uint type)
|
||||
{
|
||||
struct ata_partition *part;
|
||||
int count;
|
||||
list_foreach(partitions, part, count)
|
||||
{
|
||||
if (part->type == type)
|
||||
return part;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ata_partition *ATAPartitionCreate(uint type, uint size, uint32_t lba,
|
||||
struct ata_device *dev)
|
||||
{
|
||||
@ -614,12 +635,13 @@ int ATAReadSector(struct ata_device *dev, int lba, uint nb_sector, void *buf)
|
||||
mutexLock(&ctl->mutex);
|
||||
|
||||
if (ctl->last_device_used != dev->id) {
|
||||
outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4);
|
||||
outb(ctl->base + ATA_PIO_DRIVE,
|
||||
ATA_PIO_DRIVE_IBM | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER));
|
||||
while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) {
|
||||
}
|
||||
ctl->last_device_used = dev->id;
|
||||
}
|
||||
outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA);
|
||||
outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER));
|
||||
outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector);
|
||||
outb(ctl->base + ATA_PIO_LBALO, lba & 0xff);
|
||||
outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff);
|
||||
@ -659,7 +681,7 @@ int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf)
|
||||
}
|
||||
ctl->last_device_used = dev->id;
|
||||
}
|
||||
outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA);
|
||||
outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER));
|
||||
outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector);
|
||||
outb(ctl->base + ATA_PIO_LBALO, lba & 0xff);
|
||||
outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff);
|
||||
|
@ -104,5 +104,6 @@ int ATAReadPartitionSector(struct ata_partition *part, int offset, uint nbSector
|
||||
int ATAReadSector(struct ata_device *dev, int lba, uint nbSector, void *buf);
|
||||
int ATAWriteSector(struct ata_device *dev, int lba, uint nbSector, void *buf);
|
||||
struct ata_device *ATAGetDevice(int ctlId, int devId);
|
||||
struct ata_partition *ATAGetPartitionByType(uint type);
|
||||
int ATAReadPartition(struct ata_device *dev);
|
||||
struct ata_partition *ATAGetPartition(int id);
|
||||
|
@ -460,7 +460,7 @@ void keyboard_do_irq()
|
||||
}
|
||||
|
||||
if (key){
|
||||
printf(key);
|
||||
putc(*key);
|
||||
ringbufferEnqueue(buf, *key);
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ static void cursorMove(int x, int y)
|
||||
}
|
||||
|
||||
void VGAMap(void){
|
||||
for (paddr_t i = VGA_ADDR; i < VGA_ADDR + VGA_WIDTH * VGA_HEIGHT * sizeof(short) ; i += PAGE_SIZE) {
|
||||
for (paddr_t i = (paddr_t)vga; i < (paddr_t)vga + fbWidth * fbHeight * sizeof(short) ; i += PAGE_SIZE) {
|
||||
pageMap(i, i, PAGING_MEM_WRITE);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
#include "types.h"
|
||||
|
||||
// https://wiki.osdev.org/Text_UI
|
||||
|
124
drivers/zero.c
Normal file
124
drivers/zero.c
Normal file
@ -0,0 +1,124 @@
|
||||
#include "zero.h"
|
||||
|
||||
#include "alloc.h"
|
||||
#include "errno.h"
|
||||
#include "kernel.h"
|
||||
#include "klibc.h"
|
||||
#include "mem.h"
|
||||
#include "list.h"
|
||||
#include "paging.h"
|
||||
#include "types.h"
|
||||
|
||||
struct zeroMappedPage {
|
||||
uaddr_t mappedAddr;
|
||||
paddr_t phyAddr;
|
||||
|
||||
struct zeroMappedPage *prev, *next;
|
||||
};
|
||||
|
||||
struct zeroMappedEntry {
|
||||
int refCnt;
|
||||
|
||||
struct zeroMappedPage *listMapped;
|
||||
};
|
||||
|
||||
static int insertMappedPage(struct zeroMappedEntry *entry, uaddr_t vAddr, paddr_t pAddr){
|
||||
struct zeroMappedPage *info = (struct zeroMappedPage *)zalloc(sizeof(struct zeroMappedPage));
|
||||
|
||||
if(!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->mappedAddr = vAddr;
|
||||
info->phyAddr = pAddr;
|
||||
|
||||
list_add_tail(entry->listMapped, info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int zeroOpen(struct uAddrVirtualReg *vreg)
|
||||
{
|
||||
struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData;
|
||||
ent->refCnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zeroClose(struct uAddrVirtualReg *vreg)
|
||||
{
|
||||
struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData;
|
||||
ent->refCnt--;
|
||||
if (ent->refCnt == 0) {
|
||||
struct zeroMappedPage *pageInfo;
|
||||
list_collapse(ent->listMapped, pageInfo){
|
||||
pageUnmap(pageInfo->mappedAddr);
|
||||
free(pageInfo);
|
||||
}
|
||||
free(vreg->res->customData);
|
||||
free(vreg->res);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zeroNoPage(struct uAddrVirtualReg *vreg, uaddr_t addr, int right)
|
||||
{
|
||||
int ret = 0;
|
||||
paddr_t ppage = allocPhyPage(1);
|
||||
uaddr_t mappedAddr = ALIGN_DOWN(addr, PAGE_SIZE);
|
||||
ret = pageMap(mappedAddr, ppage, right | PAGING_MEM_USER);
|
||||
|
||||
struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData;
|
||||
|
||||
unrefPhyPage(ppage);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = insertMappedPage(ent, mappedAddr, ppage);
|
||||
if (ret) {
|
||||
pageUnmap(mappedAddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset((void *)mappedAddr, 0, PAGE_SIZE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mappedRessourceOps zeroOps = {
|
||||
.open = zeroOpen,
|
||||
.close = zeroClose,
|
||||
.unmap = NULL,
|
||||
.nopage = zeroNoPage,
|
||||
};
|
||||
|
||||
int zeroOnMapped(struct uAddrVirtualReg *vreg)
|
||||
{
|
||||
(void)vreg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights,
|
||||
uint32_t flags)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mappedRessource *res =
|
||||
(struct mappedRessource *)zalloc(sizeof(struct mappedRessource));
|
||||
struct zeroMappedEntry *cust =
|
||||
(struct zeroMappedEntry *)zalloc(sizeof(struct zeroMappedEntry));
|
||||
|
||||
list_init(cust->listMapped);
|
||||
|
||||
res->allowedRight = PAGING_MEM_READ | PAGING_MEM_WRITE | PAGING_MEM_EXEC | PAGING_MEM_USER;
|
||||
res->ops = &zeroOps;
|
||||
res->customData = cust;
|
||||
res->onResMapped = zeroOnMapped;
|
||||
|
||||
ret = uAddrSpaceMmap(as, uaddr, size, rights, flags, res, 0);
|
||||
|
||||
if (ret) {
|
||||
free(res);
|
||||
free(cust);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
11
drivers/zero.h
Normal file
11
drivers/zero.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "types.h"
|
||||
#include "uaddrspace.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
int zeroSetup();
|
||||
|
||||
int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags);
|
@ -39,6 +39,12 @@ SECTIONS
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
.multiboot_data : {
|
||||
__multiboot_data_size = 48k;
|
||||
__multiboot_data_start = .;
|
||||
. = . + __multiboot_data_size;
|
||||
__multiboot_data_end = .;
|
||||
}
|
||||
__ld_kernel_end = .;
|
||||
|
||||
/* The compiler may produce other sections, by default it will put them in
|
||||
|
@ -306,9 +306,8 @@ void sleepThread(void *arg)
|
||||
}
|
||||
unsigned long ellapsedTime = jiffies_to_msecs(jiffies - initialJiffies);
|
||||
assertmsg(ellapsedTime >= 500 && ellapsedTime < 510, "ellapsedTime %lu\n", ellapsedTime);
|
||||
threadMsleep(0);
|
||||
printf("I should never be showed\n");
|
||||
assert(1);
|
||||
threadMsleep(ULONG_MAX);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
struct mutex mutexTest;
|
||||
@ -399,7 +398,7 @@ static void userProgramm()
|
||||
"int %5\n"
|
||||
"movl %%eax, %0"
|
||||
: "=g"(ret)
|
||||
: "g"(SYSCALL_ID_YOLO), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB)
|
||||
: "g"(SYSCALL_ID_HELO), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB)
|
||||
: "eax", "ebx", "ecx", "edx");
|
||||
asm volatile("movl %1,%%eax \n"
|
||||
"movl %2,%%ebx \n"
|
||||
|
@ -5,8 +5,7 @@
|
||||
do { \
|
||||
if (!(p)) { \
|
||||
printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \
|
||||
while (1) { \
|
||||
} \
|
||||
_exit(-1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@ -15,7 +14,6 @@
|
||||
if (!(p)) { \
|
||||
printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \
|
||||
printf(__VA_ARGS__); \
|
||||
while (1) { \
|
||||
} \
|
||||
_exit(-1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
37
userspace/errno.h
Normal file
37
userspace/errno.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
extern int errno;
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Argument list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EAGAIN 11 /* Try again */
|
||||
#define ENOMEM 12 /* Out of memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device or resource busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Math argument out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
@ -4,11 +4,18 @@
|
||||
#endif
|
||||
|
||||
#define SYSCALL_ID_EXIT 1
|
||||
#define SYSCALL_ID_YOLO 2
|
||||
#define SYSCALL_ID_HELO 2
|
||||
#define SYSCALL_ID_PUTC 3
|
||||
#define SYSCALL_ID_READ 4
|
||||
#define SYSCALL_ID_TEST 5
|
||||
#define SYSCALL_ID_BRK 6
|
||||
#define SYSCALL_ID_MMAP 7
|
||||
#define SYSCALL_ID_MUNMAP 8
|
||||
#define SYSCALL_ID_NEW_THREAD 9
|
||||
#define SYSCALL_ID_USLEEP 10
|
||||
#define SYSCALL_ID_GETPID 11
|
||||
#define SYSCALL_ID_GETTID 12
|
||||
#define SYSCALL_ID_THREAD_JOIN 13
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int syscallExecute(int syscallId, const struct cpu_state *user_ctx);
|
||||
|
351
userspace/libc.c
351
userspace/libc.c
@ -1,8 +1,14 @@
|
||||
#include "libc.h"
|
||||
#include "errno.h"
|
||||
#include "list.h"
|
||||
#include "minmax.h"
|
||||
#include "swintr.h"
|
||||
#include "sys/mman.h"
|
||||
#include "syscall.h"
|
||||
#include "thread.h"
|
||||
#include "unistd.h"
|
||||
|
||||
int errno = 0;
|
||||
int memcmp(const void *aptr, const void *bptr, size_t size)
|
||||
{
|
||||
const unsigned char *a = (const unsigned char *)aptr;
|
||||
@ -42,12 +48,13 @@ void *memcpy(void *dst0, const void *src0, size_t len0)
|
||||
#else
|
||||
char *dst = dst0;
|
||||
const char *src = src0;
|
||||
long *aligned_dst;
|
||||
const long *aligned_src;
|
||||
|
||||
/* If the size is small, or either SRC or DST is unaligned,
|
||||
then punt into the byte copy loop. This should be rare. */
|
||||
if (!TOO_SMALL(len0) && !UNALIGNED(src, dst)) {
|
||||
long *aligned_dst;
|
||||
const long *aligned_src;
|
||||
|
||||
aligned_dst = (long *)dst;
|
||||
aligned_src = (long *)src;
|
||||
|
||||
@ -78,6 +85,16 @@ void *memcpy(void *dst0, const void *src0, size_t len0)
|
||||
#endif
|
||||
}
|
||||
|
||||
void *memmove(void *dst, const void *src, size_t n)
|
||||
{
|
||||
char *dstChar = dst;
|
||||
const char *srcChar = src;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
*(dstChar++) = *(srcChar++);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memset(void *src, int c, size_t n)
|
||||
{
|
||||
for (char *ptr = (char *)src; n > 0; n--, ptr++) {
|
||||
@ -248,8 +265,57 @@ int puts(const char *str)
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define PRINT_UINT(name, type) \
|
||||
int print##name(type integer, char *str, size_t size) \
|
||||
{ \
|
||||
char num[sizeof(integer) * 3]; \
|
||||
int i = 0; \
|
||||
int c = 0; \
|
||||
int ret = 0; \
|
||||
\
|
||||
do { \
|
||||
int digit = integer % 10; \
|
||||
num[i++] = (digit > 0) ? digit : -digit; \
|
||||
integer = integer / 10; \
|
||||
} while (integer != 0); \
|
||||
\
|
||||
for (i = i - 1; i >= 0; i--) { \
|
||||
if (str) { \
|
||||
if (size) { \
|
||||
str[c++] = num[i] + '0'; \
|
||||
size--; \
|
||||
ret++; \
|
||||
} else { \
|
||||
return ret; \
|
||||
} \
|
||||
} else { \
|
||||
ret++; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
PRINT_INT(Int, int);
|
||||
PRINT_INT(Int64, long long int);
|
||||
PRINT_INT(Lint, long int);
|
||||
PRINT_INT(Llint, long long int);
|
||||
PRINT_UINT(Uint, unsigned int);
|
||||
PRINT_UINT(Luint, long unsigned int);
|
||||
PRINT_UINT(Lluint, long long unsigned int);
|
||||
|
||||
#define PRINT_PART(func, type, str, size, c, ret) \
|
||||
{ \
|
||||
int s; \
|
||||
type d = va_arg(ap, type); \
|
||||
if (str) \
|
||||
s = func(d, &str[c], size); \
|
||||
else \
|
||||
s = func(d, NULL, size); \
|
||||
\
|
||||
size -= s; \
|
||||
c += s; \
|
||||
ret += s; \
|
||||
break; \
|
||||
}
|
||||
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
@ -257,24 +323,13 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
int i = 0;
|
||||
int c = 0;
|
||||
|
||||
while (format[i] != '\0' && (size || !str)) {
|
||||
while (format[i] != '\0' && (size|| !str)) {
|
||||
switch (format[i]) {
|
||||
case '%':
|
||||
switch (format[i + 1]) {
|
||||
case 'i':
|
||||
case 'd': {
|
||||
int s;
|
||||
int d = va_arg(ap, int);
|
||||
if (str)
|
||||
s = printInt(d, &str[c], size);
|
||||
else
|
||||
s = printInt(d, NULL, size);
|
||||
|
||||
size -= s;
|
||||
c += s;
|
||||
ret += s;
|
||||
break;
|
||||
}
|
||||
case 'd': PRINT_PART(printInt, int, str, size, c, ret)
|
||||
case 'u': PRINT_PART(printUint, uint, str, size, c, ret)
|
||||
case 'p':
|
||||
case 'x': {
|
||||
char val[sizeof(int) * 2];
|
||||
@ -335,24 +390,15 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
switch (format[i + 2]) {
|
||||
case 'l':
|
||||
switch (format[i + 3]) {
|
||||
case 'd': {
|
||||
int s;
|
||||
long long int d = va_arg(ap, long long int);
|
||||
if (str)
|
||||
s = printInt64(d, &str[c], size);
|
||||
else
|
||||
s = printInt64(d, NULL, size);
|
||||
|
||||
size -= s;
|
||||
c += s;
|
||||
ret += s;
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
case 'd': PRINT_PART(printLlint, long long int, str, size, c, ret)
|
||||
case 'u': PRINT_PART(printLluint, long long unsigned int, str, size, c, ret)
|
||||
case 'p':
|
||||
case 'x': {
|
||||
char val[sizeof(long long int) * 2];
|
||||
unsigned int valIdx = 0;
|
||||
long long int d = va_arg(ap, long long int);
|
||||
unsigned long long int d =
|
||||
va_arg(ap, unsigned long long int);
|
||||
itoa(d, val, 16);
|
||||
if (str) {
|
||||
while (val[valIdx]) {
|
||||
@ -373,17 +419,28 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
i++;
|
||||
break;
|
||||
case 'i':
|
||||
case 'd': {
|
||||
int s;
|
||||
long int d = va_arg(ap, long int);
|
||||
if (str)
|
||||
s = printInt64(d, &str[c], size);
|
||||
else
|
||||
s = printInt64(d, NULL, size);
|
||||
|
||||
size -= s;
|
||||
c += s;
|
||||
ret += s;
|
||||
case 'd': PRINT_PART(printLint, long int, str, size, c, ret)
|
||||
case 'u':
|
||||
PRINT_PART(printLuint, long unsigned int, str, size, c, ret)
|
||||
case 'p':
|
||||
case 'x': {
|
||||
char val[sizeof(int) * 2];
|
||||
unsigned int valIdx = 0;
|
||||
unsigned long int d = va_arg(ap, unsigned long int);
|
||||
itoa(d, val, 16);
|
||||
if (str) {
|
||||
while (val[valIdx]) {
|
||||
if (size) {
|
||||
str[c++] = val[valIdx++];
|
||||
size--;
|
||||
ret++;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret += strlen(val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -449,16 +506,19 @@ int vasprintf(char **strp, const char *fmt, va_list ap)
|
||||
|
||||
n = vsnprintf(p, size, fmt, ap);
|
||||
|
||||
if (n < 0)
|
||||
if (n < 0){
|
||||
free(p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* One extra byte for '\0' */
|
||||
|
||||
size = min(256U,(size_t)n + 1);
|
||||
size = min(256U, (size_t)n + 1);
|
||||
|
||||
n = vsnprintf(p, size, fmt, ap);
|
||||
|
||||
if (n < 0) {
|
||||
free(p);
|
||||
return -1;
|
||||
}
|
||||
*strp = p;
|
||||
@ -521,9 +581,9 @@ int putc(const int c){
|
||||
return syscall1(SYSCALL_ID_PUTC, c);
|
||||
}
|
||||
|
||||
void yolo()
|
||||
void helo()
|
||||
{
|
||||
syscall0(SYSCALL_ID_YOLO);
|
||||
syscall0(SYSCALL_ID_HELO);
|
||||
}
|
||||
|
||||
int testSycall5(uint arg1, uint arg2, uint arg3, uint arg4, uint arg5)
|
||||
@ -566,28 +626,201 @@ int readline(char *buf, int size)
|
||||
return i == (size-1);
|
||||
}
|
||||
|
||||
void *brk(void *addr)
|
||||
int brk(void *addr)
|
||||
{
|
||||
return (void *)syscall1(SYSCALL_ID_BRK, (unsigned int)addr);
|
||||
uintptr_t new = syscall1(SYSCALL_ID_BRK, (unsigned int)addr);
|
||||
|
||||
//errno = ENOMEM
|
||||
return (new >= (uintptr_t)addr)?0:-1;
|
||||
|
||||
}
|
||||
|
||||
void *sbrk(intptr_t increment)
|
||||
{
|
||||
void *current = (void *)syscall1(SYSCALL_ID_BRK, 0);
|
||||
if (increment == 0) {
|
||||
return current;
|
||||
}
|
||||
if ((uintptr_t)syscall1(SYSCALL_ID_BRK, (uintptr_t)current + increment) < ((uintptr_t)current + increment)) {
|
||||
// errno = ENOMEM
|
||||
return (void *)-1;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
// Malloc internal
|
||||
struct heapBlock {
|
||||
size_t size;
|
||||
struct heapBlock *next, *prev;
|
||||
int free;
|
||||
};
|
||||
|
||||
static struct heapBlock *heapBlkList = NULL;
|
||||
|
||||
static struct heapBlock *findFreeBlock(size_t size)
|
||||
{
|
||||
struct heapBlock *cur = NULL;
|
||||
struct heapBlock *found = NULL;
|
||||
int idx;
|
||||
|
||||
list_foreach(heapBlkList, cur, idx)
|
||||
{
|
||||
if (cur->size >= size && cur->free) {
|
||||
found = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static struct heapBlock *allocNewBlock(size_t size)
|
||||
{
|
||||
struct heapBlock *blk = sbrk(size + sizeof(struct heapBlock));
|
||||
struct heapBlock *head = sbrk(0);
|
||||
size_t blkSize = (intptr_t)head - (intptr_t)blk - sizeof(struct heapBlock);
|
||||
if (blk == (void *)-1) {
|
||||
return NULL;
|
||||
}
|
||||
blk->size = blkSize;
|
||||
blk->free = 1;
|
||||
list_add_tail(heapBlkList, blk);
|
||||
|
||||
return blk;
|
||||
}
|
||||
|
||||
static struct heapBlock *splitBlock(struct heapBlock *blk, size_t neededSize)
|
||||
{
|
||||
if (blk->size < neededSize + sizeof(struct heapBlock) + 1) {
|
||||
return NULL;
|
||||
}
|
||||
struct heapBlock *newBlk = (struct heapBlock *)((uintptr_t)(blk + 1) + neededSize);
|
||||
newBlk->free = 1;
|
||||
newBlk->size = blk->size - sizeof(struct heapBlock) - neededSize;
|
||||
blk->size = neededSize;
|
||||
|
||||
return newBlk;
|
||||
}
|
||||
|
||||
void *malloc(size_t size)
|
||||
{
|
||||
void *heapTop = 0;
|
||||
static void *free = 0;
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
if (heapTop == 0) {
|
||||
heapTop = brk(0);
|
||||
free = heapTop;
|
||||
} else {
|
||||
heapTop = brk(0);
|
||||
struct heapBlock *blk = findFreeBlock(size);
|
||||
if (!blk)
|
||||
blk = allocNewBlock(size);
|
||||
if (!blk)
|
||||
return NULL;
|
||||
struct heapBlock *remainBlock = splitBlock(blk, size);
|
||||
if (remainBlock) {
|
||||
list_add_head(heapBlkList, remainBlock);
|
||||
}
|
||||
blk->free = 0;
|
||||
|
||||
return blk + 1; // return the area after the blk description
|
||||
}
|
||||
|
||||
static struct heapBlock *getHeapBlock(void *ptr)
|
||||
{
|
||||
return (struct heapBlock *)ptr - 1;
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
struct heapBlock *blk = getHeapBlock(ptr);
|
||||
|
||||
assert(blk->free == 0);
|
||||
blk->free = 1;
|
||||
}
|
||||
|
||||
void *calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t allocSize = nmemb * size;
|
||||
void *ptr = malloc(allocSize);
|
||||
|
||||
if (ptr != NULL)
|
||||
memset(ptr, 0, allocSize);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t size)
|
||||
{
|
||||
if (!ptr) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
if (free + size > heapTop) {
|
||||
if (brk(heapTop + size))
|
||||
struct heapBlock *blk = getHeapBlock(ptr);
|
||||
if (blk->size >= size) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *new_ptr;
|
||||
new_ptr = malloc(size);
|
||||
if (!new_ptr) {
|
||||
return NULL;
|
||||
}
|
||||
memmove(new_ptr, ptr, blk->size);
|
||||
free(ptr);
|
||||
|
||||
free += size;
|
||||
return (free - size);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void *mmap(void *addr, size_t len, int prot, int flags, char *path) {
|
||||
|
||||
int ret = syscall5(SYSCALL_ID_MMAP, (unsigned int)&addr, len, prot, flags, (unsigned int)path);
|
||||
if(!ret)
|
||||
return addr;
|
||||
errno = ret;
|
||||
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
int munmap(void *addr, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return syscall2(SYSCALL_ID_MUNMAP, (unsigned int)addr, len);
|
||||
}
|
||||
|
||||
/* As when a new thread is run, the params are passed by register (See cpu_ustate_init), use
|
||||
* this function to simplify new thread usage*/
|
||||
static void thread_runner()
|
||||
{
|
||||
register unsigned long int reg_arg1 asm("%eax");
|
||||
register unsigned long int reg_arg2 asm("%ebx");
|
||||
|
||||
start_routine *func = (start_routine *)reg_arg1;
|
||||
void *arg = (void *)reg_arg2;
|
||||
|
||||
func(arg);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
int thread_create(pthread_t *thread, start_routine *func, void *arg, size_t stackSize) {
|
||||
return syscall5(SYSCALL_ID_NEW_THREAD, (unsigned int)thread, (unsigned int)thread_runner, (unsigned int)func,
|
||||
(unsigned int)arg, stackSize);
|
||||
}
|
||||
|
||||
int thread_join(pthread_t thread, void **retval){
|
||||
(void)retval;
|
||||
return syscall1(SYSCALL_ID_THREAD_JOIN, (unsigned int)thread);
|
||||
}
|
||||
|
||||
|
||||
int usleep(useconds_t usec) {
|
||||
return syscall1(SYSCALL_ID_USLEEP, (unsigned int)usec);
|
||||
}
|
||||
|
||||
pid_t gettid(void) {
|
||||
return syscall0(SYSCALL_ID_GETTID);
|
||||
}
|
||||
|
||||
pid_t getpid(void) {
|
||||
return syscall0(SYSCALL_ID_GETPID);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
#include "assert.h"
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
#include "stddef.h"
|
||||
#include "minmax.h"
|
||||
#include "unistd.h"
|
||||
|
||||
#define islower(c) (('a' <= (c)) && ((c) <= 'z'))
|
||||
#define isupper(c) (('A' <= (c)) && ((c) <= 'Z'))
|
||||
@ -12,8 +15,15 @@
|
||||
#define isprint(c) ((' ' <= (c)) && ((c) <= '~'))
|
||||
#define EOF (-1)
|
||||
|
||||
|
||||
/** compares the first @param n bytes (each interpreted as
|
||||
* unsigned char) of the memory areas @param s1 and @param s2.
|
||||
*/
|
||||
__attribute__ ((access (read_only, 1, 3), access (read_only, 2, 3))) int memcmp(const void *s1, const void *s2, size_t n);
|
||||
|
||||
/**
|
||||
* copies n bytes from memory area src to memory area dest. The memory areas may overlap
|
||||
*/
|
||||
__attribute__ ((access (write_only, 1, 3), access (read_only, 2, 3))) void *memmove(void *dest, const void *src, size_t n);
|
||||
__attribute__ ((access (write_only, 1, 3), access (read_only, 2, 3))) void *memcpy(void *dest, const void *src, size_t n);
|
||||
__attribute__ ((access (write_only, 1, 3))) void *memset(void *s, int c, size_t n);
|
||||
char *itoa(long long int value, char *str, int base);
|
||||
@ -27,8 +37,9 @@ int putc(const int c);
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list ap) __attribute__ ((__format__ (printf, 3, 0)));
|
||||
int vprintf(const char *format, va_list ap) __attribute__ ((__format__ (printf, 1, 0)));
|
||||
int printf(const char *format, ...) __attribute__ ((__format__ (printf, 1, 2)));
|
||||
void *mmap(void *addr, size_t len, int prot, int flags, char *path);
|
||||
int munmap(void *addr, size_t len);
|
||||
|
||||
// Could be used after malloc is available
|
||||
int asprintf(char **strp, const char *fmt, ...) __attribute__ ((__format__ (printf, 2, 3)));
|
||||
int vasprintf(char **strp, const char *fmt, va_list ap) __attribute__ ((__format__ (printf, 2, 0)));
|
||||
|
||||
@ -42,10 +53,17 @@ int syscall1(int id, unsigned int arg1);
|
||||
int syscall0(int id);
|
||||
|
||||
void _exit(int status);
|
||||
void yolo();
|
||||
void helo();
|
||||
int testSycall5(uint arg1, uint arg2, uint arg3, uint arg4, uint arg5);
|
||||
char readc();
|
||||
char getchar();
|
||||
int readline(char *buf, int size);
|
||||
void *brk(void *addr);
|
||||
int brk(void *addr);
|
||||
void *sbrk(intptr_t increment);
|
||||
void *malloc(size_t size);
|
||||
void *calloc(size_t nmemb, size_t size);
|
||||
void *realloc(void *ptr, size_t size);
|
||||
void free(void *ptr);
|
||||
pid_t gettid(void);
|
||||
pid_t getpid(void);
|
||||
|
||||
|
189
userspace/list.h
Normal file
189
userspace/list.h
Normal file
@ -0,0 +1,189 @@
|
||||
/* Copyright (C) 2001 David Decotigny
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA.
|
||||
*/
|
||||
#ifndef _SOS_LIST_H_
|
||||
#define _SOS_LIST_H_
|
||||
|
||||
/**
|
||||
* @file list.h
|
||||
*
|
||||
* Circular doubly-linked lists implementation entirely based on C
|
||||
* macros
|
||||
*/
|
||||
|
||||
/* *_named are used when next and prev links are not exactly next
|
||||
and prev. For instance when we have next_in_team, prev_in_team,
|
||||
prev_global and next_global */
|
||||
|
||||
#define list_init_named(list, prev, next) ((list) = NULL)
|
||||
|
||||
#define list_singleton_named(list, item, prev, next) \
|
||||
({ \
|
||||
(item)->next = (item)->prev = (item); \
|
||||
(list) = (item); \
|
||||
})
|
||||
|
||||
#define list_is_empty_named(list, prev, next) ((list) == NULL)
|
||||
|
||||
#define list_is_singleton_named(list, prev, next) \
|
||||
(((list) != NULL) && ((list)->prev == (list)->next) && ((list) == (list)->next))
|
||||
|
||||
#define list_get_head_named(list, prev, next) (list)
|
||||
|
||||
#define list_get_tail_named(list, prev, next) ((list) ? ((list)->prev) : NULL)
|
||||
|
||||
/* Internal macro : insert before the head == insert at tail */
|
||||
#define __list_insert_atleft_named(before_this, item, prev, next) \
|
||||
({ \
|
||||
(before_this)->prev->next = (item); \
|
||||
(item)->prev = (before_this)->prev; \
|
||||
(before_this)->prev = (item); \
|
||||
(item)->next = (before_this); \
|
||||
})
|
||||
|
||||
/* @note Before_this and item are expected to be valid ! */
|
||||
#define list_insert_before_named(list, before_this, item, prev, next) \
|
||||
({ \
|
||||
__list_insert_atleft_named(before_this, item, prev, next); \
|
||||
if ((list) == (before_this)) \
|
||||
(list) = (item); \
|
||||
})
|
||||
|
||||
/** @note After_this and item are expected to be valid ! */
|
||||
#define list_insert_after_named(list, after_this, item, prev, next) \
|
||||
({ \
|
||||
(after_this)->next->prev = (item); \
|
||||
(item)->next = (after_this)->next; \
|
||||
(after_this)->next = (item); \
|
||||
(item)->prev = (after_this); \
|
||||
})
|
||||
|
||||
#define list_add_head_named(list, item, prev, next) \
|
||||
({ \
|
||||
if (list) \
|
||||
__list_insert_atleft_named(list, item, prev, next); \
|
||||
else \
|
||||
list_singleton_named(list, item, prev, next); \
|
||||
(list) = (item); \
|
||||
})
|
||||
|
||||
#define list_add_tail_named(list, item, prev, next) \
|
||||
({ \
|
||||
if (list) \
|
||||
__list_insert_atleft_named(list, item, prev, next); \
|
||||
else \
|
||||
list_singleton_named(list, item, prev, next); \
|
||||
})
|
||||
|
||||
/** @note NO check whether item really is in list ! */
|
||||
#define list_delete_named(list, item, prev, next) \
|
||||
({ \
|
||||
if (((item)->next == (item)) && ((item)->prev == (item))) \
|
||||
(item)->next = (item)->prev = (list) = NULL; \
|
||||
else { \
|
||||
(item)->prev->next = (item)->next; \
|
||||
(item)->next->prev = (item)->prev; \
|
||||
if ((item) == (list)) \
|
||||
(list) = (item)->next; \
|
||||
(item)->prev = (item)->next = NULL; \
|
||||
} \
|
||||
})
|
||||
|
||||
#define list_pop_head_named(list, prev, next) \
|
||||
({ \
|
||||
typeof(list) __ret_elt = (list); \
|
||||
list_delete_named(list, __ret_elt, prev, next); \
|
||||
__ret_elt; \
|
||||
})
|
||||
|
||||
/** Loop statement that iterates through all of its elements, from
|
||||
head to tail */
|
||||
#define list_foreach_forward_named(list, iterator, nb_elements, prev, next) \
|
||||
for (nb_elements = 0, (iterator) = (list); \
|
||||
(iterator) && (!nb_elements || ((iterator) != (list))); \
|
||||
nb_elements++, (iterator) = (iterator)->next)
|
||||
|
||||
/** Loop statement that iterates through all of its elements, from
|
||||
tail back to head */
|
||||
#define list_foreach_backward_named(list, iterator, nb_elements, prev, next) \
|
||||
for (nb_elements = 0, (iterator) = list_get_tail_named(list, prev, next); \
|
||||
(iterator) && \
|
||||
(!nb_elements || ((iterator) != list_get_tail_named(list, prev, next))); \
|
||||
nb_elements++, (iterator) = (iterator)->prev)
|
||||
|
||||
#define list_foreach_named list_foreach_forward_named
|
||||
|
||||
/** True when we exitted early from the foreach loop (ie break) */
|
||||
#define list_foreach_early_break(list, iterator, nb_elements) \
|
||||
((list) && (((list) != (iterator)) || (((list) == (iterator)) && (nb_elements == 0))))
|
||||
|
||||
/** Loop statement that also removes the item at each iteration. The
|
||||
body of the loop is allowed to delete the iterator element from
|
||||
memory. */
|
||||
#define list_collapse_named(list, iterator, prev, next) \
|
||||
for (; ({ \
|
||||
((iterator) = (list)); \
|
||||
if (list) \
|
||||
list_delete_named(list, iterator, prev, next); \
|
||||
(iterator); \
|
||||
});)
|
||||
|
||||
/*
|
||||
* the same macros : assume that the prev and next fields are really
|
||||
* named "prev" and "next"
|
||||
*/
|
||||
|
||||
#define list_init(list) list_init_named(list, prev, next)
|
||||
|
||||
#define list_singleton(list, item) list_singleton_named(list, item, prev, next)
|
||||
|
||||
#define list_is_empty(list) list_is_empty_named(list, prev, next)
|
||||
|
||||
#define list_is_singleton(list) list_is_singleton_named(list, prev, next)
|
||||
|
||||
#define list_get_head(list) list_get_head_named(list, prev, next)
|
||||
|
||||
#define list_get_tail(list) list_get_tail_named(list, prev, next)
|
||||
|
||||
/* @note Before_this and item are expected to be valid ! */
|
||||
#define list_insert_after(list, after_this, item) \
|
||||
list_insert_after_named(list, after_this, item, prev, next)
|
||||
|
||||
/* @note After_this and item are expected to be valid ! */
|
||||
#define list_insert_before(list, before_this, item) \
|
||||
list_insert_before_named(list, before_this, item, prev, next)
|
||||
|
||||
#define list_add_head(list, item) list_add_head_named(list, item, prev, next)
|
||||
|
||||
#define list_add_tail(list, item) list_add_tail_named(list, item, prev, next)
|
||||
|
||||
/* @note NO check whether item really is in list ! */
|
||||
#define list_delete(list, item) list_delete_named(list, item, prev, next)
|
||||
|
||||
#define list_pop_head(list) list_pop_head_named(list, prev, next)
|
||||
|
||||
#define list_foreach_forward(list, iterator, nb_elements) \
|
||||
list_foreach_forward_named(list, iterator, nb_elements, prev, next)
|
||||
|
||||
#define list_foreach_backward(list, iterator, nb_elements) \
|
||||
list_foreach_backward_named(list, iterator, nb_elements, prev, next)
|
||||
|
||||
#define list_foreach list_foreach_forward
|
||||
|
||||
#define list_collapse(list, iterator) list_collapse_named(list, iterator, prev, next)
|
||||
|
||||
#endif /* _SOS_LIST_H_ */
|
@ -1,15 +1,23 @@
|
||||
#include "errno.h"
|
||||
#include "libc.h"
|
||||
#include "stdarg.h"
|
||||
#include "stddef.h"
|
||||
#include "sys/mman.h"
|
||||
#include "thread.h"
|
||||
#include "tiny.h"
|
||||
#include "unistd.h"
|
||||
|
||||
int func_help()
|
||||
{
|
||||
printf("\nAvailable Commands:\n");
|
||||
printf(" suicide\n");
|
||||
printf(" help\n");
|
||||
printf(" syscall5\n");
|
||||
printf(" alloc\n");
|
||||
printf(" tiny: a tiny C interpreter\n");
|
||||
printf(" help: this help\n");
|
||||
printf(" suicide: userspace self kill\n");
|
||||
printf(" syscall5: a syscall with parameters over the stack \n");
|
||||
printf(" alloc: test allocation\n");
|
||||
printf(" tiny: a tiny C-like interpreter\n");
|
||||
printf(" mmap: test mmap \n");
|
||||
printf(" munmap: test munmap \n");
|
||||
printf(" thread: run a user thread\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -21,16 +29,15 @@ int func_suicide()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *initialHeap = 0;
|
||||
char *initialHeap = 0;
|
||||
int func_alloc()
|
||||
{
|
||||
|
||||
if (initialHeap == 0) {
|
||||
initialHeap = brk(0);
|
||||
initialHeap = sbrk(0);
|
||||
}
|
||||
printf("Testing allocation\n");
|
||||
int allocSize = 4096 * 2;
|
||||
void *currentHeap = brk(0);
|
||||
char *currentHeap = sbrk(0);
|
||||
if (currentHeap - initialHeap < allocSize) {
|
||||
brk(initialHeap + allocSize);
|
||||
}
|
||||
@ -38,16 +45,104 @@ int func_alloc()
|
||||
for (unsigned int i = 0; i < allocSize / sizeof(int); i++) {
|
||||
allocatedData[i] = i;
|
||||
}
|
||||
printf("Success\n");
|
||||
printf("Success\nTesting malloc\n");
|
||||
uintptr_t heap = (uintptr_t)sbrk(0);
|
||||
|
||||
for (int i = 0; i < 12; i++) {
|
||||
void *ptr = malloc(1 << i);
|
||||
printf("malloc size %d: 0x%p\n", (1 << i), ptr);
|
||||
if (ptr == NULL) {
|
||||
printf("Malloc failed\n");
|
||||
}
|
||||
memset(ptr, 0, 1 << i);
|
||||
free(ptr);
|
||||
}
|
||||
uintptr_t newHeap = (uintptr_t)sbrk(0);
|
||||
printf("Malloc used %dB\n", newHeap - heap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
struct mmapedArea {
|
||||
void *addr;
|
||||
size_t size;
|
||||
struct mmapedArea *next;
|
||||
};
|
||||
|
||||
static struct mmapedArea *listMmap = NULL;
|
||||
|
||||
int func_mmap()
|
||||
{
|
||||
struct mmapedArea *area = (struct mmapedArea *)malloc(sizeof(struct mmapedArea));
|
||||
|
||||
if (area == NULL) {
|
||||
printf("Fail to allocate area\n");
|
||||
return -1;
|
||||
}
|
||||
char *path = "/dev/zero";
|
||||
void *mapAddr = mmap((void *)0, 4096, PROT_READ | PROT_WRITE, 0, path);
|
||||
|
||||
if (mapAddr == MAP_FAILED) {
|
||||
printf("mmap failed errno %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Zero mmaped at %p\n", mapAddr);
|
||||
int data = *(int *)mapAddr;
|
||||
*(int *)mapAddr = data;
|
||||
|
||||
area->addr = mapAddr;
|
||||
area->size = 4096;
|
||||
area->next = listMmap;
|
||||
listMmap = area;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int func_munmap()
|
||||
{
|
||||
if (!listMmap) {
|
||||
printf("Nothing to unmap... mmap first! \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct mmapedArea *area = listMmap;
|
||||
int ret = munmap(area->addr, area->size);
|
||||
|
||||
if (ret) {
|
||||
printf("Fail to unmap area at 0x%p (size %d) error %d\n", area->addr, area->size, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("unmap done\n");
|
||||
listMmap = listMmap->next;
|
||||
free(area);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *print_hello(void *arg) {
|
||||
(void)arg;
|
||||
printf("Hello World from thread %lu\n", gettid());
|
||||
usleep(100);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int func_thread() {
|
||||
pthread_t id;
|
||||
void *retval;
|
||||
thread_create(&id, print_hello, NULL, 4096);
|
||||
thread_join(id, &retval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
char buf[64];
|
||||
assert(getpid() == gettid());
|
||||
printf("Shell starting... type \"help\" for help\n");
|
||||
while (1) {
|
||||
printf(">");
|
||||
@ -70,7 +165,22 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
if (strcmp(buf, "tiny") == 0) {
|
||||
func_tiny();
|
||||
pthread_t id;
|
||||
void *retval;
|
||||
thread_create(&id, func_tiny, NULL, 4096);
|
||||
thread_join(id, &retval);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(buf, "mmap") == 0) {
|
||||
func_mmap();
|
||||
continue;
|
||||
}
|
||||
if (strcmp(buf, "munmap") == 0) {
|
||||
func_munmap();
|
||||
continue;
|
||||
}
|
||||
if (strcmp(buf, "thread") == 0) {
|
||||
func_thread();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "stdarg.h"
|
||||
#include "stdint.h"
|
||||
#include "types.h"
|
||||
|
||||
uint32_t log2(uint32_t x);
|
||||
|
@ -1,53 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__extension__ typedef __signed__ long long __s64;
|
||||
__extension__ typedef unsigned long long __u64;
|
||||
#else
|
||||
typedef __signed__ long long __s64;
|
||||
typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
/* sysv */
|
||||
typedef unsigned char unchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef __s8 int8_t;
|
||||
typedef __s16 int16_t;
|
||||
typedef __s32 int32_t;
|
||||
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u16 uint16_t;
|
||||
typedef __u32 uint32_t;
|
||||
|
||||
typedef __u64 uint64_t;
|
||||
typedef __u64 u_int64_t;
|
||||
typedef __s64 int64_t;
|
||||
|
||||
typedef enum { FALSE = 0, TRUE } bool_t;
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#if __x86_64__
|
||||
typedef unsigned long size_t;
|
||||
typedef long ssize_t;
|
||||
typedef unsigned long int uintptr_t;
|
||||
#else
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
#endif
|
||||
|
||||
//__builtin_va_list could be used instead
|
||||
typedef char *va_list;
|
||||
#define va_start(v, l) ((v) = (va_list) & (l) + sizeof(l))
|
||||
#define va_end(v) ((v) = NULL)
|
||||
|
29
userspace/stddef.h
Normal file
29
userspace/stddef.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum { FALSE = 0, TRUE } bool_t;
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#if __x86_64__
|
||||
typedef unsigned long size_t;
|
||||
typedef long ssize_t;
|
||||
typedef unsigned long int uintptr_t;
|
||||
typedef long int intptr_t;
|
||||
#else
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef int intptr_t;
|
||||
#endif
|
||||
#if __x86_64__
|
||||
typedef unsigned long size_t;
|
||||
typedef long ssize_t;
|
||||
typedef unsigned long int uintptr_t;
|
||||
typedef long int intptr_t;
|
||||
#else
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef int intptr_t;
|
||||
#endif
|
||||
|
||||
typedef int wchar_t;
|
64
userspace/stdint.h
Normal file
64
userspace/stdint.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__extension__ typedef __signed__ long long __s64;
|
||||
__extension__ typedef unsigned long long __u64;
|
||||
#else
|
||||
typedef __signed__ long long __s64;
|
||||
typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
/* sysv */
|
||||
typedef unsigned char unchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef __s8 int8_t;
|
||||
typedef __s16 int16_t;
|
||||
typedef __s32 int32_t;
|
||||
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u16 uint16_t;
|
||||
typedef __u32 uint32_t;
|
||||
|
||||
typedef __u64 uint64_t;
|
||||
typedef __u64 u_int64_t;
|
||||
typedef __s64 int64_t;
|
||||
|
||||
#define USHRT_MAX ((u16)(~0U))
|
||||
#define SHRT_MAX ((s16)(USHRT_MAX >> 1))
|
||||
#define SHRT_MIN ((s16)(-SHRT_MAX - 1))
|
||||
#define INT_MAX ((int)(~0U >> 1))
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#define UINT_MAX (~0U)
|
||||
#define LONG_MAX ((long)(~0UL >> 1))
|
||||
#define LONG_MIN (-LONG_MAX - 1)
|
||||
#define ULONG_MAX (~0UL)
|
||||
#define LLONG_MAX ((long long)(~0ULL >> 1))
|
||||
#define LLONG_MIN (-LLONG_MAX - 1)
|
||||
#define ULLONG_MAX (~0ULL)
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#define PHYS_ADDR_MAX (~(phys_addr_t)0)
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
#define S8_MAX ((s8)(U8_MAX >> 1))
|
||||
#define S8_MIN ((s8)(-S8_MAX - 1))
|
||||
#define U16_MAX ((u16)~0U)
|
||||
#define S16_MAX ((s16)(U16_MAX >> 1))
|
||||
#define S16_MIN ((s16)(-S16_MAX - 1))
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#define S32_MAX ((s32)(U32_MAX >> 1))
|
||||
#define S32_MIN ((s32)(-S32_MAX - 1))
|
||||
#define U64_MAX ((u64)~0ULL)
|
||||
#define S64_MAX ((s64)(U64_MAX >> 1))
|
||||
#define S64_MIN ((s64)(-S64_MAX - 1))
|
13
userspace/sys/mman.h
Normal file
13
userspace/sys/mman.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
/* To keep in sync with PAGING_MEM_* */
|
||||
#define PROT_EXEC (1<<3)
|
||||
#define PROT_READ (1<<1)
|
||||
#define PROT_WRITE (1<<2)
|
||||
|
||||
#define MAP_SHARED (1 << 0)
|
||||
#define MAP_PRIVATE (1 << 1)
|
||||
#define MAP_FIXED (1 << 2)
|
||||
|
||||
|
||||
#define MAP_FAILED (void *)-1
|
8
userspace/thread.h
Normal file
8
userspace/thread.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned long int pthread_t;
|
||||
typedef void *(start_routine)(void *);
|
||||
int thread_create(pthread_t *thread, start_routine *func, void *arg, size_t stackSize);
|
||||
/* retval is ignored ATM */
|
||||
int thread_join(pthread_t thread, void **retval);
|
@ -282,8 +282,27 @@ void run()
|
||||
|
||||
/* Main program. */
|
||||
|
||||
int func_tiny()
|
||||
void * func_tiny(void *args)
|
||||
{
|
||||
(void)args;
|
||||
printf("Enter your program then ESC\n\n");
|
||||
printf("TinyC grammar\n");
|
||||
printf("<program> ::= <statement>\n");
|
||||
printf("<statement> ::= \"if\" <paren_expr> <statement> |\n");
|
||||
printf(" \"if\" <paren_expr> <statement> \"else\" <statement> |\n");
|
||||
printf(" \"while\" <paren_expr> <statement> |\n");
|
||||
printf(" \"do\" <statement> \"while\" <paren_expr> \";\" |\n");
|
||||
printf(" \"{\" { <statement> } \"}\" |\n");
|
||||
printf(" <expr> \";\" |\n");
|
||||
printf(" \";\"\n");
|
||||
printf("<paren_expr> ::= \"(\" <expr> \")\"\n");
|
||||
printf("<expr> ::= <test> | <id> \"=\" <expr>\n");
|
||||
printf("<test> ::= <sum> | <sum> \"<\" <sum> | <sum> \">\" <sum>\n");
|
||||
printf("<sum> ::= <term> | <sum> \"+\" <term> | <sum> \"-\" <term>\n");
|
||||
printf("<term> ::= <id> | <int> | <paren_expr>\n");
|
||||
printf("<id> ::= \"a\" | \"b\" | \"c\" | \"d\" | ... | \"z\"\n");
|
||||
printf("<int> ::= <an_unsigned_decimal_integer>\n");
|
||||
|
||||
int i;
|
||||
ch = ' ';
|
||||
sym = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
int func_tiny();
|
||||
void * func_tiny(void *args);
|
||||
|
@ -1,32 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define USHRT_MAX ((u16)(~0U))
|
||||
#define SHRT_MAX ((s16)(USHRT_MAX >> 1))
|
||||
#define SHRT_MIN ((s16)(-SHRT_MAX - 1))
|
||||
#define INT_MAX ((int)(~0U >> 1))
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#define UINT_MAX (~0U)
|
||||
#define LONG_MAX ((long)(~0UL >> 1))
|
||||
#define LONG_MIN (-LONG_MAX - 1)
|
||||
#define ULONG_MAX (~0UL)
|
||||
#define LLONG_MAX ((long long)(~0ULL >> 1))
|
||||
#define LLONG_MIN (-LLONG_MAX - 1)
|
||||
#define ULLONG_MAX (~0ULL)
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#define PHYS_ADDR_MAX (~(phys_addr_t)0)
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
#define S8_MAX ((s8)(U8_MAX >> 1))
|
||||
#define S8_MIN ((s8)(-S8_MAX - 1))
|
||||
#define U16_MAX ((u16)~0U)
|
||||
#define S16_MAX ((s16)(U16_MAX >> 1))
|
||||
#define S16_MIN ((s16)(-S16_MAX - 1))
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#define S32_MAX ((s32)(U32_MAX >> 1))
|
||||
#define S32_MIN ((s32)(-S32_MAX - 1))
|
||||
#define U64_MAX ((u64)~0ULL)
|
||||
#define S64_MAX ((s64)(U64_MAX >> 1))
|
||||
#define S64_MIN ((s64)(-S64_MAX - 1))
|
||||
|
||||
// Virtual address
|
||||
typedef unsigned long vaddr_t;
|
||||
|
6
userspace/unistd.h
Normal file
6
userspace/unistd.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
typedef unsigned int useconds_t;
|
||||
int usleep(useconds_t usec);
|
||||
|
||||
typedef unsigned long int pid_t;
|
Loading…
Reference in New Issue
Block a user