Skip to content

Commit 367f048

Browse files
committed
Very basic thread switching.
- Kernel spawns two threads that run in userland and it switches by turns. - Add a DELAY function.
1 parent d186e52 commit 367f048

10 files changed

+217
-14
lines changed

Makefile

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,18 @@ OBJFILES+= startup.o
2828
OBJFILES+= exception.o
2929
OBJFILES+= subr_prf.o
3030
OBJFILES+= user.o
31+
OBJFILES+= thread.o
32+
OBJFILES+= syscalls.o
3133

3234
boot.bin: boot.elf
3335
$(OBJCOPY) -O binary boot.elf boot.bin
3436

3537
boot.elf: clean subr_prf.o boot.o startup.o user.o
3638
$(CC) -c subr_prf.c $(CFLAGS)
3739
$(CC) -c user.c $(CFLAGS)
38-
$(CC) -c boot.c $(CFLAGS) boot.c
40+
$(CC) -c boot.c $(CFLAGS)
41+
$(CC) -c thread.c $(CFLAGS)
42+
$(CC) -c syscalls.c $(CFLAGS)
3943
$(AS) startup.S -o startup.o
4044
$(AS) exception.S -o exception.o
4145
$(LD) -T boot.ld -nodefaultlibs -nostdlib \

boot.c

+35-2
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@
3030
#include <types.h>
3131
#include <subr.h>
3232
#include <cpufunc.h>
33+
#include <syscalls.h>
34+
#include <thread.h>
3335

3436
extern unsigned int *__bss_start;
3537
extern unsigned int *__bss_end;
3638

3739
void kern_boot(void);
3840
void clearbss(void);
41+
void usermode(void);
3942

4043
void clearbss(void)
4144
{
@@ -49,6 +52,30 @@ void clearbss(void)
4952

5053
}
5154

55+
int
56+
proc1(void *arg)
57+
{
58+
for(;;) {
59+
kprintf("[usr] running process 1\n");
60+
DELAY(500000);
61+
syscall_entry(SYS_YIELD, NULL);
62+
kprintf("[usr] again process 1\n");
63+
}
64+
return 0;
65+
}
66+
67+
int
68+
proc2(void *arg)
69+
{
70+
for(;;) {
71+
kprintf("[usr] running process 2\n");
72+
DELAY(500000);
73+
syscall_entry(SYS_YIELD, NULL);
74+
kprintf("[usr] again process 2\n");
75+
}
76+
return 0;
77+
}
78+
5279
void
5380
kern_boot(void)
5481
{
@@ -58,6 +85,12 @@ kern_boot(void)
5885
/* Startup */
5986
clearbss();
6087

61-
/* Switch to user mode */
62-
_gouser();
88+
thread_create(proc1);
89+
thread_create(proc2);
90+
91+
/* Run all user mode threads */
92+
run_threads();
93+
94+
/* Loop forever */
95+
for (;;);
6396
}

cpufunc.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,18 @@ _read_cpsr(void)
4343
}
4444

4545
static __inline void
46-
syscall_entry(int syscall)
46+
syscall_entry(int syscall, void *arg)
4747
{
4848
__asm __volatile("svc #0x0");
4949
}
5050

51+
static void
52+
DELAY(uint32_t usec)
53+
{
54+
int counts;
55+
for (; usec > 0; usec--)
56+
for (counts = 200; counts > 0; counts--)
57+
;
58+
}
59+
5160
#endif /* _CPUFUNC_H_ */

exception.S

+16-4
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,22 @@
3535
.global _e_fiq
3636

3737
_e_undef:
38+
ldr r0, =undef_text
39+
bl kprintf
3840
bl .
3941

4042
_e_svc:
41-
mov r1, r0 @ Move syscall no. to r1
42-
ldr r0, =syscall_text @ Load format string
43-
bl kprintf
44-
bl .
43+
msr cpsr_c, #0x1f @ Switch to system mode
44+
mov r5, lr @ Save LR of the user thread
45+
msr cpsr_c, #0xd3
46+
bl syscall_handler
47+
cmp r0, #1
48+
beq ret_svc
49+
mov lr, r5
50+
subs pc, lr, #0
51+
ret_svc:
52+
ldmfd sp!, {r0-r11, ip,lr}
53+
bx lr
4554

4655
_e_pref_abort:
4756
bl .
@@ -57,3 +66,6 @@ _e_fiq:
5766

5867
syscall_text:
5968
.asciz "[svc] Syscall %d used!\n"
69+
70+
undef_text:
71+
.asciz "[und] Undefined exception %p\n"

startup.S

+15-3
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,23 @@ _gouser:
8484
*
8585
* Since System mode doesn't have its own registers for
8686
* SP, LR it shares them with User mode.
87-
*/
88-
msr spsr_cxsf, #0 @ Reset SPSR
87+
*/
88+
stmfd sp!, {r0-r11,ip,lr}
89+
8990
msr cpsr_c, #0x1f @ Switch to System mode
91+
cmp r1, #0 @ Check if stack passed
92+
bne _load_custom_stack @ Set another stack if one is passed
9093
ldr sp, =usrstack_top @ Set stack for user/sys mode
94+
bl _swi
95+
96+
_load_custom_stack:
97+
mov sp, r1 @ Set a thread stack
98+
99+
_swi:
91100
msr cpsr_c, #0xd3 @ Switch to svc mode
101+
mrs r4, cpsr @ For saving SPSR
102+
msr spsr, r4 @ Read in CSPR to SPSR for manipulation
92103
msr spsr_c, #0x10 @ User mode for the exception return
93-
ldr lr, =usermode @ Userland function to switch to
104+
mov lr, r0 @ Userland function to switch to
94105
subs pc, lr, #0 @ Exception return
106+

syscalls.c

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) 2016, Antonio Huete Jimenez <[email protected]>
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright notice,
11+
* this list of conditions and the following disclaimer in the documentation
12+
* and/or other materials provided with the distribution.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
20+
* LOSS OF USE, DATA, OR PROFITS ; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*
25+
* The views and conclusions contained in the software and documentation are those
26+
* of the authors and should not be interpreted as representing official policies,
27+
* either expressed or implied, of the author.
28+
*/
29+
30+
#include <types.h>
31+
#include <cpufunc.h>
32+
#include <syscalls.h>
33+
#include <subr.h>
34+
35+
int
36+
syscall_handler(int syscall, void *arg)
37+
{
38+
static int cycle = 0;
39+
40+
switch(syscall) {
41+
case SYS_RET:
42+
run_threads();
43+
break;
44+
case SYS_DUMMY:
45+
kprintf("[svc] Called SYS_DUMMY\n");
46+
break;
47+
case SYS_THREAD:
48+
thread_create(arg);
49+
break;
50+
case SYS_YIELD:
51+
if (cycle == 0)
52+
return cycle++;
53+
else if (cycle == 1)
54+
return cycle--;
55+
break;
56+
default:
57+
kprintf("[svc] Invalid syscall %d\n", syscall);
58+
break;
59+
}
60+
61+
return 0;
62+
}

syscalls.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
#include <types.h>
3434

35-
#define SYSCALL_DUMMY 0x1
35+
#define SYS_RET 0x0
36+
#define SYS_DUMMY 0x1
37+
#define SYS_THREAD 0x2
38+
#define SYS_YIELD 0x3
3639

3740
#endif /* _SYSCALLS_H_ */

thread.c

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <cpufunc.h>
2+
#include <thread.h>
3+
4+
int nthreads;
5+
unsigned char thread_stack[MAXTHREADS][STACKSIZE];
6+
struct thread threads[MAXTHREADS];
7+
8+
struct thread *
9+
thread_create(int(*func)(void *))
10+
{
11+
int current = nthreads;
12+
13+
if (nthreads >= MAXTHREADS) {
14+
kprintf("Maximum number of threads reached\n");
15+
return NULL;
16+
}
17+
18+
threads[current].tid = current;
19+
threads[current].stack = thread_stack[current] + STACKSIZE - 1;
20+
threads[current].func = func;
21+
nthreads++;
22+
23+
kprintf("[svc] Created thread %d\n", current);
24+
25+
return &threads[current];
26+
}
27+
28+
void
29+
thread_destroy(struct thread *t)
30+
{
31+
}
32+
33+
void
34+
run_threads(void)
35+
{
36+
int current;
37+
38+
if (nthreads == 0)
39+
return;
40+
41+
for (;;) {
42+
for (current = 0; current < nthreads; current++) {
43+
/* Run thread function */
44+
_gouser(threads[current].func, threads[current].stack);
45+
}
46+
}
47+
}

thread.h

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef _THREAD_H_
2+
#define _THREAD_H_
3+
4+
#define MAXTHREADS 16
5+
#define STACKSIZE 4096
6+
extern int nthreads;
7+
8+
struct thread *thread_create(int(*func)(void *));
9+
10+
struct thread {
11+
int tid;
12+
unsigned char *stack;
13+
int (*func)(void *);
14+
};
15+
16+
#endif /* _THREAD_H_ */

user.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@
3131
#include <cpufunc.h>
3232
#include <syscalls.h>
3333
#include <subr.h>
34+
#include <thread.h>
3435

3536
void
3637
usermode(void)
3738
{
38-
kprintf("[usr] calling svc with syscall %d\n", SYSCALL_DUMMY);
39-
syscall_entry(SYSCALL_DUMMY);
39+
kprintf("[usr] calling svc with syscall %d\n", SYS_DUMMY);
40+
/* syscall_entry(SYS_DUMMY, NULL);
41+
syscall_entry(SYS_THREAD, proc1);
42+
syscall_entry(SYS_THREAD, proc2);
43+
syscall_entry(SYS_RET, NULL);
44+
*/
4045
}

0 commit comments

Comments
 (0)