Skip to content

Commit 75af1ae

Browse files
committed
Chapter 3
1 parent f43c700 commit 75af1ae

File tree

19 files changed

+488
-84
lines changed

19 files changed

+488
-84
lines changed

.github/workflows/github-autotest.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: auto-test
2+
3+
on:
4+
push:
5+
6+
jobs:
7+
base-test:
8+
runs-on: ubuntu-latest
9+
outputs:
10+
points: ${{ steps.end.outputs.points}}
11+
container:
12+
image: duskmoon/dev-env:ucore-ci
13+
steps:
14+
- uses: actions/checkout@v3
15+
- run: git clone https://github.com/LearningOS/uCore-Tutorial-Checker-2023S.git ucore-tutorial-ci
16+
- run: git clone https://github.com/LearningOS/uCore-Tutorial-Test-2023S.git ucore-tutorial-ci/workplace/user
17+
- name: run test
18+
id: tester
19+
run: cd ucore-tutorial-ci && make test passwd=${{ secrets.BASE_TEST_TOKEN }} CHAPTER=`echo ${GITHUB_REF##*/} | grep -oP 'ch\K[0-9]'` | tee ../output.txt
20+
- name: end
21+
id: end
22+
run: cat output.txt | grep "Test passed" | grep -oP "\d{1,}/\d{1,}" | xargs -i echo "points={}" >> $GITHUB_OUTPUT
23+
deploy:
24+
if: github.repository != 'LearningOS/uCore-Tutorial-Code-2023S'
25+
name: Deploy to pages
26+
needs: base-test
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v3
30+
continue-on-error: true
31+
with:
32+
ref: 'gh-pages'
33+
- name: Save Log File
34+
uses: yfblock/multi-rank-log@main
35+
with:
36+
points: ${{ needs.base-test.outputs.points }}
37+
- name: GitHub Pages
38+
uses: crazy-max/ghaction-github-pages@v3
39+
with:
40+
target_branch: gh-pages
41+
build_dir: ./public
42+
keep_history: true
43+
env:
44+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Makefile

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
.PHONY: clean build user
22
all: build_kernel
33

4-
LOG ?= error
5-
64
K = os
7-
U = user
85

96
TOOLPREFIX = riscv64-unknown-elf-
107
CC = $(TOOLPREFIX)gcc
@@ -37,6 +34,9 @@ CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
3734
CFLAGS += -I$K
3835
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
3936

37+
38+
LOG ?= error
39+
4040
ifeq ($(LOG), error)
4141
CFLAGS += -D LOG_LEVEL_ERROR
4242
else ifeq ($(LOG), warn)
@@ -89,7 +89,7 @@ build/kernel: $(OBJS) os/kernel_app.ld
8989

9090
clean:
9191
rm -rf $(BUILDDIR) os/kernel_app.ld os/link_app.S
92-
make -C $(U) clean
92+
make -C user clean
9393

9494
# BOARD
9595
BOARD ?= qemu
@@ -118,8 +118,10 @@ debug: build/kernel .gdbinit
118118

119119
CHAPTER ?= $(shell git rev-parse --abbrev-ref HEAD | grep -oP 'ch\K[0-9]')
120120

121+
BASE ?= 0
122+
121123
user:
122-
make -C $(U) CHAPTER=$(CHAPTER) BASE=$(BASE)
124+
make -C user CHAPTER=$(CHAPTER) BASE=$(BASE)
123125

124126
test: user run
125127

os/defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "const.h"
55
#include "log.h"
66
#include "printf.h"
7+
#include "proc.h"
78
#include "riscv.h"
89
#include "sbi.h"
910
#include "string.h"

os/loader.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,55 @@
22
#include "defs.h"
33
#include "trap.h"
44

5-
static int app_cur, app_num;
5+
static uint64 app_num;
66
static uint64 *app_info_ptr;
7-
extern char _app_num[], userret[], boot_stack_top[], ekernel[];
7+
extern char _app_num[], ekernel[];
88

9+
// Count finished programs. If all apps exited, shutdown.
10+
int finished()
11+
{
12+
static int fin = 0;
13+
if (++fin >= app_num)
14+
panic("all apps over");
15+
return 0;
16+
}
17+
18+
// Get user progs' infomation through pre-defined symbol in `link_app.S`
919
void loader_init()
1020
{
1121
if ((uint64)ekernel >= BASE_ADDRESS) {
1222
panic("kernel too large...\n");
1323
}
1424
app_info_ptr = (uint64 *)_app_num;
15-
app_cur = -1;
1625
app_num = *app_info_ptr;
26+
app_info_ptr++;
1727
}
1828

19-
__attribute__((aligned(4096))) char user_stack[USER_STACK_SIZE];
20-
__attribute__((aligned(4096))) char trap_page[TRAP_PAGE_SIZE];
21-
22-
int load_app(uint64 *info)
29+
// Load nth user app at
30+
// [BASE_ADDRESS + n * MAX_APP_SIZE, BASE_ADDRESS + (n+1) * MAX_APP_SIZE)
31+
int load_app(int n, uint64 *info)
2332
{
24-
uint64 start = info[0], end = info[1], length = end - start;
25-
memset((void *)BASE_ADDRESS, 0, MAX_APP_SIZE);
26-
memmove((void *)BASE_ADDRESS, (void *)start, length);
33+
uint64 start = info[n], end = info[n + 1], length = end - start;
34+
memset((void *)BASE_ADDRESS + n * MAX_APP_SIZE, 0, MAX_APP_SIZE);
35+
memmove((void *)BASE_ADDRESS + n * MAX_APP_SIZE, (void *)start, length);
2736
return length;
2837
}
2938

30-
int run_next_app()
39+
// load all apps and init the corresponding `proc` structure.
40+
int run_all_app()
3141
{
32-
struct trapframe *trapframe = (struct trapframe *)trap_page;
33-
app_cur++;
34-
app_info_ptr++;
35-
if (app_cur >= app_num) {
36-
return -1;
42+
for (int i = 0; i < app_num; ++i) {
43+
struct proc *p = allocproc();
44+
struct trapframe *trapframe = p->trapframe;
45+
load_app(i, app_info_ptr);
46+
uint64 entry = BASE_ADDRESS + i * MAX_APP_SIZE;
47+
tracef("load app %d at %p", i, entry);
48+
trapframe->epc = entry;
49+
trapframe->sp = (uint64)p->ustack + USER_STACK_SIZE;
50+
p->state = RUNNABLE;
51+
/*
52+
* LAB1: you may need to initialize your new fields of proc here
53+
*/
3754
}
38-
infof("load and run app %d", app_cur);
39-
uint64 length = load_app(app_info_ptr);
40-
debugf("bin range = [%p, %p)", *app_info_ptr, *app_info_ptr + length);
41-
memset(trapframe, 0, 4096);
42-
trapframe->epc = BASE_ADDRESS;
43-
trapframe->sp = (uint64)user_stack + USER_STACK_SIZE;
44-
usertrapret(trapframe, (uint64)boot_stack_top);
4555
return 0;
4656
}

os/loader.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
#ifndef BATCH_H
2-
#define BATCH_H
1+
#ifndef LOADER_H
2+
#define LOADER_H
33

44
#include "const.h"
55
#include "types.h"
66

7+
int finished();
78
void loader_init();
8-
int run_next_app();
9+
int run_all_app();
910

1011
#define BASE_ADDRESS (0x80400000)
1112
#define MAX_APP_SIZE (0x20000)
12-
#define USER_STACK_SIZE PAGE_SIZE
13-
#define TRAP_PAGE_SIZE PAGE_SIZE
13+
#define USER_STACK_SIZE (PAGE_SIZE)
14+
#define TRAP_PAGE_SIZE (PAGE_SIZE)
1415

15-
#endif // BATCH_H
16+
#endif // LOADER_H

os/log.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
extern void printf(char *, ...);
55
extern int threadid();
66
extern void dummy(int, ...);
7+
extern void shutdown();
78

89
#if defined(LOG_LEVEL_ERROR)
910

@@ -113,6 +114,7 @@ enum LOG_COLOR {
113114
int tid = threadid(); \
114115
printf("\x1b[%dm[%s %d] %s:%d: " fmt "\x1b[0m\n", RED, \
115116
"PANIC", tid, __FILE__, __LINE__, ##__VA_ARGS__); \
117+
shutdown(); \
116118
} while (0)
117119

118120
#endif //! LOG_H

os/main.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
#include "console.h"
22
#include "defs.h"
33
#include "loader.h"
4+
#include "timer.h"
45
#include "trap.h"
56

6-
int threadid()
7-
{
8-
return 0;
9-
}
10-
117
void clean_bss()
128
{
139
extern char s_bss[];
@@ -18,8 +14,11 @@ void clean_bss()
1814
void main()
1915
{
2016
clean_bss();
21-
printf("hello wrold!\n");
22-
trap_init();
17+
proc_init();
2318
loader_init();
24-
run_next_app();
19+
trap_init();
20+
timer_init();
21+
run_all_app();
22+
infof("start scheduler!");
23+
scheduler();
2524
}

os/proc.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include "proc.h"
2+
#include "defs.h"
3+
#include "loader.h"
4+
#include "trap.h"
5+
6+
struct proc pool[NPROC];
7+
char kstack[NPROC][PAGE_SIZE];
8+
__attribute__((aligned(4096))) char ustack[NPROC][PAGE_SIZE];
9+
__attribute__((aligned(4096))) char trapframe[NPROC][PAGE_SIZE];
10+
11+
extern char boot_stack_top[];
12+
struct proc *current_proc;
13+
struct proc idle;
14+
15+
int threadid()
16+
{
17+
return curr_proc()->pid;
18+
}
19+
20+
struct proc *curr_proc()
21+
{
22+
return current_proc;
23+
}
24+
25+
// initialize the proc table at boot time.
26+
void proc_init(void)
27+
{
28+
struct proc *p;
29+
for (p = pool; p < &pool[NPROC]; p++) {
30+
p->state = UNUSED;
31+
p->kstack = (uint64)kstack[p - pool];
32+
p->ustack = (uint64)ustack[p - pool];
33+
p->trapframe = (struct trapframe *)trapframe[p - pool];
34+
/*
35+
* LAB1: you may need to initialize your new fields of proc here
36+
*/
37+
}
38+
idle.kstack = (uint64)boot_stack_top;
39+
idle.pid = 0;
40+
current_proc = &idle;
41+
}
42+
43+
int allocpid()
44+
{
45+
static int PID = 1;
46+
return PID++;
47+
}
48+
49+
// Look in the process table for an UNUSED proc.
50+
// If found, initialize state required to run in the kernel.
51+
// If there are no free procs, or a memory allocation fails, return 0.
52+
struct proc *allocproc(void)
53+
{
54+
struct proc *p;
55+
for (p = pool; p < &pool[NPROC]; p++) {
56+
if (p->state == UNUSED) {
57+
goto found;
58+
}
59+
}
60+
return 0;
61+
62+
found:
63+
p->pid = allocpid();
64+
p->state = USED;
65+
memset(&p->context, 0, sizeof(p->context));
66+
memset(p->trapframe, 0, PAGE_SIZE);
67+
memset((void *)p->kstack, 0, PAGE_SIZE);
68+
p->context.ra = (uint64)usertrapret;
69+
p->context.sp = p->kstack + PAGE_SIZE;
70+
return p;
71+
}
72+
73+
// Scheduler never returns. It loops, doing:
74+
// - choose a process to run.
75+
// - swtch to start running that process.
76+
// - eventually that process transfers control
77+
// via swtch back to the scheduler.
78+
void scheduler(void)
79+
{
80+
struct proc *p;
81+
for (;;) {
82+
for (p = pool; p < &pool[NPROC]; p++) {
83+
if (p->state == RUNNABLE) {
84+
/*
85+
* LAB1: you may need to init proc start time here
86+
*/
87+
p->state = RUNNING;
88+
current_proc = p;
89+
swtch(&idle.context, &p->context);
90+
}
91+
}
92+
}
93+
}
94+
95+
// Switch to scheduler. Must hold only p->lock
96+
// and have changed proc->state. Saves and restores
97+
// intena because intena is a property of this
98+
// kernel thread, not this CPU. It should
99+
// be proc->intena and proc->noff, but that would
100+
// break in the few places where a lock is held but
101+
// there's no process.
102+
void sched(void)
103+
{
104+
struct proc *p = curr_proc();
105+
if (p->state == RUNNING)
106+
panic("sched running");
107+
swtch(&p->context, &idle.context);
108+
}
109+
110+
// Give up the CPU for one scheduling round.
111+
void yield(void)
112+
{
113+
current_proc->state = RUNNABLE;
114+
sched();
115+
}
116+
117+
// Exit the current process.
118+
void exit(int code)
119+
{
120+
struct proc *p = curr_proc();
121+
infof("proc %d exit with %d", p->pid, code);
122+
p->state = UNUSED;
123+
finished();
124+
sched();
125+
}

0 commit comments

Comments
 (0)