load userspace from disk
This commit is contained in:
parent
47f1d3f8ab
commit
2b32908029
20
Makefile
20
Makefile
@ -3,7 +3,7 @@ CPPFLAGS = -MMD
|
|||||||
AS=nasm
|
AS=nasm
|
||||||
ASFLAGS += -f elf32
|
ASFLAGS += -f elf32
|
||||||
LDFLAGS += -m elf_i386
|
LDFLAGS += -m elf_i386
|
||||||
CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector -fno-tree-vectorize
|
CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector -fno-tree-vectorize -D__KERNEL__
|
||||||
CXXFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-rtti -fno-pie
|
CXXFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-rtti -fno-pie
|
||||||
DEBUG_FLAGS += -g -Og -DDEBUG -fno-omit-frame-pointer -fno-inline
|
DEBUG_FLAGS += -g -Og -DDEBUG -fno-omit-frame-pointer -fno-inline
|
||||||
LIBGCC = $(shell $(CC) -print-libgcc-file-name $(CFLAGS))
|
LIBGCC = $(shell $(CC) -print-libgcc-file-name $(CFLAGS))
|
||||||
@ -34,9 +34,18 @@ fd.iso: kernel
|
|||||||
@printf "menuentry \"myos\" {\n\tmultiboot /boot/kernel\n}" > isodir/boot/grub/grub.cfg
|
@printf "menuentry \"myos\" {\n\tmultiboot /boot/kernel\n}" > isodir/boot/grub/grub.cfg
|
||||||
grub-mkrescue -o $@ isodir
|
grub-mkrescue -o $@ isodir
|
||||||
|
|
||||||
disk.img: disk.sfdisk
|
userspace: FORCE
|
||||||
|
$(MAKE) -C userspace
|
||||||
|
|
||||||
|
FORCE:
|
||||||
|
@
|
||||||
|
|
||||||
|
disk.img: disk.sfdisk userspace
|
||||||
qemu-img create -f raw $@ 32M
|
qemu-img create -f raw $@ 32M
|
||||||
sfdisk $@ < disk.sfdisk
|
sfdisk $@ < $<
|
||||||
|
# Before having filesystem support, just dump the user prog into the first partition
|
||||||
|
strip userspace/user -o userspace/user.strip
|
||||||
|
dd if=userspace/user.strip of=disk.img seek=2048 bs=512
|
||||||
|
|
||||||
# NASM without preprocessing
|
# NASM without preprocessing
|
||||||
%.o:%.asm
|
%.o:%.asm
|
||||||
@ -56,7 +65,7 @@ run:kernel disk.img
|
|||||||
|
|
||||||
debug: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST
|
debug: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST
|
||||||
debug: CXXFLAGS += $(DEBUG_FLAGS)
|
debug: CXXFLAGS += $(DEBUG_FLAGS)
|
||||||
debug:kernel kernel.sym
|
debug:kernel kernel.sym disk.img
|
||||||
gdb -q -x debug.gdb
|
gdb -q -x debug.gdb
|
||||||
|
|
||||||
debug_test: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST
|
debug_test: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST
|
||||||
@ -66,6 +75,9 @@ clean:
|
|||||||
$(RM) kernel $(asmobj) $(gasmobj) $(cobj) $(deps) fd.iso kernel.sym
|
$(RM) kernel $(asmobj) $(gasmobj) $(cobj) $(deps) fd.iso kernel.sym
|
||||||
$(RM) -r isodir
|
$(RM) -r isodir
|
||||||
|
|
||||||
|
.PHONY:
|
||||||
|
userspace
|
||||||
|
|
||||||
ifneq ($(MAKECMDGOALS),clean)
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
-include $(deps)
|
-include $(deps)
|
||||||
endif
|
endif
|
||||||
|
@ -55,6 +55,10 @@ void pagefault_handler(struct cpu_state *frame, ulong intr)
|
|||||||
struct thread *current = getCurrentThread();
|
struct thread *current = getCurrentThread();
|
||||||
printf("page fault while in thread %s code at 0x%x when trying to access 0x%x err_code 0x%x\n", current->name,
|
printf("page fault while in thread %s code at 0x%x when trying to access 0x%x err_code 0x%x\n", current->name,
|
||||||
cpu_context_get_PC(frame), cpu_context_get_EX_faulting_vaddr(frame), cpu_context_get_EX_err(frame));
|
cpu_context_get_PC(frame), cpu_context_get_EX_faulting_vaddr(frame), cpu_context_get_EX_err(frame));
|
||||||
|
if (cpu_context_is_in_user_mode(frame)) {
|
||||||
|
printf("Killing User Thread\n");
|
||||||
|
threadExit();
|
||||||
|
}
|
||||||
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr);
|
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr);
|
||||||
(void)intr;
|
(void)intr;
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -289,7 +289,7 @@ int pagingClearUserContext(vaddr_t vaddr_PD)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
paddr_t ptAddr = pd[pdIdx].pt_addr << PT_SHIFT;
|
paddr_t ptAddr = pd[pdIdx].pt_addr << PT_SHIFT;
|
||||||
assert(!pageMap(ptAddr, (vaddr_t)pt, PAGING_MEM_USER | PAGING_MEM_WRITE));
|
assert(!pageMap((vaddr_t)pt, ptAddr, PAGING_MEM_WRITE | PAGING_MEM_READ));
|
||||||
for(int ptIdx = 0; ptIdx < 1024; ptIdx ++){
|
for(int ptIdx = 0; ptIdx < 1024; ptIdx ++){
|
||||||
if(!pt[ptIdx].present){
|
if(!pt[ptIdx].present){
|
||||||
memset(&pt[ptIdx], 0, sizeof(struct pte));
|
memset(&pt[ptIdx], 0, sizeof(struct pte));
|
||||||
|
@ -3,4 +3,6 @@
|
|||||||
#define SYSCALL_INTR_NB 0x42
|
#define SYSCALL_INTR_NB 0x42
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
int syscallSetup();
|
int syscallSetup();
|
||||||
|
#endif
|
||||||
|
239
core/main.c
239
core/main.c
@ -7,9 +7,9 @@
|
|||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
|
#include "kernel.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "klibc.h"
|
#include "klibc.h"
|
||||||
#include "thread.h"
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "mmuContext.h"
|
#include "mmuContext.h"
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
@ -20,6 +20,7 @@
|
|||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
#include "stdarg.h"
|
#include "stdarg.h"
|
||||||
#include "swintr.h"
|
#include "swintr.h"
|
||||||
|
#include "thread.h"
|
||||||
#ifdef RUN_TEST
|
#ifdef RUN_TEST
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
#endif
|
#endif
|
||||||
@ -38,6 +39,228 @@ void idleThread(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure the program is in a valid ELF format, map it into memory,
|
||||||
|
* and return the address of its entry point (ie _start function)
|
||||||
|
*
|
||||||
|
* @return 0 when the program is not a valid ELF
|
||||||
|
*/
|
||||||
|
static uaddr_t loadElfProg(const char *prog)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/* e_ident value */
|
||||||
|
#define ELFMAG0 0x7f
|
||||||
|
#define ELFMAG1 'E'
|
||||||
|
#define ELFMAG2 'L'
|
||||||
|
#define ELFMAG3 'F'
|
||||||
|
|
||||||
|
/* e_ident offsets */
|
||||||
|
#define EI_MAG0 0
|
||||||
|
#define EI_MAG1 1
|
||||||
|
#define EI_MAG2 2
|
||||||
|
#define EI_MAG3 3
|
||||||
|
#define EI_CLASS 4
|
||||||
|
#define EI_DATA 5
|
||||||
|
#define EI_VERSION 6
|
||||||
|
#define EI_PAD 7
|
||||||
|
|
||||||
|
/* e_ident[EI_CLASS] */
|
||||||
|
#define ELFCLASSNONE 0
|
||||||
|
#define ELFCLASS32 1
|
||||||
|
#define ELFCLASS64 2
|
||||||
|
|
||||||
|
/* e_ident[EI_DATA] */
|
||||||
|
#define ELFDATANONE 0
|
||||||
|
#define ELFDATA2LSB 1
|
||||||
|
#define ELFDATA2MSB 2
|
||||||
|
|
||||||
|
/* e_type */
|
||||||
|
#define ET_NONE 0 /* No file type */
|
||||||
|
#define ET_REL 1 /* Relocatable file */
|
||||||
|
#define ET_EXEC 2 /* Executable file */
|
||||||
|
#define ET_DYN 3 /* Shared object file */
|
||||||
|
#define ET_CORE 4 /* Core file */
|
||||||
|
#define ET_LOPROC 0xff00 /* Processor-specific */
|
||||||
|
#define ET_HIPROC 0xffff /* Processor-specific */
|
||||||
|
|
||||||
|
/* e_machine */
|
||||||
|
#define EM_NONE 0 /* No machine */
|
||||||
|
#define EM_M32 1 /* AT&T WE 32100 */
|
||||||
|
#define EM_SPARC 2 /* SPARC */
|
||||||
|
#define EM_386 3 /* Intel 80386 */
|
||||||
|
#define EM_68K 4 /* Motorola 68000 */
|
||||||
|
#define EM_88K 5 /* Motorola 88000 */
|
||||||
|
#define EM_860 7 /* Intel 80860 */
|
||||||
|
#define EM_MIPS 8 /* MIPS RS3000 */
|
||||||
|
|
||||||
|
/* e_version */
|
||||||
|
#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
|
||||||
|
#define PT_LOAD 1
|
||||||
|
#define PT_DYNAMIC 2
|
||||||
|
#define PT_INTERP 3
|
||||||
|
#define PT_NOTE 4
|
||||||
|
#define PT_SHLIB 5
|
||||||
|
#define PT_PHDR 6
|
||||||
|
#define PT_LOPROC 0x70000000
|
||||||
|
#define PT_HIPROC 0x7fffffff
|
||||||
|
|
||||||
|
/* p_flags */
|
||||||
|
#define PF_X 1
|
||||||
|
#define PF_W 2
|
||||||
|
#define PF_R 4
|
||||||
|
|
||||||
|
Elf32_Ehdr_t *elf_hdr = (Elf32_Ehdr_t *)prog;
|
||||||
|
Elf32_Phdr_t *elf_phdrs;
|
||||||
|
|
||||||
|
/* Macro to check expected values for some fields in the ELF header */
|
||||||
|
#define ELF_CHECK(hdr, field, expected_value) \
|
||||||
|
({ \
|
||||||
|
if ((hdr)->field != (expected_value)) { \
|
||||||
|
printf("ELF prog : for %s, expected %x, got %x\n", #field, \
|
||||||
|
(unsigned)(expected_value), (unsigned)(hdr)->field); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
|
||||||
|
ELF_CHECK(elf_hdr, e_ident[EI_MAG0], ELFMAG0);
|
||||||
|
ELF_CHECK(elf_hdr, e_ident[EI_MAG1], ELFMAG1);
|
||||||
|
ELF_CHECK(elf_hdr, e_ident[EI_MAG2], ELFMAG2);
|
||||||
|
ELF_CHECK(elf_hdr, e_ident[EI_MAG3], ELFMAG3);
|
||||||
|
ELF_CHECK(elf_hdr, e_ident[EI_CLASS], ELFCLASS32);
|
||||||
|
ELF_CHECK(elf_hdr, e_ident[EI_DATA], ELFDATA2LSB);
|
||||||
|
ELF_CHECK(elf_hdr, e_type, ET_EXEC);
|
||||||
|
ELF_CHECK(elf_hdr, e_version, EV_CURRENT);
|
||||||
|
|
||||||
|
/* Get the begining of the program header table */
|
||||||
|
elf_phdrs = (Elf32_Phdr_t *)(prog + elf_hdr->e_phoff);
|
||||||
|
|
||||||
|
/* Map the program segment in R/W mode. To make things clean, we
|
||||||
|
should iterate over the sections, not the program header */
|
||||||
|
for (i = 0; i < elf_hdr->e_phnum; i++) {
|
||||||
|
uaddr_t uaddr;
|
||||||
|
|
||||||
|
/* Ignore the empty program headers that are not marked "LOAD" */
|
||||||
|
if (elf_phdrs[i].p_type != PT_LOAD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elf_phdrs[i].p_vaddr < PAGING_BASE_USER_ADDRESS) {
|
||||||
|
printf("User program has an incorrect address 0x%x\n", elf_phdrs[i].p_vaddr);
|
||||||
|
return (uaddr_t)NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map pages of physical memory into user space */
|
||||||
|
for (uaddr = ALIGN_DOWN(elf_phdrs[i].p_vaddr, PAGE_SIZE);
|
||||||
|
uaddr < elf_phdrs[i].p_vaddr + elf_phdrs[i].p_memsz; uaddr += PAGE_SIZE) {
|
||||||
|
paddr_t ppage;
|
||||||
|
ppage = allocPhyPage(1);
|
||||||
|
|
||||||
|
printf("map user page at 0x%x\n", uaddr);
|
||||||
|
assert(pageMap(uaddr, ppage,
|
||||||
|
PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0);
|
||||||
|
|
||||||
|
unrefPhyPage(ppage);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("memcpy at 0x%x from file offset %d size %d\n", elf_phdrs[i].p_vaddr, elf_phdrs[i].p_offset, elf_phdrs[i].p_filesz);
|
||||||
|
/* Copy segment into memory */
|
||||||
|
memcpy((void *)elf_phdrs[i].p_vaddr, (void *)(prog + elf_phdrs[i].p_offset),
|
||||||
|
elf_phdrs[i].p_filesz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elf_hdr->e_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadUserSpace()
|
||||||
|
{
|
||||||
|
struct ata_partition *part = ATAGetPartition(0);
|
||||||
|
|
||||||
|
if (part == NULL) {
|
||||||
|
printf("No user partition found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buf = malloc(26 * 512);
|
||||||
|
if (buf == NULL) {
|
||||||
|
printf("ENOMEM\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ATAReadPartitionSector(part, 0, 26, buf)) {
|
||||||
|
printf("Fail to read from disk\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct process *proc = processCreate("UserSpace");
|
||||||
|
|
||||||
|
threadChangeCurrentContext(processGetMMUContext(proc));
|
||||||
|
uaddr_t prog = loadElfProg(buf);
|
||||||
|
if (prog == (uaddr_t)NULL) {
|
||||||
|
free(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
threadCreateUser("UserProg", proc, prog, 0, 0, stackTop);
|
||||||
|
processUnref(proc);
|
||||||
|
threadChangeCurrentContext(NULL);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
// Multiboot information available here :
|
// Multiboot information available here :
|
||||||
// https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#kernel_002ec
|
// https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#kernel_002ec
|
||||||
// https://www.gnu.org/software/grub/manual/multiboot/html_node/Boot-information-format.html#Boot%20information%20format
|
// https://www.gnu.org/software/grub/manual/multiboot/html_node/Boot-information-format.html#Boot%20information%20format
|
||||||
@ -71,7 +294,8 @@ void kmain(unsigned long magic, unsigned long addr)
|
|||||||
int part1 = mbi->boot_device >> 16 & 0xff;
|
int part1 = mbi->boot_device >> 16 & 0xff;
|
||||||
int part2 = mbi->boot_device >> 8 & 0xff;
|
int part2 = mbi->boot_device >> 8 & 0xff;
|
||||||
int part3 = mbi->boot_device & 0xff;
|
int part3 = mbi->boot_device & 0xff;
|
||||||
printf("boot_device = 0x%x (0x0 for floppy 0x80 for disk) part %d %d %d\n", disk, part1, part2, part3);
|
printf("boot_device = 0x%x (0x0 for floppy 0x80 for disk) part %d %d %d\n", disk,
|
||||||
|
part1, part2, part3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CHECK_FLAG(mbi->flags, 3)) {
|
if (CHECK_FLAG(mbi->flags, 3)) {
|
||||||
@ -103,8 +327,11 @@ void kmain(unsigned long magic, unsigned long addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (CHECK_FLAG(mbi->flags, 12)) {
|
if (CHECK_FLAG(mbi->flags, 12)) {
|
||||||
printf("Re configure Framebuffer from 0x%llx size (%dx%d) pitch %d bpp %d\n", mbi->framebuffer_addr, mbi->framebuffer_width, mbi->framebuffer_height, mbi->framebuffer_pitch, mbi->framebuffer_bpp);
|
printf("Re configure Framebuffer from 0x%llx size (%dx%d) pitch %d bpp %d\n",
|
||||||
VGAConfigure(mbi->framebuffer_addr, mbi->framebuffer_width, mbi->framebuffer_height);
|
mbi->framebuffer_addr, mbi->framebuffer_width, mbi->framebuffer_height,
|
||||||
|
mbi->framebuffer_pitch, mbi->framebuffer_bpp);
|
||||||
|
VGAConfigure(mbi->framebuffer_addr, mbi->framebuffer_width,
|
||||||
|
mbi->framebuffer_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +369,8 @@ void kmain(unsigned long magic, unsigned long addr)
|
|||||||
printf("Cannot get memory Mapping information, using default value\n");
|
printf("Cannot get memory Mapping information, using default value\n");
|
||||||
memAddBank(lastUsedByMem, upperMemKB * 1024, 1);
|
memAddBank(lastUsedByMem, upperMemKB * 1024, 1);
|
||||||
}
|
}
|
||||||
printf("%d pages used by kernel(0x%x->0x%x))", (lastUsedByMem - firstUsedByMem)/PAGE_SIZE, firstUsedByMem, lastUsedByMem);
|
printf("%d pages used by kernel(0x%x->0x%x))",
|
||||||
|
(lastUsedByMem - firstUsedByMem) / PAGE_SIZE, firstUsedByMem, lastUsedByMem);
|
||||||
printf(" (%d pages for MM)\n", (lastUsedByMem - (paddr_t)&__ld_kernel_end) / PAGE_SIZE);
|
printf(" (%d pages for MM)\n", (lastUsedByMem - (paddr_t)&__ld_kernel_end) / PAGE_SIZE);
|
||||||
|
|
||||||
#ifdef RUN_TEST
|
#ifdef RUN_TEST
|
||||||
@ -189,6 +417,7 @@ void kmain(unsigned long magic, unsigned long addr)
|
|||||||
printf("%dKB free %dKB Used\n", free * (PAGE_SIZE / 1024), used * (PAGE_SIZE / 1024));
|
printf("%dKB free %dKB Used\n", free * (PAGE_SIZE / 1024), used * (PAGE_SIZE / 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadUserSpace();
|
||||||
// There is no real caller behind this point
|
// There is no real caller behind this point
|
||||||
// So finish this by ourself
|
// So finish this by ourself
|
||||||
threadExit();
|
threadExit();
|
||||||
|
@ -3,22 +3,27 @@
|
|||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
int syscallExecute(int syscallId, const struct cpu_state *user_ctx){
|
int syscallExecute(int syscallId, const struct cpu_state *userCtx){
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (syscallId) {
|
switch (syscallId) {
|
||||||
case SYSCALL_ID_EXIT:
|
case SYSCALL_ID_EXIT:
|
||||||
uint status;
|
uint status;
|
||||||
ret = syscallGet1arg(user_ctx, &status);
|
ret = syscallGet1arg(userCtx, &status);
|
||||||
if(ret != 0)
|
if(ret != 0)
|
||||||
break;
|
break;
|
||||||
threadExit();
|
threadExit();
|
||||||
assert(0);
|
assert(0);
|
||||||
break;
|
break;
|
||||||
case SYSCALL_ID_WRITE:
|
case SYSCALL_ID_YOLO:
|
||||||
ret = printf("YOLO FROM USERSPACE\n");
|
ret = printf("YOLO FROM USERSPACE\n");
|
||||||
break;
|
break;
|
||||||
|
case SYSCALL_ID_PUTC:
|
||||||
|
unsigned int c;
|
||||||
|
ret = syscallGet1arg(userCtx, &c);
|
||||||
|
putc(c);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Unknon syscall id %d\n", syscallId);
|
printf("Unknon syscall id %d\n", syscallId);
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#ifdef __KERNEL__
|
||||||
#include "cpu_context.h"
|
#include "cpu_context.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SYSCALL_ID_EXIT 1
|
#define SYSCALL_ID_EXIT 1
|
||||||
#define SYSCALL_ID_WRITE 2
|
#define SYSCALL_ID_YOLO 2
|
||||||
|
#define SYSCALL_ID_PUTC 3
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
int syscallExecute(int syscallId, const struct cpu_state *user_ctx);
|
int syscallExecute(int syscallId, const struct cpu_state *user_ctx);
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
add-symbol-file kernel.sym
|
add-symbol-file kernel.sym
|
||||||
|
add-symbol-file userspace/user
|
||||||
source custom_gdb_extension.py
|
source custom_gdb_extension.py
|
||||||
#For ASM sources
|
#For ASM sources
|
||||||
directory arch/x86/:core
|
directory arch/x86/:core
|
||||||
target remote | qemu-system-i386 -S -gdb stdio -kernel kernel -m 16M -serial file:serialOut
|
target remote | qemu-system-i386 -S -gdb stdio -kernel kernel -m 16M -serial file:serialOut -hda disk.img
|
||||||
|
@ -556,6 +556,8 @@ int ATAReadPartition(struct ata_device *dev)
|
|||||||
}
|
}
|
||||||
printf("Got partition %d type %s(0x%x) size %d kb lba 0x%x\n", i,
|
printf("Got partition %d type %s(0x%x) size %d kb lba 0x%x\n", i,
|
||||||
partTypeToStr(parts[i].type), parts[i].type, (parts[i].size * DISK_SECTOR_SIZE) >> 10, parts[i].lba);
|
partTypeToStr(parts[i].type), parts[i].type, (parts[i].size * DISK_SECTOR_SIZE) >> 10, parts[i].lba);
|
||||||
|
|
||||||
|
ATAPartitionCreate(parts[i].type, parts[i].size, parts[i].lba, dev);
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +633,7 @@ int ATAReadSector(struct ata_device *dev, int lba, uint nb_sector, void *buf)
|
|||||||
}
|
}
|
||||||
if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) {
|
if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) {
|
||||||
mutexUnlock(&ctl->mutex);
|
mutexUnlock(&ctl->mutex);
|
||||||
printf("ATA read error\n");
|
printf("ATA read error at sector %d\n", sector);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) {
|
for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) {
|
||||||
|
@ -22,6 +22,9 @@ struct cpu_state *pitIrqHandler(struct cpu_state *prevCpu)
|
|||||||
__atomic_add_fetch(&jiffies, 1, __ATOMIC_RELAXED);
|
__atomic_add_fetch(&jiffies, 1, __ATOMIC_RELAXED);
|
||||||
threadOnJieffiesTick();
|
threadOnJieffiesTick();
|
||||||
// Uncomment for non-preemptible kernel
|
// Uncomment for non-preemptible kernel
|
||||||
// return prevCpu;
|
if (cpu_context_is_in_user_mode(prevCpu)) {
|
||||||
return threadSwitch(prevCpu);
|
return threadSwitch(prevCpu);
|
||||||
|
} else {
|
||||||
|
return prevCpu;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,7 +366,7 @@ void testATAThread(){
|
|||||||
buf[1]= 0x2;
|
buf[1]= 0x2;
|
||||||
buf[2]= 0x3;
|
buf[2]= 0x3;
|
||||||
buf[3]= 0x4;
|
buf[3]= 0x4;
|
||||||
ATAWriteSector(dev, 0, 1, buf);
|
//ATAWriteSector(dev, 0, 1, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +398,7 @@ static void userProgramm()
|
|||||||
"int %5\n"
|
"int %5\n"
|
||||||
"movl %%eax, %0"
|
"movl %%eax, %0"
|
||||||
: "=g"(ret)
|
: "=g"(ret)
|
||||||
: "g"(SYSCALL_ID_WRITE), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB)
|
: "g"(SYSCALL_ID_YOLO), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB)
|
||||||
: "eax", "ebx", "ecx", "edx");
|
: "eax", "ebx", "ecx", "edx");
|
||||||
asm volatile("movl %1,%%eax \n"
|
asm volatile("movl %1,%%eax \n"
|
||||||
"movl %2,%%ebx \n"
|
"movl %2,%%ebx \n"
|
||||||
@ -487,9 +487,9 @@ void run_test(void)
|
|||||||
printf("Testing backtrace\n");
|
printf("Testing backtrace\n");
|
||||||
test_backtrace();
|
test_backtrace();
|
||||||
testCoroutine();
|
testCoroutine();
|
||||||
int nbThread = threadCount();
|
//int nbThread = threadCount();
|
||||||
testKthread();
|
testKthread();
|
||||||
assert(nbThread + 1 == threadCount());//For sleep Thread
|
//assert(nbThread + 1 == threadCount());//For sleep Thread
|
||||||
testMMUContext();
|
testMMUContext();
|
||||||
testProcess();
|
testProcess();
|
||||||
memGetStat(&afterFreemem, &afterUsedmem);
|
memGetStat(&afterFreemem, &afterUsedmem);
|
||||||
|
@ -1,2 +1,28 @@
|
|||||||
# Used to generated .d file that deal with header dependencies
|
# Used to generated .d file that deal with header dependencies
|
||||||
CPPFLAGS = -MMD
|
CPPFLAGS = -MMD
|
||||||
|
LDFLAGS += -m elf_i386
|
||||||
|
CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector -fno-tree-vectorize -nostdinc -fno-asynchronous-unwind-tables -g
|
||||||
|
LIBGCC = $(shell $(CC) -print-libgcc-file-name $(CFLAGS))
|
||||||
|
|
||||||
|
SUBDIRS := . kernel
|
||||||
|
|
||||||
|
ARCH?=x86
|
||||||
|
INCDIRS += $(foreach dir, $(SUBDIRS), -I$(dir))
|
||||||
|
CPPFLAGS += $(INCDIRS)
|
||||||
|
|
||||||
|
csrc=$(wildcard *.c)
|
||||||
|
cobj=$(csrc:%.c=%.o)
|
||||||
|
deps=$(csrc:%.c=%.d)
|
||||||
|
|
||||||
|
PROG = user
|
||||||
|
|
||||||
|
$(PROG) : $(cobj) linker.ld
|
||||||
|
$(CC) -static -Wl,--warn-common $(CFLAGS) -nostdlib -o $@ -T linker.ld $(cobj) $(LIBGCC)
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(PROG) $(cobj) $(deps)
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(deps)
|
||||||
|
endif
|
||||||
|
21
userspace/assert.h
Normal file
21
userspace/assert.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "libc.h"
|
||||||
|
|
||||||
|
#define assert(p) \
|
||||||
|
do { \
|
||||||
|
if (!(p)) { \
|
||||||
|
printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \
|
||||||
|
while (1) { \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define assertmsg(p, ...) \
|
||||||
|
do { \
|
||||||
|
if (!(p)) { \
|
||||||
|
printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
while (1) { \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
9
userspace/crt.c
Normal file
9
userspace/crt.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "libc.h"
|
||||||
|
|
||||||
|
void _start()
|
||||||
|
{
|
||||||
|
/* This starter function expects a main() function somewhere */
|
||||||
|
extern int main();
|
||||||
|
|
||||||
|
_exit(main());
|
||||||
|
}
|
8
userspace/kernel/swintr.h
Normal file
8
userspace/kernel/swintr.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define SYSCALL_INTR_NB 0x42
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
int syscallSetup();
|
||||||
|
#endif
|
12
userspace/kernel/syscall.h
Normal file
12
userspace/kernel/syscall.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#include "cpu_context.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SYSCALL_ID_EXIT 1
|
||||||
|
#define SYSCALL_ID_YOLO 2
|
||||||
|
#define SYSCALL_ID_PUTC 3
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
int syscallExecute(int syscallId, const struct cpu_state *user_ctx);
|
||||||
|
#endif
|
514
userspace/libc.c
Normal file
514
userspace/libc.c
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
#include "libc.h"
|
||||||
|
#include "minmax.h"
|
||||||
|
#include "swintr.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int memcmp(const void *aptr, const void *bptr, size_t size)
|
||||||
|
{
|
||||||
|
const unsigned char *a = (const unsigned char *)aptr;
|
||||||
|
const unsigned char *b = (const unsigned char *)bptr;
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
if (a[i] < b[i])
|
||||||
|
return -1;
|
||||||
|
else if (b[i] < a[i])
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspirated by https://interrupt.memfault.com/blog/memcpy-newlib-nano
|
||||||
|
/* Nonzero if either X or Y is not aligned on a "long" boundary. */
|
||||||
|
#define UNALIGNED(X, Y) \
|
||||||
|
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
|
||||||
|
|
||||||
|
/* How many bytes are copied each iteration of the 4X unrolled loop. */
|
||||||
|
#define BIGBLOCKSIZE (sizeof (long) << 2)
|
||||||
|
|
||||||
|
/* How many bytes are copied each iteration of the word copy loop. */
|
||||||
|
#define LITTLEBLOCKSIZE (sizeof (long))
|
||||||
|
|
||||||
|
/* Threshhold for punting to the byte copier. */
|
||||||
|
#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
|
||||||
|
|
||||||
|
void *memcpy(void *dst0, const void *src0, size_t len0)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
char *dstChar = dst0;
|
||||||
|
const char *srcChar = src0;
|
||||||
|
for (size_t i = 0; i < len0; i++) {
|
||||||
|
*(dstChar++) = *(srcChar++);
|
||||||
|
}
|
||||||
|
return dst0;
|
||||||
|
#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)) {
|
||||||
|
aligned_dst = (long *)dst;
|
||||||
|
aligned_src = (long *)src;
|
||||||
|
|
||||||
|
/* Copy 4X long words at a time if possible. */
|
||||||
|
while (len0 >= BIGBLOCKSIZE) {
|
||||||
|
*aligned_dst++ = *aligned_src++;
|
||||||
|
*aligned_dst++ = *aligned_src++;
|
||||||
|
*aligned_dst++ = *aligned_src++;
|
||||||
|
*aligned_dst++ = *aligned_src++;
|
||||||
|
len0 -= BIGBLOCKSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy one long word at a time if possible. */
|
||||||
|
while (len0 >= LITTLEBLOCKSIZE) {
|
||||||
|
*aligned_dst++ = *aligned_src++;
|
||||||
|
len0 -= LITTLEBLOCKSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pick up any residual with a byte copier. */
|
||||||
|
dst = (char *)aligned_dst;
|
||||||
|
src = (char *)aligned_src;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len0--)
|
||||||
|
*dst++ = *src++;
|
||||||
|
|
||||||
|
return dst0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memset(void *src, int c, size_t n)
|
||||||
|
{
|
||||||
|
for (char *ptr = (char *)src; n > 0; n--, ptr++) {
|
||||||
|
*ptr = (char)c;
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *itoa(long long int value, char *str, int base)
|
||||||
|
{
|
||||||
|
char *rc;
|
||||||
|
char *ptr;
|
||||||
|
char *low;
|
||||||
|
// Check for supported base.
|
||||||
|
if (base < 2 || base > 36) {
|
||||||
|
*str = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
rc = ptr = str;
|
||||||
|
// Set '-' for negative decimals.
|
||||||
|
if (value < 0 && base == 10) {
|
||||||
|
*ptr++ = '-';
|
||||||
|
}
|
||||||
|
// Remember where the numbers start.
|
||||||
|
low = ptr;
|
||||||
|
// The actual conversion.
|
||||||
|
do {
|
||||||
|
// Modulo is negative for negative value. This trick makes abs() unnecessary.
|
||||||
|
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
[35 + value % base];
|
||||||
|
value /= base;
|
||||||
|
} while (value);
|
||||||
|
// Terminating the string.
|
||||||
|
*ptr-- = '\0';
|
||||||
|
// Invert the numbers.
|
||||||
|
while (low < ptr) {
|
||||||
|
char tmp = *low;
|
||||||
|
*low++ = *ptr;
|
||||||
|
*ptr-- = tmp;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* K&R */
|
||||||
|
void reverse(char s[])
|
||||||
|
{
|
||||||
|
int c, i, j;
|
||||||
|
for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
|
||||||
|
c = s[i];
|
||||||
|
s[i] = s[j];
|
||||||
|
s[j] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* K&R */
|
||||||
|
int strlen(const char s[])
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (s[i] != '\0')
|
||||||
|
++i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* K&R
|
||||||
|
* Returns <0 if s1<s2, 0 if s1==s2, >0 if s1>s2 */
|
||||||
|
int strcmp(const char s1[], const char s2[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; s1[i] == s2[i]; i++) {
|
||||||
|
if (s1[i] == '\0')
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return s1[i] - s2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int strnlen(const char *s, size_t count)
|
||||||
|
{
|
||||||
|
const char *sc;
|
||||||
|
|
||||||
|
for (sc = s; count-- && *sc != '\0'; ++sc)
|
||||||
|
/* nothing */ continue;
|
||||||
|
|
||||||
|
return sc - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strzcpy(register char *dst, register const char *src, register int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
return dst;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
dst[i] = src[i];
|
||||||
|
if (src[i] == '\0')
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst[len - 1] = '\0';
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int printf(const char *format, ...)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
ret = vprintf(format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int puts(const char *str)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
while (*str) {
|
||||||
|
putc(*(str++));
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3)
|
||||||
|
// = 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3)
|
||||||
|
#define PRINT_INT(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; \
|
||||||
|
\
|
||||||
|
if (integer < 0) { \
|
||||||
|
if (str) { \
|
||||||
|
if (size) { \
|
||||||
|
str[c++] = '-'; \
|
||||||
|
size--; \
|
||||||
|
ret++; \
|
||||||
|
} else { \
|
||||||
|
return ret; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
ret++; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
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);
|
||||||
|
|
||||||
|
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int i = 0;
|
||||||
|
int c = 0;
|
||||||
|
|
||||||
|
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 'p':
|
||||||
|
case 'x': {
|
||||||
|
char val[sizeof(int) * 2];
|
||||||
|
unsigned int valIdx = 0;
|
||||||
|
int d = va_arg(ap, 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;
|
||||||
|
}
|
||||||
|
case 'c': {
|
||||||
|
if (str) {
|
||||||
|
int ch = va_arg(ap, int);
|
||||||
|
str[c++] = ch;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
ret++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
char *stri = va_arg(ap, char *);
|
||||||
|
if (!stri)
|
||||||
|
stri = "[NULL STR]";
|
||||||
|
if (str) {
|
||||||
|
while (*stri) {
|
||||||
|
if (size) {
|
||||||
|
str[c++] = *(stri++);
|
||||||
|
size--;
|
||||||
|
ret++;
|
||||||
|
} else {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret += strlen(stri);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '%':
|
||||||
|
if (str) {
|
||||||
|
str[c++] = '%';
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
ret++;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
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 'p':
|
||||||
|
case 'x': {
|
||||||
|
char val[sizeof(long long int) * 2];
|
||||||
|
unsigned int valIdx = 0;
|
||||||
|
long long int d = va_arg(ap, long 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (str) {
|
||||||
|
str[c++] = format[i];
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
if (size) {
|
||||||
|
str[c++] = '\0';
|
||||||
|
size--;
|
||||||
|
} else {
|
||||||
|
if (c > 0) {
|
||||||
|
str[c - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vprintf(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
char tmp[256];
|
||||||
|
int idx = 0;
|
||||||
|
int ret = vsnprintf(tmp, sizeof(tmp), fmt, ap);
|
||||||
|
while (ret > 0 && tmp[idx]) {
|
||||||
|
putc(tmp[idx++]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int asprintf(char **strp, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ret = vasprintf(strp, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vasprintf(char **strp, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
char p[256]; //TODO replace by malloc
|
||||||
|
|
||||||
|
/* Determine required size */
|
||||||
|
|
||||||
|
n = vsnprintf(p, size, fmt, ap);
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* One extra byte for '\0' */
|
||||||
|
|
||||||
|
size = min(256U,(size_t)n + 1);
|
||||||
|
|
||||||
|
n = vsnprintf(p, size, fmt, ap);
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*strp = p;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int syscall3(int id, unsigned int arg1, unsigned int arg2, unsigned int arg3)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
asm volatile("movl %1,%%eax \n"
|
||||||
|
"movl %2,%%ebx \n"
|
||||||
|
"movl %3,%%ecx \n"
|
||||||
|
"movl %4,%%edx \n"
|
||||||
|
"int %5\n"
|
||||||
|
"movl %%eax, %0"
|
||||||
|
: "=g"(ret)
|
||||||
|
: "g"(id), "g"(arg1), "g"(arg2), "g"(arg3), "i"(SYSCALL_INTR_NB)
|
||||||
|
: "eax", "ebx", "ecx", "edx");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int syscall2(int id, unsigned int arg1, unsigned int arg2)
|
||||||
|
{
|
||||||
|
return syscall3(id, arg1, arg2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int syscall1(int id, unsigned int arg1)
|
||||||
|
{
|
||||||
|
return syscall3(id, arg1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int syscall0(int id)
|
||||||
|
{
|
||||||
|
return syscall3(id, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _exit(int status)
|
||||||
|
{
|
||||||
|
syscall1(SYSCALL_ID_EXIT, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int putc(const int c){
|
||||||
|
return syscall1(SYSCALL_ID_PUTC, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void yolo()
|
||||||
|
{
|
||||||
|
syscall0(SYSCALL_ID_YOLO);
|
||||||
|
}
|
39
userspace/libc.h
Normal file
39
userspace/libc.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "assert.h"
|
||||||
|
#include "stdarg.h"
|
||||||
|
#include "minmax.h"
|
||||||
|
|
||||||
|
#define islower(c) (('a' <= (c)) && ((c) <= 'z'))
|
||||||
|
#define isupper(c) (('A' <= (c)) && ((c) <= 'Z'))
|
||||||
|
#define isdigit(c) (('0' <= (c)) && ((c) <= '9'))
|
||||||
|
#define isspace(c) \
|
||||||
|
(((c) == ' ') || ((c) == '\t') || ((c) == '\f') || ((c) == '\n') || ((c) == '\r') || \
|
||||||
|
((c) == '\v'))
|
||||||
|
#define isprint(c) ((' ' <= (c)) && ((c) <= '~'))
|
||||||
|
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
|
void *memset(void *s, int c, size_t n);
|
||||||
|
char *itoa(long long int value, char *str, int base);
|
||||||
|
void reverse(char s[]);
|
||||||
|
int strlen(const char s[]);
|
||||||
|
unsigned int strnlen(const char *s, size_t count);
|
||||||
|
int strcmp(const char s1[], const char s2[]);
|
||||||
|
char *strzcpy(char *dst, const char *src, int len);
|
||||||
|
int puts(const char *str);
|
||||||
|
int putc(const int c);
|
||||||
|
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||||
|
int vprintf(const char *format, va_list ap);
|
||||||
|
int printf(const char *format, ...);
|
||||||
|
|
||||||
|
// 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 syscall3(int id, unsigned int arg1, unsigned int arg2, unsigned int arg3);
|
||||||
|
int syscall2(int id, unsigned int arg1, unsigned int arg2);
|
||||||
|
int syscall1(int id, unsigned int arg1);
|
||||||
|
int syscall0(int id);
|
||||||
|
|
||||||
|
void _exit(int status);
|
||||||
|
void yolo();
|
33
userspace/linker.ld
Normal file
33
userspace/linker.ld
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
OUTPUT_FORMAT(elf32-i386);
|
||||||
|
/* C entry point: used by crt.c*/
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Userspace vitual address PAGING_BASE_USER_ADDRESS */
|
||||||
|
. = 0x40000000;
|
||||||
|
|
||||||
|
.text : ALIGN(4096)
|
||||||
|
{
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read-only data. */
|
||||||
|
.rodata : ALIGN(4096)
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read-write data (initialized) */
|
||||||
|
.data : ALIGN(4096)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read-write data (uninitialized) and stack */
|
||||||
|
.bss : ALIGN(4096)
|
||||||
|
{
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
}
|
12
userspace/main_user.c
Normal file
12
userspace/main_user.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include "libc.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
yolo();
|
||||||
|
printf("User is about to suicide\n");
|
||||||
|
int *yolo =0;
|
||||||
|
*yolo = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
9
userspace/math.c
Normal file
9
userspace/math.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
inline uint32_t log2(const uint32_t x)
|
||||||
|
{
|
||||||
|
uint32_t y;
|
||||||
|
// Get the highest set bit
|
||||||
|
asm("\tbsr %1, %0\n" : "=r"(y) : "r"(x));
|
||||||
|
return y;
|
||||||
|
}
|
5
userspace/math.h
Normal file
5
userspace/math.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "stdarg.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
uint32_t log2(uint32_t x);
|
169
userspace/minmax.h
Normal file
169
userspace/minmax.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#ifndef _LINUX_MINMAX_H
|
||||||
|
#define _LINUX_MINMAX_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From linux kernel include/linux/compiler_types.h
|
||||||
|
*/
|
||||||
|
#define ___PASTE(a,b) a##b
|
||||||
|
#define __PASTE(a,b) ___PASTE(a,b)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From Linux kernel include/linux/compiler.h
|
||||||
|
*/
|
||||||
|
/* Not-quite-unique ID. */
|
||||||
|
#ifndef __UNIQUE_ID
|
||||||
|
# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* min()/max()/clamp() macros must accomplish three things:
|
||||||
|
*
|
||||||
|
* - avoid multiple evaluations of the arguments (so side-effects like
|
||||||
|
* "x++" happen only once) when non-constant.
|
||||||
|
* - perform strict type-checking (to generate warnings instead of
|
||||||
|
* nasty runtime surprises). See the "unnecessary" pointer comparison
|
||||||
|
* in __typecheck().
|
||||||
|
* - retain result as a constant expressions when called with only
|
||||||
|
* constant expressions (to avoid tripping VLA warnings in stack
|
||||||
|
* allocation usage).
|
||||||
|
*/
|
||||||
|
#define __typecheck(x, y) \
|
||||||
|
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This returns a constant expression while determining if an argument is
|
||||||
|
* a constant expression, most importantly without evaluating the argument.
|
||||||
|
* Glory to Martin Uecker <Martin.Uecker@med.uni-goettingen.de>
|
||||||
|
*/
|
||||||
|
#define __is_constexpr(x) \
|
||||||
|
(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
|
||||||
|
|
||||||
|
#define __no_side_effects(x, y) \
|
||||||
|
(__is_constexpr(x) && __is_constexpr(y))
|
||||||
|
|
||||||
|
#define __safe_cmp(x, y) \
|
||||||
|
(__typecheck(x, y) && __no_side_effects(x, y))
|
||||||
|
|
||||||
|
#define __cmp(x, y, op) ((x) op (y) ? (x) : (y))
|
||||||
|
|
||||||
|
#define __cmp_once(x, y, unique_x, unique_y, op) ({ \
|
||||||
|
typeof(x) unique_x = (x); \
|
||||||
|
typeof(y) unique_y = (y); \
|
||||||
|
__cmp(unique_x, unique_y, op); })
|
||||||
|
|
||||||
|
#define __careful_cmp(x, y, op) \
|
||||||
|
__builtin_choose_expr(__safe_cmp(x, y), \
|
||||||
|
__cmp(x, y, op), \
|
||||||
|
__cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min - return minimum of two values of the same or compatible types
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define min(x, y) __careful_cmp(x, y, <)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max - return maximum of two values of the same or compatible types
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define max(x, y) __careful_cmp(x, y, >)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min3 - return minimum of three values
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
* @z: third value
|
||||||
|
*/
|
||||||
|
#define min3(x, y, z) min((typeof(x))min(x, y), z)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max3 - return maximum of three values
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
* @z: third value
|
||||||
|
*/
|
||||||
|
#define max3(x, y, z) max((typeof(x))max(x, y), z)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min_not_zero - return the minimum that is _not_ zero, unless both are zero
|
||||||
|
* @x: value1
|
||||||
|
* @y: value2
|
||||||
|
*/
|
||||||
|
#define min_not_zero(x, y) ({ \
|
||||||
|
typeof(x) __x = (x); \
|
||||||
|
typeof(y) __y = (y); \
|
||||||
|
__x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clamp - return a value clamped to a given range with strict typechecking
|
||||||
|
* @val: current value
|
||||||
|
* @lo: lowest allowable value
|
||||||
|
* @hi: highest allowable value
|
||||||
|
*
|
||||||
|
* This macro does strict typechecking of @lo/@hi to make sure they are of the
|
||||||
|
* same type as @val. See the unnecessary pointer comparisons.
|
||||||
|
*/
|
||||||
|
#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ..and if you can't take the strict
|
||||||
|
* types, you can specify one yourself.
|
||||||
|
*
|
||||||
|
* Or not use min/max/clamp at all, of course.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min_t - return minimum of two values, using the specified type
|
||||||
|
* @type: data type to use
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max_t - return maximum of two values, using the specified type
|
||||||
|
* @type: data type to use
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clamp_t - return a value clamped to a given range using a given type
|
||||||
|
* @type: the type of variable to use
|
||||||
|
* @val: current value
|
||||||
|
* @lo: minimum allowable value
|
||||||
|
* @hi: maximum allowable value
|
||||||
|
*
|
||||||
|
* This macro does no typechecking and uses temporary variables of type
|
||||||
|
* @type to make all the comparisons.
|
||||||
|
*/
|
||||||
|
#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clamp_val - return a value clamped to a given range using val's type
|
||||||
|
* @val: current value
|
||||||
|
* @lo: minimum allowable value
|
||||||
|
* @hi: maximum allowable value
|
||||||
|
*
|
||||||
|
* This macro does no typechecking and uses temporary variables of whatever
|
||||||
|
* type the input argument @val is. This is useful when @val is an unsigned
|
||||||
|
* type and @lo and @hi are literals that will otherwise be assigned a signed
|
||||||
|
* integer type.
|
||||||
|
*/
|
||||||
|
#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* swap - swap values of @a and @b
|
||||||
|
* @a: first value
|
||||||
|
* @b: second value
|
||||||
|
*/
|
||||||
|
#define swap(a, b) \
|
||||||
|
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
|
||||||
|
|
||||||
|
#endif /* _LINUX_MINMAX_H */
|
54
userspace/stdarg.h
Normal file
54
userspace/stdarg.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
typedef void *va_list;
|
||||||
|
#define va_start(v, l) ((v) = (va_list) & (l) + sizeof(l))
|
||||||
|
#define va_end(v) ((v) = NULL)
|
||||||
|
#define va_arg(v, type) (*(type *)(((v) += sizeof(type)) - sizeof(type)))
|
38
userspace/types.h
Normal file
38
userspace/types.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#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;
|
||||||
|
|
||||||
|
// Physical address
|
||||||
|
typedef unsigned long paddr_t;
|
||||||
|
|
||||||
|
// Userspace vaddr
|
||||||
|
typedef unsigned long uaddr_t;
|
Loading…
Reference in New Issue
Block a user