- 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:
stefan 2010-09-10 22:18:55 +00:00
parent c882b28f03
commit 81df510743
12 changed files with 160 additions and 73 deletions

View 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

View file

@ -21,6 +21,7 @@
#define __ARCH_IRQ_H__
#include <metalsvm/stddef.h>
#include <metalsvm/tasks_types.h>
#ifdef __cplusplus
extern "C" {

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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
}

View file

@ -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

View file

@ -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();
}

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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);