Compare commits
55 commits
paging-for
...
master
Author | SHA1 | Date | |
---|---|---|---|
e4d215d3d3 | |||
90937daeb5 | |||
![]() |
0192f70338 | ||
![]() |
dc8232374f | ||
![]() |
44cc72b94e | ||
![]() |
15073197a9 | ||
![]() |
dd961f8558 | ||
![]() |
bc9c1098d2 | ||
![]() |
19f871579d | ||
![]() |
2df269eac0 | ||
![]() |
a945d498d7 | ||
![]() |
dabd33f37c | ||
![]() |
75b39829f8 | ||
![]() |
8cc32095af | ||
![]() |
1936c4b3eb | ||
![]() |
4a9440dd62 | ||
![]() |
7a15541d82 | ||
![]() |
926f818e83 | ||
![]() |
ad291c5294 | ||
![]() |
3725b1f6d0 | ||
![]() |
3d84f776be | ||
![]() |
e97f08d2ea | ||
![]() |
020a89e706 | ||
![]() |
13e594d16e | ||
![]() |
168c8a30ab | ||
![]() |
41ab209d83 | ||
![]() |
c2947fbb88 | ||
![]() |
9ae03d14d5 | ||
![]() |
e3042f167a | ||
![]() |
9d7bd72ed1 | ||
![]() |
df0b192e21 | ||
![]() |
8648ca0dfe | ||
![]() |
b92ec13995 | ||
![]() |
f6a5f75725 | ||
![]() |
5ec1a4e98e | ||
![]() |
2eaa7589ee | ||
![]() |
4f6792e3c2 | ||
![]() |
c0d69c96be | ||
42571eb4eb | |||
5c4e1cee4f | |||
![]() |
49016fc0c2 | ||
09acfdfdf3 | |||
18378417a7 | |||
27274dad67 | |||
67b8ca111a | |||
![]() |
370997f516 | ||
![]() |
e9960dc78e | ||
![]() |
04290f885d | ||
![]() |
455de5f846 | ||
![]() |
2245eaecbb | ||
![]() |
1b37520664 | ||
![]() |
2d9b7cf598 | ||
![]() |
67c5b3dfd8 | ||
![]() |
5bb1494246 | ||
55952716c0 |
27 changed files with 3227 additions and 126 deletions
|
@ -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...
|
||||
|
|
10
README.md
10
README.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
82
arch/x86/include/asm/pci.h
Normal file
82
arch/x86/include/asm/pci.h
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
|
@ -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;
|
||||
}
|
||||
|
|
67
arch/x86/include/asm/uart.h
Normal file
67
arch/x86/include/asm/uart.h
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
224
arch/x86/kernel/pci.c
Normal 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
1858
arch/x86/kernel/pcihdr.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||
|
|
|
@ -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
294
arch/x86/kernel/uart.c
Normal 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
|
|
@ -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(¤t_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(¤t_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(¤t_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(¤t_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(¤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 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(¤t_task->user_usage);
|
||||
}
|
||||
}
|
||||
|
@ -177,53 +182,62 @@ int page_map_drop()
|
|||
|
||||
spinlock_irqsave_unlock(¤t_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(¤t_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(¤t_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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Constant part of the script
|
||||
symbol-file eduos.sym
|
||||
symbol-file eduos.elf
|
||||
target remote localhost:1234
|
||||
|
||||
set architecture i386
|
||||
|
|
|
@ -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
142
include/eduos/mailbox.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.
|
||||
*/
|
||||
|
||||
#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
|
75
include/eduos/mailbox_types.h
Normal file
75
include/eduos/mailbox_types.h
Normal 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
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue