- add comments
- use readable macros instead of constants - use the same error number like newlib git-svn-id: http://svn.lfbs.rwth-aachen.de/svn/scc/trunk/MetalSVM@156 315a16e6-25f9-4109-90ae-ca3045a26c18
This commit is contained in:
parent
c882b28f03
commit
81df510743
12 changed files with 160 additions and 73 deletions
72
arch/x86/include/asm/gdt.h
Normal file
72
arch/x86/include/asm/gdt.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2010 Stefan Lankes, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_GDT_H__
|
||||
#define __ARCH_GDT_H__
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GDT_FLAG_DATASEG 0x02
|
||||
#define GDT_FLAG_CODESEG 0x0a
|
||||
#define GDT_FLAG_TSS 0x09
|
||||
#define GDT_FLAG_TSS_BUSY 0x02
|
||||
|
||||
#define GDT_FLAG_SEGMENT 0x10
|
||||
#define GDT_FLAG_RING0 0x00
|
||||
#define GDT_FLAG_RING1 0x20
|
||||
#define GDT_FLAG_RING2 0x40
|
||||
#define GDT_FLAG_RING3 0x60
|
||||
#define GDT_FLAG_PRESENT 0x80
|
||||
|
||||
#define GDT_FLAG_4K_GRAN 0x80
|
||||
#define GDT_FLAG_32_BIT 0x40
|
||||
|
||||
/* Defines a GDT entry */
|
||||
typedef struct {
|
||||
unsigned short limit_low;
|
||||
unsigned short base_low;
|
||||
unsigned char base_middle;
|
||||
unsigned char access;
|
||||
unsigned char granularity;
|
||||
unsigned char base_high;
|
||||
} __attribute__ ((packed)) gdt_entry_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned short limit;
|
||||
unsigned int base;
|
||||
} __attribute__ ((packed)) gdt_ptr_t;
|
||||
|
||||
#define GDT_ENTRIES (5+MAX_TASKS)
|
||||
#if GDT_ENTRIES > 8192
|
||||
#error Too many GDT entries!
|
||||
#endif
|
||||
|
||||
//extern gdt_entry_t gdt[GDT_ENTRIES];
|
||||
|
||||
void gdt_install(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -21,6 +21,7 @@
|
|||
#define __ARCH_IRQ_H__
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
#include <metalsvm/tasks_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define __ARCH_PROCESSOR_H__
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
#include <asm/gdt.h>
|
||||
#ifdef CONFIG_PCI
|
||||
#include <asm/pci.h>
|
||||
#endif
|
||||
|
@ -60,8 +61,6 @@ static inline uint64_t rdtsc(void)
|
|||
#define NOP4 asm volatile ("nop;nop;nop;nop")
|
||||
#define NOP8 asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop")
|
||||
|
||||
void gdt_install(void);
|
||||
|
||||
inline static int system_init(void)
|
||||
{
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
|
|
|
@ -27,6 +27,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_MEMCPY
|
||||
#if 0
|
||||
inline static void *memcpy(void *dest, const void *src, size_t count)
|
||||
{
|
||||
int32_t i, j, k;
|
||||
|
@ -44,6 +45,31 @@ inline static void *memcpy(void *dest, const void *src, size_t count)
|
|||
|
||||
return dest;
|
||||
}
|
||||
#else
|
||||
inline static void *memcpy(void *dest, const void *src, size_t count)
|
||||
{
|
||||
int32_t h, i, j, k, l, m;
|
||||
|
||||
if (BUILTIN_EXPECT(!dest || !src, 0))
|
||||
return dest;
|
||||
|
||||
asm volatile (
|
||||
"cld;\n\t"
|
||||
"1: cmpl $0, %%eax ; je 2f\n\t"
|
||||
"movl (%%edi), %%edx\n\t"
|
||||
"movl $8, %%ecx\n\t"
|
||||
"rep ; movsl\n\t"
|
||||
"dec %%eax ; jmp 1b\n\t"
|
||||
"2: movl (%%edi), %%edx\n\t"
|
||||
"movl %%ebx, %%ecx\n\t"
|
||||
"andl $31, %%ecx\n\t"
|
||||
"rep ; movsb\n\t"
|
||||
: "=&a"(h), "=&D"(i), "=&S"(j), "=&b"(k), "=&c"(l), "=&d"(m)
|
||||
: "0"(count/32), "1"(dest), "2"(src), "3"(count) : "memory");
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_MEMSET
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <metalsvm/stddef.h>
|
||||
#include <metalsvm/tasks_types.h>
|
||||
|
||||
int create_default_frame(task_t* task, entry_point_t ep, void* arg, int ring);
|
||||
int create_default_frame(task_t* task, entry_point_t ep, void* arg, int user);
|
||||
int register_task(task_t* task);
|
||||
void reschedule(void);
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ typedef struct {
|
|||
uint16_t trace, bitmap;
|
||||
} __attribute__ ((packed)) tss_t;
|
||||
|
||||
/*extern tss_t task_state_segments[MAX_TASKS];*/
|
||||
//extern tss_t task_state_segments[MAX_TASKS];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
; See the License for the specific language governing permissions and
|
||||
; limitations under the License.
|
||||
;
|
||||
; This file is part of metalsvm.
|
||||
; This file is part of MetalSVM.
|
||||
|
||||
; This is the kernel's entry point. We could either call main here,
|
||||
; or we can use this to setup the stack or other nice stuff, like
|
||||
|
|
|
@ -20,42 +20,9 @@
|
|||
#include <metalsvm/string.h>
|
||||
#include <metalsvm/stdlib.h>
|
||||
#include <metalsvm/tasks.h>
|
||||
#include <asm/gdt.h>
|
||||
#include <asm/tss.h>
|
||||
|
||||
/* Defines a GDT entry */
|
||||
typedef struct {
|
||||
unsigned short limit_low;
|
||||
unsigned short base_low;
|
||||
unsigned char base_middle;
|
||||
unsigned char access;
|
||||
unsigned char granularity;
|
||||
unsigned char base_high;
|
||||
} __attribute__ ((packed)) gdt_entry_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned short limit;
|
||||
unsigned int base;
|
||||
} __attribute__ ((packed)) gdt_ptr_t;
|
||||
|
||||
#define GDT_ENTRIES (5+MAX_TASKS)
|
||||
#if GDT_ENTRIES > 8192
|
||||
#error Too many GDT entries!
|
||||
#endif
|
||||
|
||||
#define GDT_FLAG_DATASEG 0x02
|
||||
#define GDT_FLAG_CODESEG 0x0a
|
||||
#define GDT_FLAG_TSS 0x09
|
||||
|
||||
#define GDT_FLAG_SEGMENT 0x10
|
||||
#define GDT_FLAG_RING0 0x00
|
||||
#define GDT_FLAG_RING1 0x20
|
||||
#define GDT_FLAG_RING2 0x40
|
||||
#define GDT_FLAG_RING3 0x60
|
||||
#define GDT_FLAG_PRESENT 0x80
|
||||
|
||||
#define GDT_FLAG_4K_GRAN 0x80
|
||||
#define GDT_FLAG_32_BIT 0x40
|
||||
|
||||
gdt_ptr_t gp;
|
||||
static tss_t task_state_segments[MAX_TASKS];
|
||||
static gdt_entry_t gdt[GDT_ENTRIES] = {[0 ... GDT_ENTRIES-1] = {0, 0, 0, 0, 0, 0}};
|
||||
|
@ -68,8 +35,7 @@ static unsigned char kstacks[MAX_TASKS][KERNEL_STACK_SIZE];
|
|||
extern void gdt_flush(void);
|
||||
|
||||
int register_task(task_t* task) {
|
||||
uint32_t id = task->id;
|
||||
uint16_t sel = (id+5)*8;
|
||||
uint16_t sel = (task->id+5) << 3;
|
||||
|
||||
asm volatile ("mov %0, %%ax; ltr %%ax" : : "ir"(sel));
|
||||
|
||||
|
@ -176,7 +142,7 @@ void gdt_install(void)
|
|||
* uses 32-bit opcodes, and is a Code Segment descriptor.
|
||||
*/
|
||||
gdt_set_gate(1, 0, 0xFFFFFFFF,
|
||||
GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_4K_GRAN | GDT_FLAG_32_BIT);
|
||||
|
||||
/*
|
||||
|
@ -185,7 +151,7 @@ void gdt_install(void)
|
|||
* this entry's access byte says it's a Data Segment
|
||||
*/
|
||||
gdt_set_gate(2, 0, 0xFFFFFFFF,
|
||||
GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_4K_GRAN | GDT_FLAG_32_BIT);
|
||||
|
||||
/*
|
||||
|
@ -203,14 +169,15 @@ void gdt_install(void)
|
|||
GDT_FLAG_4K_GRAN | GDT_FLAG_32_BIT);
|
||||
|
||||
/*
|
||||
* Create TSS for each task (we use these segments for task switching)
|
||||
*/
|
||||
* Create a TSS for each task (we use these segments for task switching)
|
||||
*/
|
||||
for(i=0; i<MAX_TASKS; i++) {
|
||||
gdt_set_gate(5+i, (unsigned long) (task_state_segments+i), sizeof(tss_t)-1,
|
||||
gdt_set_gate(5+i, (unsigned long) (task_state_segments+i), sizeof(tss_t)-1,
|
||||
GDT_FLAG_PRESENT | GDT_FLAG_TSS | GDT_FLAG_RING3,
|
||||
GDT_FLAG_32_BIT);
|
||||
}
|
||||
|
||||
|
||||
/* Flush out the old GDT and install the new changes! */
|
||||
gdt_flush();
|
||||
}
|
||||
|
|
|
@ -148,7 +148,6 @@ void irq_init(void)
|
|||
* an EOI, you won't raise any more IRQs
|
||||
*/
|
||||
void irq_handler(struct state *s)
|
||||
|
||||
{
|
||||
/* This is a blank function pointer */
|
||||
void (*handler) (struct state * s);
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <metalsvm/processor.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/gdt.h>
|
||||
#include <asm/tss.h>
|
||||
#include <asm/vga.h>
|
||||
|
||||
/*
|
||||
|
@ -83,11 +85,15 @@ int timer_set_frequency(unsigned int freq)
|
|||
irq_disable();
|
||||
|
||||
/* set the timer frequency */
|
||||
#ifdef CONFIG_LAPICTIMER
|
||||
/* Use LAPIC timer instead of 8254 PIT */
|
||||
#else
|
||||
outportb(0x43, 0x34);
|
||||
udelay(10);
|
||||
outportb(0x40, LATCH(freq) & 0xFF); /* low byte */
|
||||
udelay(10);
|
||||
outportb(0x40, LATCH(freq) >> 8); /* high byte */
|
||||
udelay(10);
|
||||
outportb(0x40, LATCH(freq) & 0xFF); /* low byte */
|
||||
udelay(10);
|
||||
outportb(0x40, LATCH(freq) >> 8); /* high byte */
|
||||
#endif
|
||||
|
||||
curr_timer_freq = freq;
|
||||
|
||||
|
|
|
@ -41,13 +41,13 @@ struct mailbox_int32;
|
|||
|
||||
typedef struct {
|
||||
tid_t id; /* task id = position in the task table */
|
||||
uint32_t status;
|
||||
unsigned char* ustack; /* stack of an user level task */
|
||||
size_t stack_size; /* only user level tasks
|
||||
* are able to specify its stack size
|
||||
*/
|
||||
atomic_int32_t mem_usage; /* in number of pages */
|
||||
struct mailbox_int32* mbox[MAX_TASKS];
|
||||
uint32_t status;
|
||||
} __attribute__((packed)) task_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <metalsvm/stdio.h>
|
||||
#include <metalsvm/stdlib.h>
|
||||
#include <metalsvm/string.h>
|
||||
#include <metalsvm/errno.h>
|
||||
#include <metalsvm/mmu.h>
|
||||
#include <metalsvm/tasks.h>
|
||||
#include <metalsvm/processor.h>
|
||||
|
@ -28,17 +29,24 @@
|
|||
#include <metalsvm/syscall.h>
|
||||
|
||||
task_t* current_task = NULL;
|
||||
static task_t task_table[MAX_TASKS];
|
||||
static task_t task_table[MAX_TASKS] = {[0 ... MAX_TASKS-1] = {0, 0, NULL, 0, ATOMIC_INIT(0)}};
|
||||
static spinlock_t table_lock = SPINLOCK_INIT;
|
||||
|
||||
int multitasking_init(void) {
|
||||
memset(task_table, 0x00, sizeof(task_t)*MAX_TASKS);
|
||||
|
||||
task_table[0].status = TASK_RUNNING;
|
||||
current_task = task_table+0;
|
||||
register_task(current_task);
|
||||
unsigned int i;
|
||||
|
||||
return 0;
|
||||
for(i=0; i<MAX_TASKS; i++) {
|
||||
if (task_table[i].status == TASK_INVALID) {
|
||||
task_table[i].id = i;
|
||||
task_table[i].status = TASK_RUNNING;
|
||||
memset(task_table[i].mbox, 0x00, sizeof(mailbox_int32_t*)*MAX_TASKS);
|
||||
current_task = task_table+i;
|
||||
register_task(current_task);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void wakeup_blocked_tasks(int result)
|
||||
|
@ -90,7 +98,9 @@ void NORETURN leave_user_task(void) {
|
|||
|
||||
kprintf("Kernel panic! Task %d comes back from syscall \"exit\"\n", current_task->id);
|
||||
|
||||
while(1) ;
|
||||
while(1) {
|
||||
NOP8;
|
||||
}
|
||||
}
|
||||
|
||||
void NORETURN sys_exit(int arg)
|
||||
|
@ -104,11 +114,11 @@ void NORETURN abort(void) {
|
|||
|
||||
static int create_task(tid_t* id, entry_point_t ep, void* arg, size_t stack_size, int user)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret = -ENOMEM;
|
||||
unsigned int i;
|
||||
|
||||
if (BUILTIN_EXPECT(!ep, 0))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
if (user && !stack_size)
|
||||
stack_size = DEFAULT_STACK_SIZE;
|
||||
|
@ -117,8 +127,9 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, size_t stack_size
|
|||
|
||||
for(i=0; i<MAX_TASKS; i++) {
|
||||
if (task_table[i].status == TASK_INVALID) {
|
||||
atomic_int32_set(&task_table[i].mem_usage, 0);
|
||||
task_table[i].id = i;
|
||||
task_table[i].status = TASK_READY;
|
||||
|
||||
if (user) {
|
||||
task_table[i].ustack = create_stack(task_table+i, stack_size);
|
||||
if (!task_table[i].ustack)
|
||||
|
@ -128,9 +139,9 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, size_t stack_size
|
|||
task_table[i].ustack = NULL;
|
||||
task_table[i].stack_size = 0;
|
||||
}
|
||||
|
||||
|
||||
atomic_int32_set(&task_table[i].mem_usage, 0);
|
||||
memset(task_table[i].mbox, 0x00, sizeof(mailbox_int32_t*)*MAX_TASKS);
|
||||
task_table[i].status = TASK_READY;
|
||||
|
||||
if (id)
|
||||
*id = i;
|
||||
|
@ -203,12 +214,12 @@ int join_task(tid_t id, int* result)
|
|||
join_out:
|
||||
spinlock_unlock_irqsave(&table_lock);
|
||||
mailbox_int32_destroy(&mbox);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int wakeup_task(tid_t id)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret = -EINVAL;
|
||||
int need_lock = !spinlock_has_lock(&table_lock);
|
||||
|
||||
/* avoid nested locking */
|
||||
|
@ -230,7 +241,7 @@ int wakeup_task(tid_t id)
|
|||
|
||||
int block_task(tid_t id)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret = -EINVAL;
|
||||
int need_lock = !spinlock_has_lock(&table_lock);
|
||||
|
||||
/* avoid nested locking */
|
||||
|
@ -250,7 +261,8 @@ int block_task(tid_t id)
|
|||
|
||||
void scheduler(void)
|
||||
{
|
||||
unsigned int i, new_id;
|
||||
unsigned int i;
|
||||
unsigned int new_id;
|
||||
|
||||
spinlock_lock(&table_lock);
|
||||
|
||||
|
@ -258,7 +270,7 @@ void scheduler(void)
|
|||
if (current_task->status == TASK_FINISHED)
|
||||
current_task->status = TASK_INVALID;
|
||||
|
||||
for(i=1; i <= MAX_TASKS; i++) {
|
||||
for(i=1; i<MAX_TASKS; i++) {
|
||||
new_id = (current_task->id + i) % MAX_TASKS;
|
||||
|
||||
if (task_table[new_id].status == TASK_READY) {
|
||||
|
@ -271,14 +283,19 @@ void scheduler(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (current_task->status == TASK_RUNNING)
|
||||
if ((current_task->status == TASK_RUNNING) || (current_task->status == TASK_IDLE))
|
||||
goto get_task_out;
|
||||
|
||||
/*
|
||||
* we switch to the idle task (id=0), if the current task terminates
|
||||
* we switch to the idle task, if the current task terminates
|
||||
* and no other is ready
|
||||
*/
|
||||
current_task = task_table+0;
|
||||
for(i=0; i<MAX_TASKS; i++) {
|
||||
if (task_table[i].status == TASK_IDLE) {
|
||||
current_task = task_table+i;
|
||||
goto get_task_out;
|
||||
}
|
||||
}
|
||||
|
||||
get_task_out:
|
||||
spinlock_unlock(&table_lock);
|
||||
|
|
Loading…
Add table
Reference in a new issue