Compare commits

..

55 commits

Author SHA1 Message Date
e4d215d3d3 Merge branch 'master' of github.com:stv0g/eduOS 2014-12-20 00:48:15 +01:00
90937daeb5 fixes wrong return value of page_map(), fixes #2y 2014-12-20 00:47:07 +01:00
Stefan Lankes
0192f70338 Merge branch 'stage6' of https://github.com/RWTH-OS/eduOS into stage6
Conflicts:
	Makefile.example
	arch/x86/kernel/uart.c
2014-12-19 22:05:15 +01:00
Stefan Lankes
dc8232374f some cleanups 2014-12-19 21:50:26 +01:00
Stefan Lankes
44cc72b94e code cleanups, remove debug messages 2014-12-19 21:41:33 +01:00
Stefan Lankes
15073197a9 fix issue in the configuration of the UART device 2014-12-19 21:38:42 +01:00
daniel-k
dd961f8558 extent uart driver with stubs for additional interrupts and also look for
qemu's pci-serial-2x and pci-serial-4x devices
2014-12-19 17:05:01 +01:00
daniel-k
bc9c1098d2 adjust qemu commandline to enable serial communication with telnet 2014-12-19 17:01:12 +01:00
daniel-k
19f871579d Don't strip debug symbols of elf to use as symbol-file in gdb (fix crashing
gdb 7.7.1 on Ubuntu). Add debug-eclipse target and use target-specific CFLAGS
for debug targets.
2014-12-19 11:42:05 +01:00
daniel-k
2df269eac0 fix typo in Makefile example 2014-12-19 11:42:05 +01:00
Stefan Lankes
a945d498d7 reduce the number of interrupts, some cleanups 2014-12-19 11:36:09 +01:00
Stefan Lankes
dabd33f37c add helper functions to determine if the pci device use MMIO or IO ports 2014-12-19 11:35:24 +01:00
Stefan Lankes
75b39829f8 use flag PG_GLOBAL to map the video memory 2014-12-14 23:41:24 +01:00
Stefan Lankes
8cc32095af some cleanup 2014-12-14 23:40:08 +01:00
Stefan Lankes
1936c4b3eb remove typo in a comment 2014-12-13 18:47:02 +01:00
Stefan Lankes
4a9440dd62 redesign of the IO interface
- all messages are stored in a ring buffer
- new devices (e.g. UART) are able to print previous messages
2014-12-13 18:00:35 +01:00
Stefan Lankes
7a15541d82 add function to detect processor features 2014-12-13 17:56:46 +01:00
Stefan Lankes
926f818e83 reduce the number of debug messages 2014-12-13 17:55:29 +01:00
Stefan Lankes
ad291c5294 add new function to determin if a device supports MMIO 2014-12-13 17:53:42 +01:00
Stefan Lankes
3725b1f6d0 minor modifications in atomic_int32_inc/_dec
=> now, the functions returns also the current counter
2014-12-13 15:14:31 +01:00
Stefan Lankes
3d84f776be preperation to support memory mapped io 2014-12-12 14:44:21 +01:00
Stefan Lankes
e97f08d2ea add Daniel to the author list 2014-12-12 13:59:23 +01:00
Stefan Lankes
020a89e706 remove typo 2014-12-11 22:47:18 +01:00
Stefan Lankes
13e594d16e improve some comments 2014-12-11 22:45:23 +01:00
Stefan Lankes
168c8a30ab create task to handle incoming messages 2014-12-11 22:43:45 +01:00
Stefan Lankes
41ab209d83 add mailbox system 2014-12-11 22:30:06 +01:00
Stefan Lankes
c2947fbb88 add missing header 2014-12-11 22:28:45 +01:00
Stefan Lankes
9ae03d14d5 cosmetic changes 2014-12-09 22:35:38 +01:00
Stefan Lankes
e3042f167a add missing copyright statement 2014-12-09 22:32:59 +01:00
Stefan Lankes
9d7bd72ed1 add missing list of pciids 2014-12-09 10:52:47 +01:00
Stefan Lankes
df0b192e21 add basic support of an UART device 2014-12-09 10:09:03 +01:00
Stefan Lankes
8648ca0dfe add more details in the README 2014-12-05 09:43:55 +01:00
Stefan Lankes
b92ec13995 some code cleanups 2014-12-05 09:38:50 +01:00
Stefan Lankes
f6a5f75725 fix wrong calculation of active tasks 2014-12-05 09:29:10 +01:00
Stefan Lankes
5ec1a4e98e add Steffen in the copyright statement
=> he complety redesign my paging implementation
=> clearly better than my previous version
2014-12-05 07:29:38 +01:00
Stefan Lankes
2eaa7589ee enable cache for our user-level task 2014-12-05 07:26:24 +01:00
Stefan Lankes
4f6792e3c2 Merge remote-tracking branch 'stv0g/stage5' into stage5 2014-12-04 22:24:58 +01:00
Stefan Lankes
c0d69c96be add demo of a user-level process
dirty hack, map the function userfoo and its stack to user space
2014-12-04 22:19:18 +01:00
42571eb4eb added proper accounting of user used page frames 2014-12-04 21:44:02 +01:00
5c4e1cee4f add PG_PRESENT by default 2014-12-04 21:38:41 +01:00
Stefan Lankes
49016fc0c2 get_pages uses the algorithm "first fit", but starts now at the last hit 2014-12-04 21:04:22 +01:00
09acfdfdf3 rewrite of page_map_{copy,drop} functions 2014-12-04 20:42:58 +01:00
18378417a7 added new custom paging flag to mark page table entries which are used for self-references 2014-12-04 20:41:39 +01:00
27274dad67 added proper locking primitives for 'per task' page tables 2014-12-04 20:35:19 +01:00
67b8ca111a a few cleanups 2014-12-04 20:33:28 +01:00
Stefan Lankes
370997f516 copy default task's cr3 register to the PCB 2014-12-03 23:39:13 +01:00
Stefan Lankes
e9960dc78e get_current_stack set CR3 => required for a context switch 2014-12-03 23:10:32 +01:00
Stefan Lankes
04290f885d fix wrong pointer check 2014-12-02 23:37:43 +01:00
Stefan Lankes
455de5f846 add crosscompile prefix to environment variable GDB 2014-12-02 23:04:54 +01:00
Stefan Lankes
2245eaecbb Merge branch 'paging-fork' of https://github.com/stv0g/eduOS into stage6 2014-11-30 09:08:49 +01:00
Stefan Lankes
1b37520664 add description of stage5 2014-11-30 09:05:19 +01:00
Stefan Lankes
2d9b7cf598 increasing the readability 2014-11-30 09:01:11 +01:00
Stefan Lankes
67c5b3dfd8 Merge branch 'paging' of https://github.com/stv0g/eduOS
Conflicts:
	Makefile.example
2014-11-30 00:12:09 +01:00
Stefan Lankes
5bb1494246 add new variable for the emulator qemu 2014-11-29 23:42:24 +01:00
55952716c0 Merge branch 'master' of https://github.com/RWTH-OS/eduOS 2014-11-28 02:48:58 +01:00
27 changed files with 3227 additions and 126 deletions

View file

@ -1,3 +1,4 @@
TERM = xterm
TOPDIR = $(shell pwd)
ARCH = x86
NAME = eduos
@ -22,21 +23,24 @@ STRIP_FOR_TARGET = $(CROSSCOMPREFIX)strip
READELF_FOR_TARGET = $(CROSSCOMPREFIX)readelf
NASM = nasm
GDB = gdb
QEMU = qemu-system-i386
NASMFLAGS = -felf32 -g -i$(TOPDIR)/include/eduos/
GDB = $(CROSSCOMPREFIX)gdb
GDBFLAGS = -x debug.gdb
QEMU = qemu-system-i386
QEMUFLAGS = -smp 2 -monitor stdio \
-net nic,model=rtl8139 \
-net user,hostfwd=tcp::12345-:7 \
-serial tcp::12346,server,nowait
-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 -m32 -march=i586 -Wall -O2 -fno-builtin -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc $(INCLUDE) -fno-stack-protector
# Compiler options for debugging
#CFLAGS = -g -O -m32 -march=i586 -Wall -fno-builtin -DWITH_FRAME_POINTER -nostdinc $(INCLUDE) -fno-stack-protector
debug debug-eclipse : CFLAGS = -g -O0 -m32 -march=i586 -Wall -fno-builtin -DWITH_FRAME_POINTER -nostdinc $(INCLUDE) -fno-stack-protector
AR = ar
ARFLAGS = rsv
RM = rm -rf
@ -59,8 +63,8 @@ $(NAME).elf:
$Q$(LD_FOR_TARGET) $(LDFLAGS) -o $(NAME).elf $^
@echo [OBJCOPY] $(NAME).sym
$Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $(NAME).elf $(NAME).sym
@echo [OBJCOPY] $(NAME).elf
$Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $(NAME).elf
#@echo [OBJCOPY] $(NAME).elf
#$Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $(NAME).elf
clean:
$Q$(RM) $(NAME).elf $(NAME).sym *~
@ -73,9 +77,16 @@ veryclean: clean
qemu: $(NAME).elf
$(QEMU) $(QEMUFLAGS) -kernel $(NAME).elf
uart: $(NAME).elf
$(QEMU) $(QEMUFLAGS) $(QEMUSERIALFLAGS) -kernel $(NAME).elf
debug: $(NAME).elf
$(TERM) -e $(GDB) $(GDBFLAGS) &
$(QEMU) $(QEMUFLAGS) -s -S -kernel $(NAME).elf
$(QEMU) $(QEMUDEBUGFLAGS) -s -S -kernel $(NAME).elf
debug-eclipse: clean $(NAME).elf
killall $(QEMU) &
( ( $(QEMU) $(QEMUDEBUGFLAGS) $(QEMUSERIALFLAGS) -s -S -kernel $(NAME).elf & ) & )
doc:
@echo Create documentation...

View file

@ -83,6 +83,15 @@ Overview of all branches
Add support of user-level tasks with an small interface for basic system calls
5. stage5 - Enabling paging
Add support of paging. See http://www.noteblok.net/2014/06/14/bachelor
for a detailed description.
6. stage6 - Add UART support
Add basic support of a serial device
Usefull Links
-------------
0. http://www.gnu.org/software/grub/manual/multiboot/
@ -90,3 +99,4 @@ Usefull Links
2. http://www.jamesmolloy.co.uk/tutorial_html/index.html
3. http://techblog.lankes.org/tutorials/
4. http://www.os.rwth-aachen.de
5. http://www.noteblok.net/2014/06/14/bachelor

View file

@ -122,8 +122,8 @@ inline static int32_t atomic_int32_sub(atomic_int32_t *d, int32_t i)
*
* @param d The atomic_int32_t var you want to increment
*/
inline static void atomic_int32_inc(atomic_int32_t* d) {
asm volatile(LOCK "incl %0" : "+m" (d->counter));
inline static int32_t atomic_int32_inc(atomic_int32_t* d) {
return atomic_int32_add(d, 1);
}
/** @brief Atomic decrement by one
@ -132,8 +132,8 @@ inline static void atomic_int32_inc(atomic_int32_t* d) {
*
* @param d The atomic_int32_t var you want to decrement
*/
inline static void atomic_int32_dec(atomic_int32_t* d) {
asm volatile(LOCK "decl %0" : "+m" (d->counter));
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

View file

@ -1,5 +1,6 @@
/*
* 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
@ -33,6 +34,8 @@
* This file contains the several functions to manage the page tables
*/
#include <eduos/tasks_types.h>
#ifndef __PAGE_H__
#define __PAGE_H__
@ -85,8 +88,10 @@
#define PG_PAT PG_PSE
/// Global TLB entry (Pentium Pro and later)
#define PG_GLOBAL (1 << 8)
/// This page or table is used during the boot process
#define PG_BOOT (1 << 9)
/// This table is a self-reference and should skipped by page_map_copy()
#define PG_SELF (1 << 9)
/// This page is used for bootstrapping the paging code.
#define PG_BOOT PG_SELF
/// This page is reserved for copying
#define PAGE_TMP (PAGE_FLOOR((size_t) &kernel_start) - PAGE_SIZE)
@ -133,7 +138,7 @@ int page_unmap(size_t viraddr, size_t npages);
* @retval 0 Success. Everything went fine.
* @retval <0 Error. Something went wrong.
*/
int page_map_copy(size_t dest);
int page_map_copy(task_t *dest);
/** @brief Free a whole page map tree */
int page_map_drop();

View 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.
*/
/**
* @author Stefan Lankes
* @file arch/x86/include/asm/pci.h
* @brief functions related to PCI initialization and information
*
* This file contains a procedure to initialize the PCI environment
* and functions to access information about specific PCI devices.
*/
#ifndef __ARCH_PCI_H__
#define __ARCH_PCI_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint8_t slot, bus, irq;
uint32_t base[6];
uint32_t size[6];
uint8_t type[6];
} pci_info_t;
/** @brief Initialize the PCI environment
*
* return
* - 0 on success
*/
int pci_init(void);
/** @brief Determine the IObase address and the interrupt number of a specific device
*
* @param vendor_id The device's vendor ID
* @param device_id the device's ID
* @param info Pointer to the record pci_info_t where among other the IObase address will be stored
*
* @return
* - 0 on success
* - -EINVAL on failure
*/
int pci_get_device_info(uint32_t vendor_id, uint32_t device_id, pci_info_t* info);
#ifdef WITH_PCI_NAMES
/** @brief Print information of existing pci adapters
*
* @return 0 in any case
*/
int print_pci_adapters(void);
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -38,11 +38,73 @@
#include <eduos/stddef.h>
#include <asm/gdt.h>
#ifdef CONFIG_PCI
#include <asm/pci.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// feature list 1
#define CPU_FEATURE_FPU (1 << 0)
#define CPU_FEATURE_MSR (1 << 5)
#define CPU_FEATURE_APIC (1 << 9)
#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)
typedef struct {
uint32_t feature1, feature2;
} 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_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);
}
/** @brief Read out time stamp counter
*
* The rdtsc asm command puts a 64 bit time stamp value
@ -57,15 +119,54 @@ inline static uint64_t rdtsc(void)
return x;
}
/** @brief Read cr3 register
* @return cr3's value
/** @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
*/
static inline size_t read_cr3(void) {
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 %%cr3, %0" : "=r"(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
*/
@ -82,6 +183,15 @@ 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
*/
@ -89,6 +199,22 @@ 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"
@ -127,12 +253,30 @@ 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.
inline static void mb(void) { asm volatile("mfence" ::: "memory"); }
extern func_memory_barrier mb;
/// Force strict CPU ordering, serializes load operations.
inline static void rmb(void) { asm volatile("lfence" ::: "memory"); }
extern func_memory_barrier rmb;
/// Force strict CPU ordering, serializes store operations.
inline static void wmb(void) { asm volatile("sfence" ::: "memory"); }
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
*
@ -206,6 +350,10 @@ static inline size_t lsb(size_t i)
inline static int system_init(void)
{
gdt_install();
cpu_detection();
#ifdef CONFIG_PCI
pci_init();
#endif
return 0;
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2014, Stefan Lankes, Daniel Krebs, 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/uart.h
* @brief UART related code
*/
#ifndef __ARCH_UART_H__
#define __ARCH_UART_H__
#include <eduos/stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Initialize UART output
*
* @return Returns 0 on success
*/
int uart_init(void);
/** @brief Simple string output on a serial device.
*
* If you want a new line you will have to "\\n".
*
* @return Length of output in bytes
*/
int uart_puts(const char *text);
/** @brief Simple character output on a serial device.
*
* @return The original input character casted to int
*/
int uart_putchar(unsigned char c);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,4 +1,4 @@
C_source := tasks.c vga.c gdt.c irq.c idt.c isrs.c timer.c processor.c
C_source := tasks.c vga.c gdt.c irq.c idt.c isrs.c timer.c processor.c uart.c pci.c
ASM_source := entry.asm string32.asm
MODULE := arch_x86_kernel

View file

@ -153,10 +153,10 @@ flush2:
; 5: Out of Bounds Exception
; 6: Invalid Opcode Exception
; 7: Coprocessor Not Available Exception
%assign i 0
%assign i 0
%rep 8
isrstub_pseudo_error i
%assign i i+1
%assign i i+1
%endrep
; 8: Double Fault Exception (With Error Code!)
@ -330,13 +330,13 @@ ALIGN 4096
global boot_map
boot_map:
boot_pgd:
DD boot_pgt + 0x103 ; PG_GLOBAL | PG_RW | PG_PRESENT
DD boot_pgt + 0x107 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_USER
times 1022 DD 0 ; PAGE_MAP_ENTRIES - 2
DD boot_pgd + 0x103 ; PG_GLOBAL | PG_RW | PG_PRESENT (self-reference)
DD boot_pgd + 0x303 ; PG_PRESENT | PG_GLOBAL | PG_RW | PG_SELF (self-reference)
boot_pgt:
%assign i 0
%rep 1024 ; PAGE_MAP_ENTRIES
DD i | 0x203 ; PG_BOOT | PG_RW | PG_PRESENT
DD i + 0x203 ; PG_PRESENT | PG_BOOT | PG_RW
%assign i i + 4096 ; PAGE_SIZE
%endrep

View file

@ -36,7 +36,7 @@
#include <asm/tss.h>
#include <asm/page.h>
gdt_ptr_t gp;
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}};

224
arch/x86/kernel/pci.c Normal file
View file

@ -0,0 +1,224 @@
/*
* 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 <eduos/stdio.h>
#include <eduos/string.h>
#include <eduos/errno.h>
#include <asm/irqflags.h>
#include <asm/io.h>
#ifdef CONFIG_PCI
#include <asm/pci.h>
#ifdef WITH_PCI_NAMES
#include "pcihdr.h"
#endif
/*
* PCI configuration registers
*/
#define PCI_CFID 0x00 /* Configuration ID */
#define PCI_CFCS 0x04 /* Configurtion Command/Status */
#define PCI_CFRV 0x08 /* Configuration Revision */
#define PCI_CFLT 0x0c /* Configuration Latency Timer */
#define PCI_CBIO 0x10 /* Configuration Base IO Address */
#define PCI_CFIT 0x3c /* Configuration Interrupt */
#define PCI_CFDA 0x40 /* Configuration Driver Area */
#define PHYS_IO_MEM_START 0
#define PCI_MEM 0
#define PCI_INTA 0
#define PCI_NSLOTS 22
#define PCI_NBUS 0
#define PCI_CONF_ADDR_REG 0xcf8
#define PCI_CONF_FRWD_REG 0xcf8
#define PCI_CONF_DATA_REG 0xcfc
#define PCI_IO_CONF_START 0xc000
#define MAX_BUS 16
#define MAX_SLOTS 32
static uint32_t mechanism = 0;
static uint32_t adapters[MAX_BUS][MAX_SLOTS] = {[0 ... MAX_BUS-1][0 ... MAX_SLOTS-1] = -1};
static void pci_conf_write(uint32_t bus, uint32_t slot, uint32_t off, uint32_t val)
{
if (mechanism == 1) {
outportl(PCI_CONF_FRWD_REG, bus);
outportl(PCI_CONF_ADDR_REG, 0xf0);
outportl(PCI_IO_CONF_START | (slot << 8) | off, val);
} else {
outportl(PCI_CONF_ADDR_REG, (0x80000000 | (bus << 16) | (slot << 11) | off));
outportl(PCI_CONF_DATA_REG, val);
}
}
static uint32_t pci_conf_read(uint32_t bus, uint32_t slot, uint32_t off)
{
uint32_t data = -1;
outportl(PCI_CONF_ADDR_REG, (0x80000000 | (bus << 16) | (slot << 11) | off));
data = inportl(PCI_CONF_DATA_REG);
if ((data == 0xffffffff) && (slot < 0x10)) {
outportl(PCI_CONF_FRWD_REG, bus);
outportl(PCI_CONF_ADDR_REG, 0xf0);
data = inportl(PCI_IO_CONF_START | (slot << 8) | off);
if (data == 0xffffffff)
return data;
if (!mechanism)
mechanism = 1;
} else if (!mechanism)
mechanism = 2;
return data;
}
static inline uint8_t pci_what_irq(uint32_t bus, uint32_t slot)
{
return pci_conf_read(bus, slot, PCI_CFIT) & 0xFF;
}
static inline uint32_t pci_what_iobase(uint32_t bus, uint32_t slot, uint32_t nr)
{
return pci_conf_read(bus, slot, PCI_CBIO + nr*4) & 0xFFFFFFFC;
}
static inline uint32_t pci_what_type(uint32_t bus, uint32_t slot, uint32_t nr)
{
return pci_conf_read(bus, slot, PCI_CBIO + nr*4) & 0x1;
}
static inline uint32_t pci_what_size(uint32_t bus, uint32_t slot, uint32_t nr)
{
uint32_t tmp, ret;
// backup the original value
tmp = pci_conf_read(bus, slot, PCI_CBIO + nr*4);
// determine size
pci_conf_write(bus, slot, PCI_CBIO + nr*4, 0xFFFFFFFF);
ret = ~pci_conf_read(bus, slot, PCI_CBIO + nr*4) + 1;
// restore original value
pci_conf_write(bus, slot, PCI_CBIO + nr*4, tmp);
return ret;
}
int pci_init(void)
{
uint32_t slot, bus;
for (bus = 0; bus < MAX_BUS; bus++)
for (slot = 0; slot < MAX_SLOTS; slot++)
adapters[bus][slot] = pci_conf_read(bus, slot, PCI_CFID);
return 0;
}
int pci_get_device_info(uint32_t vendor_id, uint32_t device_id, pci_info_t* info)
{
uint32_t slot, bus, i;
if (!info)
return -EINVAL;
if (!mechanism)
pci_init();
for (bus = 0; bus < MAX_BUS; bus++) {
for (slot = 0; slot < MAX_SLOTS; slot++) {
if (adapters[bus][slot] != -1) {
if (((adapters[bus][slot] & 0xffff) == vendor_id) &&
(((adapters[bus][slot] & 0xffff0000) >> 16) == device_id)) {
info->slot = slot;
info->bus = bus;
for(i=0; i<6; i++) {
info->base[i] = pci_what_iobase(bus, slot, i);
info->type[i] = pci_what_type(bus, slot, i);
info->size[i] = (info->base[i]) ? pci_what_size(bus, slot, i) : 0;
}
info->irq = pci_what_irq(bus, slot);
return 0;
}
}
}
}
return -EINVAL;
}
#ifdef WITH_PCI_NAMES
int print_pci_adapters(void)
{
uint32_t slot, bus;
uint32_t i, counter = 0;
if (!mechanism)
pci_init();
for (bus = 0; bus < MAX_BUS; bus++) {
for (slot = 0; slot < MAX_SLOTS; slot++) {
if (adapters[bus][slot] != -1) {
counter++;
kprintf("%d) Vendor ID: 0x%x Device Id: 0x%x\n",
counter, adapters[bus][slot] & 0xffff,
(adapters[bus][slot] & 0xffff0000) >> 16);
for (i=0; i<PCI_VENTABLE_LEN; i++) {
if ((adapters[bus][slot] & 0xffff) ==
(uint32_t)PciVenTable[i].VenId)
kprintf("\tVendor is %s\n",
PciVenTable[i].VenShort);
}
for (i=0; i<PCI_DEVTABLE_LEN; i++) {
if ((adapters[bus][slot] & 0xffff) ==
(uint32_t)PciDevTable[i].VenId) {
if (((adapters[bus][slot] & 0xffff0000) >> 16) ==
PciDevTable[i].DevId) {
kprintf
("\tChip: %s ChipDesc: %s\n",
PciDevTable[i].Chip,
PciDevTable[i].ChipDesc);
}
}
}
}
}
}
return 0;
}
#endif
#endif

1858
arch/x86/kernel/pcihdr.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -32,8 +32,22 @@
#include <eduos/processor.h>
#include <eduos/tasks.h>
cpu_info_t cpu_info = { 0, 0 };
static uint32_t cpu_freq = 0;
static void default_mb(void)
{
asm volatile ("lock; addl $0,0(%%esp)" ::: "memory", "cc");
}
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"); }
uint32_t detect_cpu_frequency(void)
{
uint64_t start, end, diff;
@ -62,6 +76,61 @@ uint32_t detect_cpu_frequency(void)
return cpu_freq;
}
int cpu_detection(void) {
uint32_t a, b;
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);
}
cr4 = read_cr4();
if (has_fxsr())
cr4 |= 0x200; // set the OSFXSR bit
if (has_sse())
cr4 |= 0x400; // set the OSXMMEXCPT bit
write_cr4(cr4);
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, eduOS doesn't support AVX!\n");
if (has_fpu()) {
if (first_time)
kputs("Found and initialized FPU!\n");
asm volatile ("fninit");
}
if (first_time && on_hypervisor()) {
uint32_t c, d;
char vendor_id[13];
kprintf("eduOS 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)

View file

@ -36,6 +36,9 @@ 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;
}

294
arch/x86/kernel/uart.c Normal file
View file

@ -0,0 +1,294 @@
/*
* Copyright (c) 2014, Stefan Lankes, Daniel Krebs, 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 <eduos/stdio.h>
#include <eduos/string.h>
#include <eduos/mailbox.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/uart.h>
#include <asm/irq.h>
#ifdef CONFIG_PCI
#include <asm/pci.h>
#endif
#ifdef CONFIG_UART
/*
* This implementation based on following tutorial:
* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming
*/
#define UART_RX 0 /* In: Receive buffer */
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_TX 0 /* Out: Transmit buffer */
#define UART_IER 1 /* Out: Interrupt Enable Register */
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_DLL 0 /* Out: Divisor Latch Low */
#define UART_DLM 1 /* Out: Divisor Latch High */
#define UART_LCR 3 /* Out: Line Control Register */
#define UART_LSR 5 /* Line Status Register */
#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
#define UART_FCR_TRIGGER_1 0x00 /* Trigger RDI at FIFO level 1 byte */
#define UART_FCR_TRIGGER_4 0x40 /* Trigger RDI at FIFO level 4 byte */
#define UART_FCR_TRIGGER_8 0x80 /* Trigger RDI at FIFO level 8 byte */
#define UART_FCR_TRIGGER_14 0xc0 /* Trigger RDI at FIFO level 14 byte*/
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SBC 0x40 /* Set break control */
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
#define UART_LCR_EPAR 0x10 /* Even parity select */
#define UART_LCR_PARITY 0x08 /* Parity Enable */
#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 bit, 1=2 bits */
#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
#define UART_MCR_CLKSEL 0x80 /* Divide clock by 4 (TI16C752, EFR[4]=1) */
#define UART_MCR_TCRTLR 0x40 /* Access TCR/TLR (TI16C752, EFR[4]=1) */
#define UART_MCR_XONANY 0x20 /* Enable Xon Any (TI16C752, EFR[4]=1) */
#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C550C/TI16C750) */
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
#define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_OUT1 0x04 /* Out1 complement */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_MCR_DTR 0x01 /* DTR complement */
static uint8_t mmio = 0;
static uint32_t iobase = 0;
static tid_t id;
static mailbox_uint8_t input_queue;
static inline unsigned char read_from_uart(uint32_t off)
{
uint8_t c;
if (mmio)
c = *((const volatile unsigned char*) (iobase + off));
else
c = inportb(iobase + off);
return c;
}
static void write_to_uart(uint32_t off, unsigned char c)
{
if (mmio)
*((volatile unsigned char*) (iobase + off)) = c;
else
outportb(iobase + off, c);
}
/* Get a single character on a serial device */
static unsigned char uart_getchar(void)
{
return read_from_uart(UART_RX);
}
/* Puts a single character on a serial device */
int uart_putchar(unsigned char c)
{
if (!iobase)
return 0;
write_to_uart(UART_TX, c);
return (int) c;
}
/* Uses the routine above to output a string... */
int uart_puts(const char *text)
{
size_t i, len = strlen(text);
if (!iobase)
return 0;
for (i = 0; i < len; i++)
uart_putchar(text[i]);
return len;
}
/* Handles all UART's interrupt */
static void uart_handler(struct state *s)
{
unsigned char c = read_from_uart(UART_IIR);
while (!(c & UART_IIR_NO_INT)) {
if (c & UART_IIR_RDI) {
c = uart_getchar();
mailbox_uint8_post(&input_queue, c);
goto out;
}
if(c & UART_IIR_THRI) {
// acknowledge interrupt
c = read_from_uart(UART_IIR);
goto out;
}
if(c & UART_IIR_RLSI) {
// acknowledge interrupt
c = read_from_uart(UART_LSR);
goto out;
}
out:
c = read_from_uart(UART_IIR);
}
}
/* thread entry point => handles all incoming messages */
static int uart_thread(void* arg)
{
unsigned char c = 0;
while(1) {
mailbox_uint8_fetch(&input_queue, &c);
kputchar(c);
}
return 0;
}
static void uart_config(void)
{
mailbox_uint8_init(&input_queue);
/*
* enable FIFOs
* clear RX and TX FIFO
* set irq trigger to 8 bytes
*/
write_to_uart(UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_1);
/* disable interrupts */
write_to_uart(UART_IER, 0);
/* DTR + RTS */
write_to_uart(UART_MCR, UART_MCR_DTR|UART_MCR_RTS);
/*
* 8bit word length
* 1 stop bit
* no partity
* set DLAB=1
*/
char lcr = UART_LCR_WLEN8;
write_to_uart(UART_LCR, lcr);
lcr = read_from_uart(UART_LCR) | UART_LCR_DLAB;
write_to_uart(UART_LCR, lcr);
/*
* set baudrate to 115200
*/
uint32_t divisor = 1843200 / 115200;
write_to_uart(UART_DLL, divisor & 0xff);
write_to_uart(UART_DLM, (divisor >> 8) & 0xff);
/* set DLAB=0 */
write_to_uart(UART_LCR, lcr & (~UART_LCR_DLAB));
/* enable interrupt */
write_to_uart(UART_IER, UART_IER_RDI | UART_IER_RLSI | UART_IER_THRI);
int err = create_kernel_task(&id, uart_thread, NULL, HIGH_PRIO);
if (BUILTIN_EXPECT(err, 0))
kprintf("Failed to create task for the uart device: %d\n", err);
koutput_add_uart();
}
int uart_init(void)
{
#ifdef CONFIG_PCI
pci_info_t pci_info;
uint32_t bar = 0;
// Searching for Intel's UART device
if (pci_get_device_info(0x8086, 0x0936, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's UART device
if (pci_get_device_info(0x1b36, 0x0002, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's 2x UART device (pci-serial-2x)
if (pci_get_device_info(0x1b36, 0x0003, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's 4x UART device (pci-serial-4x)
if (pci_get_device_info(0x1b36, 0x0003, &pci_info) == 0)
goto Lsuccess;
return -1;
Lsuccess:
iobase = pci_info.base[bar];
irq_install_handler(32+pci_info.irq, uart_handler);
if (pci_info.type[0]) {
mmio = 0;
kprintf("UART uses io address 0x%x\n", iobase);
} else {
mmio = 1;
page_map(iobase & PAGE_MASK, iobase & PAGE_MASK, 1, PG_GLOBAL | PG_RW | PG_PCD);
kprintf("UART uses mmio address 0x%x\n", iobase);
}
#else
// per default we use COM1...
mmio = 0;
iobase = 0x3F8;
irq_install_handler(32+4, uart_handler);
#endif
// configure uart
uart_config();
return 0;
}
#endif

View file

@ -1,5 +1,6 @@
/*
* 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
@ -24,10 +25,13 @@
* (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.
* using self-referenced page tablesi.
* See http://www.noteblok.net/2014/06/14/bachelor/ for a detailed description.
*
* @author Steffen Vogel <steffen.vogel@rwth-aachen.de>
*/
#include <eduos/stdio.h>
@ -38,7 +42,6 @@
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/multiboot.h>
/* Note that linker symbols are not variables, they have no memory
@ -64,10 +67,6 @@ static size_t * other[PAGE_LEVELS] = {
(size_t *) 0xFFFFE000
};
/* Addresses of child/parent tables */
#define CHILD(map, lvl, vpn) &map[lvl-1][vpn<<PAGE_MAP_BITS]
#define PARENT(map, lvl, vpn) &map[lvl+1][vpn>>PAGE_MAP_BITS]
size_t page_virt_to_phys(size_t addr)
{
size_t vpn = addr >> PAGE_BITS; // virtual page number
@ -80,7 +79,7 @@ size_t page_virt_to_phys(size_t addr)
int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits)
{
int lvl;
int lvl, ret = -ENOMEM;
long vpn = viraddr >> PAGE_BITS;
long first[PAGE_LEVELS], last[PAGE_LEVELS];
@ -90,7 +89,11 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits)
last[lvl] = (vpn+npages-1) >> (lvl * PAGE_MAP_BITS);
}
spinlock_lock(&kslock);
/** @todo: might not be sufficient! */
if (bits & PG_USER)
spinlock_irqsave_lock(&current_task->page_lock);
else
spinlock_lock(&kslock);
/* Start iterating through the entries
* beginning at the root table (PGD or PML4) */
@ -101,16 +104,17 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits)
/* 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)) {
spinlock_unlock(&kslock);
return -ENOMEM;
}
if (BUILTIN_EXPECT(!phyaddr, 0))
goto out;
if (bits & PG_USER)
atomic_int32_inc(&current_task->user_usage);
/* Reference the new table within its parent */
self[lvl][vpn] = phyaddr | bits;
self[lvl][vpn] = phyaddr | bits | PG_PRESENT;
/* Fill new table with zeros */
memset(CHILD(self, lvl, vpn), 0, PAGE_SIZE);
memset(&self[lvl-1][vpn<<PAGE_MAP_BITS], 0, PAGE_SIZE);
}
}
else { /* PGT */
@ -119,53 +123,54 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits)
* We have to flush a single TLB entry. */
tlb_flush_one_page(vpn << PAGE_BITS);
self[lvl][vpn] = phyaddr | bits;
self[lvl][vpn] = phyaddr | bits | PG_PRESENT;
phyaddr += PAGE_SIZE;
}
}
}
spinlock_unlock(&kslock);
ret = 0;
out:
if (bits & PG_USER)
spinlock_irqsave_unlock(&current_task->page_lock);
else
spinlock_unlock(&kslock);
return 0;
return ret;
}
/** Tables are freed by page_map_drop() */
int page_unmap(size_t viraddr, size_t npages)
{
long vpn, start = viraddr >> PAGE_BITS;
long end = start + npages;
/* We aquire both locks for kernel and task tables
* as we dont know to which the region belongs. */
spinlock_irqsave_lock(&current_task->page_lock);
spinlock_lock(&kslock);
/* Start iterating through the entries.
* Only the PGT entries are removed. Tables remain allocated. */
for (vpn=start; vpn<end; vpn++)
/* 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(&current_task->page_lock);
spinlock_unlock(&kslock);
/* This can't fail because we don't make checks here */
return 0;
}
int page_map_drop()
{
void traverse(int lvl, long vpn) {
kprintf("traverse(lvl=%d, vpn=%#lx)\n", lvl, vpn);
long stop;
for (stop=vpn+PAGE_MAP_ENTRIES; vpn<stop; vpn++) {
if (self[lvl][vpn] & PG_PRESENT) {
if (self[lvl][vpn] & PG_BOOT)
continue;
// ost-order traversal
if (lvl > 1)
if ((self[lvl][vpn] & PG_PRESENT) && (self[lvl][vpn] & PG_USER)) {
/* Post-order traversal */
if (lvl)
traverse(lvl-1, vpn<<PAGE_MAP_BITS);
kprintf("%#lx, ", self[lvl][vpn] & PAGE_MASK);
//put_page(self[lvl][vpn] & PAGE_MASK);
put_pages(self[lvl][vpn] & PAGE_MASK, 1);
atomic_int32_dec(&current_task->user_usage);
}
}
@ -177,53 +182,62 @@ int page_map_drop()
spinlock_irqsave_unlock(&current_task->page_lock);
/* This can't fail because we don't make checks here */
return 0;
}
int page_map_copy(size_t dest)
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) {
size_t phyaddr = get_pages(1);
if (BUILTIN_EXPECT(phyaddr, 0))
return -ENOMEM;
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;
other[lvl][vpn] |= self[lvl][vpn] & ~PAGE_MASK;
memcpy(CHILD(other, lvl, vpn), CHILD(self, lvl, vpn), PAGE_SIZE);
// pre-order traversal
if (lvl)
traverse(lvl-1, vpn<<PAGE_MAP_BITS);
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_lock(&kslock);
spinlock_irqsave_lock(&current_task->page_lock);
self[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = dest->page_map | PG_PRESENT | PG_SELF | PG_RW;
// create another temporary self-reference
self[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = dest | PG_PRESENT | PG_RW;
int ret = traverse(PAGE_LEVELS-1, 0);
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(&current_task->page_lock);
// remove temporary self-reference
self[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = 0;
/* Flush TLB entries of 'other' self-reference */
flush_tlb();
spinlock_unlock(&kslock);
return 0;
return ret;
}
void page_fault_handler(struct state *s)
{
size_t viraddr = read_cr2();
kprintf("Page Fault Exception (%d) at cs:ip = %#x:%#lx, task = %u, addr = %#lx, error = %#x [ %s %s %s %s %s ]\n",
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",
@ -246,40 +260,40 @@ int page_init()
/* Map kernel */
addr = (size_t) &kernel_start;
npages = PAGE_FLOOR((size_t) &kernel_end - (size_t) &kernel_start) >> PAGE_BITS;
page_map(addr, addr, npages, PG_PRESENT | PG_RW | PG_GLOBAL);
page_map(addr, addr, npages, PG_RW | PG_GLOBAL);
#ifdef CONFIG_VGA
/* Map video memory */
page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_PRESENT | PG_RW | PG_PCD);
page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_RW | PG_PCD | PG_GLOBAL);
#endif
/* Map multiboot information and modules */
if (mb_info) {
addr = (size_t) mb_info & PAGE_MASK;
npages = PAGE_FLOOR(sizeof(*mb_info)) >> PAGE_BITS;
page_map(addr, addr, npages, PG_PRESENT | PG_GLOBAL);
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_PRESENT | PG_GLOBAL);
page_map(addr, addr, npages, PG_GLOBAL);
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_PRESENT | PG_USER | PG_GLOBAL);
page_map(addr, addr, npages, PG_USER | PG_GLOBAL);
}
}
}
/* Unmap bootstrap identity paging (see entry.asm, PG_BOOT) */
for (i=0; i<PAGE_MAP_ENTRIES; i++) {
if (self[0][i] & PG_BOOT) {
for (i=0; i<PAGE_MAP_ENTRIES; i++)
if (self[0][i] & PG_BOOT)
self[0][i] = 0;
tlb_flush_one_page(i << PAGE_BITS);
}
}
/* Flush TLB to adopt changes above */
flush_tlb();
return 0;
}

View file

@ -1,5 +1,5 @@
# Constant part of the script
symbol-file eduos.sym
symbol-file eduos.elf
target remote localhost:1234
set architecture i386

View file

@ -40,11 +40,15 @@ extern "C" {
#define CACHE_LINE 64
#define KERNEL_STACK_SIZE (8<<10) /* 8 KiB */
#define BITMAP_SIZE (128<<5) /* for 128 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 CONFIG_PCI
#define CONFIG_UART
#define BUILTIN_EXPECT(exp, b) __builtin_expect((exp), (b))
//#define BUILTIN_EXPECT(exp, b) (exp)

142
include/eduos/mailbox.h Normal file
View 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.
*/
#ifndef __MAILBOX_H__
#define __MAILBOX_H__
#include <eduos/string.h>
#include <eduos/mailbox_types.h>
#include <eduos/tasks.h>
#include <eduos/semaphore.h>
#include <eduos/errno.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MAILBOX(name, type) \
inline static int mailbox_##name##_init(mailbox_##name##_t* m) { \
if (BUILTIN_EXPECT(!m, 0)) \
return -EINVAL; \
\
memset(m->buffer, 0x00, sizeof(type)*MAILBOX_SIZE); \
m->wpos = m->rpos = 0; \
sem_init(&m->mails, 0); \
sem_init(&m->boxes, MAILBOX_SIZE); \
spinlock_init(&m->rlock); \
spinlock_init(&m->wlock); \
\
return 0; \
}\
\
inline static int mailbox_##name##_destroy(mailbox_##name##_t* m) { \
if (BUILTIN_EXPECT(!m, 0)) \
return -EINVAL; \
\
sem_destroy(&m->mails); \
sem_destroy(&m->boxes); \
spinlock_destroy(&m->rlock); \
spinlock_destroy(&m->wlock); \
\
return 0; \
} \
\
inline static int mailbox_##name##_post(mailbox_##name##_t* m, type mail) { \
if (BUILTIN_EXPECT(!m, 0)) \
return -EINVAL; \
\
sem_wait(&m->boxes); \
spinlock_lock(&m->wlock); \
m->buffer[m->wpos] = mail; \
m->wpos = (m->wpos+1) % MAILBOX_SIZE; \
spinlock_unlock(&m->wlock); \
sem_post(&m->mails); \
\
return 0; \
} \
\
inline static int mailbox_##name##_trypost(mailbox_##name##_t* m, type mail) { \
if (BUILTIN_EXPECT(!m, 0)) \
return -EINVAL; \
\
if (sem_trywait(&m->boxes)) \
return -EBUSY; \
spinlock_lock(&m->wlock); \
m->buffer[m->wpos] = mail; \
m->wpos = (m->wpos+1) % MAILBOX_SIZE; \
spinlock_unlock(&m->wlock); \
sem_post(&m->mails); \
\
return 0; \
} \
\
inline static int mailbox_##name##_fetch(mailbox_##name##_t* m, type* mail) { \
int err; \
\
if (BUILTIN_EXPECT(!m || !mail, 0)) \
return -EINVAL; \
\
err = sem_wait(&m->mails); \
if (err) return err; \
spinlock_lock(&m->rlock); \
*mail = m->buffer[m->rpos]; \
m->rpos = (m->rpos+1) % MAILBOX_SIZE; \
spinlock_unlock(&m->rlock); \
sem_post(&m->boxes); \
\
return 0; \
} \
\
inline static int mailbox_##name##_tryfetch(mailbox_##name##_t* m, type* mail) { \
if (BUILTIN_EXPECT(!m || !mail, 0)) \
return -EINVAL; \
\
if (sem_trywait(&m->mails) != 0) \
return -EINVAL; \
spinlock_lock(&m->rlock); \
*mail = m->buffer[m->rpos]; \
m->rpos = (m->rpos+1) % MAILBOX_SIZE; \
spinlock_unlock(&m->rlock); \
sem_post(&m->boxes); \
\
return 0; \
}\
MAILBOX(wait_msg, wait_msg_t)
MAILBOX(int32, int32_t)
MAILBOX(int16, int16_t)
MAILBOX(int8, int8_t)
MAILBOX(uint32, uint32_t)
MAILBOX(uint16, uint16_t)
MAILBOX(uint8, uint8_t)
MAILBOX(ptr, void*)
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,75 @@
/*
* 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/metalsvm/mailbox_types.h
* @brief Mailbox system for inter-task communication
*/
#ifndef __MAILBOX_TYPES_H__
#define __MAILBOX_TYPES_H__
#include <eduos/semaphore_types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Wait message structure
*
* This message struct keeps a recipient task id and the message itself */
typedef struct {
/// The task id of the task which is waiting for this message
tid_t id;
/// The message payload
int32_t result;
} wait_msg_t;
#define MAILBOX_TYPES(name, type) \
typedef struct mailbox_##name { \
type buffer[MAILBOX_SIZE]; \
int wpos, rpos; \
sem_t mails; \
sem_t boxes; \
spinlock_t rlock, wlock; \
} mailbox_##name##_t;
MAILBOX_TYPES(wait_msg, wait_msg_t)
MAILBOX_TYPES(int32, int32_t)
MAILBOX_TYPES(int16, int16_t)
MAILBOX_TYPES(int8, int8_t)
MAILBOX_TYPES(uint32, uint32_t)
MAILBOX_TYPES(uint16, uint16_t)
MAILBOX_TYPES(uint8, uint8_t)
MAILBOX_TYPES(ptr, void*)
#ifdef __cplusplus
}
#endif
#endif

View file

@ -35,6 +35,7 @@
#define __SEMAPHORE_H__
#include <eduos/string.h>
#include <eduos/tasks.h>
#include <eduos/semaphore_types.h>
#include <eduos/spinlock.h>
#include <eduos/errno.h>

View file

@ -77,6 +77,11 @@ int ksnprintf(char *str, size_t size, const char *format, ...);
*/
int kvprintf(char const *fmt, void (*func) (int, void *), void *arg, int radix, va_list ap);
/**
* Add UART device to dump kernel messages
*/
int koutput_add_uart(void);
#ifdef __cplusplus
}
#endif

View file

@ -76,7 +76,7 @@ typedef struct task {
/// Task priority
uint8_t prio;
/// Physical address of root page table
size_t page_map;
size_t page_map;
/// Lock for page tables
spinlock_irqsave_t page_lock;
/// usage in number of pages (including page map tables)

View file

@ -39,6 +39,7 @@
#include <asm/irqflags.h>
#include <asm/atomic.h>
#include <asm/page.h>
#include <asm/uart.h>
/*
* Note that linker symbols are not variables, they have no memory allocated for
@ -56,17 +57,16 @@ extern atomic_int32_t total_pages;
extern atomic_int32_t total_allocated_pages;
extern atomic_int32_t total_available_pages;
static void userfoo(void* arg)
static void NORETURN userfoo(void* arg)
{
char str[256];
ksnprintf(str, 256, "hello from %s\n", (char*) arg);
SYSCALL1(__NR_write, "hello from userfoo\n");
SYSCALL1(__NR_exit, 0);
//kprintf("hello from %s\n", (char*) arg);
while(1) ;
}
static char ustack[KERNEL_STACK_SIZE];
static char ustack[KERNEL_STACK_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
static int wrapper(void* arg)
{
@ -74,9 +74,26 @@ static int wrapper(void* arg)
memset(ustack, 0xCD, KERNEL_STACK_SIZE);
*stack-- = (size_t) arg;
*stack = (size_t) leave_user_task; // put exit function as caller on the stack
*stack = (size_t) NULL; // put exit function as caller on the stack
#if 0
// this triggers a page fault because a user task is not able to access the kernel space
return jump_to_user_code((uint32_t) userfoo, (uint32_t) stack);
#else
// dirty hack, map userfoo to the user space
size_t phys = page_virt_to_phys(((size_t) userfoo) & PAGE_MASK);
size_t vuserfoo = 0x40000000;
page_map(vuserfoo, phys, 2, PG_PRESENT | PG_USER);
vuserfoo += (size_t)userfoo & 0xFFF;
// dirty hack, map ustack to the user space
phys = page_virt_to_phys((size_t) ustack);
size_t vstack = 0x80000000;
page_map(vstack, phys, KERNEL_STACK_SIZE >> PAGE_BITS, PG_PRESENT | PG_RW | PG_USER);
vstack = (vstack + KERNEL_STACK_SIZE - 16 - sizeof(size_t));
return jump_to_user_code(vuserfoo, vstack);
#endif
}
static int foo(void* arg)
@ -100,12 +117,15 @@ static int eduos_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();
koutput_init();
multitasking_init();
memory_init();
#ifdef CONFIG_UART
uart_init();
#endif
return 0;
}

View file

@ -75,6 +75,7 @@ int multitasking_init(void)
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();
@ -121,16 +122,16 @@ static void NORETURN do_exit(int arg)
kprintf("Terminate task: %u, return value %d\n", curr_task->id, arg);
page_map_drop();
curr_task->status = TASK_FINISHED;
reschedule();
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;
@ -203,13 +204,13 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio)
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 */
size_t map = get_pages(1);
if (BUILTIN_EXPECT(map, 0))
goto out;
/* 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;
page_map_copy(map);
task_table[i].page_map = map;
/* Copy page tables & user frames of current task to new one */
page_map_copy(&task_table[i]);
if (id)
*id = i;
@ -396,7 +397,7 @@ get_task_out:
spinlock_irqsave_unlock(&readyqueues.lock);
if (current_task != orig_task) {
kprintf("schedule from %u to %u with prio %u\n", orig_task->id, current_task->id, (uint32_t)current_task->prio);
//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);
}

View file

@ -29,9 +29,27 @@
#include <eduos/string.h>
#include <eduos/stdarg.h>
#include <eduos/spinlock.h>
#include <asm/atomic.h>
#include <asm/processor.h>
#ifdef CONFIG_VGA
#include <asm/vga.h>
#endif
#ifdef CONFIG_UART
#include <asm/uart.h>
#endif
#define NO_EARLY_PRINT 0x00
#define VGA_EARLY_PRINT 0x01
#define UART_EARLY_PRINT 0x02
#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)
{
@ -44,23 +62,67 @@ int koutput_init(void)
int kputchar(int c)
{
spinlock_irqsave_lock(&olock);
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
vga_putchar(c);
if (early_print & VGA_EARLY_PRINT)
vga_putchar(c);
#endif
spinlock_irqsave_unlock(&olock);
#ifdef CONFIG_UART
if (early_print & UART_EARLY_PRINT)
uart_putchar(c);
#endif
if (early_print != NO_EARLY_PRINT)
spinlock_irqsave_unlock(&olock);
return 1;
}
int kputs(const char *str)
{
#ifdef CONFIG_VGA
int i;
for(i=0; str[i] != '\0'; i++)
vga_putchar((int) str[i]);
int pos, i, len = strlen(str);
return i;
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
#ifdef CONFIG_UART
if (early_print & UART_EARLY_PRINT)
uart_putchar(str[i]);
#endif
}
if (early_print != NO_EARLY_PRINT)
spinlock_irqsave_unlock(&olock);
return len;
}
int koutput_add_uart(void)
{
#ifdef CONFIG_UART
uint32_t i;
early_print |= UART_EARLY_PRINT;
for(i=0; i<atomic_int32_read(&kmsg_counter); i++)
uart_putchar(kmessages[i % KMSG_SIZE]);
return 0;
#else
return -EINVAL;
#endif
}

View file

@ -90,6 +90,7 @@ inline static void page_clear_mark(size_t i)
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;
@ -98,13 +99,18 @@ size_t get_pages(size_t npages)
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+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);
}