Towards finishing exchange_registers()

- Added mutex_trylock()
- Implemented most of exchange_registers()
- thread_control() now needs a lock for operations that can modify thread context.
- thread_start() does not initialise scheduler flags, now done in thread_create.

TODO:
- Fork/clone'ed threads should retain their context in tcb, not syscall stack.
- exchange_registers() calls in userspace need cleaning up.
This commit is contained in:
Bahadir Balban
2008-09-13 18:07:00 +03:00
parent 0b3ab05a98
commit 4fb5277123
23 changed files with 460 additions and 98 deletions

View File

@@ -144,6 +144,9 @@
#define EOWNERDEAD 130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */
/* Codezero specific error codes */
#define EACTIVE 132 /* Task active */
#ifdef __KERNEL__
/* Should never be seen by user programs */

22
include/l4/api/exregs.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* Exchange registers system call data.
*
* Copyright (C) 2008 Bahadir Balban
*/
#ifndef __EXREGS_H__
#define __EXREGS_H__
#include <l4/macros.h>
#include INC_GLUE(syscall.h)
#include INC_GLUE(context.h)
#include <l4/types.h>
/* Structure passed by userspace pagers for exchanging registers */
struct exregs_data {
exregs_context_t context;
u32 valid_vect;
};
#endif /* __EXREGS_H__ */

View File

@@ -1,16 +1,18 @@
#ifndef __THREAD_H__
#define __THREAD_H__
#define THREAD_FLAGS_MASK 0x00F0
/* Create new thread, copy given space */
#define THREAD_CREATE_COPYSPC 0x0010
#define THREAD_CREATE_MASK 0x00F0
/* Create new thread and new space */
#define THREAD_CREATE_NEWSPC 0x0020
#define THREAD_NEW_SPACE 0x0010
/* Create new thread, copy given space */
#define THREAD_COPY_SPACE 0x0020
/* Create new thread, use given space */
#define THREAD_CREATE_SAMESPC 0x0030
#define THREAD_SAME_SPACE 0x0030
#define THREAD_ACTION_MASK 0x000F

View File

@@ -75,6 +75,17 @@ static inline void irq_local_disable()
/* This is filled on entry to irq handler, only if a process was interrupted.*/
extern unsigned int preempted_psr;
#include <l4/generic/tcb.h>
static inline int task_in_kernel(struct tcb *t)
{
return ((t->context.spsr & ARM_MODE_MASK) == ARM_MODE_SVC) ? 1 : 0;
}
static inline int task_in_user(struct tcb *t)
{
return !task_in_kernel(t);
}
static inline int in_kernel()
{
return (((preempted_psr & ARM_MODE_MASK) == ARM_MODE_SVC)) ? 1 : 0;

View File

@@ -34,10 +34,6 @@ static inline struct ktcb *current_task(void)
#define SCHED_FL_MASK (SCHED_FL_SLEEP | SCHED_FL_RESUME \
| SCHED_FL_SUSPEND)
#define __IPC_FL_WAIT 4
#define IPC_FL_WAIT (1 << __IPC_FL_WAIT)
#define IPC_FL_MASK IPC_FL_WAIT
void sched_runqueue_init(void);
void sched_start_task(struct ktcb *task);
void sched_resume_task(struct ktcb *task);

View File

@@ -13,6 +13,7 @@
#include INC_GLUE(memory.h)
#include INC_GLUE(syscall.h)
#include INC_GLUE(message.h)
#include INC_GLUE(context.h)
#include INC_SUBARCH(mm.h)
enum task_state {
@@ -21,32 +22,6 @@ enum task_state {
TASK_RUNNABLE = 2,
};
/*
* This describes the user space register context of each task. Simply set them
* as regular structure fields, and they'll be copied onto real registers upon
* a context switch. In the ARM case, they're copied from memory to userspace
* registers using the LDM instruction with ^, no-pc flavor. See ARMARM.
*/
typedef struct arm_context {
u32 spsr; /* 0x0 */
u32 r0; /* 0x4 */
u32 r1; /* 0x8 */
u32 r2; /* 0xC */
u32 r3; /* 0x10 */
u32 r4; /* 0x14 */
u32 r5; /* 0x18 */
u32 r6; /* 0x1C */
u32 r7; /* 0x20 */
u32 r8; /* 0x24 */
u32 r9; /* 0x28 */
u32 r10; /* 0x2C */
u32 r11; /* 0x30 */
u32 r12; /* 0x34 */
u32 sp; /* 0x38 */
u32 lr; /* 0x3C */
u32 pc; /* 0x40 */
} __attribute__((__packed__)) task_context_t;
#define TASK_ID_INVALID -1
struct task_ids {
l4id_t tid;
@@ -75,7 +50,9 @@ struct ktcb {
/* Flags to hint scheduler on future task state */
unsigned int schedfl;
unsigned int flags;
/* Lock for blocking thread state modifications via a syscall */
struct mutex thread_control_lock;
/* Other related threads */
l4id_t pagerid;

View File

@@ -0,0 +1,53 @@
#ifndef __ARM_CONTEXT_H__
#define __ARM_CONTEXT_H__
#include <l4/types.h>
/*
* This describes the register context of each task. Simply set
* them as regular structure fields, and they'll be copied onto
* real registers upon a context switch to that task. Normally
* exchange_registers() system call is designed for this, whose
* input structure is defined further below.
*/
typedef struct arm_context {
u32 spsr; /* 0x0 */
u32 r0; /* 0x4 */
u32 r1; /* 0x8 */
u32 r2; /* 0xC */
u32 r3; /* 0x10 */
u32 r4; /* 0x14 */
u32 r5; /* 0x18 */
u32 r6; /* 0x1C */
u32 r7; /* 0x20 */
u32 r8; /* 0x24 */
u32 r9; /* 0x28 */
u32 r10; /* 0x2C */
u32 r11; /* 0x30 */
u32 r12; /* 0x34 */
u32 sp; /* 0x38 */
u32 lr; /* 0x3C */
u32 pc; /* 0x40 */
} __attribute__((__packed__)) task_context_t;
typedef struct arm_exregs_context {
u32 r0; /* 0x4 */
u32 r1; /* 0x8 */
u32 r2; /* 0xC */
u32 r3; /* 0x10 */
u32 r4; /* 0x14 */
u32 r5; /* 0x18 */
u32 r6; /* 0x1C */
u32 r7; /* 0x20 */
u32 r8; /* 0x24 */
u32 r9; /* 0x28 */
u32 r10; /* 0x2C */
u32 r11; /* 0x30 */
u32 r12; /* 0x34 */
u32 sp; /* 0x38 */
u32 lr; /* 0x3C */
u32 pc; /* 0x40 */
} __attribute__((__packed__)) exregs_context_t;
#endif /* __ARM_CONTEXT_H__ */

View File

@@ -68,4 +68,7 @@
#define KERN_ADDR(x) ((x >= KERNEL_AREA_START) && (x < KERNEL_AREA_END))
#define USER_ADDR(x) ((x >= USER_AREA_START) && (x < USER_AREA_END))
#define PRIVILEGED_ADDR(x) (KERN_ADDR(x) || (x >= ARM_HIGH_VECTOR) || \
(x >= IO_AREA_START && x < IO_AREA_END))
#endif /* __MEMLAYOUT_H__ */

View File

@@ -2,12 +2,13 @@
* ARM-specific system call details.
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#ifndef __ARM_GLUE_SYSCALL_H__
#define __ARM_GLUE_SYSCALL_H__
#include <l4/types.h>
/* Only specific call is the trap that gives back the kip address
* from which other system calls can be discovered. */
#define L4_TRAP_KIP 0xB4
@@ -52,7 +53,8 @@ typedef struct msg_regs {
/* NOTE:
* These references are valid only when they have been explicitly set
* by a kernel entry point, e.g. a system call, a data abort handler.
* by a kernel entry point, e.g. a system call, a data abort handler
* that imitates a page fault ipc etc.
*/
#define KTCB_REF_ARG0(ktcb) (&(ktcb)->syscall_regs->r0)
#define KTCB_REF_MR0(ktcb) (&(ktcb)->syscall_regs->r3)

View File

@@ -28,6 +28,7 @@ static inline void mutex_init(struct mutex *mutex)
INIT_LIST_HEAD(&mutex->wq.task_list);
}
int mutex_trylock(struct mutex *mutex);
void mutex_lock(struct mutex *mutex);
void mutex_unlock(struct mutex *mutex);

View File

@@ -20,7 +20,7 @@ static inline void spin_lock_init(struct spinlock *s)
*/
static inline void spin_lock(struct spinlock *s)
{
preempt_disable();
preempt_disable(); /* This must disable local preempt */
#if defined(CONFIG_SMP)
__spin_lock(&s->lock);
#endif

View File

@@ -75,6 +75,9 @@
#define printk printf
#endif
/* Converts an int-sized field offset in a struct into a bit offset in a word */
#define FIELD_TO_BIT(type, field) (1 << (offsetof(type, field) >> 2))
/* Functions who may either return a pointer or an error code can use these: */
#define PTR_ERR(x) ((void *)(x))
/* checks up to -1000, the rest might be valid pointers!!! E.g. 0xE0000000 */