diff --git a/Makefile.example b/Makefile.example index fd93ee09..e5c6d694 100644 --- a/Makefile.example +++ b/Makefile.example @@ -5,19 +5,28 @@ LWIPDIRS = lwip/src/arch lwip/src/api lwip/src/core lwip/src/core/ipv4 lwip/src/ DRIVERDIRS = drivers/net drivers/char KERNDIRS = libkern kernel mm fs apps arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/scc $(LWIPDIRS) $(DRIVERDIRS) SUBDIRS = $(KERNDIRS) +STACKPROT=-fno-stack-protector + +# Set your own cross compiler tool chain prefix here +CROSSCOMPREFIX= + +# Uncomment both lines if compiling for the SCC! +#CROSSCOMPREFIX=i386-unknown-linux-gnu- +#STACKPROT= + +CC_FOR_TARGET=$(CROSSCOMPREFIX)gcc +CXX_FOR_TARGET=$(CROSSCOMPREFIX)g++ +GCC_FOR_TARGET=$(CROSSCOMPREFIX)gcc +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 -CC_FOR_TARGET=gcc -CXX_FOR_TARGET=g++ -GCC_FOR_TARGET=gcc -AR_FOR_TARGET=ar -AS_FOR_TARGET=as -LD_FOR_TARGET=ld -NM_FOR_TARGET=nm -OBJDUMP_FOR_TARGET=objdump -OBJCOPY_FOR_TARGET=objcopy -RANLIB_FOR_TARGET=ranlib -STRIP_FOR_TARGET=strip -READELF_FOR_TARGET=readelf NASM = nasm EMU=qemu GDB=gdb @@ -26,9 +35,9 @@ MAKE = make NASMFLAGS = -felf32 -g INCLUDE = -I$(TOPDIR)/include -I$(TOPDIR)/arch/$(ARCH)/include -I$(TOPDIR)/lwip/src/include -I$(TOPDIR)/lwip/src/include/ipv4 -I$(TOPDIR)/drivers # Compiler options for final code -CFLAGS = -g -m32 -march=i586 -Wall -O2 -fno-builtin -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc $(INCLUDE) -fno-stack-protector +CFLAGS = -g -m32 -march=i586 -Wall -O2 -fno-builtin -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc $(INCLUDE) $(STACKPROT) # Compiler options for debuuging -#CFLAGS = -g -O -m32 -march=i586 -Wall -fno-builtin -DWITH_FRAME_POINTER -nostdinc $(INCLUDE) -fno-stack-protector +#CFLAGS = -g -O -m32 -march=i586 -Wall -fno-builtin -DWITH_FRAME_POINTER -nostdinc $(INCLUDE) $(STACKPROT) 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') @@ -47,7 +56,7 @@ default: all all: newlib tools $(NAME).elf newlib: - $(MAKE) ARCH=$(ARCH) LDFLAGS="-m32" CFLAGS="-m32 -O2 -march=i586 -fno-stack-protector" NASMFLAGS="$(NASMFLAGS)" CC_FOR_TARGET=$(CC_FOR_TARGET) \ + $(MAKE) ARCH=$(ARCH) LDFLAGS="-m32" CFLAGS="-m32 -O2 -march=i586 $(STACKPROT)" NASMFLAGS="$(NASMFLAGS)" CC_FOR_TARGET=$(CC_FOR_TARGET) \ CXX_FOR_TARGET=$(CXX_FOR_TARGET) \ GCC_FOR_TARGET=$(GCC_FOR_TARGET) \ AR_FOR_TARGET=$(AR_FOR_TARGET) \ diff --git a/arch/x86/kernel/timer.c b/arch/x86/kernel/timer.c index 0ea49d0b..d6b71d2c 100644 --- a/arch/x86/kernel/timer.c +++ b/arch/x86/kernel/timer.c @@ -127,6 +127,9 @@ int timer_wait(unsigned int 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 @@ -134,10 +137,6 @@ int timer_wait(unsigned int ticks) */ int timer_init(void) { -#ifndef CONFIG_ROCKCREEK - uint64_t start; -#endif - /* * Installs 'timer_handler' for the PIC and APIC timer, * only one handler will be later used. @@ -150,16 +149,27 @@ int timer_init(void) * Therefore, we have not to configure the PIC timer. */ #ifndef CONFIG_ROCKCREEK + /* + * 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); - /* before we write to 0x40, we wait some time */ - start = rdtsc(); - while(rdtsc() - start < 1000000) - ; + + WAIT_SOME_TIME(); + + /* Port 0x40 is for the counter register of channel 0 */ + outportb(0x40, LATCH(TIMER_FREQ) & 0xFF); /* low byte */ - /* before we write to 0x40, we wait some time */ - start = rdtsc(); - while(rdtsc() - start < 1000000) - ; + + WAIT_SOME_TIME(); + outportb(0x40, LATCH(TIMER_FREQ) >> 8); /* high byte */ #endif diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index 1e86cb53..b721ecf7 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -764,6 +764,11 @@ int arch_paging_init(void) if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MODS)) { multiboot_module_t* mmodule = (multiboot_module_t*) mb_info->mods_addr; + npages = mb_info->mods_count * sizeof(multiboot_module_t) >> PAGE_SHIFT; + if (mb_info->mods_count * sizeof(multiboot_module_t) & (PAGE_SIZE-1)) + npages++; + map_region((size_t) (mb_info->mods_addr), (size_t) (mb_info->mods_addr), npages, MAP_KERNEL_SPACE); + for(i=0; imods_count; i++, mmodule++) { // map physical address to the same virtual address npages = (mmodule->mod_end - mmodule->mod_start) >> PAGE_SHIFT; diff --git a/documentation/text/compilation.dox b/documentation/text/compilation.dox index 61739023..20f13d6a 100644 --- a/documentation/text/compilation.dox +++ b/documentation/text/compilation.dox @@ -45,23 +45,18 @@ $ cp include/metalsvm/config.h.example include/metalsvm/config.h \endverbatim * * -# Intel recommends to use their cross-compiler for generating code which is guaranteed to be SCC-compatible. Just set the environment variables with the following command: * \verbatim$ . /opt/compilerSetupFiles/crosscompile.sh \endverbatim - * -# The Makefile needs to be adapted to actually use the cross compiler: - * \verbatim -CC_FOR_TARGET=i386-unknown-linux-gnu-gcc -CXX_FOR_TARGET=i386-unknown-linux-gnu-g++ -GCC_FOR_TARGET=i386-unknown-linux-gnu-gcc -AR_FOR_TARGET=i386-unknown-linux-gnu-ar -AS_FOR_TARGET=i386-unknown-linux-gnu-as -LD_FOR_TARGET=i386-unknown-linux-gnu-ld -NM_FOR_TARGET=i386-unknown-linux-gnu-nm -OBJDUMP_FOR_TARGET=i386-unknown-linux-gnu-objdump -OBJCOPY_FOR_TARGET=i386-unknown-linux-gnu-objcopy -RANLIB_FOR_TARGET=i386-unknown-linux-gnu-ranlib -STRIP_FOR_TARGET=i386-unknown-linux-gnu-strip -READELF_FOR_TARGET=i386-unknown-linux-gnu-readelf \endverbatim + * -# The Makefile needs to be adapted to actually use the cross compiler. + * Just uncomment two lines like seen here: + * \code +# Set your own cross compiler tool chain prefix here +CROSSCOMPREFIX= + +# Uncomment both lines if compiling for the SCC! +CROSSCOMPREFIX=i386-unknown-linux-gnu- +STACKPROT=\endcode * -# Another important change in the Makefile is disabling the "-fno-stack-protector" option. It occurs several times. * -# The SCC requires a special configuration for the MetalSVM kernel: - * \verbatim + * \code //#define CONFIG_PCI //#define CONFIG_VGA //#define CONFIG_UART @@ -75,11 +70,11 @@ READELF_FOR_TARGET=i386-unknown-linux-gnu-readelf \endverbatim //#define GORY //#define SHMADD #define SHMDBG -//#define SHMADD_CACHEABLE \endverbatim +//#define SHMADD_CACHEABLE \endcode * -# There is only one core per tile, so it is adequate to reduce overhead by disabling SMP in MetalSVM: - * \verbatim#define MAX_CORES 1 \endverbatim + * \code#define MAX_CORES 1 \endcode * -# Cache-line size is 32 byte: - * \verbatim#define CACHE_LINE 32 \endverbatim + * \code#define CACHE_LINE 32 \endcode * -# MetalSVM can now be built using \c make. * -# Build the SCC tools: * \verbatim diff --git a/documentation/text/kernelspace.dox b/documentation/text/kernelspace.dox deleted file mode 100644 index 95e014d4..00000000 --- a/documentation/text/kernelspace.dox +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @file kernelspace.dox - * @page kernelspace Development in kernel space - * - * @section kernelthreads Starting kernel threads - * - */ diff --git a/documentation/text/tasks.dox b/documentation/text/tasks.dox new file mode 100644 index 00000000..0b9bebaf --- /dev/null +++ b/documentation/text/tasks.dox @@ -0,0 +1,136 @@ +/** + * @file tasks.dox + * @page tasks Creating your own tasks in MetalSVM + * + * + * @section toc Table of Contents + * - @ref initd + * - @ref kerneltasks + * - @ref usertasks + * + * @section initd Where MetalSVM starts tasks after boot + * + * The last step after booting is starting the \c initd process: + * + * \c kernel/main.c: + * \code +... +create_kernel_task (&id, initd, NULL, NORMAL_PRIO); +...\endcode + * + * \c Initd starts all the other processes and then exits. + * The list of processes to start is defined in \c kernel/tests.c + * within \c test_init(): + * + * \code +int test_init(void) +{ + /* This is how the ARGV parameter list is defined */ + char* argv[] = {"/bin/tests", NULL}; + char* server_argv[] = {"/bin/server", "6789", NULL}; + char* client_argv[] = {"/bin/client", "192.168.0.1", "6789", NULL}; + + ... + + /* Starting kernel- and user space tasks */ + create_kernel_task(NULL, foo, "Hello from foo1", NORMAL_PRIO); + create_kernel_task(NULL, join_test, NULL, NORMAL_PRIO); + create_user_task(NULL, "/bin/tests", argv); + + return 0; +}\endcode + * + * @section kerneltasks Creating kernel tasks + * + * To create your own kernel task, you will need to write a task first. + * This can look like the following example task in \c kernel/tests.c: + * + * \code +static int foo(void* arg) +{ + int i; + + if (!arg) + return 0; + + for(i=0; i<5; i++) { + kprintf("%s\n", (char*) arg); + sleep(1); + } + + return 42; +}\endcode + * + * A kernel task is just a procedure within the scope of init_test(). + * Its signature should match the following pattern: + * \code int my_task(void* my_args)\endcode + * + * To make \c initd start your task after booting the system, you will need to + * write a \c create_kernel_task() call within \c test_init() which looks like + * the \c foo example from the section above: + * \code create_kernel_task(NULL, foo, "Hello from foo1", NORMAL_PRIO); \endcode + * + * The \c create_kernel_task procedure has the following signature: + * \code int create_kernel_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio)\endcode + * Its parameters are the following: + * - \c id: Provide the address of a \c tid_t variable here, if you need the new + * task's ID. + * - \c ep: The entry point of your task is just its function/procedure symbol. + * - \c args: The address of the parameter structure your task expects. + * - \c prio: The priority your task shall be executed with. Priority levels are + * defined in \c include/metalsvm/tasks_types.h: + * \code +#define MAX_PRIO 31 +#define REALTIME_PRIO 31 +#define HIGH_PRIO 16 +#define NORMAL_PRIO 8 +#define LOW_PRIO 1 +#define IDLE_PRIO 0\endcode + * + * @section usertasks Creating user space tasks + * + * User space tasks are usually not defined within the kernel code, + * therefore they are launched differently. + * + * To write your own user space application, place your *.c source code within + * \c newlib/examples/ and add a target in the Makefile (\c newlib/examples/Makefile) + * to ensure that your application is built when you type \c "make" in the + * MetalSVM directory. + * + * If your code does not consist of just some *.c and *.h files and you rather want + * keep your own project folder: The only important thing for later is that your + * executables and other runtime-needed files lay in the \c newlib/examples/ directory + * during build of the initial ramdisk. + * + * The scripts which build MetalSVM's initial ramdisk are launched when the kernel + * itself is built. \c metalsvm.elf and \c tools/initrd.img together + * compose a bootable system which is rebuilt (if necessary) everytimes you run + * \c make in the project directory. + * + * The initrd building scripts include every file within the \c newlib/examples/ + * directory which is marked as \b execuable. Do not forget this if you use your + * own build scripts! + * + * After providing your own executable for the system within the initial ramdisk, + * it still needs to be executed after boot. This is done very similarly to + * launching kernel threads. + * + * Place your application launching \c create_user_task() call within \c test_init(): + * \code create_user_task(NULL, "/bin/tests", argv);\endcode + * + * In this case the executable \c tests is launched with the parameter array \c argv. + * Note that at build-time the executable is located at \c newlib/examples/tests. + * The \c argv array is constructed like in the example at the top of this page. + * + * \c create_user_task()'s signature looks like this: + * \code int create_user_task(tid_t* id, const char* fname, char** argv)\endcode + * Its parameters are the following: + * - \c id: Provide the address of a \c tid_t variable if you need the ID of your + * started process. + * - \c fname: This string denotes the path of your executable within the file system. + * Every executable which comes from \c newlib/examples/ will be located within + * \c /bin in MetalSVM's file system after boot. + * - \c argv: This is the ARGV-structure the task will be equipped with after launch. + * + * + */ diff --git a/documentation/text/userspace.dox b/documentation/text/userspace.dox deleted file mode 100644 index 9489f4d2..00000000 --- a/documentation/text/userspace.dox +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @file userspace.dox - * @page userspace Development in user space - * - * @section ownapps Installing and launching your own applications - * - */ diff --git a/mm/memory.c b/mm/memory.c index 6cad2520..2150243e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -143,6 +143,12 @@ int mmu_init(void) atomic_int32_inc(&total_allocated_pages); atomic_int32_dec(&total_available_pages); + 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_SHIFT); + atomic_int32_inc(&total_allocated_pages); + atomic_int32_dec(&total_available_pages); + } + for(i=0; imods_count; i++, mmodule++) { for(addr=mmodule->mod_start; addrmod_end; addr+=PAGE_SIZE) { page_set_mark(addr >> PAGE_SHIFT);