mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-09 00:00:03 +01:00
HermitCore is independent to the Linux kernel => move to an own subdirectory
This commit is contained in:
parent
9624428c74
commit
d7ec3d4f14
68 changed files with 9910 additions and 0 deletions
116
hermit/Makefile
Normal file
116
hermit/Makefile
Normal file
|
@ -0,0 +1,116 @@
|
|||
TERM = xterm
|
||||
TOPDIR = $(shell pwd)
|
||||
ARCH = x86
|
||||
NAME = hermit
|
||||
KERNDIRS = kernel mm libkern arch/$(ARCH)/kernel arch/$(ARCH)/mm
|
||||
SUBDIRS = $(KERNDIRS)
|
||||
|
||||
# Set your own cross compiler tool chain prefix here
|
||||
CROSSCOMPREFIX =
|
||||
STACKPROT = -fno-stack-protector
|
||||
|
||||
CC_FOR_TARGET = $(CROSSCOMPREFIX)gcc
|
||||
CXX_FOR_TARGET = $(CROSSCOMPREFIX)g++
|
||||
GCC_FOR_TARGET = $(CROSSCOMPREFIX)gcc
|
||||
CPP_FOR_TARGET = $(CROSSCOMPREFIX)cpp
|
||||
AR_FOR_TARGET = $(CROSSCOMPREFIX)ar
|
||||
AS_FOR_TARGET = $(CROSSCOMPREFIX)as
|
||||
LD_FOR_TARGET = $(CROSSCOMPREFIX)ld
|
||||
NM_FOR_TARGET = $(CROSSCOMPREFIX)nm
|
||||
OBJDUMP_FOR_TARGET = $(CROSSCOMPREFIX)objdump
|
||||
OBJCOPY_FOR_TARGET = $(CROSSCOMPREFIX)objcopy
|
||||
RANLIB_FOR_TARGET = $(CROSSCOMPREFIX)ranlib
|
||||
STRIP_FOR_TARGET = $(CROSSCOMPREFIX)strip
|
||||
READELF_FOR_TARGET = $(CROSSCOMPREFIX)readelf
|
||||
|
||||
MAKE = make
|
||||
NASM = nasm
|
||||
NASMFLAGS = -felf64 -g -i$(TOPDIR)/include/hermit/
|
||||
GDB = $(CROSSCOMPREFIX)gdb
|
||||
GDBFLAGS = -x debug.gdb
|
||||
QEMU = qemu-system-x86_64
|
||||
QEMUFLAGS = -smp 2 -monitor stdio \
|
||||
-net nic,model=rtl8139 \
|
||||
-net user,hostfwd=tcp::12345-:7
|
||||
QEMUDEBUGFLAGS = -monitor none -daemonize \
|
||||
-net nic,model=rtl8139 \
|
||||
-net user,hostfwd=tcp::12345-:7
|
||||
QEMUSERIALFLAGS = -device pci-serial,chardev=tS0 \
|
||||
-chardev socket,host=localhost,port=4555,server,id=tS0
|
||||
|
||||
INCLUDE = -I$(TOPDIR)/include -I$(TOPDIR)/arch/$(ARCH)/include
|
||||
# Compiler options for final code
|
||||
CFLAGS = -g -m64 -Wall -O2 -mno-red-zone -fstrength-reduce -fomit-frame-pointer -finline-functions -ffreestanding -nostdinc -fno-stack-protector $(INCLUDE)
|
||||
# Compiler options for debugging
|
||||
debug debug-eclipse : CFLAGS = -g -O0 -m64 -Wall -fno-builtin -DWITH_FRAME_POINTER -nostdinc -mno-red-zone -fno-stack-protector $(INCLUDE)
|
||||
AR = ar
|
||||
ARFLAGS = rsv
|
||||
RM = rm -rf
|
||||
LDFLAGS = -T link.ld -z max-page-size=4096 --defsym __BUILD_DATE=$(shell date +'%Y%m%d') --defsym __BUILD_TIME=$(shell date +'%H%M%S')
|
||||
STRIP_DEBUG = --strip-debug
|
||||
KEEP_DEBUG = --only-keep-debug
|
||||
OUTPUT_FORMAT = -O elf32-i386
|
||||
|
||||
# Prettify output
|
||||
V = 0
|
||||
ifeq ($V,0)
|
||||
Q = @
|
||||
P = > /dev/null
|
||||
endif
|
||||
|
||||
default: all
|
||||
|
||||
all: $(NAME).elf
|
||||
|
||||
$(NAME).elf:
|
||||
$Q$(LD_FOR_TARGET) $(LDFLAGS) -o $(NAME).elf $^
|
||||
@echo [OBJCOPY] $(NAME).bin
|
||||
$Q$(OBJCOPY_FOR_TARGET) -j .mboot -j .kmsg -j .text -j .data -j .rodata -j .bss -O binary $(NAME).elf $(NAME).bin
|
||||
#@echo [OBJCOPY] $(NAME).sym
|
||||
#$Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $(NAME).elf $(NAME).sym
|
||||
#@echo [OBJCOPY] $(NAME).elf
|
||||
#$Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $(OUTPUT_FORMAT) $(NAME).elf
|
||||
|
||||
clean:
|
||||
$Q$(RM) $(NAME).elf $(NAME).sym $(NAME).bin *~
|
||||
@echo Cleaned.
|
||||
|
||||
veryclean: clean
|
||||
$Q$(RM) qemu-vlan0.pcap include/hermit/config.inc
|
||||
@echo Very cleaned
|
||||
|
||||
qemu: all
|
||||
$(QEMU) $(QEMUFLAGS) -kernel $(NAME).elf
|
||||
|
||||
debug: all
|
||||
$(TERM) -e $(GDB) $(GDBFLAGS) &
|
||||
$(QEMU) $(QEMUDEBUGFLAGS) -s -S -kernel $(NAME).elf
|
||||
|
||||
doc:
|
||||
@echo Create documentation...
|
||||
@doxygen
|
||||
|
||||
%.o : %.c
|
||||
@echo [CC] $@
|
||||
$Q$(CC_FOR_TARGET) -c -D__KERNEL__ $(CFLAGS) -o $@ $<
|
||||
@echo [DEP] $*.dep
|
||||
$Q$(CC_FOR_TARGET) -MF $*.dep -MT $*.o -MM $(CFLAGS) $<
|
||||
|
||||
include/hermit/config.inc: include/hermit/config.h
|
||||
@echo "; This file is generated automatically from the config.h file." > include/hermit/config.inc
|
||||
@echo "; Before editing this, you should consider editing config.h." >> include/hermit/config.inc
|
||||
@awk '/^#define KERNEL_STACK_SIZE/{ print "%define KERNEL_STACK_SIZE", $$3 }' include/hermit/config.h >> include/hermit/config.inc
|
||||
@awk '/^#define VIDEO_MEM_ADDR/{ print "%define VIDEO_MEM_ADDR", $$3 }' include/hermit/config.h >> include/hermit/config.inc
|
||||
@awk '/^#define CONFIG_VGA/{ print "%define CONFIG_VGA" }' include/hermit/config.h >> include/hermit/config.inc
|
||||
|
||||
%.o : %.asm include/hermit/config.inc
|
||||
@echo [ASM] $@
|
||||
$Q$(NASM) $(NASMFLAGS) -o $@ $<
|
||||
|
||||
%.o : %.S
|
||||
@echo [GCC-ASM] $@
|
||||
$Q$(CC_FOR_TARGET) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
.PHONY: default all clean emu gdb
|
||||
|
||||
include $(addsuffix /Makefile,$(SUBDIRS))
|
20
hermit/Makefile.inc
Normal file
20
hermit/Makefile.inc
Normal file
|
@ -0,0 +1,20 @@
|
|||
C_source-$(MODULE) := $(addprefix $(subst _,/,$(MODULE))/,$(filter %.c,$(C_source)))
|
||||
ASM_source-$(MODULE) := $(addprefix $(subst _,/,$(MODULE))/,$(filter %.asm,$(ASM_source)))
|
||||
C_source :=
|
||||
ASM_source :=
|
||||
|
||||
OBJS-$(MODULE) := $(C_source-$(MODULE):.c=.o)
|
||||
OBJS-$(MODULE) += $(ASM_source-$(MODULE):.asm=.o)
|
||||
|
||||
$(MODULE): $(OBJS-$(MODULE))
|
||||
|
||||
$(NAME).elf: $(OBJS-$(MODULE))
|
||||
|
||||
clean: clean-$(MODULE)
|
||||
clean-$(MODULE): clean-% :
|
||||
@echo Cleaning $(subst _,/,$*)
|
||||
$Q$(RM) $(OBJS-$*) $(C_source-$*:.c=.dep)
|
||||
|
||||
.PHONY: clean-$(MODULE) $(MODULE)
|
||||
|
||||
-include $(C_source-$(MODULE):.c=.dep)
|
167
hermit/arch/x86/include/asm/atomic.h
Normal file
167
hermit/arch/x86/include/asm/atomic.h
Normal file
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/atomic.h
|
||||
* @brief Functions for atomic operations
|
||||
*
|
||||
* This file defines functions for atomic operations on int32 variables
|
||||
* which will be used in locking-mechanisms.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ATOMIC_H__
|
||||
#define __ARCH_ATOMIC_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MAX_CORES > 1
|
||||
#define LOCK "lock ; "
|
||||
#else
|
||||
#define LOCK ""
|
||||
#endif
|
||||
|
||||
/** @brief Makro for initialization of atomic_int32_t vars
|
||||
*
|
||||
* Whenever you use an atomic_int32_t variable, init it with
|
||||
* this macro first.\n
|
||||
* Example: atomic_int32_t myAtomicVar = ATOMIC_INIT(123);
|
||||
*
|
||||
* @param i The number value you want to init it with.
|
||||
*/
|
||||
#define ATOMIC_INIT(i) { (i) }
|
||||
|
||||
/** @brief Standard-datatype for atomic operations
|
||||
*
|
||||
* It just consists of an int32_t variable internally, marked as volatile.
|
||||
*/
|
||||
typedef struct { volatile int32_t counter; } atomic_int32_t;
|
||||
|
||||
/** @brief Atomic test and set operation for int32 vars.
|
||||
*
|
||||
* This function will atomically exchange the value of an atomic variable and
|
||||
* return its old value. Is used in locking-operations.\n
|
||||
* \n
|
||||
* Intel manuals: If a memory operand is referenced, the processor's locking
|
||||
* protocol is automatically implemented for the duration of the exchange
|
||||
* operation, regardless of the presence or absence of the LOCK prefix.
|
||||
*
|
||||
* @param d Pointer to the atomic_int_32_t with the value you want to exchange
|
||||
* @param ret the value you want the var test for
|
||||
*
|
||||
* @return The old value of the atomic_int_32_t var before exchange
|
||||
*/
|
||||
inline static int32_t atomic_int32_test_and_set(atomic_int32_t* d, int32_t ret)
|
||||
{
|
||||
asm volatile ("xchgl %0, %1" : "=r"(ret) : "m"(d->counter), "0"(ret) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Atomic addition of values to atomic_int32_t vars
|
||||
*
|
||||
* This function lets you add values in an atomic operation
|
||||
*
|
||||
* @param d Pointer to the atomit_int32_t var you want do add a value to
|
||||
* @param i The value you want to increment by
|
||||
*
|
||||
* @return The mathematical result
|
||||
*/
|
||||
inline static int32_t atomic_int32_add(atomic_int32_t *d, int32_t i)
|
||||
{
|
||||
int32_t res = i;
|
||||
asm volatile(LOCK "xaddl %0, %1" : "=r"(i) : "m"(d->counter), "0"(i) : "memory", "cc");
|
||||
return res+i;
|
||||
}
|
||||
|
||||
/** @brief Atomic subtraction of values from atomic_int32_t vars
|
||||
*
|
||||
* This function lets you subtract values in an atomic operation.\n
|
||||
* This function is just for convenience. It uses atomic_int32_add(d, -i)
|
||||
*
|
||||
* @param d Pointer to the atomic_int32_t var you want to subtract from
|
||||
* @param i The value you want to subtract by
|
||||
*
|
||||
* @return The mathematical result
|
||||
*/
|
||||
inline static int32_t atomic_int32_sub(atomic_int32_t *d, int32_t i)
|
||||
{
|
||||
return atomic_int32_add(d, -i);
|
||||
}
|
||||
|
||||
/** @brief Atomic increment by one
|
||||
*
|
||||
* The atomic_int32_t var will be atomically incremented by one.\n
|
||||
*
|
||||
* @param d The atomic_int32_t var you want to increment
|
||||
*/
|
||||
inline static int32_t atomic_int32_inc(atomic_int32_t* d) {
|
||||
return atomic_int32_add(d, 1);
|
||||
}
|
||||
|
||||
/** @brief Atomic decrement by one
|
||||
*
|
||||
* The atomic_int32_t var will be atomically decremented by one.\n
|
||||
*
|
||||
* @param d The atomic_int32_t var you want to decrement
|
||||
*/
|
||||
inline static int32_t atomic_int32_dec(atomic_int32_t* d) {
|
||||
return atomic_int32_add(d, -1);
|
||||
}
|
||||
|
||||
/** @brief Read out an atomic_int32_t var
|
||||
*
|
||||
* This function is for convenience: It looks into the atomic_int32_t struct
|
||||
* and returns the internal value for you.
|
||||
*
|
||||
* @param d Pointer to the atomic_int32_t var you want to read out
|
||||
* @return It's number value
|
||||
*/
|
||||
inline static int32_t atomic_int32_read(atomic_int32_t *d) {
|
||||
return d->counter;
|
||||
}
|
||||
|
||||
/** @brief Set the value of an atomic_int32_t var
|
||||
*
|
||||
* This function is for convenience: It sets the internal value of
|
||||
* an atomic_int32_t var for you.
|
||||
*
|
||||
* @param d Pointer to the atomic_int32_t var you want to set
|
||||
* @param v The value to set
|
||||
*/
|
||||
inline static void atomic_int32_set(atomic_int32_t *d, int32_t v) {
|
||||
atomic_int32_test_and_set(d, v);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
150
hermit/arch/x86/include/asm/gdt.h
Normal file
150
hermit/arch/x86/include/asm/gdt.h
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file arch/x86/include/asm/gdt.h
|
||||
* @brief Definitions and functions related to segmentation
|
||||
* @author Stefan Lankes
|
||||
*
|
||||
* This file defines the interface for segmentation as like structures to describe segments.\n
|
||||
* There are also some other gdt-private functions in the gdt.c file defined.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_GDT_H__
|
||||
#define __ARCH_GDT_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// This segment is a data segment
|
||||
#define GDT_FLAG_DATASEG 0x02
|
||||
/// This segment is a code segment
|
||||
#define GDT_FLAG_CODESEG 0x0a
|
||||
#define GDT_FLAG_TSS 0x09
|
||||
#define GDT_FLAG_TSS_BUSY 0x02
|
||||
|
||||
#define GDT_FLAG_SEGMENT 0x10
|
||||
/// Privilege level: Ring 0
|
||||
#define GDT_FLAG_RING0 0x00
|
||||
/// Privilege level: Ring 1
|
||||
#define GDT_FLAG_RING1 0x20
|
||||
/// Privilege level: Ring 2
|
||||
#define GDT_FLAG_RING2 0x40
|
||||
/// Privilege level: Ring 3
|
||||
#define GDT_FLAG_RING3 0x60
|
||||
/// Segment is present
|
||||
#define GDT_FLAG_PRESENT 0x80
|
||||
/// Segment was accessed
|
||||
#define GDT_FLAG_ACCESSED 0x01
|
||||
/**
|
||||
* @brief Granularity of segment limit
|
||||
* - set: segment limit unit is 4 KB (page size)
|
||||
* - not set: unit is bytes
|
||||
*/
|
||||
#define GDT_FLAG_4K_GRAN 0x80
|
||||
/**
|
||||
* @brief Default operand size
|
||||
* - set: 32 bit
|
||||
* - not set: 16 bit
|
||||
*/
|
||||
#define GDT_FLAG_16_BIT 0x00
|
||||
#define GDT_FLAG_32_BIT 0x40
|
||||
#define GDT_FLAG_64_BIT 0x20
|
||||
|
||||
/** @brief Defines a GDT entry
|
||||
*
|
||||
* A global descriptor table entry consists of:
|
||||
* - 32 bit base address (chunkwise embedded into this structure)
|
||||
* - 20 bit limit
|
||||
*/
|
||||
typedef struct {
|
||||
/// Lower 16 bits of limit range
|
||||
uint16_t limit_low;
|
||||
/// Lower 16 bits of base address
|
||||
uint16_t base_low;
|
||||
/// middle 8 bits of base address
|
||||
uint8_t base_middle;
|
||||
/// Access bits
|
||||
uint8_t access;
|
||||
/// Granularity bits
|
||||
uint8_t granularity;
|
||||
/// Higher 8 bits of base address
|
||||
uint8_t base_high;
|
||||
} __attribute__ ((packed)) gdt_entry_t;
|
||||
|
||||
/** @brief defines the GDT pointer structure
|
||||
*
|
||||
* This structure tells the address and size of the table.
|
||||
*/
|
||||
typedef struct {
|
||||
/// Size of the table in bytes (not the number of entries!)
|
||||
uint16_t limit;
|
||||
/// Address of the table
|
||||
size_t base;
|
||||
} __attribute__ ((packed)) gdt_ptr_t;
|
||||
|
||||
// a TSS descriptor is twice larger than a code/data descriptor
|
||||
#define GDT_ENTRIES (6+1*2)
|
||||
|
||||
#if GDT_ENTRIES > 8192
|
||||
#error Too many GDT entries!
|
||||
#endif
|
||||
|
||||
/** @brief Installs the global descriptor table
|
||||
*
|
||||
* The installation involves the following steps:
|
||||
* - set up the special GDT pointer
|
||||
* - set up the entries in our GDT
|
||||
* - finally call gdt_flush() in our assembler file
|
||||
* in order to tell the processor where the new GDT is
|
||||
* - update the new segment registers
|
||||
*/
|
||||
void gdt_install(void);
|
||||
|
||||
/** @brief Set gate with chosen attributes
|
||||
*/
|
||||
void gdt_set_gate(int num, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran);
|
||||
|
||||
/** @brief Configures and returns a GDT descriptor with chosen attributes
|
||||
*
|
||||
* Just feed this function with address, limit and the flags
|
||||
* you have seen in idt.h
|
||||
*
|
||||
* @return a preconfigured gdt descriptor
|
||||
*/
|
||||
void configure_gdt_entry(gdt_entry_t *dest_entry, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
142
hermit/arch/x86/include/asm/idt.h
Normal file
142
hermit/arch/x86/include/asm/idt.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/idt.h
|
||||
* @brief Definition of IDT flags and functions to set interrupts
|
||||
*
|
||||
* This file contains define-constants for interrupt flags
|
||||
* and installer functions for interrupt gates.\n
|
||||
* See idt.c for structure definitions.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_IDT_H__
|
||||
#define __ARCH_IDT_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
/// This bit shall be set to 0 if the IDT slot is empty
|
||||
#define IDT_FLAG_PRESENT 0x80
|
||||
/// Interrupt can be called from within RING0
|
||||
#define IDT_FLAG_RING0 0x00
|
||||
/// Interrupt can be called from within RING1 and lower
|
||||
#define IDT_FLAG_RING1 0x20
|
||||
/// Interrupt can be called from within RING2 and lower
|
||||
#define IDT_FLAG_RING2 0x40
|
||||
/// Interrupt can be called from within RING3 and lower
|
||||
#define IDT_FLAG_RING3 0x60
|
||||
/// Size of gate is 16 bit
|
||||
#define IDT_FLAG_16BIT 0x00
|
||||
/// Size of gate is 32 bit
|
||||
#define IDT_FLAG_32BIT 0x08
|
||||
/// The entry describes an interrupt gate
|
||||
#define IDT_FLAG_INTTRAP 0x06
|
||||
/// The entry describes a trap gate
|
||||
#define IDT_FLAG_TRAPGATE 0x07
|
||||
/// The entry describes a task gate
|
||||
#define IDT_FLAG_TASKGATE 0x05
|
||||
|
||||
/*
|
||||
* This is not IDT-flag related. It's the segment selectors for kernel code and data.
|
||||
*/
|
||||
#define KERNEL_CODE_SELECTOR 0x08
|
||||
#define KERNEL_DATA_SELECTOR 0x10
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Defines an IDT entry
|
||||
*
|
||||
* This structure defines interrupt descriptor table entries.\n
|
||||
* They consist of the handling function's base address, some flags
|
||||
* and a segment selector.
|
||||
*/
|
||||
typedef struct {
|
||||
/// Handler function's lower 16 address bits
|
||||
uint16_t base_lo;
|
||||
/// Handler function's segment selector.
|
||||
uint16_t sel;
|
||||
/// These bits are reserved by Intel
|
||||
uint8_t always0;
|
||||
/// These 8 bits contain flags. Exact use depends on the type of interrupt gate.
|
||||
uint8_t flags;
|
||||
/// Higher 16 bits of handler function's base address
|
||||
uint16_t base_hi;
|
||||
/// In 64 bit mode, the "highest" 32 bits of the handler function's base address
|
||||
uint32_t base_hi64;
|
||||
/// resvered entries
|
||||
uint32_t reserved;
|
||||
} __attribute__ ((packed)) idt_entry_t;
|
||||
|
||||
/** @brief Defines the idt pointer structure.
|
||||
*
|
||||
* This structure keeps information about
|
||||
* base address and size of the interrupt descriptor table.
|
||||
*/
|
||||
typedef struct {
|
||||
/// Size of the IDT in bytes (not the number of entries!)
|
||||
uint16_t limit;
|
||||
/// Base address of the IDT
|
||||
size_t base;
|
||||
} __attribute__ ((packed)) idt_ptr_t;
|
||||
|
||||
/** @brief Installs IDT
|
||||
*
|
||||
* The installation involves the following steps:
|
||||
* - Set up the IDT pointer
|
||||
* - Set up int 0x80 for syscalls
|
||||
* - process idt_load()
|
||||
*/
|
||||
void idt_install(void);
|
||||
|
||||
/** @brief Set an entry in the IDT
|
||||
*
|
||||
* @param num index in the IDT
|
||||
* @param base base-address of the handler function being installed
|
||||
* @param sel Segment the IDT will use
|
||||
* @param flags Flags this entry will have
|
||||
*/
|
||||
void idt_set_gate(unsigned char num, size_t base, unsigned short sel,
|
||||
unsigned char flags);
|
||||
|
||||
/** @brief Configures and returns a IDT entry with chosen attributes
|
||||
*
|
||||
* Just feed this function with base, selector and the flags
|
||||
* you have seen in idt.h
|
||||
*
|
||||
* @return a preconfigured idt descriptor
|
||||
*/
|
||||
void configure_idt_entry(idt_entry_t *dest_entry, size_t base,
|
||||
unsigned short sel, unsigned char flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
108
hermit/arch/x86/include/asm/io.h
Normal file
108
hermit/arch/x86/include/asm/io.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/io.h
|
||||
* @brief Functions related to processor IO
|
||||
*
|
||||
* This file contains inline functions for processor IO operations.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_IO_H__
|
||||
#define __ARCH_IO_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Read a byte from an IO port
|
||||
*
|
||||
* @param _port The port you want to read from
|
||||
* @return The value which reads out from this port
|
||||
*/
|
||||
inline static unsigned char inportb(unsigned short _port) {
|
||||
unsigned char rv;
|
||||
asm volatile("inb %1, %0":"=a"(rv):"dN"(_port));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** @brief Read a word (2 byte) from an IO port
|
||||
*
|
||||
* @param _port The port you want to read from
|
||||
* @return The value which reads out from this port
|
||||
*/
|
||||
inline static unsigned short inportw(unsigned short _port) {
|
||||
unsigned short rv;
|
||||
asm volatile("inw %1, %0":"=a"(rv):"dN"(_port));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** @brief Read a double word (4 byte) from an IO port
|
||||
*
|
||||
* @param _port The port you want to read from
|
||||
* @return The value which reads out from this port
|
||||
*/
|
||||
inline static unsigned int inportl(unsigned short _port) {
|
||||
unsigned int rv;
|
||||
asm volatile("inl %1, %0":"=a"(rv):"dN"(_port));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** @brief Write a byte to an IO port
|
||||
*
|
||||
* @param _port The port you want to write to
|
||||
* @param _data the 1 byte value you want to write
|
||||
*/
|
||||
inline static void outportb(unsigned short _port, unsigned char _data) {
|
||||
asm volatile("outb %1, %0"::"dN"(_port), "a"(_data));
|
||||
}
|
||||
|
||||
/** @brief Write a word (2 bytes) to an IO port
|
||||
*
|
||||
* @param _port The port you want to write to
|
||||
* @param _data the 2 byte value you want to write
|
||||
*/
|
||||
inline static void outportw(unsigned short _port, unsigned short _data) {
|
||||
asm volatile("outw %1, %0"::"dN"(_port), "a"(_data));
|
||||
}
|
||||
|
||||
/** @brief Write a double word (4 bytes) to an IO port
|
||||
*
|
||||
* @param _port The port you want to write to
|
||||
* @param _data the 4 byte value you want to write
|
||||
*/
|
||||
inline static void outportl(unsigned short _port, unsigned int _data)
|
||||
{
|
||||
asm volatile("outl %1, %0"::"dN"(_port), "a"(_data));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
80
hermit/arch/x86/include/asm/irq.h
Normal file
80
hermit/arch/x86/include/asm/irq.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/irq.h
|
||||
* @brief Functions related to IRQs
|
||||
*
|
||||
* This file contains functions and a pointer type related to interrupt requests.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_IRQ_H__
|
||||
#define __ARCH_IRQ_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
//#include <hermit/tasks_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Pointer-type to IRQ-handling functions
|
||||
*
|
||||
* Whenever you write a IRQ-handling function it has to match this signature.
|
||||
*/
|
||||
typedef void (*irq_handler_t)(struct state *);
|
||||
|
||||
/** @brief Install a custom IRQ handler for a given IRQ
|
||||
*
|
||||
* @param irq The desired irq
|
||||
* @param handler The handler to install
|
||||
*/
|
||||
int irq_install_handler(unsigned int irq, irq_handler_t handler);
|
||||
|
||||
/** @brief Clear the handler for a given IRQ
|
||||
*
|
||||
* @param irq The handler's IRQ
|
||||
*/
|
||||
int irq_uninstall_handler(unsigned int irq);
|
||||
|
||||
/** @brief Procedure to initialize IRQ
|
||||
*
|
||||
* This procedure is just a small collection of calls:
|
||||
* - idt_install();
|
||||
* - isrs_install();
|
||||
* - irq_install();
|
||||
*
|
||||
* @return Just returns 0 in any case
|
||||
*/
|
||||
int irq_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
105
hermit/arch/x86/include/asm/irqflags.h
Normal file
105
hermit/arch/x86/include/asm/irqflags.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/irqflags.h
|
||||
* @brief Functions related to IRQ configuration
|
||||
*
|
||||
* This file contains definitions of inline functions
|
||||
* for enabling and disabling IRQ handling.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_IRQFLAGS_H__
|
||||
#define __ARCH_IRQFLAGS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Disable IRQs
|
||||
*
|
||||
* This inline function just clears out the interrupt bit
|
||||
*/
|
||||
inline static void irq_disable(void) {
|
||||
asm volatile("cli" ::: "memory");
|
||||
}
|
||||
|
||||
/** @brief Disable IRQs (nested)
|
||||
*
|
||||
* Disable IRQs when unsure if IRQs were enabled at all.\n
|
||||
* This function together with irq_nested_enable can be used
|
||||
* in situations when interrupts shouldn't be activated if they
|
||||
* were not activated before calling this function.
|
||||
*
|
||||
* @return The set of flags which have been set until now
|
||||
*/
|
||||
inline static uint8_t irq_nested_disable(void) {
|
||||
size_t flags;
|
||||
asm volatile("pushf; cli; pop %0": "=r"(flags) : : "memory");
|
||||
if (flags & (1 << 9))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Enable IRQs */
|
||||
inline static void irq_enable(void) {
|
||||
asm volatile("sti" ::: "memory");
|
||||
}
|
||||
|
||||
/** @brief Enable IRQs (nested)
|
||||
*
|
||||
* If called after calling irq_nested_disable, this function will
|
||||
* not activate IRQs if they were not active before.
|
||||
*
|
||||
* @param flags Flags to set. Could be the old ones you got from irq_nested_disable.
|
||||
*/
|
||||
inline static void irq_nested_enable(uint8_t flags) {
|
||||
if (flags)
|
||||
irq_enable();
|
||||
}
|
||||
|
||||
/** @brief Determines, if the interrupt flags (IF) is ser
|
||||
*
|
||||
* @return
|
||||
* - 1 interrupt flag is set
|
||||
* - 0 interrupt flag is cleared
|
||||
*/
|
||||
inline static uint8_t is_irq_enabled(void)
|
||||
{
|
||||
size_t flags;
|
||||
asm volatile("pushf; pop %0": "=r"(flags) : : "memory");
|
||||
if (flags & (1 << 9))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
59
hermit/arch/x86/include/asm/isrs.h
Normal file
59
hermit/arch/x86/include/asm/isrs.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/isrs.h
|
||||
* @brief Installation of interrupt service routines
|
||||
*
|
||||
* This file contains the declaration of the ISR installer procedure.\n
|
||||
* There is more interesting code related to ISRs in the isrs.c file.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ISRS_H__
|
||||
#define __ARCH_ISRS_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief ISR installer procedure
|
||||
*
|
||||
* This procedure sets the first 32 entries in the IDT
|
||||
* to the first 32 ISRs to call one general fault handler
|
||||
* which will do some dispatching and exception message logging.\n
|
||||
* The access flags are set to 0x8E (PRESENT, privilege: RING0, size: 32bit gate, type: interrupt gate).
|
||||
*/
|
||||
void isrs_install(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
87
hermit/arch/x86/include/asm/limits.h
Normal file
87
hermit/arch/x86/include/asm/limits.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* author Stefan Lankes
|
||||
* @file arch/x86/include/asm/limits.h
|
||||
* @brief Define constants related to numerical value-ranges of variable types
|
||||
*
|
||||
* This file contains define constants for the numerical
|
||||
* ranges of the most typical variable types.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_LIMITS_H__
|
||||
#define __ARCH_LIMITS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Number of bits in a char */
|
||||
#define CHAR_BIT 8
|
||||
|
||||
/** Maximum value for a signed char */
|
||||
#define SCHAR_MAX 0x7f
|
||||
/** Minimum value for a signed char */
|
||||
#define SCHAR_MIN (-0x7f - 1)
|
||||
|
||||
/** Maximum value for an unsigned char */
|
||||
#define UCHAR_MAX 0xff
|
||||
|
||||
/** Maximum value for an unsigned short */
|
||||
#define USHRT_MAX 0xffff
|
||||
/** Maximum value for a short */
|
||||
#define SHRT_MAX 0x7fff
|
||||
/** Minimum value for a short */
|
||||
#define SHRT_MIN (-0x7fff - 1)
|
||||
|
||||
/** Maximum value for an unsigned int */
|
||||
#define UINT_MAX 0xffffffffU
|
||||
/** Maximum value for an int */
|
||||
#define INT_MAX 0x7fffffff
|
||||
/** Minimum value for an int */
|
||||
#define INT_MIN (-0x7fffffff - 1)
|
||||
|
||||
/** Maximum value for an unsigned long */
|
||||
#define ULONG_MAX 0xffffffffUL
|
||||
/** Maximum value for a long */
|
||||
#define LONG_MAX 0x7fffffffL
|
||||
/** Minimum value for a long */
|
||||
#define LONG_MIN (-0x7fffffffL - 1)
|
||||
|
||||
/** Maximum value for an unsigned long long */
|
||||
#define ULLONG_MAX 0xffffffffffffffffULL
|
||||
/** Maximum value for a long long */
|
||||
#define LLONG_MAX 0x7fffffffffffffffLL
|
||||
/** Minimum value for a long long */
|
||||
#define LLONG_MIN (-0x7fffffffffffffffLL - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
159
hermit/arch/x86/include/asm/multiboot.h
Normal file
159
hermit/arch/x86/include/asm/multiboot.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/multiboot.h
|
||||
* @brief Structures related to the Multiboot interface
|
||||
*
|
||||
* HermitCore is able to use Multiboot (http://www.gnu.org/software/grub/manual/multiboot/),
|
||||
* which specifies an interface between a boot loader and a operating system.\n
|
||||
* \n
|
||||
* This file contains several structures needed to match the interface.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_MULTIBOOT_H__
|
||||
#define __ARCH_MULTIBOOT_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
/// Does the bootloader provide mem_* fields?
|
||||
#define MULTIBOOT_INFO_MEM (1 << 0)
|
||||
/// Does the bootloader provide the command-line?
|
||||
#define MULTIBOOT_INFO_CMDLINE (1 << 2)
|
||||
/// Does the bootloader provide a list of modules?
|
||||
#define MULTIBOOT_INFO_MODS (1 << 3)
|
||||
/// Does the bootloader provide a full memory map?
|
||||
#define MULTIBOOT_INFO_MEM_MAP (1 << 6)
|
||||
|
||||
typedef uint16_t multiboot_uint16_t;
|
||||
typedef uint32_t multiboot_uint32_t;
|
||||
typedef uint64_t multiboot_uint64_t;
|
||||
|
||||
/* The symbol table for a.out. */
|
||||
struct multiboot_aout_symbol_table
|
||||
{
|
||||
multiboot_uint32_t tabsize;
|
||||
multiboot_uint32_t strsize;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t reserved;
|
||||
};
|
||||
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
|
||||
|
||||
/* The section header table for ELF. */
|
||||
struct multiboot_elf_section_header_table
|
||||
{
|
||||
multiboot_uint32_t num;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t shndx;
|
||||
};
|
||||
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
|
||||
|
||||
struct multiboot_info
|
||||
{
|
||||
/** Multiboot info version number */
|
||||
multiboot_uint32_t flags;
|
||||
|
||||
/** Available memory from BIOS */
|
||||
multiboot_uint32_t mem_lower;
|
||||
multiboot_uint32_t mem_upper;
|
||||
|
||||
/** "root" partition */
|
||||
multiboot_uint32_t boot_device;
|
||||
|
||||
/** Kernel command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/** Boot-Module list */
|
||||
multiboot_uint32_t mods_count;
|
||||
multiboot_uint32_t mods_addr;
|
||||
|
||||
union
|
||||
{
|
||||
multiboot_aout_symbol_table_t aout_sym;
|
||||
multiboot_elf_section_header_table_t elf_sec;
|
||||
} u;
|
||||
|
||||
/** Memory Mapping buffer */
|
||||
multiboot_uint32_t mmap_length;
|
||||
multiboot_uint32_t mmap_addr;
|
||||
|
||||
/** Drive Info buffer */
|
||||
multiboot_uint32_t drives_length;
|
||||
multiboot_uint32_t drives_addr;
|
||||
|
||||
/** ROM configuration table */
|
||||
multiboot_uint32_t config_table;
|
||||
|
||||
/** Boot Loader Name */
|
||||
multiboot_uint32_t boot_loader_name;
|
||||
|
||||
/** APM table */
|
||||
multiboot_uint32_t apm_table;
|
||||
|
||||
/** Video */
|
||||
multiboot_uint32_t vbe_control_info;
|
||||
multiboot_uint32_t vbe_mode_info;
|
||||
multiboot_uint16_t vbe_mode;
|
||||
multiboot_uint16_t vbe_interface_seg;
|
||||
multiboot_uint16_t vbe_interface_off;
|
||||
multiboot_uint16_t vbe_interface_len;
|
||||
};
|
||||
|
||||
typedef struct multiboot_info multiboot_info_t;
|
||||
|
||||
struct multiboot_mmap_entry
|
||||
{
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint64_t addr;
|
||||
multiboot_uint64_t len;
|
||||
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||
multiboot_uint32_t type;
|
||||
} __attribute__((packed));
|
||||
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
|
||||
|
||||
struct multiboot_mod_list
|
||||
{
|
||||
/** the memory used goes from bytes ’mod start’ to ’mod end-1’ inclusive */
|
||||
multiboot_uint32_t mod_start;
|
||||
multiboot_uint32_t mod_end;
|
||||
|
||||
/** Module command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/** padding to take it to 16 bytes (must be zero) */
|
||||
multiboot_uint32_t pad;
|
||||
};
|
||||
typedef struct multiboot_mod_list multiboot_module_t;
|
||||
|
||||
/// Pointer to multiboot structure
|
||||
/// This pointer is declared at set by entry.asm
|
||||
extern multiboot_info_t* mb_info;
|
||||
|
||||
#endif
|
193
hermit/arch/x86/include/asm/page.h
Normal file
193
hermit/arch/x86/include/asm/page.h
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* 2014, Steffen Vogel, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Steffen Vogel
|
||||
* @file arch/x86/include/asm/page.h
|
||||
* @brief Paging related functions
|
||||
*
|
||||
* This file contains the several functions to manage the page tables
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdlib.h>
|
||||
|
||||
#ifndef __PAGE_H__
|
||||
#define __PAGE_H__
|
||||
|
||||
/// Page offset bits
|
||||
#define PAGE_BITS 12
|
||||
/// The size of a single page in bytes
|
||||
#define PAGE_SIZE ( 1L << PAGE_BITS)
|
||||
/// Mask the page address without page map flags and XD flag
|
||||
#if 0
|
||||
#define PAGE_MASK (-1L << PAGE_BITS)
|
||||
#else
|
||||
#define PAGE_MASK ((-1L << PAGE_BITS) & ~PG_XD)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/// Total operand width in bits
|
||||
#define BITS 32
|
||||
/// Physical address width (we dont support PAE)
|
||||
#define PHYS_BITS BITS
|
||||
/// Linear/virtual address width
|
||||
#define VIRT_BITS BITS
|
||||
/// Page map bits
|
||||
#define PAGE_MAP_BITS 10
|
||||
/// Number of page map indirections
|
||||
#define PAGE_LEVELS 2
|
||||
#else
|
||||
/// Total operand width in bits
|
||||
#define BITS 64
|
||||
/// Physical address width (maximum value)
|
||||
#define PHYS_BITS 52
|
||||
/// Linear/virtual address width
|
||||
#define VIRT_BITS 48
|
||||
/// Page map bits
|
||||
#define PAGE_MAP_BITS 9
|
||||
/// Number of page map indirections
|
||||
#define PAGE_LEVELS 4
|
||||
|
||||
/** @brief Sign extending a integer
|
||||
*
|
||||
* @param addr The integer to extend
|
||||
* @param bits The width if addr which should be extended
|
||||
* @return The extended integer
|
||||
*/
|
||||
static inline size_t sign_extend(ssize_t addr, int bits)
|
||||
{
|
||||
int shift = BITS - bits;
|
||||
return (addr << shift) >> shift; // sign bit gets copied during arithmetic right shift
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Make address canonical
|
||||
#if 0
|
||||
#define CANONICAL(addr) (addr) // only for 32 bit paging
|
||||
#else
|
||||
#define CANONICAL(addr) sign_extend(addr, VIRT_BITS)
|
||||
#endif
|
||||
|
||||
/// The number of entries in a page map table
|
||||
#define PAGE_MAP_ENTRIES (1L << PAGE_MAP_BITS)
|
||||
|
||||
/// Align to next page
|
||||
#define PAGE_FLOOR(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
|
||||
/// Align to page
|
||||
#define PAGE_CEIL(addr) ( (addr) & PAGE_MASK)
|
||||
|
||||
/// Page is present
|
||||
#define PG_PRESENT (1 << 0)
|
||||
/// Page is read- and writable
|
||||
#define PG_RW (1 << 1)
|
||||
/// Page is addressable from userspace
|
||||
#define PG_USER (1 << 2)
|
||||
/// Page write through is activated
|
||||
#define PG_PWT (1 << 3)
|
||||
/// Page cache is disabled
|
||||
#define PG_PCD (1 << 4)
|
||||
/// Page was recently accessed (set by CPU)
|
||||
#define PG_ACCESSED (1 << 5)
|
||||
/// Page is dirty due to recent write-access (set by CPU)
|
||||
#define PG_DIRTY (1 << 6)
|
||||
/// Huge page: 4MB (or 2MB, 1GB)
|
||||
#define PG_PSE (1 << 7)
|
||||
/// Page attribute table
|
||||
#define PG_PAT PG_PSE
|
||||
/// Global TLB entry (Pentium Pro and later)
|
||||
#define PG_GLOBAL (1 << 8)
|
||||
/// This table is a self-reference and should skipped by page_map_copy()
|
||||
#define PG_SELF (1 << 9)
|
||||
|
||||
/// Disable execution for this page
|
||||
#define PG_XD (1L << 63)
|
||||
|
||||
/** @brief Converts a virtual address to a physical
|
||||
*
|
||||
* A non mapped virtual address causes a pagefault!
|
||||
*
|
||||
* @param addr Virtual address to convert
|
||||
* @return physical address
|
||||
*/
|
||||
size_t virt_to_phys(size_t vir);
|
||||
|
||||
/** @brief Initialize paging subsystem
|
||||
*
|
||||
* This function uses the existing bootstrap page tables (boot_{pgd, pgt})
|
||||
* to map required regions (video memory, kernel, etc..).
|
||||
* Before calling page_init(), the bootstrap tables contain a simple identity
|
||||
* paging. Which is replaced by more specific mappings.
|
||||
*/
|
||||
int page_init(void);
|
||||
|
||||
/** @brief Map a continuous region of pages
|
||||
*
|
||||
* @param viraddr Desired virtual address
|
||||
* @param phyaddr Physical address to map from
|
||||
* @param npages The region's size in number of pages
|
||||
* @param bits Further page flags
|
||||
* @return
|
||||
*/
|
||||
int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits);
|
||||
|
||||
/** @brief Unmap a continuous region of pages
|
||||
*
|
||||
* @param viraddr The virtual start address
|
||||
* @param npages The range's size in pages
|
||||
* @return
|
||||
*/
|
||||
int page_unmap(size_t viraddr, size_t npages);
|
||||
|
||||
/** @brief Change the page permission in the page tables of the current task
|
||||
*
|
||||
* Applies given flags noted in the 'flags' parameter to
|
||||
* the range denoted by virtual start and end addresses.
|
||||
*
|
||||
* @param start Range's virtual start address
|
||||
* @param end Range's virtual end address
|
||||
* @param flags flags to apply
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure.
|
||||
*/
|
||||
int page_set_flags(size_t viraddr, uint32_t npages, int flags);
|
||||
|
||||
/** @brief Copy a whole page map tree
|
||||
*
|
||||
* @param dest Physical address of new page map
|
||||
* @retval 0 Success. Everything went fine.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int page_map_copy(struct task *dest);
|
||||
|
||||
/** @brief Free a whole page map tree */
|
||||
int page_map_drop(void);
|
||||
|
||||
#endif
|
526
hermit/arch/x86/include/asm/processor.h
Normal file
526
hermit/arch/x86/include/asm/processor.h
Normal file
|
@ -0,0 +1,526 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/processor.h
|
||||
* @brief CPU-specific functions
|
||||
*
|
||||
* This file contains structures and functions related to CPU-specific assembler commands.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_PROCESSOR_H__
|
||||
#define __ARCH_PROCESSOR_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <asm/gdt.h>
|
||||
//#include <asm/apic.h>
|
||||
#include <asm/irqflags.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// feature list 1
|
||||
#define CPU_FEATURE_FPU (1 << 0)
|
||||
#define CPU_FEATUE_PSE (1 << 3)
|
||||
#define CPU_FEATURE_MSR (1 << 5)
|
||||
#define CPU_FEATURE_PAE (1 << 6)
|
||||
#define CPU_FEATURE_APIC (1 << 9)
|
||||
#define CPU_FEATURE_SEP (1 << 11)
|
||||
#define CPU_FEATURE_PGE (1 << 13)
|
||||
#define CPU_FEATURE_PAT (1 << 16)
|
||||
#define CPU_FEATURE_PSE36 (1 << 17)
|
||||
#define CPU_FEATURE_MMX (1 << 23)
|
||||
#define CPU_FEATURE_FXSR (1 << 24)
|
||||
#define CPU_FEATURE_SSE (1 << 25)
|
||||
#define CPU_FEATURE_SSE2 (1 << 26)
|
||||
|
||||
// feature list 2
|
||||
#define CPU_FEATURE_X2APIC (1 << 21)
|
||||
#define CPU_FEATURE_AVX (1 << 28)
|
||||
#define CPU_FEATURE_HYPERVISOR (1 << 31)
|
||||
|
||||
// CPUID.80000001H:EDX feature list
|
||||
#define CPU_FEATURE_SYSCALL (1 << 11)
|
||||
#define CPU_FEATURE_NX (1 << 20)
|
||||
#define CPU_FEATURE_1GBHP (1 << 26)
|
||||
#define CPU_FEATURE_LM (1 << 29)
|
||||
|
||||
// x86 control registers
|
||||
|
||||
/// Protected Mode Enable
|
||||
#define CR0_PE (1 << 0)
|
||||
/// Monitor coprocessor
|
||||
#define CR0_MP (1 << 1)
|
||||
/// Enable FPU emulation
|
||||
#define CR0_EM (1 << 2)
|
||||
/// Task switched
|
||||
#define CR0_TS (1 << 3)
|
||||
/// Extension type of coprocessor
|
||||
#define CR0_ET (1 << 4)
|
||||
/// Enable FPU error reporting
|
||||
#define CR0_NE (1 << 5)
|
||||
/// Enable write protected pages
|
||||
#define CR0_WP (1 << 16)
|
||||
/// Enable alignment checks
|
||||
#define CR0_AM (1 << 18)
|
||||
/// Globally enables/disable write-back caching
|
||||
#define CR0_NW (1 << 29)
|
||||
/// Globally disable memory caching
|
||||
#define CR0_CD (1 << 30)
|
||||
/// Enable paging
|
||||
#define CR0_PG (1 << 31)
|
||||
|
||||
/// Virtual 8086 Mode Extensions
|
||||
#define CR4_VME (1 << 0)
|
||||
/// Protected-mode Virtual Interrupts
|
||||
#define CR4_PVI (1 << 1)
|
||||
/// Disable Time Stamp Counter register (rdtsc instruction)
|
||||
#define CR4_TSD (1 << 2)
|
||||
/// Enable debug extensions
|
||||
#define CR4_DE (1 << 3)
|
||||
/// Enable hugepage support
|
||||
#define CR4_PSE (1 << 4)
|
||||
/// Enable physical address extension
|
||||
#define CR4_PAE (1 << 5)
|
||||
/// Enable machine check exceptions
|
||||
#define CR4_MCE (1 << 6)
|
||||
/// Enable global pages
|
||||
#define CR4_PGE (1 << 7)
|
||||
/// Enable Performance-Monitoring Counter
|
||||
#define CR4_PCE (1 << 8)
|
||||
/// Enable Operating system support for FXSAVE and FXRSTOR instructions
|
||||
#define CR4_OSFXSR (1 << 9)
|
||||
/// Enable Operating System Support for Unmasked SIMD Floating-Point Exceptions
|
||||
#define CR4_OSXMMEXCPT (1 << 10)
|
||||
/// Enable Virtual Machine Extensions, see Intel VT-x
|
||||
#define CR4_VMXE (1 << 13)
|
||||
/// Enable Safer Mode Extensions, see Trusted Execution Technology (TXT)
|
||||
#define CR4_SMXE (1 << 14)
|
||||
/// Enables the instructions RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE
|
||||
#define CR4_FSGSBASE (1 << 16)
|
||||
/// Enables process-context identifiers
|
||||
#define CR4_PCIDE (1 << 17)
|
||||
/// Enable XSAVE and Processor Extended States
|
||||
#define CR4_OSXSAVE (1 << 18)
|
||||
/// Enable Supervisor Mode Execution Protection
|
||||
#define CR4_SMEP (1 << 20)
|
||||
/// Enable Supervisor Mode Access Protection
|
||||
#define CR4_SMAP (1 << 21)
|
||||
|
||||
// x86-64 specific MSRs
|
||||
|
||||
/// APIC register
|
||||
#define MSR_APIC_BASE 0x0000001B
|
||||
/// extended feature register
|
||||
#define MSR_EFER 0xc0000080
|
||||
/// legacy mode SYSCALL target
|
||||
#define MSR_STAR 0xc0000081
|
||||
/// long mode SYSCALL target
|
||||
#define MSR_LSTAR 0xc0000082
|
||||
/// compat mode SYSCALL target
|
||||
#define MSR_CSTAR 0xc0000083
|
||||
/// EFLAGS mask for syscall
|
||||
#define MSR_SYSCALL_MASK 0xc0000084
|
||||
/// 64bit FS base
|
||||
#define MSR_FS_BASE 0xc0000100
|
||||
/// 64bit GS base
|
||||
#define MSR_GS_BASE 0xc0000101
|
||||
/// SwapGS GS shadow
|
||||
#define MSR_KERNEL_GS_BASE 0xc0000102
|
||||
|
||||
// MSR EFER bits
|
||||
#define EFER_SCE (1 << 0)
|
||||
#define EFER_LME (1 << 8)
|
||||
#define EFER_LMA (1 << 10)
|
||||
#define EFER_NXE (1 << 11)
|
||||
#define EFER_SVME (1 << 12)
|
||||
#define EFER_LMSLE (1 << 13)
|
||||
#define EFER_FFXSR (1 << 14)
|
||||
#define EFER_TCE (1 << 15)
|
||||
|
||||
typedef struct {
|
||||
uint32_t feature1, feature2, feature3;
|
||||
uint32_t addr_width;
|
||||
} cpu_info_t;
|
||||
|
||||
extern cpu_info_t cpu_info;
|
||||
|
||||
// determine the cpu features
|
||||
int cpu_detection(void);
|
||||
|
||||
inline static uint32_t has_fpu(void) {
|
||||
return (cpu_info.feature1 & CPU_FEATURE_FPU);
|
||||
}
|
||||
|
||||
inline static uint32_t has_msr(void) {
|
||||
return (cpu_info.feature1 & CPU_FEATURE_MSR);
|
||||
}
|
||||
|
||||
inline static uint32_t has_apic(void) {
|
||||
return (cpu_info.feature1 & CPU_FEATURE_APIC);
|
||||
}
|
||||
|
||||
inline static uint32_t has_fxsr(void) {
|
||||
return (cpu_info.feature1 & CPU_FEATURE_FXSR);
|
||||
}
|
||||
|
||||
inline static uint32_t has_sse(void) {
|
||||
return (cpu_info.feature1 & CPU_FEATURE_SSE);
|
||||
}
|
||||
|
||||
inline static uint32_t has_sse2(void) {
|
||||
return (cpu_info.feature1 & CPU_FEATURE_SSE2);
|
||||
}
|
||||
|
||||
inline static uint32_t has_pge(void)
|
||||
{
|
||||
return (cpu_info.feature1 & CPU_FEATURE_PGE);
|
||||
}
|
||||
|
||||
inline static uint32_t has_sep(void) {
|
||||
return (cpu_info.feature1 & CPU_FEATURE_SEP);
|
||||
}
|
||||
|
||||
inline static uint32_t has_x2apic(void) {
|
||||
return (cpu_info.feature2 & CPU_FEATURE_X2APIC);
|
||||
}
|
||||
|
||||
inline static uint32_t has_avx(void) {
|
||||
return (cpu_info.feature2 & CPU_FEATURE_AVX);
|
||||
}
|
||||
|
||||
inline static uint32_t on_hypervisor(void) {
|
||||
return (cpu_info.feature2 & CPU_FEATURE_HYPERVISOR);
|
||||
}
|
||||
|
||||
inline static uint32_t has_nx(void)
|
||||
{
|
||||
return (cpu_info.feature3 & CPU_FEATURE_NX);
|
||||
}
|
||||
|
||||
/** @brief Read out time stamp counter
|
||||
*
|
||||
* The rdtsc asm command puts a 64 bit time stamp value
|
||||
* into EDX:EAX.
|
||||
*
|
||||
* @return The 64 bit time stamp value
|
||||
*/
|
||||
inline static uint64_t rdtsc(void)
|
||||
{
|
||||
uint64_t lo, hi;
|
||||
asm volatile ("rdtsc" : "=a"(lo), "=d"(hi) );
|
||||
return (hi << 32 | lo);
|
||||
}
|
||||
|
||||
/** @brief Read MSR
|
||||
*
|
||||
* The asm instruction rdmsr which stands for "Read from model specific register"
|
||||
* is used here.
|
||||
*
|
||||
* @param msr The parameter which rdmsr assumes in ECX
|
||||
* @return The value rdmsr put into EDX:EAX
|
||||
*/
|
||||
inline static uint64_t rdmsr(uint32_t msr) {
|
||||
uint32_t low, high;
|
||||
|
||||
asm volatile ("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
|
||||
|
||||
return ((uint64_t)high << 32) | low;
|
||||
}
|
||||
|
||||
/** @brief Write a value to a Machine-Specific Registers (MSR)
|
||||
*
|
||||
* The asm instruction wrmsr which stands for "Write to model specific register"
|
||||
* is used here.
|
||||
*
|
||||
* @param msr The MSR identifier
|
||||
* @param value Value, which will be store in the MSR
|
||||
*/
|
||||
inline static void wrmsr(uint32_t msr, uint64_t value)
|
||||
{
|
||||
uint32_t low = value & 0xFFFFFFFF;
|
||||
uint32_t high = value >> 32;
|
||||
|
||||
asm volatile("wrmsr" :: "a"(low), "c"(msr), "d"(high));
|
||||
}
|
||||
|
||||
/** @brief Read cr0 register
|
||||
* @return cr0's value
|
||||
*/
|
||||
static inline size_t read_cr0(void) {
|
||||
size_t val;
|
||||
asm volatile("mov %%cr0, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/** @brief Write a value into cr0 register
|
||||
* @param val The value you want to write into cr0
|
||||
*/
|
||||
static inline void write_cr0(size_t val) {
|
||||
asm volatile("mov %0, %%cr0" : : "r"(val));
|
||||
}
|
||||
|
||||
/** @brief Read cr2 register
|
||||
* @return cr2's value
|
||||
*/
|
||||
static inline size_t read_cr2(void) {
|
||||
size_t val;
|
||||
asm volatile("mov %%cr2, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/** @brief Write a value into cr2 register
|
||||
* @param val The value you want to write into cr2
|
||||
*/
|
||||
static inline void write_cr2(size_t val) {
|
||||
asm volatile("mov %0, %%cr2" : : "r"(val));
|
||||
}
|
||||
|
||||
/** @brief Read cr3 register
|
||||
* @return cr3's value
|
||||
*/
|
||||
static inline size_t read_cr3(void) {
|
||||
size_t val;
|
||||
asm volatile("mov %%cr3, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/** @brief Write a value into cr3 register
|
||||
* @param val The value you want to write into cr3
|
||||
*/
|
||||
static inline void write_cr3(size_t val) {
|
||||
asm volatile("mov %0, %%cr3" : : "r"(val));
|
||||
}
|
||||
|
||||
/** @brief Read cr4 register
|
||||
* @return cr4's value
|
||||
*/
|
||||
static inline size_t read_cr4(void) {
|
||||
size_t val;
|
||||
asm volatile("mov %%cr4, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/** @brief Write a value into cr4 register
|
||||
* @param val The value you want to write into cr4
|
||||
*/
|
||||
static inline void write_cr4(size_t val) {
|
||||
asm volatile("mov %0, %%cr4" : : "r"(val));
|
||||
}
|
||||
|
||||
/** @brief Flush cache
|
||||
*
|
||||
* The wbinvd asm instruction which stands for "Write back and invalidate"
|
||||
* is used here
|
||||
*/
|
||||
inline static void flush_cache(void) {
|
||||
asm volatile ("wbinvd" ::: "memory");
|
||||
}
|
||||
|
||||
/** @brief Invalidate cache
|
||||
*
|
||||
* The invd asm instruction which invalidates cache without writing back
|
||||
* is used here
|
||||
*/
|
||||
inline static void invalidate_cache(void) {
|
||||
asm volatile ("invd" ::: "memory");
|
||||
}
|
||||
|
||||
/** @brief Flush Translation Lookaside Buffer
|
||||
*
|
||||
* Just reads cr3 and writes the same value back into it.
|
||||
*/
|
||||
static inline void flush_tlb(void)
|
||||
{
|
||||
size_t val = read_cr3();
|
||||
|
||||
if (val)
|
||||
write_cr3(val);
|
||||
}
|
||||
|
||||
/** @brief Flush a specific page entry in TLB
|
||||
* @param addr The (virtual) address of the page to flush
|
||||
*/
|
||||
static inline void tlb_flush_one_page(size_t addr)
|
||||
{
|
||||
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
|
||||
}
|
||||
|
||||
/** @brief Invalidate cache
|
||||
*
|
||||
* The invd asm instruction which invalidates cache without writing back
|
||||
* is used here
|
||||
*/
|
||||
inline static void invalid_cache(void) {
|
||||
asm volatile ("invd");
|
||||
}
|
||||
|
||||
/* Force strict CPU ordering */
|
||||
typedef void (*func_memory_barrier)(void);
|
||||
|
||||
/// Force strict CPU ordering, serializes load and store operations.
|
||||
extern func_memory_barrier mb;
|
||||
/// Force strict CPU ordering, serializes load operations.
|
||||
extern func_memory_barrier rmb;
|
||||
/// Force strict CPU ordering, serializes store operations.
|
||||
extern func_memory_barrier wmb;
|
||||
|
||||
/** @brief Read out CPU ID
|
||||
*
|
||||
* The cpuid asm-instruction does fill some information into registers and
|
||||
* this function fills those register values into the given uint32_t vars.\n
|
||||
*
|
||||
* @param code Input parameter for the cpuid instruction. Take a look into the intel manual.
|
||||
* @param a EAX value will be stores here
|
||||
* @param b EBX value will be stores here
|
||||
* @param c ECX value will be stores here
|
||||
* @param d EDX value will be stores here
|
||||
*/
|
||||
inline static void cpuid(uint32_t code, uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d) {
|
||||
asm volatile ("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "0"(code), "2"(*c));
|
||||
}
|
||||
|
||||
/** @brief Read EFLAGS
|
||||
*
|
||||
* @return The EFLAGS value
|
||||
*/
|
||||
static inline uint32_t read_eflags(void)
|
||||
{
|
||||
uint32_t result;
|
||||
asm volatile ("pushf; pop %0" : "=r"(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @brief search the first most significant bit
|
||||
*
|
||||
* @param i source operand
|
||||
* @return
|
||||
* - first bit, which is set in the source operand
|
||||
* - invalid value, if not bit ist set
|
||||
*/
|
||||
static inline size_t msb(size_t i)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
if (!i)
|
||||
return (sizeof(size_t)*8);
|
||||
asm volatile ("bsr %1, %0" : "=r"(ret) : "r"(i) : "cc");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief search the least significant bit
|
||||
*
|
||||
* @param i source operand
|
||||
* @return
|
||||
* - first bit, which is set in the source operand
|
||||
* - invalid value, if not bit ist set
|
||||
*/
|
||||
static inline size_t lsb(size_t i)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
if (!i)
|
||||
return (sizeof(size_t)*8);
|
||||
asm volatile ("bsf %1, %0" : "=r"(ret) : "r"(i) : "cc");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// A one-instruction-do-nothing
|
||||
#define NOP1 asm volatile ("nop")
|
||||
/// A two-instruction-do-nothing
|
||||
#define NOP2 asm volatile ("nop;nop")
|
||||
/// A four-instruction-do-nothing
|
||||
#define NOP4 asm volatile ("nop;nop;nop;nop")
|
||||
/// A eight-instruction-do-nothing
|
||||
#define NOP8 asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop")
|
||||
/// The PAUSE instruction provides a hint to the processor that the code sequence is a spin-wait loop.
|
||||
#define PAUSE asm volatile ("pause")
|
||||
/// The HALT instruction stops the processor until the next interrupt arrives
|
||||
#define HALT asm volatile ("hlt")
|
||||
|
||||
/** @brief Init several subsystems
|
||||
*
|
||||
* This function calls the initialization procedures for:
|
||||
* - GDT
|
||||
* - APIC
|
||||
* - PCI [if configured]
|
||||
*
|
||||
* @return 0 in any case
|
||||
*/
|
||||
inline static int system_init(void)
|
||||
{
|
||||
gdt_install();
|
||||
cpu_detection();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Detect and read out CPU frequency
|
||||
*
|
||||
* @return The CPU frequency in MHz
|
||||
*/
|
||||
uint32_t detect_cpu_frequency(void);
|
||||
|
||||
/** @brief Read out CPU frequency if detected before
|
||||
*
|
||||
* If you did not issue the detect_cpu_frequency() function before,
|
||||
* this function will call it implicitly.
|
||||
*
|
||||
* @return The CPU frequency in MHz
|
||||
*/
|
||||
uint32_t get_cpu_frequency(void);
|
||||
|
||||
/** @brief Busywait an microseconds interval of time
|
||||
* @param usecs The time to wait in microseconds
|
||||
*/
|
||||
void udelay(uint32_t usecs);
|
||||
|
||||
/** @brief System calibration
|
||||
*
|
||||
* This procedure will detect the CPU frequency and calibrate the APIC timer.
|
||||
*
|
||||
* @return 0 in any case.
|
||||
*/
|
||||
inline static int system_calibration(void)
|
||||
{
|
||||
//apic_init();
|
||||
irq_enable();
|
||||
detect_cpu_frequency();
|
||||
//apic_calibration();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
141
hermit/arch/x86/include/asm/stddef.h
Normal file
141
hermit/arch/x86/include/asm/stddef.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/stddef.h
|
||||
* @brief Standard datatypes
|
||||
*
|
||||
* This file contains typedefs for standard datatypes for numerical and character values.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_STDDEF_H__
|
||||
#define __ARCH_STDDEF_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __SIZEOF_POINTER__ == 4
|
||||
|
||||
#define KERNEL_SPACE (1UL << 30) /* 1 GiB */
|
||||
|
||||
/// This type is used to represent the size of an object.
|
||||
typedef unsigned long size_t;
|
||||
/// Pointer differences
|
||||
typedef long ptrdiff_t;
|
||||
/// It is similar to size_t, but must be a signed type.
|
||||
typedef long ssize_t;
|
||||
/// The type represents an offset and is similar to size_t, but must be a signed type.
|
||||
typedef long off_t;
|
||||
#elif __SIZEOF_POINTER__ == 8
|
||||
|
||||
#define KERNEL_SPACE (1ULL << 30)
|
||||
|
||||
// A popular type for addresses
|
||||
typedef unsigned long long size_t;
|
||||
/// Pointer differences
|
||||
typedef long long ptrdiff_t;
|
||||
#ifdef __KERNEL__
|
||||
typedef long long ssize_t;
|
||||
typedef long long off_t;
|
||||
#endif
|
||||
#else
|
||||
#error unsupported architecture
|
||||
#endif
|
||||
|
||||
/// Unsigned 64 bit integer
|
||||
typedef unsigned long long uint64_t;
|
||||
/// Signed 64 bit integer
|
||||
typedef long long int64_t;
|
||||
/// Unsigned 32 bit integer
|
||||
typedef unsigned int uint32_t;
|
||||
/// Signed 32 bit integer
|
||||
typedef int int32_t;
|
||||
/// Unsigned 16 bit integer
|
||||
typedef unsigned short uint16_t;
|
||||
/// Signed 16 bit integer
|
||||
typedef short int16_t;
|
||||
/// Unsigned 8 bit integer (/char)
|
||||
typedef unsigned char uint8_t;
|
||||
/// Signed 8 bit integer (/char)
|
||||
typedef char int8_t;
|
||||
/// 16 bit wide char type
|
||||
typedef unsigned short wchar_t;
|
||||
|
||||
/// This defines what the stack looks like after the task context is saved.
|
||||
struct state {
|
||||
/// R15 register
|
||||
uint64_t r15;
|
||||
/// R14 register
|
||||
uint64_t r14;
|
||||
/// R13 register
|
||||
uint64_t r13;
|
||||
/// R12 register
|
||||
uint64_t r12;
|
||||
/// R11 register
|
||||
uint64_t r11;
|
||||
/// R10 register
|
||||
uint64_t r10;
|
||||
/// R9 register
|
||||
uint64_t r9;
|
||||
/// R8 register
|
||||
uint64_t r8;
|
||||
/// RDI register
|
||||
uint64_t rdi;
|
||||
/// RSI register
|
||||
uint64_t rsi;
|
||||
/// RBP register
|
||||
uint64_t rbp;
|
||||
/// (pseudo) RSP register
|
||||
uint64_t rsp;
|
||||
/// RBX register
|
||||
uint64_t rbx;
|
||||
/// RDX register
|
||||
uint64_t rdx;
|
||||
/// RCX register
|
||||
uint64_t rcx;
|
||||
/// RAX register
|
||||
uint64_t rax;
|
||||
|
||||
/// Interrupt number
|
||||
uint64_t int_no;
|
||||
|
||||
// pushed by the processor automatically
|
||||
uint64_t error;
|
||||
uint64_t rip;
|
||||
uint64_t cs;
|
||||
uint64_t rflags;
|
||||
uint64_t userrsp;
|
||||
uint64_t ss;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
130
hermit/arch/x86/include/asm/string.h
Normal file
130
hermit/arch/x86/include/asm/string.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Written by the Chair for Operating Systems, RWTH Aachen University
|
||||
*
|
||||
* NO Copyright (C) 2010-2011, Stefan Lankes
|
||||
* consider these trivial functions to be public domain.
|
||||
*
|
||||
* These functions are distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/string.h
|
||||
* @brief Functions related to memcpy and strings.
|
||||
*
|
||||
* This file deals with memcpy, memset, string functions and everything related to
|
||||
* continuous byte fields.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_STRING_H__
|
||||
#define __ARCH_STRING_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_MEMCPY
|
||||
/** @brief Copy a byte range from source to dest
|
||||
*
|
||||
* @param dest Destination address
|
||||
* @param src Source address
|
||||
* @param count Range of the byte field in bytes
|
||||
*/
|
||||
inline static void *memcpy(void* dest, const void *src, size_t count)
|
||||
{
|
||||
size_t i, j, k;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest || !src, 0))
|
||||
return dest;
|
||||
|
||||
asm volatile (
|
||||
"cld; rep movsq\n\t"
|
||||
"movq %4, %%rcx\n\t"
|
||||
"andq $7, %%rcx\n\t"
|
||||
"rep movsb\n\t"
|
||||
: "=&c"(i), "=&D"(j), "=&S"(k)
|
||||
: "0"(count/8), "g"(count), "1"(dest), "2"(src) : "memory","cc");
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_MEMSET
|
||||
/** @brief Repeated write of a value to a whole range of bytes
|
||||
*
|
||||
* @param dest Destination address
|
||||
* @param val Value to flood the range with
|
||||
* @param count Size of target range in bytes
|
||||
*/
|
||||
inline static void *memset(void* dest, int val, size_t count)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest, 0))
|
||||
return dest;
|
||||
|
||||
asm volatile ("cld; rep stosb"
|
||||
: "=&c"(i), "=&D"(j)
|
||||
: "a"(val), "1"(dest), "0"(count) : "memory","cc");
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_STRLEN
|
||||
/** @brief Standard string length
|
||||
*
|
||||
* This function computed the length of the given null terminated string
|
||||
* just like the strlen functions you are used to.
|
||||
*
|
||||
* @return
|
||||
* - The length of the string
|
||||
* - 0 if str is a NULL pointer
|
||||
*/
|
||||
inline static size_t strlen(const char* str)
|
||||
{
|
||||
size_t len = 0;
|
||||
size_t i, j;
|
||||
|
||||
if (BUILTIN_EXPECT(!str, 0))
|
||||
return len;
|
||||
|
||||
asm volatile("not %%rcx; cld; repne scasb; not %%rcx; dec %%rcx"
|
||||
: "=&c"(len), "=&D"(i), "=&a"(j)
|
||||
: "2"(0), "1"(str), "0"(len)
|
||||
: "memory","cc");
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_STRNCPY
|
||||
/** @brief Copy string with maximum of n byte length
|
||||
*
|
||||
* @param dest Destination string pointer
|
||||
* @param src Source string pointer
|
||||
* @param n maximum number of bytes to copy
|
||||
*/
|
||||
char* strncpy(char* dest, const char* src, size_t n);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_STRCPY
|
||||
/** @brief Copy string
|
||||
*
|
||||
* Note that there is another safer variant of this function: strncpy.\n
|
||||
* That one could save you from accidents with buffer overruns.
|
||||
*
|
||||
* @param dest Destination string pointer
|
||||
* @param src Source string pointer
|
||||
*/
|
||||
char* strcpy(char* dest, const char* src);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
94
hermit/arch/x86/include/asm/syscall.h
Normal file
94
hermit/arch/x86/include/asm/syscall.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/syscall.h
|
||||
* @brief Systemcall related code
|
||||
*
|
||||
* This file defines the syscall function and convenience
|
||||
* based macro definitions for calling it.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_SYSCALL_H__
|
||||
#define __ARCH_SYSCALL_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _STR(token) #token
|
||||
#define _SYSCALLSTR(x) "int $" _STR(x) " "
|
||||
|
||||
/** @brief the syscall function which issues an interrupt to the kernel
|
||||
*
|
||||
* It's supposed to be used by the macros defined in this file as the could would read
|
||||
* cleaner then.
|
||||
*
|
||||
* @param nr System call number
|
||||
* @param arg0 Argument 0
|
||||
* @param arg1 Argument 1
|
||||
* @param arg2 Argument 2
|
||||
* @param arg3 Argument 3
|
||||
* @param arg4 Argument 4
|
||||
* @return The return value of the system call
|
||||
*/
|
||||
inline static long
|
||||
syscall(int nr, unsigned long arg0, unsigned long arg1, unsigned long arg2,
|
||||
unsigned long arg3, unsigned long arg4)
|
||||
{
|
||||
long res;
|
||||
|
||||
asm volatile ("mov %5, %%r8; mov %6, %%r9; syscall"
|
||||
: "=a" (res)
|
||||
: "D" (nr), "S" (arg0), "d" (arg1), "c" (arg2), "m" (arg3), "m" (arg4)
|
||||
: "memory", "cc", "%r8", "%r9");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// System call macro with one single argument; the syscall number
|
||||
#define SYSCALL0(NR) \
|
||||
syscall(NR, 0, 0, 0, 0, 0)
|
||||
#define SYSCALL1(NR, ARG0) \
|
||||
syscall(NR, (unsigned long)ARG0, 0, 0, 0, 0)
|
||||
#define SYSCALL2(NR, ARG0, ARG1) \
|
||||
syscall(NR, (unsigned long)ARG0, (unsigned long)ARG1, 0, 0, 0)
|
||||
#define SYSCALL3(NR, ARG0, ARG1, ARG2) \
|
||||
syscall(NR, (unsigned long)ARG0, (unsigned long)ARG1, (unsigned long)ARG2, 0, 0)
|
||||
#define SYSCALL4(NR, ARG0, ARG1, ARG2, ARG3) \
|
||||
syscall(NR, (unsigned long)ARG0, (unsigned long)ARG1, (unsigned long)ARG2, (unsigned long) ARG3, 0)
|
||||
#define SYSCALL5(NR, ARG0, ARG1, ARG2, ARG3, ARG4) \
|
||||
syscall(NR, (unsigned long)ARG0, (unsigned long)ARG1, (unsigned long)ARG2, (unsigned long) ARG3, (unsigned long) ARG4)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
102
hermit/arch/x86/include/asm/tasks.h
Normal file
102
hermit/arch/x86/include/asm/tasks.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/tasks.h
|
||||
* @brief Task related structure definitions
|
||||
*
|
||||
* This file contains the task_t structure definition
|
||||
* and task state define constants
|
||||
*/
|
||||
|
||||
#ifndef __ASM_TASKS_H__
|
||||
#define __ASM_TASKS_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Switch to current task
|
||||
*
|
||||
* @param stack Pointer to the old stack pointer
|
||||
*/
|
||||
void switch_context(size_t** stack);
|
||||
|
||||
/** @brief Setup a default frame for a new task
|
||||
*
|
||||
* @param task Pointer to the task structure
|
||||
* @param ep The entry point for code execution
|
||||
* @param arg Arguments list pointer for the task's stack
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int create_default_frame(task_t* task, entry_point_t ep, void* arg);
|
||||
|
||||
/** @brief Register a task's TSS at GDT
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
*/
|
||||
static inline int register_task(void)
|
||||
{
|
||||
uint16_t sel = 6 << 3;
|
||||
|
||||
asm volatile ("ltr %%ax" : : "a"(sel));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Jump to user code
|
||||
*
|
||||
* This function runs the user code after stopping it just as if
|
||||
* it was a return from a procedure.
|
||||
*
|
||||
* @return 0 in any case
|
||||
*/
|
||||
static inline int jump_to_user_code(size_t ep, size_t stack)
|
||||
{
|
||||
// Create a pseudo interrupt on the stack and return to user function
|
||||
size_t ds = 0x23, cs = 0x2b;
|
||||
|
||||
// x86_64 doesn't longer use segment registers
|
||||
//asm volatile ("mov %0, %%ds; mov %0, %%es" :: "r"(ds));
|
||||
asm volatile ("push %0; push %1; pushfq; push %2; push %3" :: "r"(ds), "r"(stack), "r"(cs), "r"(ep));
|
||||
asm volatile ("iretq");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
94
hermit/arch/x86/include/asm/tasks_types.h
Normal file
94
hermit/arch/x86/include/asm/tasks_types.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/tasks_types.h
|
||||
* @brief Task related structure definitions
|
||||
*
|
||||
* This file contains the task_t structure definition
|
||||
* and task state define constants
|
||||
*/
|
||||
|
||||
#ifndef __ASM_TASKS_TYPES_H__
|
||||
#define __ASM_TASKS_TYPES_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
long cwd;
|
||||
long swd;
|
||||
long twd;
|
||||
long fip;
|
||||
long fcs;
|
||||
long foo;
|
||||
long fos;
|
||||
long st_space[20];
|
||||
long status;
|
||||
} i387_fsave_t;
|
||||
|
||||
typedef struct i387_fxsave_struct {
|
||||
unsigned short cwd;
|
||||
unsigned short swd;
|
||||
unsigned short twd;
|
||||
unsigned short fop;
|
||||
long fip;
|
||||
long fcs;
|
||||
long foo;
|
||||
long fos;
|
||||
long mxcsr;
|
||||
long mxcsr_mask;
|
||||
long st_space[32];
|
||||
long xmm_space[64];
|
||||
long padding[12];
|
||||
union {
|
||||
long padding1[12];
|
||||
long sw_reserved[12];
|
||||
};
|
||||
} i387_fxsave_t __attribute__ ((aligned (16)));
|
||||
|
||||
union fpu_state {
|
||||
i387_fsave_t fsave;
|
||||
i387_fxsave_t fxsave;
|
||||
};
|
||||
|
||||
typedef void (*handle_fpu_state)(union fpu_state* state);
|
||||
|
||||
extern handle_fpu_state save_fpu_state;
|
||||
extern handle_fpu_state restore_fpu_state;
|
||||
extern handle_fpu_state fpu_init;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
66
hermit/arch/x86/include/asm/tss.h
Normal file
66
hermit/arch/x86/include/asm/tss.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/tss.h
|
||||
* @brief Task state segment structure definition
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_TSS_H__
|
||||
#define __ARCH_TSS_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief The tast state segment structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t res0, res1; // reserved entries
|
||||
uint64_t rsp0;
|
||||
uint64_t rsp1;
|
||||
uint64_t rsp2;
|
||||
uint32_t res2, res3; // reserved entries
|
||||
uint64_t ist_rsp1;
|
||||
uint64_t ist_rsp2;
|
||||
uint64_t ist_rsp3;
|
||||
uint64_t ist_rsp4;
|
||||
uint64_t ist_rsp5;
|
||||
uint64_t ist_rsp6;
|
||||
uint64_t ist_rsp7;
|
||||
uint32_t res4, res5; // reserved entries
|
||||
uint16_t res6, bitmap;
|
||||
} __attribute__ ((packed)) tss_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
67
hermit/arch/x86/include/asm/vga.h
Normal file
67
hermit/arch/x86/include/asm/vga.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/vga.h
|
||||
* @brief VGA output related code
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_VGA_H__
|
||||
#define __ARCH_VGA_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Initialize VGA output and clear the screen */
|
||||
void vga_init(void);
|
||||
|
||||
/** @brief Simple string output on screen.
|
||||
*
|
||||
* If you want a new line you will have to "\\n".
|
||||
*
|
||||
* @return Length of output in bytes
|
||||
*/
|
||||
int vga_puts(const char *text);
|
||||
|
||||
/** @brief Simple character output on screen.
|
||||
*
|
||||
* @return The original input character casted to int
|
||||
*/
|
||||
int vga_putchar(unsigned char c);
|
||||
|
||||
/** @brief Clear the screen */
|
||||
void vga_cls(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
5
hermit/arch/x86/kernel/Makefile
Normal file
5
hermit/arch/x86/kernel/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
C_source := irq.c idt.c isrs.c gdt.c processor.c timer.c tasks.c vga.c
|
||||
ASM_source := entry.asm string.asm
|
||||
MODULE := arch_x86_kernel
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
544
hermit/arch/x86/kernel/entry.asm
Normal file
544
hermit/arch/x86/kernel/entry.asm
Normal file
|
@ -0,0 +1,544 @@
|
|||
|
||||
; Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the University nor the names of its contributors
|
||||
; may be used to endorse or promote products derived from this software
|
||||
; without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
; This is the kernel's entry point. We could either call main here,
|
||||
; or we can use this to setup the stack or other nice stuff, like
|
||||
; perhaps setting up the GDT and segments. Please note that interrupts
|
||||
; are disabled at this point: More on interrupts later!
|
||||
|
||||
%include "config.inc"
|
||||
|
||||
[BITS 32]
|
||||
|
||||
extern kernel_start ; defined in linker script
|
||||
extern kernel_end
|
||||
|
||||
; We use a special name to map this section at the begin of our kernel
|
||||
; => Multiboot expects its magic number at the beginning of the kernel.
|
||||
SECTION .mboot
|
||||
global start
|
||||
start:
|
||||
jmp stublet
|
||||
|
||||
; This part MUST be 4 byte aligned, so we solve that issue using 'ALIGN 4'.
|
||||
ALIGN 4
|
||||
mboot:
|
||||
; Multiboot macros to make a few lines more readable later
|
||||
MULTIBOOT_PAGE_ALIGN equ (1 << 0)
|
||||
MULTIBOOT_MEMORY_INFO equ (1 << 1)
|
||||
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
|
||||
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
|
||||
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
|
||||
|
||||
; This is the GRUB Multiboot header. A boot signature
|
||||
dd MULTIBOOT_HEADER_MAGIC
|
||||
dd MULTIBOOT_HEADER_FLAGS
|
||||
dd MULTIBOOT_CHECKSUM
|
||||
dd 0, 0, 0, 0, 0 ; address fields
|
||||
dd 0, 0, 0, 0,
|
||||
global base
|
||||
global limit
|
||||
base dq 0
|
||||
limit dq 0
|
||||
|
||||
ALIGN 4
|
||||
; we need already a valid GDT to switch in the 64bit modus
|
||||
GDT64: ; Global Descriptor Table (64-bit).
|
||||
.Null: equ $ - GDT64 ; The null descriptor.
|
||||
dw 0 ; Limit (low).
|
||||
dw 0 ; Base (low).
|
||||
db 0 ; Base (middle)
|
||||
db 0 ; Access.
|
||||
db 0 ; Granularity.
|
||||
db 0 ; Base (high).
|
||||
.Code: equ $ - GDT64 ; The code descriptor.
|
||||
dw 0 ; Limit (low).
|
||||
dw 0 ; Base (low).
|
||||
db 0 ; Base (middle)
|
||||
db 10011000b ; Access.
|
||||
db 00100000b ; Granularity.
|
||||
db 0 ; Base (high).
|
||||
.Data: equ $ - GDT64 ; The data descriptor.
|
||||
dw 0 ; Limit (low).
|
||||
dw 0 ; Base (low).
|
||||
db 0 ; Base (middle)
|
||||
db 10010010b ; Access.
|
||||
db 00000000b ; Granularity.
|
||||
db 0 ; Base (high).
|
||||
.Pointer: ; The GDT-pointer.
|
||||
dw $ - GDT64 - 1 ; Limit.
|
||||
dq GDT64 ; Base.
|
||||
|
||||
SECTION .text
|
||||
ALIGN 4
|
||||
stublet:
|
||||
; Initialize stack pointer
|
||||
mov esp, boot_stack
|
||||
add esp, KERNEL_STACK_SIZE - 16
|
||||
|
||||
; Interpret multiboot information
|
||||
mov DWORD [mb_info], ebx
|
||||
|
||||
; Initialize CPU features
|
||||
call cpu_init
|
||||
|
||||
lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table.
|
||||
jmp GDT64.Code:start64 ; Set the code segment and enter 64-bit long mode.
|
||||
|
||||
; This will set up the x86 control registers:
|
||||
; Caching and the floating point unit are enabled
|
||||
; Bootstrap page tables are loaded and page size
|
||||
; extensions (huge pages) enabled.
|
||||
global cpu_init
|
||||
cpu_init:
|
||||
|
||||
; initialize page tables
|
||||
|
||||
; map vga 1:1
|
||||
%ifdef CONFIG_VGA
|
||||
push edi
|
||||
mov eax, VIDEO_MEM_ADDR ; map vga
|
||||
and eax, 0xFFFFF000 ; page align lower half
|
||||
mov edi, eax
|
||||
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
|
||||
add edi, boot_pgt
|
||||
or eax, 0x113 ; set present, global, writable and cache disable bits
|
||||
mov DWORD [edi], eax
|
||||
pop edi
|
||||
%endif
|
||||
|
||||
; map multiboot info 1:1
|
||||
push edi
|
||||
mov eax, DWORD [mb_info] ; map multiboot info
|
||||
cmp eax, 0
|
||||
je Lno_mbinfo
|
||||
and eax, 0xFFFFF000 ; page align lower half
|
||||
mov edi, eax
|
||||
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
|
||||
add edi, boot_pgt
|
||||
or eax, 0x101 ; set present and global bits
|
||||
mov DWORD [edi], eax
|
||||
Lno_mbinfo:
|
||||
pop edi
|
||||
|
||||
; map kernel 1:1, use a page size of 2MB
|
||||
push edi
|
||||
mov eax, kernel_start
|
||||
and eax, 0xFFE00000
|
||||
mov edi, eax
|
||||
shr edi, 18 ; (edi >> 21) * 8 (index for boot_pgd)
|
||||
add edi, boot_pgd
|
||||
or eax, 0x183
|
||||
mov DWORD [edi], eax
|
||||
pop edi
|
||||
|
||||
; check for long mode
|
||||
|
||||
; do we have the instruction cpuid?
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 1 << 21
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
push ecx
|
||||
popfd
|
||||
xor eax, ecx
|
||||
jz Linvalid
|
||||
|
||||
; cpuid > 0x80000000?
|
||||
mov eax, 0x80000000
|
||||
cpuid
|
||||
cmp eax, 0x80000001
|
||||
jb Linvalid ; It is less, there is no long mode.
|
||||
|
||||
; do we have a long mode?
|
||||
mov eax, 0x80000001
|
||||
cpuid
|
||||
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
|
||||
jz Linvalid ; They aren't, there is no long mode.
|
||||
|
||||
|
||||
; we need to enable PAE modus
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; switch to the compatibility mode (which is part of long mode)
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8
|
||||
wrmsr
|
||||
|
||||
; Set CR3
|
||||
mov eax, boot_pml4
|
||||
mov cr3, eax
|
||||
|
||||
; Set CR4
|
||||
mov eax, cr4
|
||||
and eax, 0xfffbf9ff ; disable SSE
|
||||
or eax, (1 << 4) ; enable PSE
|
||||
mov cr4, eax
|
||||
|
||||
; Set CR0
|
||||
mov eax, cr0
|
||||
and eax, ~(1 << 30) ; enable caching
|
||||
and eax, ~(1 << 16) ; allow kernel write access to read-only pages
|
||||
or eax, (1 << 31) ; enable paging
|
||||
or eax, (1 << 0) ; long mode also needs PM-bit set
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
; there is no long mode
|
||||
Linvalid:
|
||||
jmp $
|
||||
|
||||
[BITS 64]
|
||||
start64:
|
||||
; initialize segment registers
|
||||
mov ax, GDT64.Data
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov ax, 0x00
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; set default stack pointer
|
||||
mov rsp, boot_stack
|
||||
add rsp, KERNEL_STACK_SIZE-16
|
||||
|
||||
; jump to the boot processors's C code
|
||||
extern main
|
||||
call main
|
||||
jmp $
|
||||
|
||||
global gdt_flush
|
||||
extern gp
|
||||
|
||||
; This will set up our new segment registers and is declared in
|
||||
; C as 'extern void gdt_flush();'
|
||||
gdt_flush:
|
||||
lgdt [gp]
|
||||
ret
|
||||
|
||||
; The first 32 interrupt service routines (ISR) entries correspond to exceptions.
|
||||
; Some exceptions will push an error code onto the stack which is specific to
|
||||
; the exception caused. To decrease the complexity, we handle this by pushing a
|
||||
; Dummy error code of 0 onto the stack for any ISR that doesn't push an error
|
||||
; code already.
|
||||
;
|
||||
; ISRs are registered as "Interrupt Gate".
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
|
||||
; NASM macro which pushs also an pseudo error code
|
||||
%macro isrstub_pseudo_error 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte %1
|
||||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; Similar to isrstub_pseudo_error, but without pushing
|
||||
; a pseudo error code => The error code is already
|
||||
; on the stack.
|
||||
%macro isrstub 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
push byte %1
|
||||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; Create isr entries, where the number after the
|
||||
; pseudo error code represents following interrupts:
|
||||
; 0: Divide By Zero Exception
|
||||
; 1: Debug Exception
|
||||
; 2: Non Maskable Interrupt Exception
|
||||
; 3: Int 3 Exception
|
||||
; 4: INTO Exception
|
||||
; 5: Out of Bounds Exception
|
||||
; 6: Invalid Opcode Exception
|
||||
; 7: Coprocessor Not Available Exception
|
||||
%assign i 0
|
||||
%rep 8
|
||||
isrstub_pseudo_error i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; 8: Double Fault Exception (With Error Code!)
|
||||
isrstub 8
|
||||
|
||||
; 9: Coprocessor Segment Overrun Exception
|
||||
isrstub_pseudo_error 9
|
||||
|
||||
; 10: Bad TSS Exception (With Error Code!)
|
||||
; 11: Segment Not Present Exception (With Error Code!)
|
||||
; 12: Stack Fault Exception (With Error Code!)
|
||||
; 13: General Protection Fault Exception (With Error Code!)
|
||||
; 14: Page Fault Exception (With Error Code!)
|
||||
%assign i 10
|
||||
%rep 5
|
||||
isrstub i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; 15: Reserved Exception
|
||||
; 16: Floating Point Exception
|
||||
; 17: Alignment Check Exception
|
||||
; 18: Machine Check Exceptio
|
||||
; 19-31: Reserved
|
||||
%assign i 15
|
||||
%rep 17
|
||||
isrstub_pseudo_error i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; NASM macro for asynchronous interrupts (no exceptions)
|
||||
%macro irqstub 1
|
||||
global irq%1
|
||||
irq%1:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte 32+%1
|
||||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; Create entries for the interrupts 0 to 23
|
||||
%assign i 0
|
||||
%rep 24
|
||||
irqstub i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
global apic_timer
|
||||
apic_timer:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte 123
|
||||
jmp common_stub
|
||||
|
||||
global apic_lint0
|
||||
apic_lint0:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte 124
|
||||
jmp common_stub
|
||||
|
||||
global apic_lint1
|
||||
apic_lint1:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte 125
|
||||
jmp common_stub
|
||||
|
||||
global apic_error
|
||||
apic_error:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte 126
|
||||
jmp common_stub
|
||||
|
||||
global apic_svr
|
||||
apic_svr:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte 127
|
||||
jmp common_stub
|
||||
|
||||
extern irq_handler
|
||||
extern get_current_stack
|
||||
extern finish_task_switch
|
||||
|
||||
global isrsyscall
|
||||
; used to realize system calls
|
||||
isrsyscall:
|
||||
cli
|
||||
; set kernel stack
|
||||
extern get_kernel_stack
|
||||
call get_kernel_stack
|
||||
xchg rsp, rax ; => rax contains original rsp
|
||||
|
||||
push rax ; contains original rsp
|
||||
push r15
|
||||
push r14
|
||||
push r13
|
||||
push r12
|
||||
push r11
|
||||
push rbp
|
||||
push rdx
|
||||
push rcx
|
||||
push rbx
|
||||
push rdi
|
||||
push rsi
|
||||
sti
|
||||
|
||||
extern syscall_handler
|
||||
call syscall_handler
|
||||
|
||||
cli
|
||||
pop rsi
|
||||
pop rdi
|
||||
pop rbx
|
||||
pop rcx
|
||||
pop rdx
|
||||
pop rbp
|
||||
pop r11
|
||||
pop r12
|
||||
pop r13
|
||||
pop r14
|
||||
pop r15
|
||||
pop r10
|
||||
mov rsp, r10
|
||||
sti
|
||||
o64 sysret
|
||||
|
||||
global switch_context
|
||||
ALIGN 8
|
||||
switch_context:
|
||||
; create on the stack a pseudo interrupt
|
||||
; afterwards, we switch to the task with iret
|
||||
mov rax, rdi ; rdi contains the address to store the old rsp
|
||||
pushf ; RFLAGS
|
||||
push QWORD 0x08 ; CS
|
||||
push QWORD rollback ; RIP
|
||||
push QWORD 0x00 ; Interrupt number
|
||||
push QWORD 0x00edbabe ; Error code
|
||||
push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push rbx
|
||||
push rsp
|
||||
push rbp
|
||||
push rsi
|
||||
push rdi
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
jmp common_switch
|
||||
|
||||
ALIGN 8
|
||||
rollback:
|
||||
ret
|
||||
|
||||
ALIGN 8
|
||||
common_stub:
|
||||
push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push rbx
|
||||
push rsp
|
||||
push rbp
|
||||
push rsi
|
||||
push rdi
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
; use the same handler for interrupts and exceptions
|
||||
mov rdi, rsp
|
||||
call irq_handler
|
||||
|
||||
cmp rax, 0
|
||||
je no_context_switch
|
||||
|
||||
common_switch:
|
||||
mov [rax], rsp ; store old rsp
|
||||
call get_current_stack ; get new rsp
|
||||
xchg rax, rsp
|
||||
|
||||
; set task switched flag
|
||||
mov rax, cr0
|
||||
or eax, 8
|
||||
mov cr0, rax
|
||||
|
||||
; set rsp0 in the task state segment
|
||||
extern set_kernel_stack
|
||||
call set_kernel_stack
|
||||
|
||||
; call cleanup code
|
||||
call finish_task_switch
|
||||
|
||||
no_context_switch:
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbp
|
||||
add rsp, 8
|
||||
pop rbx
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
|
||||
add rsp, 16
|
||||
iretq
|
||||
|
||||
SECTION .data
|
||||
|
||||
global mb_info:
|
||||
ALIGN 8
|
||||
mb_info:
|
||||
DQ 0
|
||||
|
||||
ALIGN 4096
|
||||
global boot_stack
|
||||
boot_stack:
|
||||
TIMES (KERNEL_STACK_SIZE) DB 0xcd
|
||||
|
||||
; Bootstrap page tables are used during the initialization.
|
||||
ALIGN 4096
|
||||
boot_pml4:
|
||||
DQ boot_pdpt + 0x107 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_USER
|
||||
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
|
||||
DQ boot_pml4 + 0x303 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_SELF (self-reference)
|
||||
boot_pdpt:
|
||||
DQ boot_pgd + 0x107 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_USER
|
||||
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
|
||||
DQ boot_pml4 + 0x303 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_SELF (self-reference)
|
||||
boot_pgd:
|
||||
DQ boot_pgt + 0x107 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_USER
|
||||
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
|
||||
DQ boot_pml4 + 0x303 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_SELF (self-reference)
|
||||
boot_pgt:
|
||||
times 512 DQ 0
|
||||
|
||||
; add some hints to the ELF file
|
||||
SECTION .note.GNU-stack noalloc noexec nowrite progbits
|
154
hermit/arch/x86/kernel/gdt.c
Normal file
154
hermit/arch/x86/kernel/gdt.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/stdlib.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <hermit/processor.h>
|
||||
#include <asm/gdt.h>
|
||||
#include <asm/tss.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
gdt_ptr_t gp;
|
||||
static tss_t task_state_segment __attribute__ ((aligned (PAGE_SIZE)));
|
||||
// currently, our kernel has full access to the ioports
|
||||
static gdt_entry_t gdt[GDT_ENTRIES] = {[0 ... GDT_ENTRIES-1] = {0, 0, 0, 0, 0, 0}};
|
||||
|
||||
/*
|
||||
* This is defined in entry.asm. We use this to properly reload
|
||||
* the new segment registers
|
||||
*/
|
||||
extern void gdt_flush(void);
|
||||
|
||||
extern const void boot_stack;
|
||||
|
||||
void set_kernel_stack(void)
|
||||
{
|
||||
task_t* curr_task = current_task;
|
||||
|
||||
task_state_segment.rsp0 = (size_t) curr_task->stack + KERNEL_STACK_SIZE - 16; // => stack is 16byte aligned
|
||||
}
|
||||
|
||||
size_t get_kernel_stack(void)
|
||||
{
|
||||
task_t* curr_task = current_task;
|
||||
|
||||
return (size_t) curr_task->stack + KERNEL_STACK_SIZE - 16;
|
||||
}
|
||||
|
||||
/* Setup a descriptor in the Global Descriptor Table */
|
||||
void gdt_set_gate(int num, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran)
|
||||
{
|
||||
configure_gdt_entry(&gdt[num], base, limit, access, gran);
|
||||
}
|
||||
|
||||
void configure_gdt_entry(gdt_entry_t *dest_entry, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran)
|
||||
{
|
||||
/* Setup the descriptor base address */
|
||||
dest_entry->base_low = (base & 0xFFFF);
|
||||
dest_entry->base_middle = (base >> 16) & 0xFF;
|
||||
dest_entry->base_high = (base >> 24) & 0xFF;
|
||||
|
||||
/* Setup the descriptor limits */
|
||||
dest_entry->limit_low = (limit & 0xFFFF);
|
||||
dest_entry->granularity = ((limit >> 16) & 0x0F);
|
||||
|
||||
/* Finally, set up the granularity and access flags */
|
||||
dest_entry->granularity |= (gran & 0xF0);
|
||||
dest_entry->access = access;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will setup the special GDT
|
||||
* pointer, set up the entries in our GDT, and then
|
||||
* finally call gdt_flush() in our assembler file in order
|
||||
* to tell the processor where the new GDT is and update the
|
||||
* new segment registers
|
||||
*/
|
||||
void gdt_install(void)
|
||||
{
|
||||
unsigned long gran_ds, gran_cs, limit;
|
||||
int num = 0;
|
||||
|
||||
memset(&task_state_segment, 0x00, sizeof(tss_t));
|
||||
|
||||
gran_cs = GDT_FLAG_64_BIT;
|
||||
gran_ds = 0;
|
||||
limit = 0;
|
||||
|
||||
/* Setup the GDT pointer and limit */
|
||||
gp.limit = (sizeof(gdt_entry_t) * GDT_ENTRIES) - 1;
|
||||
gp.base = (size_t) &gdt;
|
||||
|
||||
/* Our NULL descriptor */
|
||||
gdt_set_gate(num++, 0, 0, 0, 0);
|
||||
|
||||
/*
|
||||
* The second entry is our Code Segment. The base address
|
||||
* is 0, the limit is 4 GByte, it uses 4KByte granularity,
|
||||
* and is a Code Segment descriptor.
|
||||
*/
|
||||
gdt_set_gate(num++, 0, limit,
|
||||
GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, gran_cs);
|
||||
|
||||
/*
|
||||
* The third entry is our Data Segment. It's EXACTLY the
|
||||
* same as our code segment, but the descriptor type in
|
||||
* this entry's access byte says it's a Data Segment
|
||||
*/
|
||||
gdt_set_gate(num++, 0, limit,
|
||||
GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, gran_ds);
|
||||
|
||||
/*
|
||||
* Create code segment for 32bit user-space applications (ring 3)
|
||||
*/
|
||||
gdt_set_gate(num++, 0, 0xFFFFFFFF,
|
||||
GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, GDT_FLAG_32_BIT | GDT_FLAG_4K_GRAN);
|
||||
|
||||
/*
|
||||
* Create data segment for user-space applications (ring 3)
|
||||
*/
|
||||
gdt_set_gate(num++, 0, limit,
|
||||
GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, gran_ds);
|
||||
|
||||
/*
|
||||
* Create code segment for 64bit user-space applications (ring 3)
|
||||
*/
|
||||
gdt_set_gate(num++, 0, limit,
|
||||
GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, gran_cs);
|
||||
|
||||
task_state_segment.rsp0 = (size_t) &boot_stack - 0x10;
|
||||
gdt_set_gate(num++, (unsigned long) (&task_state_segment), sizeof(tss_t)-1,
|
||||
GDT_FLAG_PRESENT | GDT_FLAG_TSS | GDT_FLAG_RING0, gran_ds);
|
||||
|
||||
/* Flush out the old GDT and install the new changes! */
|
||||
gdt_flush();
|
||||
}
|
100
hermit/arch/x86/kernel/idt.c
Normal file
100
hermit/arch/x86/kernel/idt.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/kernel/idt.c
|
||||
* @brief Definitions and functions related to IDT
|
||||
*
|
||||
*
|
||||
* This file defines the interface for interrupts as like
|
||||
* structures to describe interrupt descriptor table entries.\n
|
||||
* See idt.h for flag definitions.
|
||||
*/
|
||||
|
||||
#include <hermit/string.h>
|
||||
#include <asm/idt.h>
|
||||
|
||||
/*
|
||||
* Declare an IDT of 256 entries. Although we will only use the
|
||||
* first 32 entries in this tutorial, the rest exists as a bit
|
||||
* of a trap. If any undefined IDT entry is hit, it normally
|
||||
* will cause an "Unhandled Interrupt" exception. Any descriptor
|
||||
* for which the 'presence' bit is cleared (0) will generate an
|
||||
* "Unhandled Interrupt" exception
|
||||
*/
|
||||
static idt_entry_t idt[256] = {[0 ... 255] = {0, 0, 0, 0, 0, 0, 0}};
|
||||
static idt_ptr_t idtp;
|
||||
|
||||
void configure_idt_entry(idt_entry_t *dest_entry, size_t base,
|
||||
unsigned short sel, unsigned char flags)
|
||||
{
|
||||
/* The interrupt routine's base address */
|
||||
dest_entry->base_lo = (base & 0xFFFF);
|
||||
dest_entry->base_hi = (base >> 16) & 0xFFFF;
|
||||
|
||||
/* The segment or 'selector' that this IDT entry will use
|
||||
* is set here, along with any access flags */
|
||||
dest_entry->sel = sel;
|
||||
dest_entry->always0 = 0;
|
||||
dest_entry->flags = flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this function to set an entry in the IDT. Alot simpler
|
||||
* than twiddling with the GDT ;)
|
||||
*/
|
||||
void idt_set_gate(unsigned char num, size_t base, unsigned short sel,
|
||||
unsigned char flags)
|
||||
{
|
||||
configure_idt_entry(&idt[num], base, sel, flags);
|
||||
}
|
||||
|
||||
extern void isrsyscall(void);
|
||||
|
||||
/* Installs the IDT */
|
||||
void idt_install(void)
|
||||
{
|
||||
static int initialized = 0;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
|
||||
/* Sets the special IDT pointer up, just like in 'gdt.c' */
|
||||
idtp.limit = (sizeof(idt_entry_t) * 256) - 1;
|
||||
idtp.base = (size_t)&idt;
|
||||
|
||||
#if 0
|
||||
/* Add any new ISRs to the IDT here using idt_set_gate */
|
||||
idt_set_gate(INT_SYSCALL, (size_t)isrsyscall, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING3|IDT_FLAG_32BIT|IDT_FLAG_TRAPGATE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Points the processor's internal register to the new IDT */
|
||||
asm volatile("lidt %0" : : "m" (idtp));
|
||||
}
|
278
hermit/arch/x86/kernel/irq.c
Normal file
278
hermit/arch/x86/kernel/irq.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/kernel/irq.c
|
||||
* @brief Function definitions for irq.h and a standard IRQ-handler
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/idt.h>
|
||||
#include <asm/isrs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* These are our own ISRs that point to our special IRQ handler
|
||||
* instead of the regular 'fault_handler' function
|
||||
*/
|
||||
extern void irq0(void);
|
||||
extern void irq1(void);
|
||||
extern void irq2(void);
|
||||
extern void irq3(void);
|
||||
extern void irq4(void);
|
||||
extern void irq5(void);
|
||||
extern void irq6(void);
|
||||
extern void irq7(void);
|
||||
extern void irq8(void);
|
||||
extern void irq9(void);
|
||||
extern void irq10(void);
|
||||
extern void irq11(void);
|
||||
extern void irq12(void);
|
||||
extern void irq13(void);
|
||||
extern void irq14(void);
|
||||
extern void irq15(void);
|
||||
extern void irq16(void);
|
||||
extern void irq17(void);
|
||||
extern void irq18(void);
|
||||
extern void irq19(void);
|
||||
extern void irq20(void);
|
||||
extern void irq21(void);
|
||||
extern void irq22(void);
|
||||
extern void irq23(void);
|
||||
extern void apic_timer(void);
|
||||
extern void apic_lint0(void);
|
||||
extern void apic_lint1(void);
|
||||
extern void apic_error(void);
|
||||
extern void apic_svr(void);
|
||||
|
||||
#define MAX_HANDLERS 256
|
||||
|
||||
/** @brief IRQ handle pointers
|
||||
*
|
||||
* This array is actually an array of function pointers. We use
|
||||
* this to handle custom IRQ handlers for a given IRQ
|
||||
*/
|
||||
static void* irq_routines[MAX_HANDLERS] = {[0 ... MAX_HANDLERS-1] = NULL};
|
||||
|
||||
/* This installs a custom IRQ handler for the given IRQ */
|
||||
int irq_install_handler(unsigned int irq, irq_handler_t handler)
|
||||
{
|
||||
if (irq >= MAX_HANDLERS)
|
||||
return -EINVAL;
|
||||
|
||||
irq_routines[irq] = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This clears the handler for a given IRQ */
|
||||
int irq_uninstall_handler(unsigned int irq)
|
||||
{
|
||||
if (irq >= MAX_HANDLERS)
|
||||
return -EINVAL;
|
||||
|
||||
irq_routines[irq] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Remapping IRQs with a couple of IO output operations
|
||||
*
|
||||
* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
|
||||
* is a problem in protected mode, because IDT entry 8 is a
|
||||
* Double Fault! Without remapping, every time IRQ0 fires,
|
||||
* you get a Double Fault Exception, which is NOT what's
|
||||
* actually happening. We send commands to the Programmable
|
||||
* Interrupt Controller (PICs - also called the 8259's) in
|
||||
* order to make IRQ0 to 15 be remapped to IDT entries 32 to
|
||||
* 47
|
||||
*/
|
||||
static int irq_remap(void)
|
||||
{
|
||||
outportb(0x20, 0x11);
|
||||
outportb(0xA0, 0x11);
|
||||
outportb(0x21, 0x20);
|
||||
outportb(0xA1, 0x28);
|
||||
outportb(0x21, 0x04);
|
||||
outportb(0xA1, 0x02);
|
||||
outportb(0x21, 0x01);
|
||||
outportb(0xA1, 0x01);
|
||||
outportb(0x21, 0x0);
|
||||
outportb(0xA1, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Remap IRQs and install ISRs in IDT
|
||||
*
|
||||
* We first remap the interrupt controllers, and then we install
|
||||
* the appropriate ISRs to the correct entries in the IDT.\n
|
||||
* This is just like installing the exception handlers
|
||||
*/
|
||||
static int irq_install(void)
|
||||
{
|
||||
irq_remap();
|
||||
|
||||
idt_set_gate(32, (size_t)irq0, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(33, (size_t)irq1, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(34, (size_t)irq2, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(35, (size_t)irq3, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(36, (size_t)irq4, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(37, (size_t)irq5, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(38, (size_t)irq6, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(39, (size_t)irq7, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(40, (size_t)irq8, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(41, (size_t)irq9, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(42, (size_t)irq10, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(43, (size_t)irq11, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(44, (size_t)irq12, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(45, (size_t)irq13, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(46, (size_t)irq14, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(47, (size_t)irq15, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(48, (size_t)irq16, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(49, (size_t)irq17, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(50, (size_t)irq18, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(51, (size_t)irq19, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(52, (size_t)irq20, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(53, (size_t)irq21, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(54, (size_t)irq22, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(55, (size_t)irq23, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
||||
// add APIC interrupt handler
|
||||
idt_set_gate(123, (size_t)apic_timer, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(124, (size_t)apic_lint0, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(125, (size_t)apic_lint1, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(126, (size_t)apic_error, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(127, (size_t)apic_svr, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irq_init(void)
|
||||
{
|
||||
idt_install();
|
||||
isrs_install();
|
||||
irq_install();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Default IRQ handler
|
||||
*
|
||||
* Each of the IRQ ISRs point to this function, rather than
|
||||
* the 'fault_handler' in 'isrs.c'. The IRQ Controllers need
|
||||
* to be told when you are done servicing them, so you need
|
||||
* to send them an "End of Interrupt" command. If we use the PIC
|
||||
* instead of the APIC, we have two 8259 chips: The first one
|
||||
* exists at 0x20, the second one exists at 0xA0. If the second
|
||||
* controller (an IRQ from 8 to 15) gets an interrupt, you need to
|
||||
* acknowledge the interrupt at BOTH controllers, otherwise, you
|
||||
* only send an EOI command to the first controller. If you don't send
|
||||
* an EOI, it won't raise any more IRQs.
|
||||
*
|
||||
* Note: If we enabled the APIC, we also disabled the PIC. Afterwards,
|
||||
* we get no interrupts between 0 and 15.
|
||||
*/
|
||||
size_t** irq_handler(struct state *s)
|
||||
{
|
||||
size_t** ret = NULL;
|
||||
|
||||
/* This is a blank function pointer */
|
||||
void (*handler) (struct state * s);
|
||||
|
||||
/*
|
||||
* Find out if we have a custom handler to run for this
|
||||
* IRQ and then finally, run it
|
||||
*/
|
||||
if (BUILTIN_EXPECT(s->int_no < MAX_HANDLERS, 1)) {
|
||||
handler = irq_routines[s->int_no];
|
||||
if (handler)
|
||||
handler(s);
|
||||
} else kprintf("Invalid interrupt number %d\n", s->int_no);
|
||||
|
||||
#if 0
|
||||
// timer interrupt?
|
||||
if ((s->int_no == 32) || (s->int_no == 123))
|
||||
ret = scheduler(); // switch to a new task
|
||||
else if ((s->int_no >= 32) && (get_highest_priority() > current_task->prio))
|
||||
ret = scheduler();
|
||||
|
||||
apic_eoi(s->int_no);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the IDT entry that was invoked was greater-than-or-equal to 40
|
||||
* and lower than 48 (meaning IRQ8 - 15), then we need to
|
||||
* send an EOI to the slave controller of the PIC
|
||||
*/
|
||||
if (s->int_no >= 40)
|
||||
outportb(0xA0, 0x20);
|
||||
|
||||
/*
|
||||
* In either case, we need to send an EOI to the master
|
||||
* interrupt controller of the PIC, too
|
||||
*/
|
||||
outportb(0x20, 0x20);
|
||||
|
||||
return ret;
|
||||
}
|
226
hermit/arch/x86/kernel/isrs.c
Normal file
226
hermit/arch/x86/kernel/isrs.c
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/kernel/isrs.c
|
||||
* @brief Installation of interrupt service routines and definition of fault handler.
|
||||
*
|
||||
* This file contains prototypes for the first 32 entries of the IDT,
|
||||
* an ISR installer procedure and a fault handler.\n
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/isrs.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/idt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* These are function prototypes for all of the exception
|
||||
* handlers: The first 32 entries in the IDT are reserved
|
||||
* by Intel and are designed to service exceptions!
|
||||
*/
|
||||
extern void isr0(void);
|
||||
extern void isr1(void);
|
||||
extern void isr2(void);
|
||||
extern void isr3(void);
|
||||
extern void isr4(void);
|
||||
extern void isr5(void);
|
||||
extern void isr6(void);
|
||||
extern void isr7(void);
|
||||
extern void isr8(void);
|
||||
extern void isr9(void);
|
||||
extern void isr10(void);
|
||||
extern void isr11(void);
|
||||
extern void isr12(void);
|
||||
extern void isr13(void);
|
||||
extern void isr14(void);
|
||||
extern void isr15(void);
|
||||
extern void isr16(void);
|
||||
extern void isr17(void);
|
||||
extern void isr18(void);
|
||||
extern void isr19(void);
|
||||
extern void isr20(void);
|
||||
extern void isr21(void);
|
||||
extern void isr22(void);
|
||||
extern void isr23(void);
|
||||
extern void isr24(void);
|
||||
extern void isr25(void);
|
||||
extern void isr26(void);
|
||||
extern void isr27(void);
|
||||
extern void isr28(void);
|
||||
extern void isr29(void);
|
||||
extern void isr30(void);
|
||||
extern void isr31(void);
|
||||
|
||||
static void fault_handler(struct state *s);
|
||||
static void fpu_handler(struct state *s);
|
||||
|
||||
/*
|
||||
* This is a very repetitive function... it's not hard, it's
|
||||
* just annoying. As you can see, we set the first 32 entries
|
||||
* in the IDT to the first 32 ISRs. We can't use a for loop
|
||||
* for this, because there is no way to get the function names
|
||||
* that correspond to that given entry. We set the access
|
||||
* flags to 0x8E. This means that the entry is present, is
|
||||
* running in ring 0 (kernel level), and has the lower 5 bits
|
||||
* set to the required '14', which is represented by 'E' in
|
||||
* hex.
|
||||
*/
|
||||
void isrs_install(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
idt_set_gate(0, (size_t)isr0, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(1, (size_t)isr1, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(2, (size_t)isr2, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(3, (size_t)isr3, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(4, (size_t)isr4, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(5, (size_t)isr5, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(6, (size_t)isr6, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(7, (size_t)isr7, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(8, (size_t)isr8, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(9, (size_t)isr9, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(10, (size_t)isr10, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(11, (size_t)isr11, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(12, (size_t)isr12, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(13, (size_t)isr13, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(14, (size_t)isr14, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(15, (size_t)isr15, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(16, (size_t)isr16, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(17, (size_t)isr17, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(18, (size_t)isr18, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(19, (size_t)isr19, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(20, (size_t)isr20, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(21, (size_t)isr21, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(22, (size_t)isr22, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(23, (size_t)isr23, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(24, (size_t)isr24, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(25, (size_t)isr25, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(26, (size_t)isr26, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(27, (size_t)isr27, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(28, (size_t)isr28, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(29, (size_t)isr29, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(30, (size_t)isr30, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(31, (size_t)isr31, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
||||
// install the default handler
|
||||
for(i=0; i<32; i++)
|
||||
irq_install_handler(i, fault_handler);
|
||||
|
||||
// set hanlder for fpu exceptions
|
||||
irq_uninstall_handler(7);
|
||||
irq_install_handler(7, fpu_handler);
|
||||
}
|
||||
|
||||
static void fpu_handler(struct state *s)
|
||||
{
|
||||
task_t* task = current_task;
|
||||
|
||||
asm volatile ("clts"); // clear the TS flag of cr0
|
||||
if (!(task->flags & TASK_FPU_INIT)) {
|
||||
// use the FPU at the first time => Initialize FPU
|
||||
fpu_init(&task->fpu);
|
||||
task->flags |= TASK_FPU_INIT;
|
||||
}
|
||||
|
||||
restore_fpu_state(&task->fpu);
|
||||
task->flags |= TASK_FPU_USED;
|
||||
}
|
||||
|
||||
/** @brief Exception messages
|
||||
*
|
||||
* This is a simple string array. It contains the message that
|
||||
* corresponds to each and every exception. We get the correct
|
||||
* message by accessing it like this:
|
||||
* exception_message[interrupt_number]
|
||||
*/
|
||||
static const char *exception_messages[] = {
|
||||
"Division By Zero", "Debug", "Non Maskable Interrupt",
|
||||
"Breakpoint", "Into Detected Overflow", "Out of Bounds", "Invalid Opcode",
|
||||
"No Coprocessor", "Double Fault", "Coprocessor Segment Overrun", "Bad TSS",
|
||||
"Segment Not Present", "Stack Fault", "General Protection Fault", "Page Fault",
|
||||
"Unknown Interrupt", "Coprocessor Fault", "Alignment Check", "Machine Check",
|
||||
"Reserved", "Reserved", "Reserved", "Reserved", "Reserved",
|
||||
"Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved",
|
||||
"Reserved", "Reserved" };
|
||||
|
||||
/*
|
||||
* All of our Exception handling Interrupt Service Routines will
|
||||
* point to this function. This will tell us what exception has
|
||||
* occured! Right now, we simply abort the current task.
|
||||
* All ISRs disable interrupts while they are being
|
||||
* serviced as a 'locking' mechanism to prevent an IRQ from
|
||||
* happening and messing up kernel data structures
|
||||
*/
|
||||
static void fault_handler(struct state *s)
|
||||
{
|
||||
if (s->int_no < 32) {
|
||||
kputs(exception_messages[s->int_no]);
|
||||
kprintf(" Exception (%d) at 0x%llx:0x%llx, error code 0x%llx, rflags 0x%llx\n",
|
||||
s->int_no, s->cs, s->rip, s->error, s->rflags);
|
||||
outportb(0x20, 0x20);
|
||||
|
||||
irq_enable();
|
||||
abort();
|
||||
}
|
||||
}
|
230
hermit/arch/x86/kernel/processor.c
Normal file
230
hermit/arch/x86/kernel/processor.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/time.h>
|
||||
#include <hermit/processor.h>
|
||||
#include <hermit/tasks.h>
|
||||
|
||||
extern void isrsyscall(void);
|
||||
|
||||
cpu_info_t cpu_info = { 0, 0, 0, 0};
|
||||
static uint32_t cpu_freq = 0;
|
||||
|
||||
static void default_mb(void)
|
||||
{
|
||||
asm volatile ("lock; addl $0,0(%%esp)" ::: "memory", "cc");
|
||||
}
|
||||
|
||||
static void default_save_fpu_state(union fpu_state* state)
|
||||
{
|
||||
asm volatile ("fnsave %0; fwait" : "=m"((*state).fsave) :: "memory");
|
||||
}
|
||||
|
||||
static void default_restore_fpu_state(union fpu_state* state)
|
||||
{
|
||||
asm volatile ("frstor %0" :: "m"(state->fsave));
|
||||
}
|
||||
|
||||
static void default_fpu_init(union fpu_state* fpu)
|
||||
{
|
||||
i387_fsave_t *fp = &fpu->fsave;
|
||||
|
||||
memset(fp, 0x00, sizeof(i387_fsave_t));
|
||||
fp->cwd = 0xffff037fu;
|
||||
fp->swd = 0xffff0000u;
|
||||
fp->twd = 0xffffffffu;
|
||||
fp->fos = 0xffff0000u;
|
||||
}
|
||||
|
||||
func_memory_barrier mb = default_mb;
|
||||
func_memory_barrier rmb = default_mb;
|
||||
func_memory_barrier wmb = default_mb;
|
||||
|
||||
static void mfence(void) { asm volatile("mfence" ::: "memory"); }
|
||||
static void lfence(void) { asm volatile("lfence" ::: "memory"); }
|
||||
static void sfence(void) { asm volatile("sfence" ::: "memory"); }
|
||||
handle_fpu_state save_fpu_state = default_save_fpu_state;
|
||||
handle_fpu_state restore_fpu_state = default_restore_fpu_state;
|
||||
handle_fpu_state fpu_init = default_fpu_init;
|
||||
|
||||
static void save_fpu_state_fxsr(union fpu_state* state)
|
||||
{
|
||||
asm volatile ("fxsave %0; fnclex" : "=m"((*state).fxsave) :: "memory");
|
||||
}
|
||||
|
||||
static void restore_fpu_state_fxsr(union fpu_state* state)
|
||||
{
|
||||
asm volatile ("fxrstor %0" :: "m"(state->fxsave));
|
||||
}
|
||||
|
||||
static void fpu_init_fxsr(union fpu_state* fpu)
|
||||
{
|
||||
i387_fxsave_t* fx = &fpu->fxsave;
|
||||
|
||||
memset(fx, 0x00, sizeof(i387_fxsave_t));
|
||||
fx->cwd = 0x37f;
|
||||
if (BUILTIN_EXPECT(has_sse(), 1))
|
||||
fx->mxcsr = 0x1f80;
|
||||
}
|
||||
|
||||
uint32_t detect_cpu_frequency(void)
|
||||
{
|
||||
uint64_t start, end, diff;
|
||||
uint64_t ticks, old;
|
||||
|
||||
if (BUILTIN_EXPECT(cpu_freq > 0, 0))
|
||||
return cpu_freq;
|
||||
|
||||
old = get_clock_tick();
|
||||
|
||||
/* wait for the next time slice */
|
||||
while((ticks = get_clock_tick()) - old == 0)
|
||||
HALT;
|
||||
|
||||
rmb();
|
||||
start = rdtsc();
|
||||
/* wait a second to determine the frequency */
|
||||
while(get_clock_tick() - ticks < TIMER_FREQ)
|
||||
HALT;
|
||||
rmb();
|
||||
end = rdtsc();
|
||||
|
||||
diff = end > start ? end - start : start - end;
|
||||
cpu_freq = (uint32_t) (diff / (uint64_t) 1000000);
|
||||
|
||||
return cpu_freq;
|
||||
}
|
||||
|
||||
int cpu_detection(void) {
|
||||
uint32_t a=0, b=0, c=0, d=0;
|
||||
uint32_t family, model, stepping;
|
||||
size_t cr4;
|
||||
uint8_t first_time = 0;
|
||||
|
||||
if (!cpu_info.feature1) {
|
||||
first_time = 1;
|
||||
cpuid(1, &a, &b, &cpu_info.feature2, &cpu_info.feature1);
|
||||
|
||||
family = (a & 0x00000F00) >> 8;
|
||||
model = (a & 0x000000F0) >> 4;
|
||||
stepping = a & 0x0000000F;
|
||||
if ((family == 6) && (model < 3) && (stepping < 3))
|
||||
cpu_info.feature1 &= ~CPU_FEATURE_SEP;
|
||||
|
||||
cpuid(0x80000001, &a, &b, &c, &cpu_info.feature3);
|
||||
cpuid(0x80000008, &cpu_info.addr_width, &b, &c, &d);
|
||||
}
|
||||
|
||||
if (first_time) {
|
||||
kprintf("Paging features: %s%s%s%s%s%s%s%s\n",
|
||||
(cpu_info.feature1 & CPU_FEATUE_PSE) ? "PSE (2/4Mb) " : "",
|
||||
(cpu_info.feature1 & CPU_FEATURE_PAE) ? "PAE " : "",
|
||||
(cpu_info.feature1 & CPU_FEATURE_PGE) ? "PGE " : "",
|
||||
(cpu_info.feature1 & CPU_FEATURE_PAT) ? "PAT " : "",
|
||||
(cpu_info.feature1 & CPU_FEATURE_PSE36) ? "PSE36 " : "",
|
||||
(cpu_info.feature3 & CPU_FEATURE_NX) ? "NX " : "",
|
||||
(cpu_info.feature3 & CPU_FEATURE_1GBHP) ? "PSE (1Gb) " : "",
|
||||
(cpu_info.feature3 & CPU_FEATURE_LM) ? "LM" : "");
|
||||
|
||||
kprintf("Physical adress-width: %u bits\n", cpu_info.addr_width & 0xff);
|
||||
kprintf("Linear adress-width: %u bits\n", (cpu_info.addr_width >> 8) & 0xff);
|
||||
kprintf("Sysenter instruction: %s\n", (cpu_info.feature1 & CPU_FEATURE_SEP) ? "available" : "unavailable");
|
||||
kprintf("Syscall instruction: %s\n", (cpu_info.feature3 & CPU_FEATURE_SYSCALL) ? "available" : "unavailable");
|
||||
}
|
||||
|
||||
cr4 = read_cr4();
|
||||
if (has_fxsr())
|
||||
cr4 |= CR4_OSFXSR; // set the OSFXSR bit
|
||||
if (has_sse())
|
||||
cr4 |= CR4_OSXMMEXCPT; // set the OSXMMEXCPT bit
|
||||
if (has_pge())
|
||||
cr4 |= CR4_PGE;
|
||||
write_cr4(cr4);
|
||||
|
||||
if (cpu_info.feature3 & CPU_FEATURE_SYSCALL) {
|
||||
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_LMA | EFER_SCE);
|
||||
wrmsr(MSR_STAR, (0x1BULL << 48) | (0x08ULL << 32));
|
||||
wrmsr(MSR_LSTAR, (size_t) &isrsyscall);
|
||||
wrmsr(MSR_SYSCALL_MASK, 0); // we didn't clear RFLAGS during an interrupt
|
||||
} else kputs("Processor doesn't support syscalls\n");
|
||||
|
||||
if (has_nx())
|
||||
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NXE);
|
||||
|
||||
if (first_time && has_sse())
|
||||
wmb = sfence;
|
||||
|
||||
if (first_time && has_sse2()) {
|
||||
rmb = lfence;
|
||||
mb = mfence;
|
||||
}
|
||||
|
||||
if (first_time && has_avx())
|
||||
kprintf("The CPU owns the Advanced Vector Extensions (AVX). However, HermitCore doesn't support AVX!\n");
|
||||
|
||||
if (has_fpu()) {
|
||||
if (first_time)
|
||||
kputs("Found and initialized FPU!\n");
|
||||
asm volatile ("fninit");
|
||||
}
|
||||
|
||||
if (first_time && has_fxsr()) {
|
||||
save_fpu_state = save_fpu_state_fxsr;
|
||||
restore_fpu_state = restore_fpu_state_fxsr;
|
||||
fpu_init = fpu_init_fxsr;
|
||||
}
|
||||
|
||||
if (first_time && on_hypervisor()) {
|
||||
uint32_t c, d;
|
||||
char vendor_id[13];
|
||||
|
||||
kprintf("HermitCore is running on a hypervisor!\n");
|
||||
|
||||
cpuid(0x40000000, &a, &b, &c, &d);
|
||||
memcpy(vendor_id, &b, 4);
|
||||
memcpy(vendor_id + 4, &c, 4);
|
||||
memcpy(vendor_id + 8, &d, 4);
|
||||
vendor_id[12] = '\0';
|
||||
|
||||
kprintf("Hypervisor Vendor Id: %s\n", vendor_id);
|
||||
kprintf("Maximum input value for hypervisor: 0x%x\n", a);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t get_cpu_frequency(void)
|
||||
{
|
||||
if (cpu_freq > 0)
|
||||
return cpu_freq;
|
||||
|
||||
return detect_cpu_frequency();
|
||||
}
|
||||
|
89
hermit/arch/x86/kernel/string.asm
Normal file
89
hermit/arch/x86/kernel/string.asm
Normal file
|
@ -0,0 +1,89 @@
|
|||
;
|
||||
; Written by the Chair for Operating Systems, RWTH Aachen University
|
||||
;
|
||||
; NO Copyright (C) 2010-2011, Stefan Lankes
|
||||
; consider these trivial functions to be public domain.
|
||||
;
|
||||
; These functions are distributed on an "AS IS" BASIS,
|
||||
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
;
|
||||
|
||||
%include "config.inc"
|
||||
|
||||
%ifdef CONFIG_X86_32
|
||||
[BITS 32]
|
||||
%else
|
||||
[BITS 64]
|
||||
%endif
|
||||
SECTION .text
|
||||
global strcpy
|
||||
strcpy:
|
||||
%ifdef CONFIG_X86_32
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push edi
|
||||
push esi
|
||||
|
||||
mov esi, [ebp+12]
|
||||
mov edi, [ebp+8]
|
||||
%else
|
||||
push rdi
|
||||
%endif
|
||||
|
||||
L1:
|
||||
lodsb
|
||||
stosb
|
||||
test al, al
|
||||
jne L1
|
||||
|
||||
%ifdef CONFIG_X86_32
|
||||
mov eax, [ebp+8]
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebp
|
||||
%else
|
||||
pop rax
|
||||
%endif
|
||||
ret
|
||||
|
||||
global strncpy
|
||||
strncpy:
|
||||
%ifdef CONFIG_X86_32
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push edi
|
||||
push esi
|
||||
|
||||
mov ecx, [ebp+16]
|
||||
mov esi, [ebp+12]
|
||||
mov edi, [ebp+8]
|
||||
|
||||
L2:
|
||||
dec ecx
|
||||
%else
|
||||
push rdi
|
||||
mov rcx, rdx
|
||||
|
||||
L2:
|
||||
dec rcx
|
||||
%endif
|
||||
js L3
|
||||
lodsb
|
||||
stosb
|
||||
test al, al
|
||||
jne L1
|
||||
rep
|
||||
stosb
|
||||
|
||||
L3:
|
||||
%ifdef CONFIG_X86_32
|
||||
mov eax, [ebp+8]
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebp
|
||||
%else
|
||||
pop rax
|
||||
%endif
|
||||
ret
|
||||
|
||||
SECTION .note.GNU-stack noalloc noexec nowrite progbits
|
426
hermit/arch/x86/kernel/tasks.c
Normal file
426
hermit/arch/x86/kernel/tasks.c
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/stdlib.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <hermit/processor.h>
|
||||
#include <hermit/memory.h>
|
||||
//#include <hermit/fs.h>
|
||||
#include <hermit/vma.h>
|
||||
//#include <asm/elf.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
size_t* get_current_stack(void)
|
||||
{
|
||||
task_t* curr_task = current_task;
|
||||
|
||||
// use new page table
|
||||
write_cr3(curr_task->page_map);
|
||||
|
||||
return curr_task->last_stack_pointer;
|
||||
}
|
||||
|
||||
int create_default_frame(task_t* task, entry_point_t ep, void* arg)
|
||||
{
|
||||
size_t *stack;
|
||||
struct state *stptr;
|
||||
size_t state_size;
|
||||
|
||||
if (BUILTIN_EXPECT(!task, 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (BUILTIN_EXPECT(!task->stack, 0))
|
||||
return -EINVAL;
|
||||
|
||||
memset(task->stack, 0xCD, KERNEL_STACK_SIZE);
|
||||
|
||||
/* The difference between setting up a task for SW-task-switching
|
||||
* and not for HW-task-switching is setting up a stack and not a TSS.
|
||||
* This is the stack which will be activated and popped off for iret later.
|
||||
*/
|
||||
stack = (size_t*) (task->stack + KERNEL_STACK_SIZE - 16); // => stack is 16byte aligned
|
||||
|
||||
/* Only marker for debugging purposes, ... */
|
||||
*stack-- = 0xDEADBEEF;
|
||||
|
||||
/* and the "caller" we shall return to.
|
||||
* This procedure cleans the task after exit. */
|
||||
*stack = (size_t) leave_kernel_task;
|
||||
|
||||
/* Next bunch on the stack is the initial register state.
|
||||
* The stack must look like the stack of a task which was
|
||||
* scheduled away previously. */
|
||||
state_size = sizeof(struct state);
|
||||
stack = (size_t*) ((size_t) stack - state_size);
|
||||
|
||||
stptr = (struct state *) stack;
|
||||
memset(stptr, 0x00, state_size);
|
||||
stptr->rsp = (size_t)stack + state_size;
|
||||
/* the first-function-to-be-called's arguments, ... */
|
||||
stptr->rdi = (size_t) arg;
|
||||
stptr->int_no = 0xB16B00B5;
|
||||
stptr->error = 0xC03DB4B3;
|
||||
|
||||
/* The instruction pointer shall be set on the first function to be called
|
||||
after IRETing */
|
||||
stptr->rip = (size_t)ep;
|
||||
stptr->cs = 0x08;
|
||||
stptr->ss = 0x10;
|
||||
stptr->rflags = 0x1202;
|
||||
stptr->userrsp = stptr->rsp;
|
||||
|
||||
/* Set the task's stack pointer entry to the stack we have crafted right now. */
|
||||
task->last_stack_pointer = (size_t*)stack;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#define MAX_ARGS (PAGE_SIZE - 2*sizeof(int) - sizeof(vfs_node_t*))
|
||||
|
||||
/** @brief Structure which keeps all
|
||||
* relevant data for a new user task to start */
|
||||
typedef struct {
|
||||
/// Points to the node with the executable in the file system
|
||||
vfs_node_t* node;
|
||||
/// Argument count
|
||||
int argc;
|
||||
/// Environment var count
|
||||
int envc;
|
||||
/// Buffer for env and argv values
|
||||
char buffer[MAX_ARGS];
|
||||
} load_args_t;
|
||||
|
||||
/** @brief Internally used function to load tasks with a load_args_t structure
|
||||
* keeping all the information needed to launch.
|
||||
*
|
||||
* This is where the serious loading action is done.
|
||||
*/
|
||||
static int load_task(load_args_t* largs)
|
||||
{
|
||||
uint32_t i, offset, idx;
|
||||
uint32_t addr, npages;
|
||||
size_t stack = 0, heap = 0;
|
||||
size_t flags;
|
||||
elf_header_t header;
|
||||
elf_program_header_t prog_header;
|
||||
//elf_section_header_t sec_header;
|
||||
///!!! kfree is missing!
|
||||
fildes_t *file = kmalloc(sizeof(fildes_t));
|
||||
file->offset = 0;
|
||||
file->flags = 0;
|
||||
|
||||
//TODO: init the hole fildes_t struct!
|
||||
task_t* curr_task = current_task;
|
||||
int err;
|
||||
|
||||
if (!largs)
|
||||
return -EINVAL;
|
||||
|
||||
file->node = largs->node;
|
||||
if (!file->node)
|
||||
return -EINVAL;
|
||||
|
||||
err = read_fs(file, (uint8_t*)&header, sizeof(elf_header_t));
|
||||
if (err < 0) {
|
||||
kprintf("read_fs failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (BUILTIN_EXPECT(header.ident.magic != ELF_MAGIC, 0))
|
||||
goto invalid;
|
||||
|
||||
if (BUILTIN_EXPECT(header.type != ELF_ET_EXEC, 0))
|
||||
goto invalid;
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
if (BUILTIN_EXPECT(header.machine != ELF_EM_386, 0))
|
||||
goto invalid;
|
||||
#elif defined(CONFIG_X86_64)
|
||||
if (BUILTIN_EXPECT(header.machine != ELF_EM_X86_64, 0))
|
||||
goto invalid;
|
||||
#else
|
||||
goto invalid;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
if (BUILTIN_EXPECT(header.ident._class != ELF_CLASS_32, 0))
|
||||
goto invalid;
|
||||
#elif defined(CONFIG_X86_64)
|
||||
if (BUILTIN_EXPECT(header.ident._class != ELF_CLASS_64, 0))
|
||||
goto invalid;
|
||||
#else
|
||||
goto invalid;
|
||||
#endif
|
||||
|
||||
if (BUILTIN_EXPECT(header.ident.data != ELF_DATA_2LSB, 0))
|
||||
goto invalid;
|
||||
|
||||
if (header.entry <= KERNEL_SPACE)
|
||||
goto invalid;
|
||||
|
||||
// interpret program header table
|
||||
for (i=0; i<header.ph_entry_count; i++) {
|
||||
file->offset = header.ph_offset+i*header.ph_entry_size;
|
||||
if (read_fs(file, (uint8_t*)&prog_header, sizeof(elf_program_header_t)) == 0) {
|
||||
kprintf("Could not read programm header!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(prog_header.type)
|
||||
{
|
||||
case ELF_PT_LOAD: // load program segment
|
||||
if (!prog_header.virt_addr)
|
||||
continue;
|
||||
|
||||
npages = (prog_header.mem_size >> PAGE_BITS);
|
||||
if (prog_header.mem_size & (PAGE_SIZE-1))
|
||||
npages++;
|
||||
|
||||
addr = get_pages(npages);
|
||||
|
||||
flags = PG_USER;
|
||||
#ifdef CONFIG_X86_64
|
||||
if (has_nx() && !(prog_header.flags & PF_X))
|
||||
flags |= PG_XD;
|
||||
#endif
|
||||
// map page frames in the address space of the current task
|
||||
if (page_map(prog_header.virt_addr, addr, npages, flags|PG_RW))
|
||||
kprintf("Could not map 0x%x at 0x%x\n", addr, prog_header.virt_addr);
|
||||
|
||||
// clear pages
|
||||
memset((void*) prog_header.virt_addr, 0x00, npages*PAGE_SIZE);
|
||||
|
||||
// update heap location
|
||||
if (heap < prog_header.virt_addr + prog_header.mem_size)
|
||||
heap = prog_header.virt_addr + prog_header.mem_size;
|
||||
|
||||
// load program
|
||||
file->offset = prog_header.offset;
|
||||
read_fs(file, (uint8_t*)prog_header.virt_addr, prog_header.file_size);
|
||||
|
||||
flags = VMA_CACHEABLE;
|
||||
if (prog_header.flags & PF_R)
|
||||
flags |= VMA_READ;
|
||||
if (prog_header.flags & PF_W)
|
||||
flags |= VMA_WRITE;
|
||||
if (prog_header.flags & PF_X)
|
||||
flags |= VMA_EXECUTE;
|
||||
vma_add(prog_header.virt_addr, prog_header.virt_addr+npages*PAGE_SIZE-1, flags);
|
||||
|
||||
if (!(prog_header.flags & PF_W))
|
||||
page_set_flags(prog_header.virt_addr, npages, flags);
|
||||
break;
|
||||
|
||||
case ELF_PT_GNU_STACK: // Indicates stack executability
|
||||
// create user-level stack
|
||||
npages = DEFAULT_STACK_SIZE >> PAGE_BITS;
|
||||
if (DEFAULT_STACK_SIZE & (PAGE_SIZE-1))
|
||||
npages++;
|
||||
|
||||
addr = get_pages(npages);
|
||||
stack = header.entry*2; // virtual address of the stack
|
||||
flags = PG_USER|PG_RW;
|
||||
#ifdef CONFIG_X86_64
|
||||
if (has_nx() && !(prog_header.flags & PF_X))
|
||||
flags |= PG_XD;
|
||||
#endif
|
||||
|
||||
if (page_map(stack, addr, npages, flags)) {
|
||||
kprintf("Could not map stack at 0x%x\n", stack);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset((void*) stack, 0x00, npages*PAGE_SIZE);
|
||||
|
||||
// create vma regions for the user-level stack
|
||||
flags = VMA_CACHEABLE;
|
||||
if (prog_header.flags & PF_R)
|
||||
flags |= VMA_READ;
|
||||
if (prog_header.flags & PF_W)
|
||||
flags |= VMA_WRITE;
|
||||
if (prog_header.flags & PF_X)
|
||||
flags |= VMA_EXECUTE;
|
||||
vma_add(stack, stack+npages*PAGE_SIZE-1, flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// setup heap
|
||||
if (!curr_task->heap)
|
||||
curr_task->heap = (vma_t*) kmalloc(sizeof(vma_t));
|
||||
|
||||
if (BUILTIN_EXPECT(!curr_task->heap || !heap, 0)) {
|
||||
kprintf("load_task: heap is missing!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
curr_task->heap->flags = VMA_HEAP|VMA_USER;
|
||||
curr_task->heap->start = PAGE_FLOOR(heap);
|
||||
curr_task->heap->end = PAGE_FLOOR(heap);
|
||||
|
||||
if (BUILTIN_EXPECT(!stack, 0)) {
|
||||
kprintf("Stack is missing!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// push strings on the stack
|
||||
offset = DEFAULT_STACK_SIZE-8;
|
||||
memset((void*) (stack+offset), 0, 4);
|
||||
offset -= MAX_ARGS;
|
||||
memcpy((void*) (stack+offset), largs->buffer, MAX_ARGS);
|
||||
idx = offset;
|
||||
|
||||
// push argv on the stack
|
||||
offset -= largs->argc * sizeof(char*);
|
||||
for(i=0; i<largs->argc; i++) {
|
||||
((char**) (stack+offset))[i] = (char*) (stack+idx);
|
||||
|
||||
while(((char*) stack)[idx] != '\0')
|
||||
idx++;
|
||||
idx++;
|
||||
}
|
||||
|
||||
// push env on the stack
|
||||
offset -= (largs->envc+1) * sizeof(char*);
|
||||
for(i=0; i<largs->envc; i++) {
|
||||
((char**) (stack+offset))[i] = (char*) (stack+idx);
|
||||
|
||||
while(((char*) stack)[idx] != '\0')
|
||||
idx++;
|
||||
idx++;
|
||||
}
|
||||
((char**) (stack+offset))[largs->envc] = NULL;
|
||||
|
||||
// push pointer to env
|
||||
offset -= sizeof(char**);
|
||||
if (!(largs->envc))
|
||||
*((char***) (stack+offset)) = NULL;
|
||||
else
|
||||
*((char***) (stack+offset)) = (char**) (stack + offset + sizeof(char**));
|
||||
|
||||
// push pointer to argv
|
||||
offset -= sizeof(char**);
|
||||
*((char***) (stack+offset)) = (char**) (stack + offset + 2*sizeof(char**) + (largs->envc+1) * sizeof(char*));
|
||||
|
||||
// push argc on the stack
|
||||
offset -= sizeof(ssize_t);
|
||||
*((ssize_t*) (stack+offset)) = (ssize_t) largs->argc;
|
||||
|
||||
kfree(largs);
|
||||
|
||||
// clear fpu state => currently not supported
|
||||
curr_task->flags &= ~(TASK_FPU_USED|TASK_FPU_INIT);
|
||||
|
||||
jump_to_user_code(header.entry, stack+offset);
|
||||
|
||||
return 0;
|
||||
|
||||
invalid:
|
||||
kprintf("Invalid executable!\n");
|
||||
kprintf("magic number 0x%x\n", (uint32_t) header.ident.magic);
|
||||
kprintf("header type 0x%x\n", (uint32_t) header.type);
|
||||
kprintf("machine type 0x%x\n", (uint32_t) header.machine);
|
||||
kprintf("elf ident class 0x%x\n", (uint32_t) header.ident._class);
|
||||
kprintf("elf identdata 0x%x\n", header.ident.data);
|
||||
kprintf("program entry point 0x%lx\n", (size_t) header.entry);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/** @brief This call is used to adapt create_task calls
|
||||
* which want to have a start function and argument list */
|
||||
static int user_entry(void* arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
finish_task_switch();
|
||||
|
||||
if (BUILTIN_EXPECT(!arg, 0))
|
||||
return -EINVAL;
|
||||
|
||||
ret = load_task((load_args_t*) arg);
|
||||
|
||||
kfree(arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Luxus-edition of create_user_task functions. Just call with an exe name
|
||||
*
|
||||
* @param id Pointer to the tid_t structure which shall be filles
|
||||
* @param fname Executable's path and filename
|
||||
* @param argv Arguments list
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -ENOMEM (-12) or -EINVAL (-22) on failure
|
||||
*/
|
||||
int create_user_task(tid_t* id, const char* fname, char** argv)
|
||||
{
|
||||
vfs_node_t* node;
|
||||
int argc = 0;
|
||||
size_t i, buffer_size = 0;
|
||||
load_args_t* load_args = NULL;
|
||||
char *dest, *src;
|
||||
|
||||
node = findnode_fs((char*) fname);
|
||||
if (!node || !(node->type == FS_FILE))
|
||||
return -EINVAL;
|
||||
|
||||
// determine buffer size of argv
|
||||
if (argv) {
|
||||
while (argv[argc]) {
|
||||
buffer_size += (strlen(argv[argc]) + 1);
|
||||
argc++;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc <= 0)
|
||||
return -EINVAL;
|
||||
if (buffer_size >= MAX_ARGS)
|
||||
return -EINVAL;
|
||||
|
||||
load_args = kmalloc(sizeof(load_args_t));
|
||||
if (BUILTIN_EXPECT(!load_args, 0))
|
||||
return -ENOMEM;
|
||||
load_args->node = node;
|
||||
load_args->argc = argc;
|
||||
load_args->envc = 0;
|
||||
dest = load_args->buffer;
|
||||
for (i=0; i<argc; i++) {
|
||||
src = argv[i];
|
||||
while ((*dest++ = *src++) != 0);
|
||||
}
|
||||
|
||||
|
||||
/* create new task */
|
||||
return create_task(id, user_entry, load_args, NORMAL_PRIO);
|
||||
}
|
||||
#endif
|
101
hermit/arch/x86/kernel/timer.c
Normal file
101
hermit/arch/x86/kernel/timer.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/processor.h>
|
||||
#include <hermit/time.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* This will keep track of how many ticks the system
|
||||
* has been running for
|
||||
*/
|
||||
static volatile uint64_t timer_ticks = 0;
|
||||
|
||||
uint64_t get_clock_tick(void)
|
||||
{
|
||||
return timer_ticks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles the timer. In this case, it's very simple: We
|
||||
* increment the 'timer_ticks' variable every time the
|
||||
* timer fires.
|
||||
*/
|
||||
static void timer_handler(struct state *s)
|
||||
{
|
||||
/* Increment our 'tick counter' */
|
||||
timer_ticks++;
|
||||
}
|
||||
|
||||
#define LATCH(f) ((CLOCK_TICK_RATE + f/2) / f)
|
||||
#define WAIT_SOME_TIME() do { uint64_t start = rdtsc(); \
|
||||
while(rdtsc() - start < 1000000) ; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Sets up the system clock by installing the timer handler
|
||||
* into IRQ0
|
||||
*/
|
||||
int timer_init(void)
|
||||
{
|
||||
/*
|
||||
* Installs 'timer_handler' for the PIC and APIC timer,
|
||||
* only one handler will be later used.
|
||||
*/
|
||||
irq_install_handler(32, timer_handler);
|
||||
irq_install_handler(123, timer_handler);
|
||||
|
||||
/*
|
||||
* Port 0x43 is for initializing the PIT:
|
||||
*
|
||||
* 0x34 means the following:
|
||||
* 0b... (step-by-step binary representation)
|
||||
* ... 00 - channel 0
|
||||
* ... 11 - write two values to counter register:
|
||||
* first low-, then high-byte
|
||||
* ... 010 - mode number 2: "rate generator" / frequency divider
|
||||
* ... 0 - binary counter (the alternative is BCD)
|
||||
*/
|
||||
outportb(0x43, 0x34);
|
||||
|
||||
WAIT_SOME_TIME();
|
||||
|
||||
/* Port 0x40 is for the counter register of channel 0 */
|
||||
|
||||
outportb(0x40, LATCH(TIMER_FREQ) & 0xFF); /* low byte */
|
||||
|
||||
WAIT_SOME_TIME();
|
||||
|
||||
outportb(0x40, LATCH(TIMER_FREQ) >> 8); /* high byte */
|
||||
|
||||
return 0;
|
||||
}
|
239
hermit/arch/x86/kernel/vga.c
Normal file
239
hermit/arch/x86/kernel/vga.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/string.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/vga.h>
|
||||
|
||||
#ifdef CONFIG_VGA
|
||||
|
||||
/*
|
||||
* These define our textpointer, our background and foreground
|
||||
* colors (attributes), and x and y cursor coordinates
|
||||
*/
|
||||
static unsigned short *textmemptr;
|
||||
static int attrib = 0x0F;
|
||||
static int csr_x = 0, csr_y = 0;
|
||||
|
||||
inline static unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest, 0))
|
||||
return dest;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
dest[i] = val;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Scrolls the screen */
|
||||
static void scroll(void)
|
||||
{
|
||||
unsigned blank, temp;
|
||||
|
||||
/*
|
||||
* A blank is defined as a space... we need to give it
|
||||
* backcolor too
|
||||
*/
|
||||
blank = 0x20 | (attrib << 8);
|
||||
|
||||
/* Row 25 is the end, this means we need to scroll up */
|
||||
if (csr_y >= 25) {
|
||||
|
||||
/*
|
||||
* Move the current text chunk that makes up the screen
|
||||
*
|
||||
* back in the buffer by one line
|
||||
*/
|
||||
temp = csr_y - 25 + 1;
|
||||
memcpy(textmemptr, textmemptr + temp * 80,
|
||||
(25 - temp) * 80 * 2);
|
||||
|
||||
/*
|
||||
* Finally, we set the chunk of memory that occupies
|
||||
* the last line of text to our 'blank' character
|
||||
*/
|
||||
memsetw(textmemptr + (25 - temp) * 80, blank, 80);
|
||||
csr_y = 25 - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the hardware cursor: the little blinking line
|
||||
* on the screen under the last character pressed!
|
||||
*/
|
||||
static void move_csr(void)
|
||||
{
|
||||
unsigned temp;
|
||||
|
||||
/*
|
||||
* The equation for finding the index in a linear
|
||||
* chunk of memory can be represented by:
|
||||
* Index = [(y * width) + x] */
|
||||
temp = csr_y * 80 + csr_x;
|
||||
|
||||
/*
|
||||
* This sends a command to indicies 14 and 15 in the
|
||||
* CRT Control Register of the VGA controller. These
|
||||
* are the high and low bytes of the index that show
|
||||
* where the hardware cursor is to be 'blinking'. To
|
||||
* learn more, you should look up some VGA specific
|
||||
* programming documents. A great start to graphics:
|
||||
* http://www.brackeen.com/home/vga
|
||||
*/
|
||||
outportb(0x3D4, 14);
|
||||
outportb(0x3D5, temp >> 8);
|
||||
outportb(0x3D4, 15);
|
||||
outportb(0x3D5, temp);
|
||||
}
|
||||
|
||||
/* Clears the screen */
|
||||
void vga_clear(void)
|
||||
{
|
||||
unsigned blank;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Again, we need the 'short' that will be used to
|
||||
* represent a space with color
|
||||
*/
|
||||
blank = 0x20 | (attrib << 8);
|
||||
|
||||
/*
|
||||
* Fills the entire screen with spaces in our current
|
||||
* color
|
||||
**/
|
||||
for (i = 0; i < 25; i++)
|
||||
memsetw(textmemptr + i * 80, blank, 80);
|
||||
|
||||
/*
|
||||
* Update out virtual cursor, and then move the
|
||||
* hardware cursor
|
||||
*/
|
||||
csr_x = 0;
|
||||
csr_y = 0;
|
||||
move_csr();
|
||||
}
|
||||
|
||||
/* Puts a single character on the screen */
|
||||
int vga_putchar(unsigned char c)
|
||||
{
|
||||
unsigned short *where;
|
||||
unsigned att = attrib << 8;
|
||||
|
||||
/* Handle a backspace by moving the cursor back one space */
|
||||
if (c == 0x08) {
|
||||
if (csr_x != 0)
|
||||
csr_x--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles a tab by incrementing the cursor's x, but only
|
||||
* to a point that will make it divisible by 8
|
||||
*/
|
||||
else if (c == 0x09) {
|
||||
csr_x = (csr_x + 8) & ~(8 - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles a 'Carriage Return', which simply brings the
|
||||
* cursor back to the margin
|
||||
*/
|
||||
else if (c == '\r') {
|
||||
csr_x = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We handle our newlines the way DOS and BIOS do: we
|
||||
* treat it as if a 'CR' was there also, so we bring the
|
||||
* cursor to the margin and increment the 'y' value
|
||||
*/
|
||||
else if (c == '\n') {
|
||||
csr_x = 0;
|
||||
csr_y++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any character greater than and including the space is a
|
||||
* printable character. The equation for finding the index
|
||||
* in a linear chunk of memory can be represented by:
|
||||
* Index = [(y * width) + x]
|
||||
*/
|
||||
else if (c >= ' ') {
|
||||
where = textmemptr + (csr_y * 80 + csr_x);
|
||||
*where = c | att; /* Character AND attributes: color */
|
||||
csr_x++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the cursor has reached the edge of the screen's width, we
|
||||
* insert a new line in there
|
||||
*/
|
||||
if (csr_x >= 80) {
|
||||
csr_x = 0;
|
||||
csr_y++;
|
||||
}
|
||||
|
||||
/* Scroll the screen if needed, and finally move the cursor */
|
||||
scroll();
|
||||
move_csr();
|
||||
|
||||
return (int) c;
|
||||
}
|
||||
|
||||
/* Uses the routine above to output a string... */
|
||||
int vga_puts(const char *text)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < strlen(text); i++)
|
||||
vga_putchar(text[i]);
|
||||
|
||||
return i-1;
|
||||
}
|
||||
|
||||
/* Sets the forecolor and backcolor we will use */
|
||||
//void settextcolor(unsigned char forecolor, unsigned char backcolor)
|
||||
//{
|
||||
|
||||
/*
|
||||
* Top 4 bytes are the background, bottom 4 bytes
|
||||
* are the foreground color
|
||||
*/
|
||||
// attrib = (backcolor << 4) | (forecolor & 0x0F);
|
||||
//}
|
||||
|
||||
/* Sets our text-mode VGA pointer, then clears the screen for us */
|
||||
void vga_init(void)
|
||||
{
|
||||
textmemptr = (unsigned short *)VIDEO_MEM_ADDR;
|
||||
vga_clear();
|
||||
}
|
||||
|
||||
#endif
|
4
hermit/arch/x86/mm/Makefile
Normal file
4
hermit/arch/x86/mm/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
C_source := page.c
|
||||
MODULE := arch_x86_mm
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
350
hermit/arch/x86/mm/page.c
Normal file
350
hermit/arch/x86/mm/page.c
Normal file
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* 2014, Steffen Vogel, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a 32/64 bit portable paging implementation for the x86 architecture
|
||||
* using self-referenced page tables i.
|
||||
* See http://www.noteblok.net/2014/06/14/bachelor/ for a detailed description.
|
||||
*
|
||||
* @author Steffen Vogel <steffen.vogel@rwth-aachen.de>
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/memory.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/spinlock.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/multiboot.h>
|
||||
|
||||
/* Note that linker symbols are not variables, they have no memory
|
||||
* allocated for maintaining a value, rather their address is their value. */
|
||||
extern const void kernel_start;
|
||||
//extern const void kernel_end;
|
||||
|
||||
/// This page is reserved for copying
|
||||
#define PAGE_TMP (PAGE_FLOOR((size_t) &kernel_start) - PAGE_SIZE)
|
||||
|
||||
/** Lock for kernel space page tables */
|
||||
static spinlock_t kslock = SPINLOCK_INIT;
|
||||
|
||||
/** This PGD table is initialized in entry.asm */
|
||||
extern size_t* boot_map;
|
||||
|
||||
#if 0
|
||||
/** A self-reference enables direct access to all page tables */
|
||||
static size_t * const self[PAGE_LEVELS] = {
|
||||
(size_t *) 0xFFC00000,
|
||||
(size_t *) 0xFFFFF000
|
||||
};
|
||||
|
||||
/** An other self-reference for page_map_copy() */
|
||||
static size_t * const other[PAGE_LEVELS] = {
|
||||
(size_t *) 0xFF800000,
|
||||
(size_t *) 0xFFFFE000
|
||||
};
|
||||
#else
|
||||
/** A self-reference enables direct access to all page tables */
|
||||
static size_t* const self[PAGE_LEVELS] = {
|
||||
(size_t *) 0xFFFFFF8000000000,
|
||||
(size_t *) 0xFFFFFFFFC0000000,
|
||||
(size_t *) 0xFFFFFFFFFFE00000,
|
||||
(size_t *) 0xFFFFFFFFFFFFF000
|
||||
};
|
||||
|
||||
/** An other self-reference for page_map_copy() */
|
||||
static size_t * const other[PAGE_LEVELS] = {
|
||||
(size_t *) 0xFFFFFF0000000000,
|
||||
(size_t *) 0xFFFFFFFF80000000,
|
||||
(size_t *) 0xFFFFFFFFFFC00000,
|
||||
(size_t *) 0xFFFFFFFFFFFFE000
|
||||
};
|
||||
#endif
|
||||
|
||||
size_t virt_to_phys(size_t addr)
|
||||
{
|
||||
size_t vpn = addr >> PAGE_BITS; // virtual page number
|
||||
size_t entry = self[0][vpn]; // page table entry
|
||||
size_t off = addr & ~PAGE_MASK; // offset within page
|
||||
size_t phy = entry & PAGE_MASK; // physical page frame number
|
||||
|
||||
return phy | off;
|
||||
}
|
||||
|
||||
//TODO: code is missing
|
||||
int page_set_flags(size_t viraddr, uint32_t npages, int flags)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits)
|
||||
{
|
||||
int lvl, ret = -ENOMEM;
|
||||
long vpn = viraddr >> PAGE_BITS;
|
||||
long first[PAGE_LEVELS], last[PAGE_LEVELS];
|
||||
|
||||
/* Calculate index boundaries for page map traversal */
|
||||
for (lvl=0; lvl<PAGE_LEVELS; lvl++) {
|
||||
first[lvl] = (vpn ) >> (lvl * PAGE_MAP_BITS);
|
||||
last[lvl] = (vpn+npages-1) >> (lvl * PAGE_MAP_BITS);
|
||||
}
|
||||
|
||||
/** @todo: might not be sufficient! */
|
||||
if (bits & PG_USER)
|
||||
spinlock_irqsave_lock(¤t_task->page_lock);
|
||||
else
|
||||
spinlock_lock(&kslock);
|
||||
|
||||
/* Start iterating through the entries
|
||||
* beginning at the root table (PGD or PML4) */
|
||||
for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) {
|
||||
for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) {
|
||||
if (lvl) { /* PML4, PDPT, PGD */
|
||||
if (!(self[lvl][vpn] & PG_PRESENT)) {
|
||||
/* There's no table available which covers the region.
|
||||
* Therefore we need to create a new empty table. */
|
||||
size_t phyaddr = get_pages(1);
|
||||
if (BUILTIN_EXPECT(!phyaddr, 0))
|
||||
goto out;
|
||||
|
||||
if (bits & PG_USER)
|
||||
atomic_int32_inc(¤t_task->user_usage);
|
||||
|
||||
/* Reference the new table within its parent */
|
||||
#if 0
|
||||
self[lvl][vpn] = phyaddr | bits | PG_PRESENT | PG_USER | PG_RW;
|
||||
#else
|
||||
self[lvl][vpn] = (phyaddr | bits | PG_PRESENT | PG_USER | PG_RW) & ~PG_XD;
|
||||
#endif
|
||||
|
||||
/* Fill new table with zeros */
|
||||
memset(&self[lvl-1][vpn<<PAGE_MAP_BITS], 0, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
else { /* PGT */
|
||||
if (self[lvl][vpn] & PG_PRESENT)
|
||||
/* There's already a page mapped at this address.
|
||||
* We have to flush a single TLB entry. */
|
||||
tlb_flush_one_page(vpn << PAGE_BITS);
|
||||
|
||||
self[lvl][vpn] = phyaddr | bits | PG_PRESENT;
|
||||
phyaddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (bits & PG_USER)
|
||||
spinlock_irqsave_unlock(¤t_task->page_lock);
|
||||
else
|
||||
spinlock_unlock(&kslock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Tables are freed by page_map_drop() */
|
||||
int page_unmap(size_t viraddr, size_t npages)
|
||||
{
|
||||
/* We aquire both locks for kernel and task tables
|
||||
* as we dont know to which the region belongs. */
|
||||
spinlock_irqsave_lock(¤t_task->page_lock);
|
||||
spinlock_lock(&kslock);
|
||||
|
||||
/* Start iterating through the entries.
|
||||
* Only the PGT entries are removed. Tables remain allocated. */
|
||||
size_t vpn, start = viraddr>>PAGE_BITS;
|
||||
for (vpn=start; vpn<start+npages; vpn++)
|
||||
self[0][vpn] = 0;
|
||||
|
||||
spinlock_irqsave_unlock(¤t_task->page_lock);
|
||||
spinlock_unlock(&kslock);
|
||||
|
||||
/* This can't fail because we don't make checks here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int page_map_drop(void)
|
||||
{
|
||||
void traverse(int lvl, long vpn) {
|
||||
long stop;
|
||||
for (stop=vpn+PAGE_MAP_ENTRIES; vpn<stop; vpn++) {
|
||||
if ((self[lvl][vpn] & PG_PRESENT) && (self[lvl][vpn] & PG_USER)) {
|
||||
/* Post-order traversal */
|
||||
if (lvl)
|
||||
traverse(lvl-1, vpn<<PAGE_MAP_BITS);
|
||||
|
||||
put_pages(self[lvl][vpn] & PAGE_MASK, 1);
|
||||
atomic_int32_dec(¤t_task->user_usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_irqsave_lock(¤t_task->page_lock);
|
||||
|
||||
traverse(PAGE_LEVELS-1, 0);
|
||||
|
||||
spinlock_irqsave_unlock(¤t_task->page_lock);
|
||||
|
||||
/* This can't fail because we don't make checks here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int page_map_copy(task_t *dest)
|
||||
{
|
||||
int traverse(int lvl, long vpn) {
|
||||
long stop;
|
||||
for (stop=vpn+PAGE_MAP_ENTRIES; vpn<stop; vpn++) {
|
||||
if (self[lvl][vpn] & PG_PRESENT) {
|
||||
if (self[lvl][vpn] & PG_USER) {
|
||||
size_t phyaddr = get_pages(1);
|
||||
if (BUILTIN_EXPECT(!phyaddr, 0))
|
||||
return -ENOMEM;
|
||||
|
||||
atomic_int32_inc(&dest->user_usage);
|
||||
|
||||
other[lvl][vpn] = phyaddr | (self[lvl][vpn] & ~PAGE_MASK);
|
||||
if (lvl) /* PML4, PDPT, PGD */
|
||||
traverse(lvl-1, vpn<<PAGE_MAP_BITS); /* Pre-order traversal */
|
||||
else { /* PGT */
|
||||
page_map(PAGE_TMP, phyaddr, 1, PG_RW);
|
||||
memcpy((void*) PAGE_TMP, (void*) (vpn<<PAGE_BITS), PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
else if (self[lvl][vpn] & PG_SELF)
|
||||
other[lvl][vpn] = 0;
|
||||
else
|
||||
other[lvl][vpn] = self[lvl][vpn];
|
||||
}
|
||||
else
|
||||
other[lvl][vpn] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
spinlock_irqsave_lock(¤t_task->page_lock);
|
||||
self[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = dest->page_map | PG_PRESENT | PG_SELF | PG_RW;
|
||||
|
||||
int ret = traverse(PAGE_LEVELS-1, 0);
|
||||
|
||||
other[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-1] = dest->page_map | PG_PRESENT | PG_SELF | PG_RW;
|
||||
self [PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = 0;
|
||||
spinlock_irqsave_unlock(¤t_task->page_lock);
|
||||
|
||||
/* Flush TLB entries of 'other' self-reference */
|
||||
flush_tlb();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void page_fault_handler(struct state *s)
|
||||
{
|
||||
size_t viraddr = read_cr2();
|
||||
task_t* task = current_task;
|
||||
|
||||
// on demand userspace heap mapping
|
||||
if ((task->heap) && (viraddr >= task->heap->start) && (viraddr < task->heap->end)) {
|
||||
viraddr &= PAGE_MASK;
|
||||
|
||||
size_t phyaddr = get_page();
|
||||
if (BUILTIN_EXPECT(!phyaddr, 0)) {
|
||||
kprintf("out of memory: task = %u\n", task->id);
|
||||
goto default_handler;
|
||||
}
|
||||
|
||||
int ret = page_map(viraddr, phyaddr, 1, PG_USER|PG_RW);
|
||||
if (BUILTIN_EXPECT(ret, 0)) {
|
||||
kprintf("map_region: could not map %#lx to %#lx, task = %u\n", phyaddr, viraddr, task->id);
|
||||
put_page(phyaddr);
|
||||
|
||||
goto default_handler;
|
||||
}
|
||||
|
||||
memset((void*) viraddr, 0x00, PAGE_SIZE); // fill with zeros
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
default_handler:
|
||||
#if 0
|
||||
kprintf("Page Fault Exception (%d) at cs:ip = %#x:%#lx, task = %u, addr = %#lx, error = %#x [ %s %s %s %s %s ]\n",
|
||||
s->int_no, s->cs, s->eip, current_task->id, viraddr, s->error,
|
||||
(s->error & 0x4) ? "user" : "supervisor",
|
||||
(s->error & 0x10) ? "instruction" : "data",
|
||||
(s->error & 0x2) ? "write" : ((s->error & 0x10) ? "fetch" : "read"),
|
||||
(s->error & 0x1) ? "protection" : "not present",
|
||||
(s->error & 0x8) ? "reserved bit" : "\b");
|
||||
#else
|
||||
kprintf("Page Fault Exception (%d) at cs:ip = %#x:%#lx, task = %u, addr = %#lx, error = %#x [ %s %s %s %s %s ]\n",
|
||||
s->int_no, s->cs, s->rip, current_task->id, viraddr, s->error,
|
||||
(s->error & 0x4) ? "user" : "supervisor",
|
||||
(s->error & 0x10) ? "instruction" : "data",
|
||||
(s->error & 0x2) ? "write" : ((s->error & 0x10) ? "fetch" : "read"),
|
||||
(s->error & 0x1) ? "protection" : "not present",
|
||||
(s->error & 0x8) ? "reserved bit" : "\b");
|
||||
#endif
|
||||
|
||||
while(1) HALT;
|
||||
}
|
||||
|
||||
int page_init(void)
|
||||
{
|
||||
size_t addr, npages;
|
||||
int i;
|
||||
|
||||
/* Replace default pagefault handler */
|
||||
irq_uninstall_handler(14);
|
||||
irq_install_handler(14, page_fault_handler);
|
||||
|
||||
/* Map multiboot information and modules */
|
||||
if (mb_info) {
|
||||
// already mapped => entry.asm
|
||||
//addr = (size_t) mb_info & PAGE_MASK;
|
||||
//npages = PAGE_FLOOR(sizeof(*mb_info)) >> PAGE_BITS;
|
||||
//page_map(addr, addr, npages, PG_GLOBAL);
|
||||
|
||||
if (mb_info->flags & MULTIBOOT_INFO_MODS) {
|
||||
addr = mb_info->mods_addr;
|
||||
npages = PAGE_FLOOR(mb_info->mods_count*sizeof(multiboot_module_t)) >> PAGE_BITS;
|
||||
page_map(addr, addr, npages, PG_GLOBAL);
|
||||
kprintf("Map module info at 0x%lx\n", addr);
|
||||
|
||||
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
|
||||
for(i=0; i<mb_info->mods_count; i++) {
|
||||
addr = mmodule[i].mod_start;
|
||||
npages = PAGE_FLOOR(mmodule[i].mod_end - mmodule[i].mod_start) >> PAGE_BITS;
|
||||
page_map(addr, addr, npages, PG_GLOBAL);
|
||||
kprintf("Map modules at 0x%lx\n", addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
68
hermit/include/hermit/config.h
Normal file
68
hermit/include/hermit/config.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HERMIT_VERSION "0.1"
|
||||
#define MAX_TASKS 16
|
||||
#define MAX_FNAME 128
|
||||
#define TIMER_FREQ 100 /* in HZ */
|
||||
#define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */
|
||||
#define VIDEO_MEM_ADDR 0xB8000 /* the video memory address */
|
||||
#define CACHE_LINE 64
|
||||
#define KERNEL_STACK_SIZE (8<<10) /* 8 KiB */
|
||||
#define DEFAULT_STACK_SIZE (16*1024) /* 16 KiB */
|
||||
#define BITMAP_SIZE (16<<5) /* for 16 MiB of RAM */
|
||||
#define KMSG_SIZE (8*1024)
|
||||
#define INT_SYSCALL 0x80
|
||||
#define MAILBOX_SIZE 32
|
||||
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
//#define CONFIG_VGA
|
||||
|
||||
#define BUILTIN_EXPECT(exp, b) __builtin_expect((exp), (b))
|
||||
//#define BUILTIN_EXPECT(exp, b) (exp)
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define STDCALL __attribute__((stdcall))
|
||||
|
||||
#define HAVE_ARCH_MEMSET
|
||||
#define HAVE_ARCH_MEMCPY
|
||||
#define HAVE_ARCH_STRLEN
|
||||
#define HAVE_ARCH_STRCPY
|
||||
#define HAVE_ARCH_STRNCPY
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
129
hermit/include/hermit/ctype.h
Normal file
129
hermit/include/hermit/ctype.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/****************************************************************************************
|
||||
*
|
||||
* Author: Stefan Lankes
|
||||
* Chair for Operating Systems, RWTH Aachen University
|
||||
* Date: 24/03/2011
|
||||
*
|
||||
****************************************************************************************
|
||||
*
|
||||
* Written by the Chair for Operating Systems, RWTH Aachen University
|
||||
*
|
||||
* NO Copyright (C) 2010, Stefan Lankes,
|
||||
* consider these trivial functions to be public domain.
|
||||
*
|
||||
* These functions are distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/ctype.h
|
||||
* @brief Functions related to alphanumerical character values
|
||||
*
|
||||
* This file contains functions helping to determine
|
||||
* the type of alphanumerical character values.
|
||||
*/
|
||||
|
||||
#ifndef __CTYPE_H_
|
||||
#define __CYTPE_H_
|
||||
|
||||
/** Returns true if the value of 'c' is an ASCII-charater */
|
||||
static inline int isascii(int c)
|
||||
{
|
||||
return (((unsigned char)(c))<=0x7f);
|
||||
}
|
||||
|
||||
/** Applies an and-operation to
|
||||
* push the value of 'c' into the ASCII-range */
|
||||
static inline int toascii(int c)
|
||||
{
|
||||
return (((unsigned char)(c))&0x7f);
|
||||
}
|
||||
|
||||
/** Returns true if the value of 'c' is the
|
||||
* space character or a control character */
|
||||
static inline int isspace(int c)
|
||||
{
|
||||
if (!isascii(c))
|
||||
return 0;
|
||||
|
||||
if (' ' == (unsigned char) c)
|
||||
return 1;
|
||||
if ('\n' == (unsigned char) c)
|
||||
return 1;
|
||||
if ('\r' == (unsigned char) c)
|
||||
return 1;
|
||||
if ('\t' == (unsigned char) c)
|
||||
return 1;
|
||||
if ('\v' == (unsigned char) c)
|
||||
return 1;
|
||||
if ('\f' == (unsigned char) c)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns true if the value of 'c' is a number */
|
||||
static inline int isdigit(int c)
|
||||
{
|
||||
if (!isascii(c))
|
||||
return 0;
|
||||
|
||||
if (((unsigned char) c >= '0') && ((unsigned char) c <= '9'))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns true if the value of 'c' is a lower case letter */
|
||||
static inline int islower(int c)
|
||||
{
|
||||
if (!isascii(c))
|
||||
return 0;
|
||||
|
||||
if (((unsigned char) c >= 'a') && ((unsigned char) c <= 'z'))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns true if the value of 'c' is an upper case letter */
|
||||
static inline int isupper(int c)
|
||||
{
|
||||
if (!isascii(c))
|
||||
return 0;
|
||||
|
||||
if (((unsigned char) c >= 'A') && ((unsigned char) c <= 'Z'))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns true if the value of 'c' is an alphabetic character */
|
||||
static inline int isalpha(int c)
|
||||
{
|
||||
if (isupper(c) || islower(c))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Makes the input character lower case.\n Will do nothing if it
|
||||
* was something different than an upper case letter before. */
|
||||
static inline unsigned char tolower(unsigned char c)
|
||||
{
|
||||
if (isupper(c))
|
||||
c -= 'A'-'a';
|
||||
return c;
|
||||
}
|
||||
|
||||
/** Makes the input character upper case.\n Will do nothing if it
|
||||
* was something different than a lower case letter before. */
|
||||
static inline unsigned char toupper(unsigned char c)
|
||||
{
|
||||
if (islower(c))
|
||||
c -= 'a'-'A';
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
180
hermit/include/hermit/errno.h
Normal file
180
hermit/include/hermit/errno.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/errno.h
|
||||
* @brief Error number define constants
|
||||
*
|
||||
* This file just contains the full list of error numbers which can
|
||||
* be returned somewhere. In principle, we use the same error codes
|
||||
* than newlib.
|
||||
*/
|
||||
|
||||
#ifndef __ERRNO_H__
|
||||
#define __ERRNO_H__
|
||||
|
||||
#include <hermit/config.h>
|
||||
#include <asm/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EPERM 1 /* Not super-user */
|
||||
#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 /* Arg list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No children */
|
||||
#define EAGAIN 11 /* No more processes */
|
||||
#define ENOMEM 12 /* Not enough core */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#endif
|
||||
#define EBUSY 16 /* Mount device 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 /* Too many open files in system */
|
||||
#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 arg out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
||||
#define ENOMSG 35 /* No message of desired type */
|
||||
#define EIDRM 36 /* Identifier removed */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ECHRNG 37 /* Channel number out of range */
|
||||
#define EL2NSYNC 38 /* Level 2 not synchronized */
|
||||
#define EL3HLT 39 /* Level 3 halted */
|
||||
#define EL3RST 40 /* Level 3 reset */
|
||||
#define ELNRNG 41 /* Link number out of range */
|
||||
#define EUNATCH 42 /* Protocol driver not attached */
|
||||
#define ENOCSI 43 /* No CSI structure available */
|
||||
#define EL2HLT 44 /* Level 2 halted */
|
||||
#endif
|
||||
#define EDEADLK 45 /* Deadlock condition */
|
||||
#define ENOLCK 46 /* No record locks available */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define EBADE 50 /* Invalid exchange */
|
||||
#define EBADR 51 /* Invalid request descriptor */
|
||||
#define EXFULL 52 /* Exchange full */
|
||||
#define ENOANO 53 /* No anode */
|
||||
#define EBADRQC 54 /* Invalid request code */
|
||||
#define EBADSLT 55 /* Invalid slot */
|
||||
#define EDEADLOCK 56 /* File locking deadlock error */
|
||||
#define EBFONT 57 /* Bad font file fmt */
|
||||
#endif
|
||||
#define ENOSTR 60 /* Device not a stream */
|
||||
#define ENODATA 61 /* No data (for no delay io) */
|
||||
#define ETIME 62 /* Timer expired */
|
||||
#define ENOSR 63 /* Out of streams resources */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#define ENOPKG 65 /* Package not installed */
|
||||
#define EREMOTE 66 /* The object is remote */
|
||||
#endif
|
||||
#define ENOLINK 67 /* The link has been severed */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define EADV 68 /* Advertise error */
|
||||
#define ESRMNT 69 /* Srmount error */
|
||||
#define ECOMM 70 /* Communication error on send */
|
||||
#endif
|
||||
#define EPROTO 71 /* Protocol error */
|
||||
#define EMULTIHOP 74 /* Multihop attempted */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ELBIN 75 /* Inode is remote (not really error) */
|
||||
#define EDOTDOT 76 /* Cross mount point (not really error) */
|
||||
#endif
|
||||
#define EBADMSG 77 /* Trying to read unreadable message */
|
||||
#define EFTYPE 79 /* Inappropriate file type or format */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ENOTUNIQ 80 /* Given log. name not unique */
|
||||
#define EBADFD 81 /* f.d. invalid for this operation */
|
||||
#define EREMCHG 82 /* Remote address changed */
|
||||
#define ELIBACC 83 /* Can't access a needed shared lib */
|
||||
#define ELIBBAD 84 /* Accessing a corrupted shared lib */
|
||||
#define ELIBSCN 85 /* .lib section in a.out corrupted */
|
||||
#define ELIBMAX 86 /* Attempting to link in too many libs */
|
||||
#define ELIBEXEC 87 /* Attempting to exec a shared library */
|
||||
#endif
|
||||
#define ENOSYS 88 /* Function not implemented */
|
||||
#ifdef __CYGWIN__
|
||||
#define ENMFILE 89 /* No more files */
|
||||
#endif
|
||||
#define ENOTEMPTY 90 /* Directory not empty */
|
||||
#define ENAMETOOLONG 91 /* File or path name too long */
|
||||
#define ELOOP 92 /* Too many symbolic links */
|
||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||
#define ECONNRESET 104 /* Connection reset by peer */
|
||||
#define ENOBUFS 105 /* No buffer space available */
|
||||
#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */
|
||||
#define EPROTOTYPE 107 /* Protocol wrong type for socket */
|
||||
#define ENOTSOCK 108 /* Socket operation on non-socket */
|
||||
#define ENOPROTOOPT 109 /* Protocol not available */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ESHUTDOWN 110 /* Can't send after socket shutdown */
|
||||
#endif
|
||||
#define ECONNREFUSED 111 /* Connection refused */
|
||||
#define EADDRINUSE 112 /* Address already in use */
|
||||
#define ECONNABORTED 113 /* Connection aborted */
|
||||
#define ENETUNREACH 114 /* Network is unreachable */
|
||||
#define ENETDOWN 115 /* Network interface is not configured */
|
||||
#define ETIMEDOUT 116 /* Connection timed out */
|
||||
#define EHOSTDOWN 117 /* Host is down */
|
||||
#define EHOSTUNREACH 118 /* Host is unreachable */
|
||||
#define EINPROGRESS 119 /* Connection already in progress */
|
||||
#define EALREADY 120 /* Socket already connected */
|
||||
#define EDESTADDRREQ 121 /* Destination address required */
|
||||
#define EMSGSIZE 122 /* Message too long */
|
||||
#define EPROTONOSUPPORT 123 /* Unknown protocol */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ESOCKTNOSUPPORT 124 /* Socket type not supported */
|
||||
#endif
|
||||
#define EADDRNOTAVAIL 125 /* Address not available */
|
||||
#define ENETRESET 126
|
||||
#define EISCONN 127 /* Socket is already connected */
|
||||
#define ENOTCONN 128 /* Socket is not connected */
|
||||
#define ETOOMANYREFS 129
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define EPROCLIM 130
|
||||
#define EUSERS 131
|
||||
#endif
|
||||
#define EDQUOT 132
|
||||
#define ESTALE 133
|
||||
#define ENOTSUP 134 /* Not supported */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ENOMEDIUM 135 /* No medium (in tape drive) */
|
||||
#endif
|
||||
#ifdef __CYGWIN__
|
||||
#define ENOSHARE 136 /* No such host or network path */
|
||||
#define ECASECLASH 137 /* Filename exists with different case */
|
||||
#endif
|
||||
#define EILSEQ 138
|
||||
#define EOVERFLOW 139 /* Value too large for defined data type */
|
||||
#define ECANCELED 140 /* Operation canceled */
|
||||
#define ENOTRECOVERABLE 141 /* State not recoverable */
|
||||
#define EOWNERDEAD 142 /* Previous owner died */
|
||||
#ifdef __LINUX_ERRNO_EXTENSIONS__
|
||||
#define ESTRPIPE 143 /* Streams pipe error */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
85
hermit/include/hermit/malloc.h
Normal file
85
hermit/include/hermit/malloc.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Steffen Vogel, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Steffen Vogel <steffen.vogel@rwth-aachen.de>
|
||||
*/
|
||||
|
||||
#ifndef __MALLOC_H__
|
||||
#define __MALLOC_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Binary exponent of maximal size for kmalloc()
|
||||
#define BUDDY_MAX 32 // 4 GB
|
||||
/// Binary exponent of minimal buddy size
|
||||
#define BUDDY_MIN 3 // 8 Byte >= sizeof(buddy_t)
|
||||
/// Binary exponent of the size which we allocate with buddy_fill()
|
||||
#define BUDDY_ALLOC 16 // 64 KByte = 16 * PAGE_SIZE
|
||||
|
||||
#define BUDDY_LISTS (BUDDY_MAX-BUDDY_MIN+1)
|
||||
#define BUDDY_MAGIC 0xBABE
|
||||
|
||||
union buddy;
|
||||
|
||||
/** @brief Buddy
|
||||
*
|
||||
* Every free memory block is stored in a linked list according to its size.
|
||||
* We can use this free memory to store store this buddy_t union which represents
|
||||
* this block (the buddy_t union is alligned to the front).
|
||||
* Therefore the address of the buddy_t union is equal with the address
|
||||
* of the underlying free memory block.
|
||||
*
|
||||
* Every allocated memory block is prefixed with its binary size exponent and
|
||||
* a known magic number. This prefix is hidden by the user because its located
|
||||
* before the actual memory address returned by kmalloc()
|
||||
*/
|
||||
typedef union buddy {
|
||||
/// Pointer to the next buddy in the linked list.
|
||||
union buddy* next;
|
||||
struct {
|
||||
/// The binary exponent of the block size
|
||||
uint8_t exponent;
|
||||
/// Must be equal to BUDDY_MAGIC for a valid memory block
|
||||
uint16_t magic;
|
||||
} prefix;
|
||||
} buddy_t;
|
||||
|
||||
/** @brief Dump free buddies */
|
||||
void buddy_dump(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
70
hermit/include/hermit/memory.h
Normal file
70
hermit/include/hermit/memory.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Steffen Vogel
|
||||
* @file include/memory.h
|
||||
* @brief Memory related functions
|
||||
*
|
||||
* This file contains platform independent memory functions
|
||||
*/
|
||||
|
||||
#ifndef __MEMORY_H__
|
||||
#define __MEMORY_H__
|
||||
|
||||
/** @brief Initialize the memory subsystem */
|
||||
int memory_init(void);
|
||||
|
||||
/** @brief Request physical page frames */
|
||||
size_t get_pages(size_t npages);
|
||||
|
||||
/** @brief Get a single page
|
||||
*
|
||||
* Convenience function: uses get_pages(1);
|
||||
*/
|
||||
static inline size_t get_page(void) { return get_pages(1); }
|
||||
|
||||
/** @brief release physical page frames */
|
||||
int put_pages(size_t phyaddr, size_t npages);
|
||||
|
||||
/** @brief Put a single page
|
||||
*
|
||||
* Convenience function: uses put_pages(1);
|
||||
*/
|
||||
static inline int put_page(size_t phyaddr) { return put_pages(phyaddr, 1); }
|
||||
|
||||
/** @brief Copy a physical page frame
|
||||
*
|
||||
* @param psrc physical address of source page frame
|
||||
* @param pdest physical address of source page frame
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -1 on failure
|
||||
*/
|
||||
int copy_page(size_t pdest, size_t psrc);
|
||||
|
||||
#endif
|
43
hermit/include/hermit/processor.h
Normal file
43
hermit/include/hermit/processor.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __PROCESSOR_H__
|
||||
#define __PROCESSOR_H__
|
||||
|
||||
#include <hermit/config.h>
|
||||
#include <hermit/stddef.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
219
hermit/include/hermit/spinlock.h
Normal file
219
hermit/include/hermit/spinlock.h
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/spinlock.h
|
||||
* @brief Spinlock functions
|
||||
*/
|
||||
|
||||
#ifndef __SPINLOCK_H__
|
||||
#define __SPINLOCK_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/spinlock_types.h>
|
||||
#include <hermit/tasks_types.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/irqflags.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Initialization of a spinlock
|
||||
*
|
||||
* Initialize each spinlock before use!
|
||||
*
|
||||
* @param s Pointer to the spinlock structure to initialize.
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_init(spinlock_t* s) {
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
atomic_int32_set(&s->queue, 0);
|
||||
atomic_int32_set(&s->dequeue, 1);
|
||||
s->owner = MAX_TASKS;
|
||||
s->counter = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Destroy spinlock after use
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_destroy(spinlock_t* s) {
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
s->owner = MAX_TASKS;
|
||||
s->counter = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Lock spinlock at entry of critical section
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_lock(spinlock_t* s) {
|
||||
int32_t ticket;
|
||||
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (s->owner == current_task->id) {
|
||||
s->counter++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ticket = atomic_int32_add(&s->queue, 1);
|
||||
while(atomic_int32_read(&s->dequeue) != ticket) {
|
||||
PAUSE;
|
||||
}
|
||||
s->owner = current_task->id;
|
||||
s->counter = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Unlock spinlock on exit of critical section
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_unlock(spinlock_t* s) {
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
s->counter--;
|
||||
if (!s->counter) {
|
||||
s->owner = MAX_TASKS;
|
||||
atomic_int32_inc(&s->dequeue);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Initialization of a irqsave spinlock
|
||||
*
|
||||
* Initialize each irqsave spinlock before use!
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_irqsave_init(spinlock_irqsave_t* s) {
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
atomic_int32_set(&s->queue, 0);
|
||||
atomic_int32_set(&s->dequeue, 1);
|
||||
s->flags = 0;
|
||||
s->counter = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Destroy irqsave spinlock after use
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_irqsave_destroy(spinlock_irqsave_t* s) {
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
s->flags = 0;
|
||||
s->counter = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Unlock an irqsave spinlock on exit of critical section
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_irqsave_lock(spinlock_irqsave_t* s) {
|
||||
int32_t ticket;
|
||||
uint8_t flags;
|
||||
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
if (s->counter == 1) {
|
||||
s->counter++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ticket = atomic_int32_add(&s->queue, 1);
|
||||
while (atomic_int32_read(&s->dequeue) != ticket) {
|
||||
PAUSE;
|
||||
}
|
||||
|
||||
s->flags = flags;
|
||||
s->counter = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Unlock irqsave spinlock on exit of critical section and re-enable interrupts
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
inline static int spinlock_irqsave_unlock(spinlock_irqsave_t* s) {
|
||||
uint8_t flags;
|
||||
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return -EINVAL;
|
||||
|
||||
s->counter--;
|
||||
if (!s->counter) {
|
||||
flags = s->flags;
|
||||
s->flags = 0;
|
||||
atomic_int32_inc(&s->dequeue);
|
||||
irq_nested_enable(flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
77
hermit/include/hermit/spinlock_types.h
Normal file
77
hermit/include/hermit/spinlock_types.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/spinlock_types.h
|
||||
* @brief Spinlock type definition
|
||||
*/
|
||||
|
||||
#ifndef __SPINLOCK_TYPES_H__
|
||||
#define __SPINLOCK_TYPES_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** @brief Spinlock structure */
|
||||
typedef struct spinlock {
|
||||
/// Internal queue
|
||||
atomic_int32_t queue;
|
||||
/// Internal dequeue
|
||||
atomic_int32_t dequeue;
|
||||
/// Owner of this spinlock structure
|
||||
tid_t owner;
|
||||
/// Internal counter var
|
||||
uint32_t counter;
|
||||
} spinlock_t;
|
||||
|
||||
typedef struct spinlock_irqsave {
|
||||
/// Internal queue
|
||||
atomic_int32_t queue;
|
||||
/// Internal dequeue
|
||||
atomic_int32_t dequeue;
|
||||
/// Internal counter var
|
||||
uint32_t counter;
|
||||
/// Interrupt flag
|
||||
uint8_t flags;
|
||||
} spinlock_irqsave_t;
|
||||
|
||||
/// Macro for spinlock initialization
|
||||
#define SPINLOCK_INIT { ATOMIC_INIT(0), ATOMIC_INIT(1), MAX_TASKS, 0}
|
||||
/// Macro for irqsave spinlock initialization
|
||||
#define SPINLOCK_IRQSAVE_INIT { ATOMIC_INIT(0), ATOMIC_INIT(1), 0, 0}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
56
hermit/include/hermit/stdarg.h
Normal file
56
hermit/include/hermit/stdarg.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __STDARG_H__
|
||||
#define __STDARG_H__
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/stdarg.h
|
||||
* @brief Definition of variable argument lists
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
|
||||
/// Initialize a variable argument list
|
||||
#define va_start __builtin_va_start
|
||||
/// Retrieve next argument
|
||||
#define va_arg __builtin_va_arg
|
||||
/// End using variable argument list
|
||||
#define va_end __builtin_va_end
|
||||
/// copies the (previously initialized) variable argument list
|
||||
#define va_copy __builtin_va_copy
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
57
hermit/include/hermit/stddef.h
Normal file
57
hermit/include/hermit/stddef.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __STDDEF_H__
|
||||
#define __STDDEF_H__
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/stddef.h
|
||||
* @brief Definition of basic data types
|
||||
*/
|
||||
|
||||
#include <hermit/config.h>
|
||||
#include <asm/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NULL ((void*) 0)
|
||||
|
||||
/// represents a task identifier
|
||||
typedef unsigned int tid_t;
|
||||
|
||||
struct task;
|
||||
/// pointer to the current (running) task
|
||||
extern struct task* current_task;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
84
hermit/include/hermit/stdio.h
Normal file
84
hermit/include/hermit/stdio.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/stdio.h
|
||||
* @brief Stringstream related functions. Mainly printf-stuff.
|
||||
*/
|
||||
|
||||
#ifndef __STDIO_H__
|
||||
#define __STDIO_H__
|
||||
|
||||
#include <hermit/config.h>
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Works like the ANSI C function puts
|
||||
*/
|
||||
int kputs(const char *);
|
||||
|
||||
/**
|
||||
* Works like the ANSI C function putchar
|
||||
*/
|
||||
int kputchar(int);
|
||||
|
||||
/**
|
||||
* Works like the ANSI C function printf
|
||||
*/
|
||||
int kprintf(const char*, ...);
|
||||
|
||||
/**
|
||||
* Initialize the I/O functions
|
||||
*/
|
||||
int koutput_init(void);
|
||||
|
||||
/**
|
||||
* Works like the ANSI c function sprintf
|
||||
*/
|
||||
int ksprintf(char *str, const char *format, ...);
|
||||
|
||||
/**
|
||||
* Works like the ANSI c function sprintf
|
||||
*/
|
||||
int ksnprintf(char *str, size_t size, const char *format, ...);
|
||||
|
||||
/**
|
||||
* Scaled down version of printf(3)
|
||||
*/
|
||||
int kvprintf(char const *fmt, void (*func) (int, void *), void *arg, int radix, va_list ap);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
117
hermit/include/hermit/stdlib.h
Normal file
117
hermit/include/hermit/stdlib.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/stdlib.h
|
||||
* @brief Kernel space malloc and free functions and conversion functions
|
||||
*
|
||||
* This file contains some memory alloc and free calls for the kernel
|
||||
* and conversion functions.
|
||||
*/
|
||||
|
||||
#ifndef __STDLIB_H__
|
||||
#define __STDLIB_H__
|
||||
|
||||
#include <hermit/config.h>
|
||||
#include <hermit/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief General page allocator function
|
||||
*
|
||||
* This function allocates and maps whole pages.
|
||||
* To avoid fragmentation you should use kmalloc() and kfree()!
|
||||
*
|
||||
* @param sz Desired size of the new memory
|
||||
* @param flags Flags to for map_region(), vma_add()
|
||||
*
|
||||
* @return Pointer to the new memory range
|
||||
*/
|
||||
void* palloc(size_t sz, uint32_t flags);
|
||||
|
||||
/** @brief Free general kernel memory
|
||||
*
|
||||
* The pmalloc() doesn't track how much memory was allocated for which pointer,
|
||||
* so you have to specify how much memory shall be freed.
|
||||
*
|
||||
* @param sz The size which should freed
|
||||
*/
|
||||
void pfree(void* addr, size_t sz);
|
||||
|
||||
/** @brief The memory allocator function
|
||||
*
|
||||
* This allocator uses a buddy system to manage free memory.
|
||||
*
|
||||
* @return Pointer to the new memory range
|
||||
*/
|
||||
void* kmalloc(size_t sz);
|
||||
|
||||
/** @brief The memory free function
|
||||
*
|
||||
* Releases memory allocated by malloc()
|
||||
*
|
||||
* @param addr The address to the memory block allocated by malloc()
|
||||
*/
|
||||
void kfree(void* addr);
|
||||
|
||||
/** @brief Create a new stack for a new task
|
||||
*
|
||||
* @return start address of the new stack
|
||||
*/
|
||||
void* create_stack(tid_t id);
|
||||
|
||||
/** @brief String to long
|
||||
*
|
||||
* @return Long value of the parsed numerical string
|
||||
*/
|
||||
long strtol(const char* str, char** endptr, int base);
|
||||
|
||||
/** @brief String to unsigned long
|
||||
*
|
||||
* @return Unsigned long value of the parsed numerical string
|
||||
*/
|
||||
unsigned long strtoul(const char* nptr, char** endptr, int base);
|
||||
|
||||
/** @brief ASCII to integer
|
||||
*
|
||||
* Convenience function using strtol().
|
||||
*
|
||||
* @return Integer value of the parsed numerical string
|
||||
*/
|
||||
static inline int atoi(const char *str)
|
||||
{
|
||||
return (int)strtol(str, (char **)NULL, 10);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
78
hermit/include/hermit/string.h
Normal file
78
hermit/include/hermit/string.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __STRING_H__
|
||||
#define __STRING_H__
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/string.h
|
||||
* @brief Definition of basic string and memory opeations
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <asm/string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_MEMCPY
|
||||
void *memcpy(void *dest, const void *src, size_t count);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_MEMSET
|
||||
void *memset(void *dest, int val, size_t count);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRLEN
|
||||
size_t strlen(const char *str);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRNCPY
|
||||
char *strncpy(char *dest, const char *src, size_t n);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRCPY
|
||||
char *strcpy(char *dest, const char *src);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRCMP
|
||||
int strcmp(const char *s1, const char *s2);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRNCMP
|
||||
int strncmp(const char *s1, const char *s2, size_t n);
|
||||
#endif
|
||||
|
||||
char *strstr(const char *s, const char *find);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
83
hermit/include/hermit/syscall.h
Normal file
83
hermit/include/hermit/syscall.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/syscall.h
|
||||
* @brief System call number definitions
|
||||
*
|
||||
* This file contains define constants for every syscall's number.
|
||||
*/
|
||||
|
||||
#ifndef __SYSCALL_H__
|
||||
#define __SYSCALL_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <asm/syscall.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define __NR_exit 0
|
||||
#define __NR_write 1
|
||||
#define __NR_open 2
|
||||
#define __NR_close 3
|
||||
#define __NR_read 4
|
||||
#define __NR_lseek 6
|
||||
#define __NR_unlink 7
|
||||
#define __NR_getpid 8
|
||||
#define __NR_kill 9
|
||||
#define __NR_fstat 10
|
||||
#define __NR_sbrk 11
|
||||
#define __NR_fork 12
|
||||
#define __NR_wait 13
|
||||
#define __NR_execve 14
|
||||
#define __NR_times 15
|
||||
#define __NR_accept 16
|
||||
#define __NR_bind 17
|
||||
#define __NR_closesocket 18
|
||||
#define __NR_connect 19
|
||||
#define __NR_listen 20
|
||||
#define __NR_recv 21
|
||||
#define __NR_send 22
|
||||
#define __NR_socket 23
|
||||
#define __NR_getsockopt 24
|
||||
#define __NR_setsockopt 25
|
||||
#define __NR_gethostbyname 26
|
||||
#define __NR_sendto 27
|
||||
#define __NR_recvfrom 28
|
||||
#define __NR_select 29
|
||||
#define __NR_stat 30
|
||||
#define __NR_dup 31
|
||||
#define __NR_dup2 32
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
162
hermit/include/hermit/tasks.h
Normal file
162
hermit/include/hermit/tasks.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/tasks.h
|
||||
* @brief Task related
|
||||
*
|
||||
* Create and leave tasks or fork them.
|
||||
*/
|
||||
|
||||
#ifndef __TASKS_H__
|
||||
#define __TASKS_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/tasks_types.h>
|
||||
#include <asm/tasks.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief System call to terminate a user level process */
|
||||
void NORETURN sys_exit(int);
|
||||
|
||||
/** @brief Task switcher
|
||||
*
|
||||
* Timer-interrupted use of this function for task switching
|
||||
*
|
||||
* @return
|
||||
* - 0 no context switch
|
||||
* - !0 address of the old stack pointer
|
||||
*/
|
||||
size_t** scheduler(void);
|
||||
|
||||
/** @brief Initialize the multitasking subsystem
|
||||
*
|
||||
* This procedure sets the current task to the
|
||||
* current "task" (there are no tasks, yet) and that was it.
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -ENOMEM (-12) on failure
|
||||
*/
|
||||
int multitasking_init(void);
|
||||
|
||||
/** @brief create a kernel-level task.
|
||||
*
|
||||
* @param id The value behind this pointer will be set to the new task's id
|
||||
* @param ep Pointer to the entry function for the new task
|
||||
* @param args Arguments the task shall start with
|
||||
* @param prio Desired priority of the new kernel task
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int create_kernel_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio);
|
||||
|
||||
/** @brief Create a user level task.
|
||||
*
|
||||
* @param id The value behind this pointer will be set to the new task's id
|
||||
* @param fname Filename of the executable to start the task with
|
||||
* @param argv Pointer to arguments array
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) or -ENOMEM (-12)on failure
|
||||
*/
|
||||
int create_user_task(tid_t* id, const char* fame, char** argv);
|
||||
|
||||
/** @brief Create a task with a specific entry point
|
||||
*
|
||||
* @todo Don't acquire table_lock for the whole task creation.
|
||||
*
|
||||
* @param id Pointer to a tid_t struct were the id shall be set
|
||||
* @param ep Pointer to the function the task shall start with
|
||||
* @param arg Arguments list
|
||||
* @param prio Desired priority of the new task
|
||||
* @param core_id Start the new task on the core with this id
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -ENOMEM (-12) or -EINVAL (-22) on failure
|
||||
*/
|
||||
int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio);
|
||||
|
||||
/** @brief Cleanup function for the task termination
|
||||
*
|
||||
* On termination, the task call this function to cleanup its address space.
|
||||
*/
|
||||
void finish_task_switch(void);
|
||||
|
||||
/** @brief determine the highest priority of all tasks, which are ready
|
||||
*
|
||||
* @return
|
||||
* - return highest priority
|
||||
* - if no task is ready, the function returns an invalid value (> MAX_PRIO)
|
||||
*/
|
||||
uint32_t get_highest_priority(void);
|
||||
|
||||
/** @brief Call to rescheduling
|
||||
*
|
||||
* This is a purely assembled procedure for rescheduling
|
||||
*/
|
||||
void reschedule(void);
|
||||
|
||||
/** @brief Wake up a blocked task
|
||||
*
|
||||
* The task's status will be changed to TASK_READY
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int wakeup_task(tid_t);
|
||||
|
||||
/** @brief Block current task
|
||||
*
|
||||
* The current task's status will be changed to TASK_BLOCKED
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int block_current_task(void);
|
||||
|
||||
/** @brief Abort current task */
|
||||
void NORETURN abort(void);
|
||||
|
||||
/** @brief This function shall be called by leaving kernel-level tasks */
|
||||
void NORETURN leave_kernel_task(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
129
hermit/include/hermit/tasks_types.h
Normal file
129
hermit/include/hermit/tasks_types.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/tasks_types.h
|
||||
* @brief Task related structure definitions
|
||||
*
|
||||
* This file contains the task_t structure definition
|
||||
* and task state define constants
|
||||
*/
|
||||
|
||||
#ifndef __TASKS_TYPES_H__
|
||||
#define __TASKS_TYPES_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/spinlock_types.h>
|
||||
#include <hermit/vma.h>
|
||||
#include <asm/tasks_types.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TASK_INVALID 0
|
||||
#define TASK_READY 1
|
||||
#define TASK_RUNNING 2
|
||||
#define TASK_BLOCKED 3
|
||||
#define TASK_FINISHED 4
|
||||
#define TASK_IDLE 5
|
||||
|
||||
#define TASK_DEFAULT_FLAGS 0
|
||||
#define TASK_FPU_INIT (1 << 0)
|
||||
#define TASK_FPU_USED (1 << 1)
|
||||
|
||||
#define MAX_PRIO 31
|
||||
#define REALTIME_PRIO 31
|
||||
#define HIGH_PRIO 16
|
||||
#define NORMAL_PRIO 8
|
||||
#define LOW_PRIO 1
|
||||
#define IDLE_PRIO 0
|
||||
|
||||
typedef int (*entry_point_t)(void*);
|
||||
|
||||
/** @brief Represents a the process control block */
|
||||
typedef struct task {
|
||||
/// Task id = position in the task table
|
||||
tid_t id __attribute__ ((aligned (CACHE_LINE)));
|
||||
/// Task status (INVALID, READY, RUNNING, ...)
|
||||
uint32_t status;
|
||||
/// copy of the stack pointer before a context switch
|
||||
size_t* last_stack_pointer;
|
||||
/// start address of the stack
|
||||
void* stack;
|
||||
/// Additional status flags. For instance, to signalize the using of the FPU
|
||||
uint8_t flags;
|
||||
/// Task priority
|
||||
uint8_t prio;
|
||||
/// Physical address of root page table
|
||||
size_t page_map;
|
||||
/// Lock for page tables
|
||||
spinlock_irqsave_t page_lock;
|
||||
/// lock for the VMA_list
|
||||
spinlock_t vma_lock;
|
||||
/// list of VMAs
|
||||
vma_t* vma_list;
|
||||
/// the userspace heap
|
||||
vma_t* heap;
|
||||
/// usage in number of pages (including page map tables)
|
||||
atomic_int32_t user_usage;
|
||||
/// next task in the queue
|
||||
struct task* next;
|
||||
/// previous task in the queue
|
||||
struct task* prev;
|
||||
/// FPU state
|
||||
union fpu_state fpu;
|
||||
} task_t;
|
||||
|
||||
typedef struct {
|
||||
task_t* first;
|
||||
task_t* last;
|
||||
} task_list_t;
|
||||
|
||||
/** @brief Represents a queue for all runable tasks */
|
||||
typedef struct {
|
||||
/// idle task
|
||||
task_t* idle __attribute__ ((aligned (CACHE_LINE)));
|
||||
/// previous task
|
||||
task_t* old_task;
|
||||
/// total number of tasks in the queue
|
||||
uint32_t nr_tasks;
|
||||
/// indicates the used priority queues
|
||||
uint32_t prio_bitmap;
|
||||
/// a queue for each priority
|
||||
task_list_t queue[MAX_PRIO];
|
||||
/// lock for this runqueue
|
||||
spinlock_irqsave_t lock;
|
||||
} readyqueues_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
56
hermit/include/hermit/time.h
Normal file
56
hermit/include/hermit/time.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/hermit/time.h
|
||||
* @brief Time related functions
|
||||
*/
|
||||
|
||||
#ifndef __TIME_H__
|
||||
#define __TIME_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Initialize Timer interrupts
|
||||
*
|
||||
* This procedure installs IRQ handlers for timer interrupts
|
||||
*/
|
||||
int timer_init(void);
|
||||
|
||||
/** @brief Returns the current number of ticks.
|
||||
* @return Current number of ticks
|
||||
*/
|
||||
uint64_t get_clock_tick(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
160
hermit/include/hermit/vma.h
Normal file
160
hermit/include/hermit/vma.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Stefan Lankes, RWTH Aachen University
|
||||
* 2014, Steffen Vogel, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @author Steffen Vogel <steffen.vogel@rwth-aachen.de>
|
||||
* @file include/hermit/vma.h
|
||||
* @brief VMA related sructure and functions
|
||||
*/
|
||||
|
||||
#ifndef __VMA_H__
|
||||
#define __VMA_H__
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Read access to this VMA is allowed
|
||||
#define VMA_READ (1 << 0)
|
||||
/// Write access to this VMA is allowed
|
||||
#define VMA_WRITE (1 << 1)
|
||||
/// Instructions fetches in this VMA are allowed
|
||||
#define VMA_EXECUTE (1 << 2)
|
||||
/// This VMA is cacheable
|
||||
#define VMA_CACHEABLE (1 << 3)
|
||||
/// This VMA is not accessable
|
||||
#define VMA_NO_ACCESS (1 << 4)
|
||||
/// This VMA should be part of the userspace
|
||||
#define VMA_USER (1 << 5)
|
||||
/// A collection of flags used for the kernel heap (kmalloc)
|
||||
#define VMA_HEAP (VMA_READ|VMA_WRITE|VMA_CACHEABLE)
|
||||
|
||||
// boundaries for VAS allocation
|
||||
#define VMA_KERN_MIN 0xC0000
|
||||
#define VMA_KERN_MAX KERNEL_SPACE
|
||||
#define VMA_USER_MIN KERNEL_SPACE
|
||||
|
||||
// last three top level entries are reserved
|
||||
#define VMA_USER_MAX 0xFFFFFE8000000000
|
||||
|
||||
struct vma;
|
||||
|
||||
/** @brief VMA structure definition
|
||||
*
|
||||
* Each item in this linked list marks a used part of the virtual address space.
|
||||
* Its used by vm_alloc() to find holes between them.
|
||||
*/
|
||||
typedef struct vma {
|
||||
/// Start address of the memory area
|
||||
size_t start;
|
||||
/// End address of the memory area
|
||||
size_t end;
|
||||
/// Type flags field
|
||||
uint32_t flags;
|
||||
/// Pointer of next VMA element in the list
|
||||
struct vma* next;
|
||||
/// Pointer to previous VMA element in the list
|
||||
struct vma* prev;
|
||||
} vma_t;
|
||||
|
||||
/** @brief Initalize the kernelspace VMA list
|
||||
*
|
||||
* Reserves several system-relevant virtual memory regions:
|
||||
* - SMP boot page (SMP_SETUP_ADDR)
|
||||
* - VGA video memory (VIDEO_MEM_ADDR)
|
||||
* - The kernel (kernel_start - kernel_end)
|
||||
* - Multiboot structure (mb_info)
|
||||
* - Multiboot mmap (mb_info->mmap_*)
|
||||
* - Multiboot modules (mb_info->mods_*)
|
||||
* - Init Ramdisk
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - <0 on failure
|
||||
*/
|
||||
int vma_init(void);
|
||||
|
||||
/** @brief Add a new virtual memory area to the list of VMAs
|
||||
*
|
||||
* @param start Start address of the new area
|
||||
* @param end End address of the new area
|
||||
* @param flags Type flags the new area shall have
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) or -EINVAL (-12) on failure
|
||||
*/
|
||||
int vma_add(size_t start, size_t end, uint32_t flags);
|
||||
|
||||
/** @brief Search for a free memory area
|
||||
*
|
||||
* @param size Size of requestes VMA in bytes
|
||||
* @param flags
|
||||
* @return Type flags the new area shall have
|
||||
* - 0 on failure
|
||||
* - the start address of a free area
|
||||
*/
|
||||
size_t vma_alloc(size_t size, uint32_t flags);
|
||||
|
||||
/** @brief Free an allocated memory area
|
||||
*
|
||||
* @param start Start address of the area to be freed
|
||||
* @param end End address of the to be freed
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int vma_free(size_t start, size_t end);
|
||||
|
||||
/** @brief Free all virtual memory areas
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
*/
|
||||
int drop_vma_list(struct task* task);
|
||||
|
||||
/** @brief Copy the VMA list of the current task to task
|
||||
*
|
||||
* @param task The task where the list should be copied to
|
||||
* @return
|
||||
* - 0 on success
|
||||
*/
|
||||
int copy_vma_list(struct task* src, struct task* dest);
|
||||
|
||||
/** @brief Dump information about this task's VMAs into the terminal. */
|
||||
void vma_dump(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
4
hermit/kernel/Makefile
Normal file
4
hermit/kernel/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
C_source := main.c tasks.c syscall.c
|
||||
MODULE := kernel
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
90
hermit/kernel/main.c
Normal file
90
hermit/kernel/main.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/time.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <hermit/processor.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <hermit/syscall.h>
|
||||
#include <hermit/memory.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
/*
|
||||
* Note that linker symbols are not variables, they have no memory allocated for
|
||||
* maintaining a value, rather their address is their value.
|
||||
*/
|
||||
extern const void kernel_start;
|
||||
extern const void kernel_end;
|
||||
extern const void bss_start;
|
||||
extern const void bss_end;
|
||||
extern char __BUILD_DATE;
|
||||
extern char __BUILD_TIME;
|
||||
|
||||
/* Page frame counters */
|
||||
extern atomic_int32_t total_pages;
|
||||
extern atomic_int32_t total_allocated_pages;
|
||||
extern atomic_int32_t total_available_pages;
|
||||
|
||||
static int hermit_init(void)
|
||||
{
|
||||
// initialize .bss section
|
||||
memset((void*)&bss_start, 0x00, ((size_t) &bss_end - (size_t) &bss_start));
|
||||
|
||||
koutput_init();
|
||||
system_init();
|
||||
irq_init();
|
||||
timer_init();
|
||||
multitasking_init();
|
||||
memory_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
hermit_init();
|
||||
system_calibration(); // enables also interrupts
|
||||
|
||||
kprintf("This is Hermit %s Build %u, %u\n", HERMIT_VERSION, &__BUILD_DATE, &__BUILD_TIME);
|
||||
kprintf("Kernel starts at %p and ends at %p\n", &kernel_start, &kernel_end);
|
||||
kprintf("Processor frequency: %u MHz\n", get_cpu_frequency());
|
||||
kprintf("Total memory: %lu KiB\n", atomic_int32_read(&total_pages) * PAGE_SIZE / 1024);
|
||||
kprintf("Current allocated memory: %lu KiB\n", atomic_int32_read(&total_allocated_pages) * PAGE_SIZE / 1024);
|
||||
kprintf("Current available memory: %lu KiB\n", atomic_int32_read(&total_available_pages) * PAGE_SIZE / 1024);
|
||||
|
||||
while(1) {
|
||||
HALT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
113
hermit/kernel/syscall.c
Normal file
113
hermit/kernel/syscall.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <hermit/syscall.h>
|
||||
#include <hermit/spinlock.h>
|
||||
|
||||
static int sys_write(int fd, const char* buf, size_t len)
|
||||
{
|
||||
//TODO: Currently, we ignore the file descriptor
|
||||
|
||||
if (BUILTIN_EXPECT(!buf, 0))
|
||||
return -1;
|
||||
|
||||
kputs(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t sys_sbrk(int incr)
|
||||
{
|
||||
task_t* task = current_task;
|
||||
vma_t* heap = task->heap;
|
||||
ssize_t ret;
|
||||
|
||||
spinlock_lock(&task->vma_lock);
|
||||
|
||||
if (BUILTIN_EXPECT(!heap, 0)) {
|
||||
kprintf("sys_sbrk: missing heap!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = heap->end;
|
||||
heap->end += incr;
|
||||
if (heap->end < heap->start)
|
||||
heap->end = heap->start;
|
||||
|
||||
// allocation and mapping of new pages for the heap
|
||||
// is catched by the pagefault handler
|
||||
|
||||
spinlock_unlock(&task->vma_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t syscall_handler(uint32_t sys_nr, ...)
|
||||
{
|
||||
ssize_t ret = -EINVAL;
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, sys_nr);
|
||||
|
||||
switch(sys_nr)
|
||||
{
|
||||
case __NR_exit:
|
||||
sys_exit(va_arg(vl, uint32_t));
|
||||
ret = 0;
|
||||
break;
|
||||
case __NR_write: {
|
||||
int fd = va_arg(vl, int);
|
||||
const char* buf = va_arg(vl, const char*);
|
||||
size_t len = va_arg(vl, size_t);
|
||||
ret = sys_write(fd, buf, len);
|
||||
break;
|
||||
}
|
||||
//TODO: Currently, we ignore file descriptors
|
||||
case __NR_open:
|
||||
case __NR_close:
|
||||
ret = 0;
|
||||
break;
|
||||
case __NR_sbrk: {
|
||||
int incr = va_arg(vl, int);
|
||||
|
||||
ret = sys_sbrk(incr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
kprintf("invalid system call: %u\n", sys_nr);
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
};
|
||||
|
||||
va_end(vl);
|
||||
|
||||
return ret;
|
||||
}
|
404
hermit/kernel/tasks.c
Normal file
404
hermit/kernel/tasks.c
Normal file
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdlib.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/tasks.h>
|
||||
#include <hermit/tasks_types.h>
|
||||
#include <hermit/spinlock.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <hermit/syscall.h>
|
||||
#include <hermit/memory.h>
|
||||
|
||||
/** @brief Array of task structures (aka PCB)
|
||||
*
|
||||
* A task's id will be its position in this array.
|
||||
*/
|
||||
static task_t task_table[MAX_TASKS] = { \
|
||||
[0] = {0, TASK_IDLE, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, NULL, ATOMIC_INIT(0), NULL, NULL}, \
|
||||
[1 ... MAX_TASKS-1] = {0, TASK_INVALID, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, NULL,ATOMIC_INIT(0), NULL, NULL}};
|
||||
|
||||
static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT;
|
||||
|
||||
static readyqueues_t readyqueues = {task_table+0, NULL, 0, 0, {[0 ... MAX_PRIO-2] = {NULL, NULL}}, SPINLOCK_IRQSAVE_INIT};
|
||||
|
||||
task_t* current_task = task_table+0;
|
||||
extern const void boot_stack;
|
||||
|
||||
/** @brief helper function for the assembly code to determine the current task
|
||||
* @return Pointer to the task_t structure of current task
|
||||
*/
|
||||
task_t* get_current_task(void)
|
||||
{
|
||||
return current_task;
|
||||
}
|
||||
|
||||
uint32_t get_highest_priority(void)
|
||||
{
|
||||
return msb(readyqueues.prio_bitmap);
|
||||
}
|
||||
|
||||
int multitasking_init(void)
|
||||
{
|
||||
if (BUILTIN_EXPECT(task_table[0].status != TASK_IDLE, 0)) {
|
||||
kputs("Task 0 is not an idle task\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
task_table[0].prio = IDLE_PRIO;
|
||||
task_table[0].stack = (void*) &boot_stack;
|
||||
task_table[0].page_map = read_cr3();
|
||||
|
||||
// register idle task
|
||||
register_task();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void finish_task_switch(void)
|
||||
{
|
||||
task_t* old;
|
||||
uint8_t prio;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
|
||||
if ((old = readyqueues.old_task) != NULL) {
|
||||
if (old->status == TASK_INVALID) {
|
||||
old->stack = NULL;
|
||||
old->last_stack_pointer = NULL;
|
||||
readyqueues.old_task = NULL;
|
||||
} else {
|
||||
prio = old->prio;
|
||||
if (!readyqueues.queue[prio-1].first) {
|
||||
old->next = old->prev = NULL;
|
||||
readyqueues.queue[prio-1].first = readyqueues.queue[prio-1].last = old;
|
||||
} else {
|
||||
old->next = NULL;
|
||||
old->prev = readyqueues.queue[prio-1].last;
|
||||
readyqueues.queue[prio-1].last->next = old;
|
||||
readyqueues.queue[prio-1].last = old;
|
||||
}
|
||||
readyqueues.old_task = NULL;
|
||||
readyqueues.prio_bitmap |= (1 << prio);
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
|
||||
if (current_task->heap)
|
||||
kfree(current_task->heap);
|
||||
}
|
||||
|
||||
/** @brief A procedure to be called by
|
||||
* procedures which are called by exiting tasks. */
|
||||
static void NORETURN do_exit(int arg)
|
||||
{
|
||||
task_t* curr_task = current_task;
|
||||
|
||||
kprintf("Terminate task: %u, return value %d\n", curr_task->id, arg);
|
||||
|
||||
page_map_drop();
|
||||
|
||||
// decrease the number of active tasks
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
readyqueues.nr_tasks--;
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
|
||||
curr_task->status = TASK_FINISHED;
|
||||
reschedule();
|
||||
|
||||
kprintf("Kernel panic: scheduler found no valid task\n");
|
||||
while(1) {
|
||||
HALT;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief A procedure to be called by kernel tasks */
|
||||
void NORETURN leave_kernel_task(void) {
|
||||
int result;
|
||||
|
||||
result = 0; //get_return_value();
|
||||
do_exit(result);
|
||||
}
|
||||
|
||||
/** @brief To be called by the systemcall to exit tasks */
|
||||
void NORETURN sys_exit(int arg) {
|
||||
do_exit(arg);
|
||||
}
|
||||
|
||||
/** @brief Aborting a task is like exiting it with result -1 */
|
||||
void NORETURN abort(void) {
|
||||
do_exit(-1);
|
||||
}
|
||||
|
||||
int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
uint32_t i;
|
||||
|
||||
if (BUILTIN_EXPECT(!ep, 0))
|
||||
return -EINVAL;
|
||||
if (BUILTIN_EXPECT(prio == IDLE_PRIO, 0))
|
||||
return -EINVAL;
|
||||
if (BUILTIN_EXPECT(prio > MAX_PRIO, 0))
|
||||
return -EINVAL;
|
||||
|
||||
spinlock_irqsave_lock(&table_lock);
|
||||
|
||||
for(i=0; i<MAX_TASKS; i++) {
|
||||
if (task_table[i].status == TASK_INVALID) {
|
||||
task_table[i].id = i;
|
||||
task_table[i].status = TASK_READY;
|
||||
task_table[i].last_stack_pointer = NULL;
|
||||
task_table[i].stack = create_stack(i);
|
||||
task_table[i].prio = prio;
|
||||
spinlock_init(&task_table[i].vma_lock);
|
||||
task_table[i].vma_list = NULL;
|
||||
task_table[i].heap = NULL;
|
||||
|
||||
spinlock_irqsave_init(&task_table[i].page_lock);
|
||||
atomic_int32_set(&task_table[i].user_usage, 0);
|
||||
|
||||
/* Allocated new PGD or PML4 and copy page table */
|
||||
task_table[i].page_map = get_pages(1);
|
||||
if (BUILTIN_EXPECT(!task_table[i].page_map, 0))
|
||||
goto out;
|
||||
|
||||
/* Copy page tables & user frames of current task to new one */
|
||||
page_map_copy(&task_table[i]);
|
||||
|
||||
if (id)
|
||||
*id = i;
|
||||
|
||||
ret = create_default_frame(task_table+i, ep, arg);
|
||||
|
||||
// add task in the readyqueues
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
readyqueues.prio_bitmap |= (1 << prio);
|
||||
readyqueues.nr_tasks++;
|
||||
if (!readyqueues.queue[prio-1].first) {
|
||||
task_table[i].next = task_table[i].prev = NULL;
|
||||
readyqueues.queue[prio-1].first = task_table+i;
|
||||
readyqueues.queue[prio-1].last = task_table+i;
|
||||
} else {
|
||||
task_table[i].prev = readyqueues.queue[prio-1].last;
|
||||
task_table[i].next = NULL;
|
||||
readyqueues.queue[prio-1].last->next = task_table+i;
|
||||
readyqueues.queue[prio-1].last = task_table+i;
|
||||
}
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spinlock_irqsave_unlock(&table_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int create_kernel_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio)
|
||||
{
|
||||
if (prio > MAX_PRIO)
|
||||
prio = NORMAL_PRIO;
|
||||
|
||||
return create_task(id, ep, args, prio);
|
||||
}
|
||||
|
||||
/** @brief Wakeup a blocked task
|
||||
* @param id The task's tid_t structure
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int wakeup_task(tid_t id)
|
||||
{
|
||||
task_t* task;
|
||||
uint32_t prio;
|
||||
int ret = -EINVAL;
|
||||
uint8_t flags;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
|
||||
task = task_table + id;
|
||||
prio = task->prio;
|
||||
|
||||
if (task->status == TASK_BLOCKED) {
|
||||
task->status = TASK_READY;
|
||||
ret = 0;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
// increase the number of ready tasks
|
||||
readyqueues.nr_tasks++;
|
||||
|
||||
// add task to the runqueue
|
||||
if (!readyqueues.queue[prio-1].last) {
|
||||
readyqueues.queue[prio-1].last = readyqueues.queue[prio-1].first = task;
|
||||
task->next = task->prev = NULL;
|
||||
readyqueues.prio_bitmap |= (1 << prio);
|
||||
} else {
|
||||
task->prev = readyqueues.queue[prio-1].last;
|
||||
task->next = NULL;
|
||||
readyqueues.queue[prio-1].last->next = task;
|
||||
readyqueues.queue[prio-1].last = task;
|
||||
}
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
}
|
||||
|
||||
irq_nested_enable(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Block current task
|
||||
*
|
||||
* The current task's status will be changed to TASK_BLOCKED
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -EINVAL (-22) on failure
|
||||
*/
|
||||
int block_current_task(void)
|
||||
{
|
||||
tid_t id;
|
||||
uint32_t prio;
|
||||
int ret = -EINVAL;
|
||||
uint8_t flags;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
|
||||
id = current_task->id;
|
||||
prio = current_task->prio;
|
||||
|
||||
if (task_table[id].status == TASK_RUNNING) {
|
||||
task_table[id].status = TASK_BLOCKED;
|
||||
ret = 0;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
// reduce the number of ready tasks
|
||||
readyqueues.nr_tasks--;
|
||||
|
||||
// remove task from queue
|
||||
if (task_table[id].prev)
|
||||
task_table[id].prev->next = task_table[id].next;
|
||||
if (task_table[id].next)
|
||||
task_table[id].next->prev = task_table[id].prev;
|
||||
if (readyqueues.queue[prio-1].first == task_table+id)
|
||||
readyqueues.queue[prio-1].first = task_table[id].next;
|
||||
if (readyqueues.queue[prio-1].last == task_table+id) {
|
||||
readyqueues.queue[prio-1].last = task_table[id].prev;
|
||||
if (!readyqueues.queue[prio-1].last)
|
||||
readyqueues.queue[prio-1].last = readyqueues.queue[prio-1].first;
|
||||
}
|
||||
|
||||
// No valid task in queue => update prio_bitmap
|
||||
if (!readyqueues.queue[prio-1].first)
|
||||
readyqueues.prio_bitmap &= ~(1 << prio);
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
}
|
||||
|
||||
irq_nested_enable(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t** scheduler(void)
|
||||
{
|
||||
task_t* orig_task;
|
||||
uint32_t prio;
|
||||
|
||||
orig_task = current_task;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
|
||||
/* signalizes that this task could be reused */
|
||||
if (current_task->status == TASK_FINISHED) {
|
||||
current_task->status = TASK_INVALID;
|
||||
readyqueues.old_task = current_task;
|
||||
} else readyqueues.old_task = NULL; // reset old task
|
||||
|
||||
prio = msb(readyqueues.prio_bitmap); // determines highest priority
|
||||
if (prio > MAX_PRIO) {
|
||||
if ((current_task->status == TASK_RUNNING) || (current_task->status == TASK_IDLE))
|
||||
goto get_task_out;
|
||||
current_task = readyqueues.idle;
|
||||
} else {
|
||||
// Does the current task have an higher priority? => no task switch
|
||||
if ((current_task->prio > prio) && (current_task->status == TASK_RUNNING))
|
||||
goto get_task_out;
|
||||
|
||||
if (current_task->status == TASK_RUNNING) {
|
||||
current_task->status = TASK_READY;
|
||||
readyqueues.old_task = current_task;
|
||||
}
|
||||
|
||||
current_task = readyqueues.queue[prio-1].first;
|
||||
if (BUILTIN_EXPECT(current_task->status == TASK_INVALID, 0)) {
|
||||
kprintf("Upps!!!!!!! Got invalid task %d, orig task %d\n", current_task->id, orig_task->id);
|
||||
}
|
||||
current_task->status = TASK_RUNNING;
|
||||
|
||||
// remove new task from queue
|
||||
// by the way, priority 0 is only used by the idle task and doesn't need own queue
|
||||
readyqueues.queue[prio-1].first = current_task->next;
|
||||
if (!current_task->next) {
|
||||
readyqueues.queue[prio-1].last = NULL;
|
||||
readyqueues.prio_bitmap &= ~(1 << prio);
|
||||
}
|
||||
current_task->next = current_task->prev = NULL;
|
||||
}
|
||||
|
||||
get_task_out:
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
|
||||
if (current_task != orig_task) {
|
||||
/* if the original task is using the FPU, we need to save the FPU context */
|
||||
if ((orig_task->flags & TASK_FPU_USED) && (orig_task->status == TASK_READY)) {
|
||||
save_fpu_state(&(orig_task->fpu));
|
||||
orig_task->flags &= ~TASK_FPU_USED;
|
||||
}
|
||||
|
||||
kprintf("schedule from %u to %u with prio %u\n", orig_task->id, current_task->id, (uint32_t)current_task->prio);
|
||||
|
||||
return (size_t**) &(orig_task->last_stack_pointer);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void reschedule(void)
|
||||
{
|
||||
size_t** stack;
|
||||
uint8_t flags;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
if ((stack = scheduler()))
|
||||
switch_context(stack);
|
||||
irq_nested_enable(flags);
|
||||
}
|
4
hermit/libkern/Makefile
Normal file
4
hermit/libkern/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
C_source := string.c stdio.c printf.c sprintf.c strtol.c strtoul.c strstr.c
|
||||
MODULE := libkern
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
485
hermit/libkern/printf.c
Normal file
485
hermit/libkern/printf.c
Normal file
|
@ -0,0 +1,485 @@
|
|||
/*-
|
||||
* Copyright (c) 1986, 1988, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* HermitCore's printf implementation is based on a implementation which was
|
||||
* published at http://www.pagetable.com/?p=298.
|
||||
* The authors built a full-featured standalone version of printf(). The
|
||||
* base code has been taken from FreeBSD (sys/kern/subr_prf.c) and is
|
||||
* consequently BSD-licensed. Unnecessary functions have been removed and
|
||||
* all typedefs required have been added.
|
||||
*/
|
||||
|
||||
#include <hermit/string.h>
|
||||
|
||||
#define __64BIT__
|
||||
|
||||
#ifdef __64BIT__
|
||||
typedef unsigned long long uintmax_t;
|
||||
typedef long long intmax_t;
|
||||
#else
|
||||
typedef unsigned int uintmax_t;
|
||||
typedef int intmax_t;
|
||||
#endif
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned int u_int;
|
||||
typedef unsigned long u_long;
|
||||
typedef unsigned short u_short;
|
||||
typedef unsigned long long u_quad_t;
|
||||
typedef long long quad_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
#define NBBY 8 /* number of bits in a byte */
|
||||
char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
#define hex2ascii(hex) (hex2ascii_data[hex])
|
||||
#define va_list __builtin_va_list
|
||||
#define va_start __builtin_va_start
|
||||
#define va_arg __builtin_va_arg
|
||||
#define va_end __builtin_va_end
|
||||
#define toupper(c) ((c) - 0x20 * (((c) >= 'a') && ((c) <= 'z')))
|
||||
|
||||
/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
|
||||
#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
|
||||
|
||||
/*
|
||||
* Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
|
||||
* order; return an optional length and a pointer to the last character
|
||||
* written in the buffer (i.e., the first character of the string).
|
||||
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
|
||||
*/
|
||||
static char *ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
|
||||
{
|
||||
char *p, c;
|
||||
|
||||
p = nbuf;
|
||||
*p = '\0';
|
||||
do {
|
||||
c = hex2ascii(num % base);
|
||||
*++p = upper ? toupper(c) : c;
|
||||
} while (num /= base);
|
||||
if (lenp)
|
||||
*lenp = p - nbuf;
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scaled down version of printf(3).
|
||||
*
|
||||
* Two additional formats:
|
||||
*
|
||||
* The format %b is supported to decode error registers.
|
||||
* Its usage is:
|
||||
*
|
||||
* printf("reg=%b\n", regval, "*");
|
||||
*
|
||||
* where the output base is expressed as a control character, e.g.
|
||||
* \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
|
||||
* the first of which gives the bit number to be inspected (origin 1), and
|
||||
* the next characters (up to a control character, i.e. a character <= 32),
|
||||
* give the name of the register. Thus:
|
||||
*
|
||||
* kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
|
||||
*
|
||||
* would produce output:
|
||||
*
|
||||
* reg=3
|
||||
*
|
||||
* XXX: %D -- Hexdump, takes pointer and separator string:
|
||||
* ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
|
||||
* ("%*D", len, ptr, " " -> XX XX XX XX ...
|
||||
*/
|
||||
int kvprintf(char const *fmt, void (*func) (int, void *), void *arg, int radix,
|
||||
va_list ap)
|
||||
{
|
||||
#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
|
||||
char nbuf[MAXNBUF];
|
||||
char *d;
|
||||
const char *p, *percent, *q;
|
||||
u_char *up;
|
||||
int ch, n;
|
||||
uintmax_t num;
|
||||
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
|
||||
int cflag, hflag, jflag, tflag, zflag;
|
||||
int dwidth, upper;
|
||||
char padc;
|
||||
int stop = 0, retval = 0;
|
||||
|
||||
num = 0;
|
||||
if (!func)
|
||||
d = (char *)arg;
|
||||
else
|
||||
d = NULL;
|
||||
|
||||
if (fmt == NULL)
|
||||
fmt = "(fmt null)\n";
|
||||
|
||||
if (radix < 2 || radix > 36)
|
||||
radix = 10;
|
||||
|
||||
for (;;) {
|
||||
padc = ' ';
|
||||
width = 0;
|
||||
while ((ch = (u_char) * fmt++) != '%' || stop) {
|
||||
if (ch == '\0')
|
||||
return (retval);
|
||||
PCHAR(ch);
|
||||
}
|
||||
percent = fmt - 1;
|
||||
qflag = 0;
|
||||
lflag = 0;
|
||||
ladjust = 0;
|
||||
sharpflag = 0;
|
||||
neg = 0;
|
||||
sign = 0;
|
||||
dot = 0;
|
||||
dwidth = 0;
|
||||
upper = 0;
|
||||
cflag = 0;
|
||||
hflag = 0;
|
||||
jflag = 0;
|
||||
tflag = 0;
|
||||
zflag = 0;
|
||||
reswitch: switch (ch = (u_char) * fmt++) {
|
||||
case '.':
|
||||
dot = 1;
|
||||
goto reswitch;
|
||||
case '#':
|
||||
sharpflag = 1;
|
||||
goto reswitch;
|
||||
case '+':
|
||||
sign = 1;
|
||||
goto reswitch;
|
||||
case '-':
|
||||
ladjust = 1;
|
||||
goto reswitch;
|
||||
case '%':
|
||||
PCHAR(ch);
|
||||
break;
|
||||
case '*':
|
||||
if (!dot) {
|
||||
width = va_arg(ap, int);
|
||||
if (width < 0) {
|
||||
ladjust = !ladjust;
|
||||
width = -width;
|
||||
}
|
||||
} else {
|
||||
dwidth = va_arg(ap, int);
|
||||
}
|
||||
goto reswitch;
|
||||
case '0':
|
||||
if (!dot) {
|
||||
padc = '0';
|
||||
goto reswitch;
|
||||
}
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
for (n = 0;; ++fmt) {
|
||||
n = n * 10 + ch - '0';
|
||||
ch = *fmt;
|
||||
if (ch < '0' || ch > '9')
|
||||
break;
|
||||
}
|
||||
if (dot)
|
||||
dwidth = n;
|
||||
else
|
||||
width = n;
|
||||
goto reswitch;
|
||||
case 'b':
|
||||
num = (u_int) va_arg(ap, int);
|
||||
p = va_arg(ap, char *);
|
||||
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
|
||||
PCHAR(*q--);
|
||||
|
||||
if (num == 0)
|
||||
break;
|
||||
|
||||
for (tmp = 0; *p;) {
|
||||
n = *p++;
|
||||
if (num & (1 << (n - 1))) {
|
||||
PCHAR(tmp ? ',' : '<');
|
||||
for (; (n = *p) > ' '; ++p)
|
||||
PCHAR(n);
|
||||
tmp = 1;
|
||||
} else
|
||||
for (; *p > ' '; ++p)
|
||||
continue;
|
||||
}
|
||||
if (tmp)
|
||||
PCHAR('>');
|
||||
break;
|
||||
case 'c':
|
||||
PCHAR(va_arg(ap, int));
|
||||
break;
|
||||
case 'D':
|
||||
up = va_arg(ap, u_char *);
|
||||
p = va_arg(ap, char *);
|
||||
if (!width)
|
||||
width = 16;
|
||||
while (width--) {
|
||||
PCHAR(hex2ascii(*up >> 4));
|
||||
PCHAR(hex2ascii(*up & 0x0f));
|
||||
up++;
|
||||
if (width)
|
||||
for (q = p; *q; q++)
|
||||
PCHAR(*q);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
base = 10;
|
||||
sign = 1;
|
||||
goto handle_sign;
|
||||
case 'h':
|
||||
if (hflag) {
|
||||
hflag = 0;
|
||||
cflag = 1;
|
||||
} else
|
||||
hflag = 1;
|
||||
goto reswitch;
|
||||
case 'j':
|
||||
jflag = 1;
|
||||
goto reswitch;
|
||||
case 'l':
|
||||
if (lflag) {
|
||||
lflag = 0;
|
||||
qflag = 1;
|
||||
} else
|
||||
lflag = 1;
|
||||
goto reswitch;
|
||||
case 'n':
|
||||
if (jflag)
|
||||
*(va_arg(ap, intmax_t *)) = retval;
|
||||
else if (qflag)
|
||||
*(va_arg(ap, quad_t *)) = retval;
|
||||
else if (lflag)
|
||||
*(va_arg(ap, long *)) = retval;
|
||||
else if (zflag)
|
||||
*(va_arg(ap, size_t *)) = retval;
|
||||
else if (hflag)
|
||||
*(va_arg(ap, short *)) = retval;
|
||||
else if (cflag)
|
||||
*(va_arg(ap, char *)) = retval;
|
||||
else
|
||||
*(va_arg(ap, int *)) = retval;
|
||||
break;
|
||||
case 'o':
|
||||
base = 8;
|
||||
goto handle_nosign;
|
||||
case 'p':
|
||||
base = 16;
|
||||
sharpflag = (width == 0);
|
||||
sign = 0;
|
||||
num = (uintptr_t) va_arg(ap, void *);
|
||||
goto number;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
goto reswitch;
|
||||
case 'r':
|
||||
base = radix;
|
||||
if (sign)
|
||||
goto handle_sign;
|
||||
goto handle_nosign;
|
||||
case 's':
|
||||
p = va_arg(ap, char *);
|
||||
if (p == NULL)
|
||||
p = "(null)";
|
||||
if (!dot)
|
||||
n = strlen(p);
|
||||
else
|
||||
for (n = 0; n < dwidth && p[n]; n++)
|
||||
continue;
|
||||
|
||||
width -= n;
|
||||
|
||||
if (!ladjust && width > 0)
|
||||
while (width--)
|
||||
PCHAR(padc);
|
||||
while (n--)
|
||||
PCHAR(*p++);
|
||||
if (ladjust && width > 0)
|
||||
while (width--)
|
||||
PCHAR(padc);
|
||||
break;
|
||||
case 't':
|
||||
tflag = 1;
|
||||
goto reswitch;
|
||||
case 'u':
|
||||
base = 10;
|
||||
goto handle_nosign;
|
||||
case 'X':
|
||||
upper = 1;
|
||||
case 'x':
|
||||
base = 16;
|
||||
goto handle_nosign;
|
||||
case 'y':
|
||||
base = 16;
|
||||
sign = 1;
|
||||
goto handle_sign;
|
||||
case 'z':
|
||||
zflag = 1;
|
||||
goto reswitch;
|
||||
handle_nosign:
|
||||
sign = 0;
|
||||
if (jflag)
|
||||
num = va_arg(ap, uintmax_t);
|
||||
else if (qflag)
|
||||
num = va_arg(ap, u_quad_t);
|
||||
else if (tflag)
|
||||
num = va_arg(ap, ptrdiff_t);
|
||||
else if (lflag)
|
||||
num = va_arg(ap, u_long);
|
||||
else if (zflag)
|
||||
num = va_arg(ap, size_t);
|
||||
else if (hflag)
|
||||
num = (u_short) va_arg(ap, int);
|
||||
else if (cflag)
|
||||
num = (u_char) va_arg(ap, int);
|
||||
else
|
||||
num = va_arg(ap, u_int);
|
||||
goto number;
|
||||
handle_sign:
|
||||
if (jflag)
|
||||
num = va_arg(ap, intmax_t);
|
||||
else if (qflag)
|
||||
num = va_arg(ap, quad_t);
|
||||
else if (tflag)
|
||||
num = va_arg(ap, ptrdiff_t);
|
||||
else if (lflag)
|
||||
num = va_arg(ap, long);
|
||||
else if (zflag)
|
||||
num = va_arg(ap, ssize_t);
|
||||
else if (hflag)
|
||||
num = (short)va_arg(ap, int);
|
||||
else if (cflag)
|
||||
num = (char)va_arg(ap, int);
|
||||
else
|
||||
num = va_arg(ap, int);
|
||||
number:
|
||||
if (sign && (intmax_t) num < 0) {
|
||||
neg = 1;
|
||||
num = -(intmax_t) num;
|
||||
}
|
||||
p = ksprintn(nbuf, num, base, &tmp, upper);
|
||||
if (sharpflag && num != 0) {
|
||||
if (base == 8)
|
||||
tmp++;
|
||||
else if (base == 16)
|
||||
tmp += 2;
|
||||
}
|
||||
if (neg)
|
||||
tmp++;
|
||||
|
||||
if (!ladjust && padc != '0' && width
|
||||
&& (width -= tmp) > 0)
|
||||
while (width--)
|
||||
PCHAR(padc);
|
||||
if (neg)
|
||||
PCHAR('-');
|
||||
if (sharpflag && num != 0) {
|
||||
if (base == 8) {
|
||||
PCHAR('0');
|
||||
} else if (base == 16) {
|
||||
PCHAR('0');
|
||||
PCHAR('x');
|
||||
}
|
||||
}
|
||||
if (!ladjust && width && (width -= tmp) > 0)
|
||||
while (width--)
|
||||
PCHAR(padc);
|
||||
|
||||
while (*p)
|
||||
PCHAR(*p--);
|
||||
|
||||
if (ladjust && width && (width -= tmp) > 0)
|
||||
while (width--)
|
||||
PCHAR(padc);
|
||||
|
||||
break;
|
||||
default:
|
||||
while (percent < fmt)
|
||||
PCHAR(*percent++);
|
||||
/*
|
||||
* Since we ignore a formatting argument it is no
|
||||
* longer safe to obey the remaining formatting
|
||||
* arguments as the arguments will no longer match
|
||||
* the format specs.
|
||||
*/
|
||||
stop = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#undef PCHAR
|
||||
}
|
||||
|
||||
/*
|
||||
* Print directly a character on the screen
|
||||
*/
|
||||
extern int kputchar(int);
|
||||
|
||||
/*
|
||||
* A wrapper function for kputchar because
|
||||
* kvprintf needs an output function, which possesses two arguments.
|
||||
* The first arguments defines the output character, the second could be used to pass
|
||||
* additional arguments. In the case of kputchar is no additional argument needed.
|
||||
*/
|
||||
static void _putchar(int c, void *arg)
|
||||
{
|
||||
kputchar(c);
|
||||
}
|
||||
|
||||
int kprintf(const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* http://www.pagetable.com/?p=298 */
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = kvprintf(fmt,
|
||||
_putchar, /* output function */
|
||||
NULL, /* additional argument for the output function */
|
||||
10, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
82
hermit/libkern/sprintf.c
Normal file
82
hermit/libkern/sprintf.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
size_t pos;
|
||||
size_t max;
|
||||
} sputchar_arg_t;
|
||||
|
||||
static void sputchar(int c, void *arg)
|
||||
{
|
||||
sputchar_arg_t *dest = (sputchar_arg_t *) arg;
|
||||
|
||||
if (dest->pos < dest->max) {
|
||||
dest->str[dest->pos] = (char)c;
|
||||
dest->pos++;
|
||||
}
|
||||
}
|
||||
|
||||
int ksnprintf(char *str, size_t size, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
sputchar_arg_t dest;
|
||||
|
||||
dest.str = str;
|
||||
dest.pos = 0;
|
||||
dest.max = size;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = kvprintf(format, sputchar, &dest, 10, ap);
|
||||
va_end(ap);
|
||||
|
||||
str[ret] = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ksprintf(char *str, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
sputchar_arg_t dest;
|
||||
|
||||
dest.str = str;
|
||||
dest.pos = 0;
|
||||
dest.max = (size_t) -1;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = kvprintf(format, sputchar, &dest, 10, ap);
|
||||
va_end(ap);
|
||||
|
||||
str[ret] = 0;
|
||||
|
||||
return ret;
|
||||
}
|
102
hermit/libkern/stdio.c
Normal file
102
hermit/libkern/stdio.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/stdlib.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/stdarg.h>
|
||||
#include <hermit/spinlock.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/multiboot.h>
|
||||
#ifdef CONFIG_VGA
|
||||
#include <asm/vga.h>
|
||||
#endif
|
||||
|
||||
#define NO_EARLY_PRINT 0x00
|
||||
#define VGA_EARLY_PRINT 0x01
|
||||
|
||||
#ifdef CONFIG_VGA
|
||||
static uint32_t early_print = VGA_EARLY_PRINT;
|
||||
#else
|
||||
static uint32_t early_print = NO_EARLY_PRINT;
|
||||
#endif
|
||||
static spinlock_irqsave_t olock = SPINLOCK_IRQSAVE_INIT;
|
||||
static atomic_int32_t kmsg_counter = ATOMIC_INIT(0);
|
||||
static unsigned char kmessages[KMSG_SIZE] __attribute__ ((section(".kmsg"))) = {[0 ... KMSG_SIZE-1] = 0x00};
|
||||
|
||||
int koutput_init(void)
|
||||
{
|
||||
#ifdef CONFIG_VGA
|
||||
vga_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kputchar(int c)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (early_print != NO_EARLY_PRINT)
|
||||
spinlock_irqsave_lock(&olock);
|
||||
|
||||
pos = atomic_int32_inc(&kmsg_counter);
|
||||
kmessages[pos % KMSG_SIZE] = (unsigned char) c;
|
||||
|
||||
#ifdef CONFIG_VGA
|
||||
if (early_print & VGA_EARLY_PRINT)
|
||||
vga_putchar(c);
|
||||
#endif
|
||||
|
||||
if (early_print != NO_EARLY_PRINT)
|
||||
spinlock_irqsave_unlock(&olock);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int kputs(const char *str)
|
||||
{
|
||||
int pos, i, len = strlen(str);
|
||||
|
||||
if (early_print != NO_EARLY_PRINT)
|
||||
spinlock_irqsave_lock(&olock);
|
||||
|
||||
for(i=0; i<len; i++) {
|
||||
pos = atomic_int32_inc(&kmsg_counter);
|
||||
kmessages[pos % KMSG_SIZE] = str[i];
|
||||
#ifdef CONFIG_VGA
|
||||
if (early_print & VGA_EARLY_PRINT)
|
||||
vga_putchar(str[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (early_print != NO_EARLY_PRINT)
|
||||
spinlock_irqsave_unlock(&olock);
|
||||
|
||||
return len;
|
||||
}
|
120
hermit/libkern/string.c
Normal file
120
hermit/libkern/string.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Written by the Chair for Operating Systems, RWTH Aachen University
|
||||
*
|
||||
* NO Copyright (C) 2010-2011, Stefan Lankes
|
||||
* consider these trivial functions to be public domain.
|
||||
*
|
||||
* These functions are distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <hermit/string.h>
|
||||
|
||||
#ifndef HAVE_ARCH_MEMCPY
|
||||
void *memcpy(void *dest, const void *src, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest || !src, 0))
|
||||
return dest;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
((char*)dest)[i] = ((char*)src)[i];
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_MEMSET
|
||||
void *memset(void *dest, int val, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest, 0))
|
||||
return dest;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
((char*) dest)[i] = (char) val;
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRLEN
|
||||
size_t strlen(const char *str)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
if (BUILTIN_EXPECT(!str, 0))
|
||||
return len;
|
||||
|
||||
while (str[len] != '\0')
|
||||
len++;
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRNCPY
|
||||
char* strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest || !src, 0))
|
||||
return dest;
|
||||
|
||||
for (i = 0 ; i < n && src[i] != '\0' ; i++)
|
||||
dest[i] = src[i];
|
||||
if (i < n)
|
||||
dest[i] = '\0';
|
||||
else
|
||||
dest[n-1] = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRCPY
|
||||
char* strcpy(char *dest, const char *src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest || !src, 0))
|
||||
return dest;
|
||||
|
||||
for (i = 0 ; src[i] != '\0' ; i++)
|
||||
dest[i] = src[i];
|
||||
dest[i] = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRCMP
|
||||
int strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
while (*s1 != '\0' && *s1 == *s2) {
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
||||
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_STRNCMP
|
||||
int strncmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
if (BUILTIN_EXPECT(n == 0, 0))
|
||||
return 0;
|
||||
|
||||
while (n-- != 0 && *s1 == *s2) {
|
||||
if (n == 0 || *s1 == '\0')
|
||||
break;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
||||
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
|
||||
}
|
||||
#endif
|
73
hermit/libkern/strstr.c
Normal file
73
hermit/libkern/strstr.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* $NetBSD: strstr.c,v 1.1 2005/12/20 19:28:52 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code has been taken from NetBSD (sys/libkern/strstr.c) and is consequently
|
||||
* BSD-licensed. Unnecessary functions have been removed and all typedefs required
|
||||
* have been added.
|
||||
*/
|
||||
|
||||
/* HermiCore prelude */
|
||||
#include <hermit/stdlib.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/ctype.h>
|
||||
#include <asm/limits.h>
|
||||
|
||||
/*
|
||||
* Find the first occurrence of find in s.
|
||||
*/
|
||||
char *
|
||||
strstr(s, find)
|
||||
const char *s, *find;
|
||||
{
|
||||
char c, sc;
|
||||
size_t len;
|
||||
|
||||
if (BUILTIN_EXPECT(!s, 0))
|
||||
return NULL;
|
||||
if (BUILTIN_EXPECT(!find, 0))
|
||||
return NULL;
|
||||
|
||||
if ((c = *find++) != 0) {
|
||||
len = strlen(find);
|
||||
do {
|
||||
do {
|
||||
if ((sc = *s++) == 0)
|
||||
return (NULL);
|
||||
} while (sc != c);
|
||||
} while (strncmp(s, find, len) != 0);
|
||||
s--;
|
||||
}
|
||||
return ((char *) s);
|
||||
}
|
133
hermit/libkern/strtol.c
Normal file
133
hermit/libkern/strtol.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* From: @(#)strtol.c 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code has been taken from FreeBSD (sys/libkern/strtol.c) and is consequently
|
||||
* BSD-licensed. Unnecessary functions have been removed and all typedefs required
|
||||
* have been added.
|
||||
*/
|
||||
|
||||
/* HermitCore prelude */
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/ctype.h>
|
||||
#include <asm/limits.h>
|
||||
|
||||
/*
|
||||
* Convert a string to a long integer.
|
||||
*
|
||||
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||
* alphabets and digits are each contiguous.
|
||||
*/
|
||||
long
|
||||
strtol(nptr, endptr, base)
|
||||
const char *nptr;
|
||||
char **endptr;
|
||||
int base;
|
||||
{
|
||||
const char *s = nptr;
|
||||
unsigned long acc;
|
||||
unsigned char c;
|
||||
unsigned long cutoff;
|
||||
int neg = 0, any, cutlim;
|
||||
|
||||
/*
|
||||
* Skip white space and pick up leading +/- sign if any.
|
||||
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||
* assume decimal; if base is already 16, allow 0x.
|
||||
*/
|
||||
do {
|
||||
c = *s++;
|
||||
} while (isspace(c));
|
||||
if (c == '-') {
|
||||
neg = 1;
|
||||
c = *s++;
|
||||
} else if (c == '+')
|
||||
c = *s++;
|
||||
if ((base == 0 || base == 16) &&
|
||||
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
|
||||
/*
|
||||
* Compute the cutoff value between legal numbers and illegal
|
||||
* numbers. That is the largest legal value, divided by the
|
||||
* base. An input number that is greater than this value, if
|
||||
* followed by a legal input character, is too big. One that
|
||||
* is equal to this value may be valid or not; the limit
|
||||
* between valid and invalid numbers is then based on the last
|
||||
* digit. For instance, if the range for longs is
|
||||
* [-2147483648..2147483647] and the input base is 10,
|
||||
* cutoff will be set to 214748364 and cutlim to either
|
||||
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
|
||||
* a value > 214748364, or equal but the next digit is > 7 (or 8),
|
||||
* the number is too big, and we will return a range error.
|
||||
*
|
||||
* Set any if any `digits' consumed; make it negative to indicate
|
||||
* overflow.
|
||||
*/
|
||||
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
|
||||
cutlim = cutoff % (unsigned long)base;
|
||||
cutoff /= (unsigned long)base;
|
||||
for (acc = 0, any = 0;; c = *s++) {
|
||||
if (!isascii(c))
|
||||
break;
|
||||
if (isdigit(c))
|
||||
c -= '0';
|
||||
else if (isalpha(c))
|
||||
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||
else
|
||||
break;
|
||||
if (c >= base)
|
||||
break;
|
||||
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
||||
any = -1;
|
||||
else {
|
||||
any = 1;
|
||||
acc *= base;
|
||||
acc += c;
|
||||
}
|
||||
}
|
||||
if (any < 0) {
|
||||
acc = neg ? LONG_MIN : LONG_MAX;
|
||||
} else if (neg)
|
||||
acc = -acc;
|
||||
if (endptr != 0)
|
||||
*((const char **)endptr) = any ? s - 1 : nptr;
|
||||
return (acc);
|
||||
}
|
||||
|
112
hermit/libkern/strtoul.c
Normal file
112
hermit/libkern/strtoul.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* From: @(#)strtoul.c 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code has been taken from FreeBSD (sys/libkern/strtoul.c) and is consequently
|
||||
* BSD-licensed. Unnecessary functions have been removed and all typedefs required
|
||||
* have been added.
|
||||
*/
|
||||
|
||||
/* HermitCore prelude */
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/ctype.h>
|
||||
#include <asm/limits.h>
|
||||
|
||||
/*
|
||||
* Convert a string to an unsigned long integer.
|
||||
*
|
||||
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||
* alphabets and digits are each contiguous.
|
||||
*/
|
||||
unsigned long
|
||||
strtoul(nptr, endptr, base)
|
||||
const char *nptr;
|
||||
char **endptr;
|
||||
int base;
|
||||
{
|
||||
const char *s = nptr;
|
||||
unsigned long acc;
|
||||
unsigned char c;
|
||||
unsigned long cutoff;
|
||||
int neg = 0, any, cutlim;
|
||||
|
||||
/*
|
||||
* See strtol for comments as to the logic used.
|
||||
*/
|
||||
do {
|
||||
c = *s++;
|
||||
} while (isspace(c));
|
||||
if (c == '-') {
|
||||
neg = 1;
|
||||
c = *s++;
|
||||
} else if (c == '+')
|
||||
c = *s++;
|
||||
if ((base == 0 || base == 16) &&
|
||||
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
|
||||
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
|
||||
for (acc = 0, any = 0;; c = *s++) {
|
||||
if (!isascii(c))
|
||||
break;
|
||||
if (isdigit(c))
|
||||
c -= '0';
|
||||
else if (isalpha(c))
|
||||
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||
else
|
||||
break;
|
||||
if (c >= base)
|
||||
break;
|
||||
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
||||
any = -1;
|
||||
else {
|
||||
any = 1;
|
||||
acc *= base;
|
||||
acc += c;
|
||||
}
|
||||
}
|
||||
if (any < 0) {
|
||||
acc = ULONG_MAX;
|
||||
} else if (neg)
|
||||
acc = -acc;
|
||||
if (endptr != 0)
|
||||
*((const char **)endptr) = any ? s - 1 : nptr;
|
||||
return (acc);
|
||||
}
|
||||
|
30
hermit/link.ld
Normal file
30
hermit/link.ld
Normal file
|
@ -0,0 +1,30 @@
|
|||
OUTPUT_FORMAT("elf64-x86-64")
|
||||
OUTPUT_ARCH("i386:x86-64")
|
||||
ENTRY(start)
|
||||
phys = 0x1400000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
kernel_start = phys;
|
||||
.mboot phys : AT(ADDR(.mboot)) {
|
||||
*(.mboot)
|
||||
. = ALIGN((1 << 12));
|
||||
*(.kmsg)
|
||||
}
|
||||
.text ALIGN(4096) : AT(ADDR(.text)) {
|
||||
*(.text)
|
||||
}
|
||||
.rodata ALIGN(4096) : AT(ADDR(.rodata)) {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
}
|
||||
.data ALIGN(4096) : AT(ADDR(.data)) {
|
||||
*(.data)
|
||||
}
|
||||
.bss ALIGN(4096) : AT(ADDR(.bss)) {
|
||||
bss_start = .;
|
||||
*(.bss)
|
||||
}
|
||||
bss_end = .;
|
||||
kernel_end = .;
|
||||
}
|
4
hermit/mm/Makefile
Normal file
4
hermit/mm/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
C_source := memory.c malloc.c vma.c
|
||||
MODULE := mm
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
223
hermit/mm/malloc.c
Normal file
223
hermit/mm/malloc.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Steffen Vogel, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Steffen Vogel <steffen.vogel@rwth-aachen.de>
|
||||
*/
|
||||
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/malloc.h>
|
||||
#include <hermit/spinlock.h>
|
||||
#include <hermit/memory.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
/// A linked list for each binary size exponent
|
||||
static buddy_t* buddy_lists[BUDDY_LISTS] = { [0 ... BUDDY_LISTS-1] = NULL };
|
||||
/// Lock for the buddy lists
|
||||
static spinlock_t buddy_lock = SPINLOCK_INIT;
|
||||
|
||||
/** @brief Check if larger free buddies are available */
|
||||
static inline int buddy_large_avail(uint8_t exp)
|
||||
{
|
||||
while (exp<BUDDY_MAX && !buddy_lists[exp-BUDDY_MIN])
|
||||
exp++;
|
||||
|
||||
return exp != BUDDY_MAX;
|
||||
}
|
||||
|
||||
/** @brief Calculate the required buddy size */
|
||||
static inline int buddy_exp(size_t sz)
|
||||
{
|
||||
int exp;
|
||||
for (exp=0; sz>(1<<exp); exp++);
|
||||
|
||||
if (exp > BUDDY_MAX)
|
||||
exp = 0;
|
||||
if (exp < BUDDY_MIN)
|
||||
exp = BUDDY_MIN;
|
||||
|
||||
return exp;
|
||||
}
|
||||
|
||||
/** @brief Get a free buddy by potentially splitting a larger one */
|
||||
static buddy_t* buddy_get(int exp)
|
||||
{
|
||||
spinlock_lock(&buddy_lock);
|
||||
buddy_t** list = &buddy_lists[exp-BUDDY_MIN];
|
||||
buddy_t* buddy = *list;
|
||||
buddy_t* split;
|
||||
|
||||
if (buddy)
|
||||
// there is already a free buddy =>
|
||||
// we remove it from the list
|
||||
*list = buddy->next;
|
||||
else if (exp >= BUDDY_ALLOC && !buddy_large_avail(exp))
|
||||
// theres no free buddy larger than exp =>
|
||||
// we can allocate new memory
|
||||
buddy = (buddy_t*) palloc(1<<exp, 0);
|
||||
else {
|
||||
// we recursivly request a larger buddy...
|
||||
buddy = buddy_get(exp+1);
|
||||
if (BUILTIN_EXPECT(!buddy, 0))
|
||||
goto out;
|
||||
|
||||
// ... and split it, by putting the second half back to the list
|
||||
split = (buddy_t*) ((size_t) buddy + (1<<exp));
|
||||
split->next = *list;
|
||||
*list = split;
|
||||
}
|
||||
|
||||
out:
|
||||
spinlock_unlock(&buddy_lock);
|
||||
|
||||
return buddy;
|
||||
}
|
||||
|
||||
/** @brief Put a buddy back to its free list
|
||||
*
|
||||
* TODO: merge adjacent buddies (memory compaction)
|
||||
*/
|
||||
static void buddy_put(buddy_t* buddy)
|
||||
{
|
||||
spinlock_lock(&buddy_lock);
|
||||
buddy_t** list = &buddy_lists[buddy->prefix.exponent-BUDDY_MIN];
|
||||
buddy->next = *list;
|
||||
*list = buddy;
|
||||
spinlock_unlock(&buddy_lock);
|
||||
}
|
||||
|
||||
void buddy_dump(void)
|
||||
{
|
||||
size_t free = 0;
|
||||
int i;
|
||||
for (i=0; i<BUDDY_LISTS; i++) {
|
||||
buddy_t* buddy;
|
||||
int exp = i+BUDDY_MIN;
|
||||
|
||||
if (buddy_lists[i])
|
||||
kprintf("buddy_list[%u] (exp=%u, size=%lu bytes):\n", i, exp, 1<<exp);
|
||||
|
||||
for (buddy=buddy_lists[i]; buddy; buddy=buddy->next) {
|
||||
kprintf(" %p -> %p \n", buddy, buddy->next);
|
||||
free += 1<<exp;
|
||||
}
|
||||
}
|
||||
kprintf("free buddies: %lu bytes\n", free);
|
||||
}
|
||||
|
||||
void* palloc(size_t sz, uint32_t flags)
|
||||
{
|
||||
size_t phyaddr, viraddr;
|
||||
uint32_t npages = PAGE_FLOOR(sz) >> PAGE_BITS;
|
||||
int err;
|
||||
|
||||
//kprintf("palloc(%lu) (%lu pages)\n", sz, npages);
|
||||
|
||||
// get free virtual address space
|
||||
viraddr = vma_alloc(npages*PAGE_SIZE, VMA_HEAP);
|
||||
if (BUILTIN_EXPECT(!viraddr, 0))
|
||||
return NULL;
|
||||
|
||||
// get continous physical pages
|
||||
phyaddr = get_pages(npages);
|
||||
if (BUILTIN_EXPECT(!phyaddr, 0)) {
|
||||
vma_free(viraddr, viraddr+npages*PAGE_SIZE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// map physical pages to VMA
|
||||
err = page_map(viraddr, phyaddr, npages, PG_RW|PG_GLOBAL);
|
||||
if (BUILTIN_EXPECT(err, 0)) {
|
||||
vma_free(viraddr, viraddr+npages*PAGE_SIZE);
|
||||
put_pages(phyaddr, npages);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void*) viraddr;
|
||||
}
|
||||
|
||||
void pfree(void* addr, size_t sz)
|
||||
{
|
||||
if (BUILTIN_EXPECT(!addr || !sz, 0))
|
||||
return;
|
||||
|
||||
size_t i;
|
||||
size_t phyaddr;
|
||||
size_t viraddr = (size_t) addr & PAGE_MASK;
|
||||
uint32_t npages = PAGE_FLOOR(sz) >> PAGE_BITS;
|
||||
|
||||
// memory is probably not continuously mapped! (userspace heap)
|
||||
for (i=0; i<npages; i++) {
|
||||
phyaddr = virt_to_phys(viraddr+i*PAGE_SIZE);
|
||||
put_page(phyaddr);
|
||||
}
|
||||
|
||||
page_unmap(viraddr, npages);
|
||||
vma_free(viraddr, viraddr+npages*PAGE_SIZE);
|
||||
}
|
||||
|
||||
void* kmalloc(size_t sz)
|
||||
{
|
||||
if (BUILTIN_EXPECT(!sz, 0))
|
||||
return NULL;
|
||||
|
||||
// add space for the prefix
|
||||
sz += sizeof(buddy_t);
|
||||
|
||||
int exp = buddy_exp(sz);
|
||||
if (BUILTIN_EXPECT(!exp, 0))
|
||||
return NULL;
|
||||
|
||||
buddy_t* buddy = buddy_get(exp);
|
||||
if (BUILTIN_EXPECT(!buddy, 0))
|
||||
return NULL;
|
||||
|
||||
// setup buddy prefix
|
||||
buddy->prefix.magic = BUDDY_MAGIC;
|
||||
buddy->prefix.exponent = exp;
|
||||
|
||||
//kprintf("kmalloc(%lu) = %p\n", sz, buddy+1);
|
||||
|
||||
// pointer arithmetic: we hide the prefix
|
||||
return buddy+1;
|
||||
}
|
||||
|
||||
void kfree(void *addr)
|
||||
{
|
||||
if (BUILTIN_EXPECT(!addr, 0))
|
||||
return;
|
||||
|
||||
//kprintf("kfree(%lu)\n", addr);
|
||||
|
||||
buddy_t* buddy = (buddy_t*) addr - 1; // get prefix
|
||||
|
||||
// check magic
|
||||
if (BUILTIN_EXPECT(buddy->prefix.magic != BUDDY_MAGIC, 0))
|
||||
return;
|
||||
|
||||
buddy_put(buddy);
|
||||
}
|
326
hermit/mm/memory.c
Normal file
326
hermit/mm/memory.c
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/stddef.h>
|
||||
#include <hermit/stdlib.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/string.h>
|
||||
#include <hermit/spinlock.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/multiboot.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
extern size_t base;
|
||||
extern size_t limit;
|
||||
|
||||
/*
|
||||
* Note that linker symbols are not variables, they have no memory allocated for
|
||||
* maintaining a value, rather their address is their value.
|
||||
*/
|
||||
extern const void kernel_start;
|
||||
extern const void kernel_end;
|
||||
|
||||
static char stack[MAX_TASKS-1][KERNEL_STACK_SIZE];
|
||||
static char bitmap[BITMAP_SIZE];
|
||||
|
||||
static spinlock_t bitmap_lock = SPINLOCK_INIT;
|
||||
|
||||
atomic_int32_t total_pages = ATOMIC_INIT(0);
|
||||
atomic_int32_t total_allocated_pages = ATOMIC_INIT(0);
|
||||
atomic_int32_t total_available_pages = ATOMIC_INIT(0);
|
||||
|
||||
void* create_stack(tid_t id)
|
||||
{
|
||||
// idle task uses stack, which is defined in entry.asm
|
||||
if (BUILTIN_EXPECT(!id, 0))
|
||||
return NULL;
|
||||
// do we have a valid task id?
|
||||
if (BUILTIN_EXPECT(id >= MAX_TASKS, 0))
|
||||
return NULL;
|
||||
|
||||
return (void*) stack[id-1];
|
||||
}
|
||||
|
||||
inline static int page_marked(size_t i)
|
||||
{
|
||||
size_t index = i >> 3;
|
||||
size_t mod = i & 0x7;
|
||||
|
||||
return (bitmap[index] & (1 << mod));
|
||||
}
|
||||
|
||||
inline static void page_set_mark(size_t i)
|
||||
{
|
||||
size_t index = i >> 3;
|
||||
size_t mod = i & 0x7;
|
||||
|
||||
bitmap[index] = bitmap[index] | (1 << mod);
|
||||
}
|
||||
|
||||
inline static void page_clear_mark(size_t i)
|
||||
{
|
||||
size_t index = i / 8;
|
||||
size_t mod = i % 8;
|
||||
|
||||
bitmap[index] = bitmap[index] & ~(1 << mod);
|
||||
}
|
||||
|
||||
size_t get_pages(size_t npages)
|
||||
{
|
||||
size_t cnt, off;
|
||||
static size_t alloc_start = (size_t) -1;
|
||||
|
||||
if (BUILTIN_EXPECT(!npages, 0))
|
||||
return 0;
|
||||
if (BUILTIN_EXPECT(npages > atomic_int32_read(&total_available_pages), 0))
|
||||
return 0;
|
||||
|
||||
spinlock_lock(&bitmap_lock);
|
||||
|
||||
if (alloc_start == (size_t)-1)
|
||||
alloc_start = ((size_t) &kernel_end >> PAGE_BITS);
|
||||
off = 1;
|
||||
while (off <= BITMAP_SIZE*8 - npages) {
|
||||
for (cnt=0; cnt<npages; cnt++) {
|
||||
if (page_marked(((off+alloc_start)%(BITMAP_SIZE*8 - npages))+cnt))
|
||||
goto next;
|
||||
}
|
||||
|
||||
off = (off+alloc_start) % (BITMAP_SIZE*8 - npages);
|
||||
alloc_start = off+npages;
|
||||
|
||||
for (cnt=0; cnt<npages; cnt++) {
|
||||
page_set_mark(off+cnt);
|
||||
}
|
||||
|
||||
spinlock_unlock(&bitmap_lock);
|
||||
|
||||
atomic_int32_add(&total_allocated_pages, npages);
|
||||
atomic_int32_sub(&total_available_pages, npages);
|
||||
|
||||
return off << PAGE_BITS;
|
||||
|
||||
next: off += cnt+1;
|
||||
}
|
||||
|
||||
spinlock_unlock(&bitmap_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int put_pages(size_t phyaddr, size_t npages)
|
||||
{
|
||||
size_t i, ret = 0;
|
||||
size_t base = phyaddr >> PAGE_BITS;
|
||||
|
||||
if (BUILTIN_EXPECT(!phyaddr, 0))
|
||||
return -EINVAL;
|
||||
if (BUILTIN_EXPECT(!npages, 0))
|
||||
return -EINVAL;
|
||||
|
||||
spinlock_lock(&bitmap_lock);
|
||||
|
||||
for (i=0; i<npages; i++) {
|
||||
if (page_marked(base+i)) {
|
||||
page_clear_mark(base+i);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_unlock(&bitmap_lock);
|
||||
|
||||
atomic_int32_sub(&total_allocated_pages, ret);
|
||||
atomic_int32_add(&total_available_pages, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int copy_page(size_t pdest, size_t psrc)
|
||||
{
|
||||
int err;
|
||||
|
||||
static size_t viraddr;
|
||||
if (!viraddr) { // statically allocate virtual memory area
|
||||
viraddr = vma_alloc(2 * PAGE_SIZE, VMA_HEAP);
|
||||
if (BUILTIN_EXPECT(!viraddr, 0))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// map pages
|
||||
size_t vsrc = viraddr;
|
||||
err = page_map(vsrc, psrc, 1, PG_GLOBAL|PG_RW);
|
||||
if (BUILTIN_EXPECT(err, 0)) {
|
||||
page_unmap(viraddr, 1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
size_t vdest = viraddr + PAGE_SIZE;
|
||||
err = page_map(vdest, pdest, 1, PG_GLOBAL|PG_RW);
|
||||
if (BUILTIN_EXPECT(err, 0)) {
|
||||
page_unmap(viraddr + PAGE_SIZE, 1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kprintf("copy_page: copy page frame from: %#lx (%#lx) to %#lx (%#lx)\n", vsrc, psrc, vdest, pdest); // TODO remove
|
||||
|
||||
// copy the whole page
|
||||
memcpy((void*) vdest, (void*) vsrc, PAGE_SIZE);
|
||||
|
||||
// householding
|
||||
page_unmap(viraddr, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int memory_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
size_t addr;
|
||||
int ret = 0;
|
||||
|
||||
// mark all memory as used
|
||||
memset(bitmap, 0xff, BITMAP_SIZE);
|
||||
|
||||
// enable paging and map Multiboot modules etc.
|
||||
ret = page_init();
|
||||
if (BUILTIN_EXPECT(ret, 0)) {
|
||||
kputs("Failed to initialize paging!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// parse multiboot information for available memory
|
||||
if (mb_info) {
|
||||
if (mb_info->flags & MULTIBOOT_INFO_MEM_MAP) {
|
||||
size_t end_addr;
|
||||
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) ((size_t) mb_info->mmap_addr);
|
||||
multiboot_memory_map_t* mmap_end = (void*) ((size_t) mb_info->mmap_addr + mb_info->mmap_length);
|
||||
|
||||
// mark available memory as free
|
||||
while (mmap < mmap_end) {
|
||||
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
|
||||
/* set the available memory as "unused" */
|
||||
addr = mmap->addr;
|
||||
end_addr = addr + mmap->len;
|
||||
|
||||
while ((addr < end_addr) && (addr < (BITMAP_SIZE*8*PAGE_SIZE))) {
|
||||
if (page_marked(addr >> PAGE_BITS)) {
|
||||
page_clear_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_pages);
|
||||
atomic_int32_inc(&total_available_pages);
|
||||
}
|
||||
addr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
mmap = (multiboot_memory_map_t*) ((size_t) mmap + sizeof(uint32_t) + mmap->size);
|
||||
}
|
||||
} else if (mb_info->flags & MULTIBOOT_INFO_MEM) {
|
||||
size_t page;
|
||||
size_t pages_lower = mb_info->mem_lower >> 2; /* KiB to page number */
|
||||
size_t pages_upper = mb_info->mem_upper >> 2;
|
||||
|
||||
for (page=0; page<pages_lower; page++)
|
||||
page_clear_mark(page);
|
||||
|
||||
if (pages_upper > BITMAP_SIZE*8-256)
|
||||
pages_upper = BITMAP_SIZE*8-256;
|
||||
|
||||
for (page=0; page<pages_upper; page++)
|
||||
page_clear_mark(page + 256); /* 1 MiB == 256 pages offset */
|
||||
|
||||
atomic_int32_add(&total_pages, pages_lower + pages_upper);
|
||||
atomic_int32_add(&total_available_pages, pages_lower + pages_upper);
|
||||
} else {
|
||||
kputs("Unable to initialize the memory management subsystem\n");
|
||||
while (1) HALT;
|
||||
}
|
||||
|
||||
// mark mb_info as used
|
||||
page_set_mark((size_t) mb_info >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
|
||||
|
||||
if (mb_info->flags & MULTIBOOT_INFO_MODS) {
|
||||
// mark modules list as used
|
||||
for(addr=mb_info->mods_addr; addr<mb_info->mods_addr+mb_info->mods_count*sizeof(multiboot_module_t); addr+=PAGE_SIZE) {
|
||||
page_set_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
}
|
||||
|
||||
// mark modules as used
|
||||
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
|
||||
for(i=0; i<mb_info->mods_count; i++) {
|
||||
for(addr=mmodule[i].mod_start; addr<mmodule[i].mod_end; addr+=PAGE_SIZE) {
|
||||
page_set_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// mark available memory as free
|
||||
for(addr=base; addr<limit; addr+=PAGE_SIZE) {
|
||||
if (page_marked(addr >> PAGE_BITS)) {
|
||||
page_clear_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_pages);
|
||||
atomic_int32_inc(&total_available_pages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mark kernel as used, we use 2MB pages to map the kernel
|
||||
for(addr=(size_t) &kernel_start; addr<(((size_t) &kernel_end + 0x200000ULL) & 0xFFFFFFFFFFE00000ULL); addr+=PAGE_SIZE) {
|
||||
page_set_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
}
|
||||
|
||||
ret = vma_init();
|
||||
if (BUILTIN_EXPECT(ret, 0)) {
|
||||
kprintf("Failed to initialize VMA regions: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modules like the init ram disk are already loaded.
|
||||
* Therefore, we set these pages as used.
|
||||
*/
|
||||
if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MODS)) {
|
||||
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
|
||||
for(i=0; i<mb_info->mods_count; i++) {
|
||||
for(addr=mmodule[i].mod_start; addr<mmodule[i].mod_end; addr+=PAGE_SIZE) {
|
||||
page_set_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
400
hermit/mm/vma.c
Normal file
400
hermit/mm/vma.c
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Steffen Vogel, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <hermit/vma.h>
|
||||
#include <hermit/stdlib.h>
|
||||
#include <hermit/stdio.h>
|
||||
#include <hermit/tasks_types.h>
|
||||
#include <hermit/spinlock.h>
|
||||
#include <hermit/errno.h>
|
||||
#include <asm/multiboot.h>
|
||||
|
||||
/*
|
||||
* Note that linker symbols are not variables, they have no memory allocated for
|
||||
* maintaining a value, rather their address is their value.
|
||||
*/
|
||||
extern const void kernel_start;
|
||||
extern const void kernel_end;
|
||||
|
||||
/*
|
||||
* Kernel space VMA list and lock
|
||||
*
|
||||
* For bootstrapping we initialize the VMA list with one empty VMA
|
||||
* (start == end) and expand this VMA by calls to vma_alloc()
|
||||
*/
|
||||
static vma_t vma_boot = { VMA_KERN_MIN, VMA_KERN_MIN, VMA_HEAP };
|
||||
static vma_t* vma_list = &vma_boot;
|
||||
static spinlock_t vma_lock = SPINLOCK_INIT;
|
||||
|
||||
// TODO: we might move the architecture specific VMA regions to a
|
||||
// seperate function arch_vma_init()
|
||||
int vma_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// add Kernel
|
||||
ret = vma_add(PAGE_CEIL((size_t) &kernel_start),
|
||||
(((size_t) &kernel_end + 0x200000ULL) & 0xFFFFFFFFFFE00000ULL), /* we use 2MB pages to map the kernel */
|
||||
VMA_READ|VMA_WRITE|VMA_EXECUTE|VMA_CACHEABLE);
|
||||
if (BUILTIN_EXPECT(ret, 0))
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_VGA
|
||||
// add VGA video memory
|
||||
ret = vma_add(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR + PAGE_SIZE, VMA_READ|VMA_WRITE);
|
||||
if (BUILTIN_EXPECT(ret, 0))
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
// add Multiboot structures as modules
|
||||
if (mb_info) {
|
||||
ret = vma_add(PAGE_CEIL((size_t) mb_info),
|
||||
PAGE_FLOOR((size_t) mb_info + sizeof(multiboot_info_t)),
|
||||
VMA_READ|VMA_CACHEABLE);
|
||||
if (BUILTIN_EXPECT(ret, 0))
|
||||
goto out;
|
||||
|
||||
if (mb_info->flags & MULTIBOOT_INFO_MODS) {
|
||||
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
|
||||
|
||||
ret = vma_add(PAGE_CEIL((size_t) mb_info->mods_addr),
|
||||
PAGE_FLOOR((size_t) mb_info->mods_addr + mb_info->mods_count*sizeof(multiboot_module_t)),
|
||||
VMA_READ|VMA_CACHEABLE);
|
||||
|
||||
//TODO: Why do we get error code -22 (-EINVAL);
|
||||
ret = 0; // TODO: Remove workaround
|
||||
|
||||
int i;
|
||||
for(i=0; i<mb_info->mods_count; i++) {
|
||||
ret = vma_add(PAGE_CEIL(mmodule[i].mod_start),
|
||||
PAGE_FLOOR(mmodule[i].mod_end),
|
||||
VMA_READ|VMA_WRITE|VMA_CACHEABLE);
|
||||
if (BUILTIN_EXPECT(ret, 0))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t vma_alloc(size_t size, uint32_t flags)
|
||||
{
|
||||
task_t* task = current_task;
|
||||
spinlock_t* lock;
|
||||
vma_t** list;
|
||||
|
||||
//kprintf("vma_alloc: size = %#lx, flags = %#x\n", size, flags);
|
||||
|
||||
size_t base, limit; // boundaries for search
|
||||
size_t start, end; // boundaries of free gaps
|
||||
|
||||
if (flags & VMA_USER) {
|
||||
base = VMA_USER_MIN;
|
||||
limit = VMA_USER_MAX;
|
||||
list = &task->vma_list;
|
||||
lock = &task->vma_lock;
|
||||
}
|
||||
else {
|
||||
base = VMA_KERN_MIN;
|
||||
limit = VMA_KERN_MAX;
|
||||
list = &vma_list;
|
||||
lock = &vma_lock;
|
||||
}
|
||||
|
||||
spinlock_lock(lock);
|
||||
|
||||
// first fit search for free memory area
|
||||
vma_t* pred = NULL; // vma before current gap
|
||||
vma_t* succ = *list; // vma after current gap
|
||||
do {
|
||||
start = (pred) ? pred->end : base;
|
||||
end = (succ) ? succ->start : limit;
|
||||
|
||||
if (start + size < end && start >= base && start + size < limit)
|
||||
goto found; // we found a gap which is large enough and in the bounds
|
||||
|
||||
pred = succ;
|
||||
succ = (pred) ? pred->next : NULL;
|
||||
} while (pred || succ);
|
||||
|
||||
fail:
|
||||
spinlock_unlock(lock); // we were unlucky to find a free gap
|
||||
|
||||
return 0;
|
||||
|
||||
found:
|
||||
if (pred && pred->flags == flags)
|
||||
pred->end = start + size; // resize VMA
|
||||
else {
|
||||
// insert new VMA
|
||||
vma_t* new = kmalloc(sizeof(vma_t));
|
||||
if (BUILTIN_EXPECT(!new, 0))
|
||||
goto fail;
|
||||
|
||||
new->start = start;
|
||||
new->end = start + size;
|
||||
new->flags = flags;
|
||||
new->next = succ;
|
||||
new->prev = pred;
|
||||
|
||||
if (succ)
|
||||
succ->prev = new;
|
||||
if (pred)
|
||||
pred->next = new;
|
||||
else
|
||||
*list = new;
|
||||
}
|
||||
|
||||
spinlock_unlock(lock);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
int vma_free(size_t start, size_t end)
|
||||
{
|
||||
task_t* task = current_task;
|
||||
spinlock_t* lock;
|
||||
vma_t* vma;
|
||||
vma_t** list = NULL;
|
||||
|
||||
//kprintf("vma_free: start = %#lx, end = %#lx\n", start, end);
|
||||
|
||||
if (BUILTIN_EXPECT(start >= end, 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (end < VMA_KERN_MAX) {
|
||||
lock = &vma_lock;
|
||||
list = &vma_list;
|
||||
}
|
||||
else if (start >= VMA_KERN_MAX) {
|
||||
lock = &task->vma_lock;
|
||||
list = &task->vma_list;
|
||||
}
|
||||
|
||||
if (BUILTIN_EXPECT(!list || !*list, 0))
|
||||
return -EINVAL;
|
||||
|
||||
spinlock_lock(lock);
|
||||
|
||||
// search vma
|
||||
vma = *list;
|
||||
while (vma) {
|
||||
if (start >= vma->start && end <= vma->end) break;
|
||||
vma = vma->next;
|
||||
}
|
||||
|
||||
if (BUILTIN_EXPECT(!vma, 0)) {
|
||||
spinlock_unlock(lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// free/resize vma
|
||||
if (start == vma->start && end == vma->end) {
|
||||
if (vma == *list)
|
||||
*list = vma->next; // update list head
|
||||
if (vma->prev)
|
||||
vma->prev->next = vma->next;
|
||||
if (vma->next)
|
||||
vma->next->prev = vma->prev;
|
||||
kfree(vma);
|
||||
}
|
||||
else if (start == vma->start)
|
||||
vma->start = end;
|
||||
else if (end == vma->end)
|
||||
vma->end = start;
|
||||
else {
|
||||
vma_t* new = kmalloc(sizeof(vma_t));
|
||||
if (BUILTIN_EXPECT(!new, 0)) {
|
||||
spinlock_unlock(lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
new->end = vma->end;
|
||||
vma->end = start;
|
||||
new->start = end;
|
||||
|
||||
new->next = vma->next;
|
||||
vma->next = new;
|
||||
new->prev = vma;
|
||||
}
|
||||
|
||||
spinlock_unlock(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vma_add(size_t start, size_t end, uint32_t flags)
|
||||
{
|
||||
task_t* task = current_task;
|
||||
spinlock_t* lock;
|
||||
vma_t** list;
|
||||
|
||||
if (BUILTIN_EXPECT(start >= end, 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & VMA_USER) {
|
||||
list = &task->vma_list;
|
||||
lock = &task->vma_lock;
|
||||
|
||||
// check if address is in userspace
|
||||
if (BUILTIN_EXPECT(start < VMA_KERN_MAX, 0))
|
||||
return -EINVAL;
|
||||
}
|
||||
else {
|
||||
list = &vma_list;
|
||||
lock = &vma_lock;
|
||||
|
||||
// check if address is in kernelspace
|
||||
if (BUILTIN_EXPECT(end >= VMA_KERN_MAX, 0))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
//kprintf("vma_add: start = %#lx, end = %#lx, flags = %#x\n", start, end, flags);
|
||||
|
||||
spinlock_lock(lock);
|
||||
|
||||
// search gap
|
||||
vma_t* pred = NULL;
|
||||
vma_t* succ = *list;
|
||||
|
||||
while (pred || succ) {
|
||||
if ((!pred || pred->end <= start) &&
|
||||
(!succ || succ->start >= end))
|
||||
break;
|
||||
|
||||
pred = succ;
|
||||
succ = (succ) ? succ->next : NULL;
|
||||
}
|
||||
|
||||
if (BUILTIN_EXPECT(*list && !pred && !succ, 0)) {
|
||||
spinlock_unlock(lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// insert new VMA
|
||||
vma_t* new = kmalloc(sizeof(vma_t));
|
||||
if (BUILTIN_EXPECT(!new, 0)) {
|
||||
spinlock_unlock(lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
new->start = start;
|
||||
new->end = end;
|
||||
new->flags = flags;
|
||||
new->next = succ;
|
||||
new->prev = pred;
|
||||
|
||||
if (succ)
|
||||
succ->prev = new;
|
||||
if (pred)
|
||||
pred->next = new;
|
||||
else
|
||||
*list = new;
|
||||
|
||||
spinlock_unlock(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_vma_list(task_t* src, task_t* dest)
|
||||
{
|
||||
spinlock_init(&dest->vma_lock);
|
||||
|
||||
spinlock_lock(&src->vma_lock);
|
||||
spinlock_lock(&dest->vma_lock);
|
||||
|
||||
vma_t* last = NULL;
|
||||
vma_t* old;
|
||||
for (old=src->vma_list; old; old=old->next) {
|
||||
vma_t *new = kmalloc(sizeof(vma_t));
|
||||
if (BUILTIN_EXPECT(!new, 0)) {
|
||||
spinlock_unlock(&dest->vma_lock);
|
||||
spinlock_unlock(&src->vma_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
new->start = old->start;
|
||||
new->end = old->end;
|
||||
new->flags = old->flags;
|
||||
new->prev = last;
|
||||
|
||||
if (last)
|
||||
last->next = new;
|
||||
else
|
||||
dest->vma_list = new;
|
||||
|
||||
last = new;
|
||||
}
|
||||
|
||||
spinlock_unlock(&dest->vma_lock);
|
||||
spinlock_unlock(&src->vma_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drop_vma_list(task_t *task)
|
||||
{
|
||||
vma_t* vma;
|
||||
|
||||
spinlock_lock(&task->vma_lock);
|
||||
|
||||
while ((vma = task->vma_list)) {
|
||||
task->vma_list = vma->next;
|
||||
kfree(vma);
|
||||
}
|
||||
|
||||
spinlock_unlock(&task->vma_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vma_dump(void)
|
||||
{
|
||||
void print_vma(vma_t *vma) {
|
||||
while (vma) {
|
||||
kprintf("0x%lx - 0x%lx: size=%x, flags=%c%c%c\n", vma->start, vma->end, vma->end - vma->start,
|
||||
(vma->flags & VMA_READ) ? 'r' : '-',
|
||||
(vma->flags & VMA_WRITE) ? 'w' : '-',
|
||||
(vma->flags & VMA_EXECUTE) ? 'x' : '-');
|
||||
vma = vma->next;
|
||||
}
|
||||
}
|
||||
|
||||
task_t* task = current_task;
|
||||
|
||||
kputs("Kernelspace VMAs:\n");
|
||||
spinlock_lock(&vma_lock);
|
||||
print_vma(vma_list);
|
||||
spinlock_unlock(&vma_lock);
|
||||
|
||||
kputs("Userspace VMAs:\n");
|
||||
spinlock_lock(&task->vma_lock);
|
||||
print_vma(task->vma_list);
|
||||
spinlock_unlock(&task->vma_lock);
|
||||
}
|
Loading…
Add table
Reference in a new issue