Skip to content

Commit 50637e7

Browse files
committed
Chapter 4
1 parent 75af1ae commit 50637e7

File tree

19 files changed

+628
-76
lines changed

19 files changed

+628
-76
lines changed

.github/workflows/github-autotest.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: auto-test
22

3-
on:
3+
on:
44
push:
55

66
jobs:
@@ -12,7 +12,7 @@ jobs:
1212
image: duskmoon/dev-env:ucore-ci
1313
steps:
1414
- uses: actions/checkout@v3
15-
- run: git clone https://github.com/LearningOS/uCore-Tutorial-Checker-2023S.git ucore-tutorial-ci
15+
- run: git clone https://github.com/LearningOS/uCore-Tutorial-Checker-2023S.git ucore-tutorial-ci
1616
- run: git clone https://github.com/LearningOS/uCore-Tutorial-Test-2023S.git ucore-tutorial-ci/workplace/user
1717
- name: run test
1818
id: tester

os/const.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,28 @@ enum {
99
STDERR = 2,
1010
};
1111

12+
// memory layout
13+
14+
// the kernel expects there to be RAM
15+
// for use by the kernel and user pages
16+
// from physical address 0x80000000 to PHYSTOP.
17+
#define KERNBASE 0x80200000L
18+
#define PHYSTOP (0x80000000 + 128 * 1024 * 1024) // we have 128M memroy
19+
20+
// one beyond the highest possible virtual address.
21+
// MAXVA is actually one bit less than the max allowed by
22+
// Sv39, to avoid having to sign-extend virtual addresses
23+
// that have the high bit set.
24+
#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))
25+
26+
// map the trampoline page to the highest address,
27+
// in both user and kernel space.
28+
#define USER_TOP (MAXVA)
29+
#define TRAMPOLINE (USER_TOP - PGSIZE)
30+
#define TRAPFRAME (TRAMPOLINE - PGSIZE)
31+
32+
// memory layout end
33+
34+
#define MAX_STR_LEN (200)
35+
1236
#endif // CONST_H

os/defs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
#define DEFS_H
33

44
#include "const.h"
5+
#include "kalloc.h"
56
#include "log.h"
67
#include "printf.h"
78
#include "proc.h"
89
#include "riscv.h"
910
#include "sbi.h"
1011
#include "string.h"
1112
#include "types.h"
13+
#include "vm.h"
1214

1315
// number of elements in fixed-size array
1416
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))

os/kalloc.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "kalloc.h"
2+
#include "defs.h"
3+
#include "riscv.h"
4+
5+
extern char ekernel[];
6+
7+
struct linklist {
8+
struct linklist *next;
9+
};
10+
11+
struct {
12+
struct linklist *freelist;
13+
} kmem;
14+
15+
void freerange(void *pa_start, void *pa_end)
16+
{
17+
char *p;
18+
p = (char *)PGROUNDUP((uint64)pa_start);
19+
for (; p + PGSIZE <= (char *)pa_end; p += PGSIZE)
20+
kfree(p);
21+
}
22+
23+
void kinit()
24+
{
25+
freerange(ekernel, (void *)PHYSTOP);
26+
}
27+
28+
// Free the page of physical memory pointed at by v,
29+
// which normally should have been returned by a
30+
// call to kalloc(). (The exception is when
31+
// initializing the allocator; see kinit above.)
32+
void kfree(void *pa)
33+
{
34+
struct linklist *l;
35+
if (((uint64)pa % PGSIZE) != 0 || (char *)pa < ekernel ||
36+
(uint64)pa >= PHYSTOP)
37+
panic("kfree");
38+
// Fill with junk to catch dangling refs.
39+
memset(pa, 1, PGSIZE);
40+
l = (struct linklist *)pa;
41+
l->next = kmem.freelist;
42+
kmem.freelist = l;
43+
}
44+
45+
// Allocate one 4096-byte page of physical memory.
46+
// Returns a pointer that the kernel can use.
47+
// Returns 0 if the memory cannot be allocated.
48+
void *kalloc(void)
49+
{
50+
struct linklist *l;
51+
l = kmem.freelist;
52+
if (l) {
53+
kmem.freelist = l->next;
54+
memset((char *)l, 5, PGSIZE); // fill with junk
55+
}
56+
return (void *)l;
57+
}

os/kalloc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef KALLOC_H
2+
#define KALLOC_H
3+
4+
void *kalloc(void);
5+
void kfree(void *);
6+
void kinit(void);
7+
8+
#endif // KALLOC_H

os/loader.c

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

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

99
// Count finished programs. If all apps exited, shutdown.
1010
int finished()
@@ -18,39 +18,60 @@ int finished()
1818
// Get user progs' infomation through pre-defined symbol in `link_app.S`
1919
void loader_init()
2020
{
21-
if ((uint64)ekernel >= BASE_ADDRESS) {
22-
panic("kernel too large...\n");
23-
}
2421
app_info_ptr = (uint64 *)_app_num;
2522
app_num = *app_info_ptr;
2623
app_info_ptr++;
2724
}
2825

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)
26+
pagetable_t bin_loader(uint64 start, uint64 end, struct proc *p)
3227
{
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);
36-
return length;
28+
pagetable_t pg = uvmcreate();
29+
if (mappages(pg, TRAPFRAME, PGSIZE, (uint64)p->trapframe,
30+
PTE_R | PTE_W) < 0) {
31+
panic("mappages fail");
32+
}
33+
if (!PGALIGNED(start)) {
34+
panic("user program not aligned, start = %p", start);
35+
}
36+
if (!PGALIGNED(end)) {
37+
// Fix in ch5
38+
warnf("Some kernel data maybe mapped to user, start = %p, end = %p",
39+
start, end);
40+
}
41+
end = PGROUNDUP(end);
42+
uint64 length = end - start;
43+
if (mappages(pg, BASE_ADDRESS, length, start,
44+
PTE_U | PTE_R | PTE_W | PTE_X) != 0) {
45+
panic("mappages fail");
46+
}
47+
p->pagetable = pg;
48+
uint64 ustack_bottom_vaddr = BASE_ADDRESS + length + PAGE_SIZE;
49+
if (USTACK_SIZE != PAGE_SIZE) {
50+
// Fix in ch5
51+
panic("Unsupported");
52+
}
53+
mappages(pg, ustack_bottom_vaddr, USTACK_SIZE, (uint64)kalloc(),
54+
PTE_U | PTE_R | PTE_W | PTE_X);
55+
p->ustack = ustack_bottom_vaddr;
56+
p->trapframe->epc = BASE_ADDRESS;
57+
p->trapframe->sp = p->ustack + USTACK_SIZE;
58+
p->max_page = PGROUNDUP(p->ustack + USTACK_SIZE - 1) / PAGE_SIZE;
59+
p->program_brk = p->ustack + USTACK_SIZE;
60+
p->heap_bottom = p->ustack + USTACK_SIZE;
61+
return pg;
3762
}
3863

3964
// load all apps and init the corresponding `proc` structure.
4065
int run_all_app()
4166
{
4267
for (int i = 0; i < app_num; ++i) {
4368
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;
69+
tracef("load app %d", i);
70+
bin_loader(app_info_ptr[i], app_info_ptr[i + 1], p);
5071
p->state = RUNNABLE;
5172
/*
5273
* LAB1: you may need to initialize your new fields of proc here
5374
*/
5475
}
5576
return 0;
56-
}
77+
}

os/loader.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ int finished();
88
void loader_init();
99
int run_all_app();
1010

11-
#define BASE_ADDRESS (0x80400000)
12-
#define MAX_APP_SIZE (0x20000)
13-
#define USER_STACK_SIZE (PAGE_SIZE)
11+
#define BASE_ADDRESS (0x1000)
12+
#define USTACK_SIZE (PAGE_SIZE)
13+
#define KSTACK_SIZE (PAGE_SIZE)
1414
#define TRAP_PAGE_SIZE (PAGE_SIZE)
1515

1616
#endif // LOADER_H

os/main.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ void clean_bss()
1414
void main()
1515
{
1616
clean_bss();
17+
printf("hello world!\n");
1718
proc_init();
19+
kinit();
20+
kvm_init();
1821
loader_init();
1922
trap_init();
2023
timer_init();
2124
run_all_app();
2225
infof("start scheduler!");
2326
scheduler();
24-
}
27+
}

os/proc.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
#include "defs.h"
33
#include "loader.h"
44
#include "trap.h"
5+
#include "vm.h"
56

67
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];
8+
__attribute__((aligned(16))) char kstack[NPROC][PAGE_SIZE];
9+
__attribute__((aligned(4096))) char trapframe[NPROC][TRAP_PAGE_SIZE];
1010

1111
extern char boot_stack_top[];
1212
struct proc *current_proc;
@@ -29,7 +29,6 @@ void proc_init(void)
2929
for (p = pool; p < &pool[NPROC]; p++) {
3030
p->state = UNUSED;
3131
p->kstack = (uint64)kstack[p - pool];
32-
p->ustack = (uint64)ustack[p - pool];
3332
p->trapframe = (struct trapframe *)trapframe[p - pool];
3433
/*
3534
* LAB1: you may need to initialize your new fields of proc here
@@ -62,11 +61,16 @@ struct proc *allocproc(void)
6261
found:
6362
p->pid = allocpid();
6463
p->state = USED;
64+
p->pagetable = 0;
65+
p->ustack = 0;
66+
p->max_page = 0;
67+
p->program_brk = 0;
68+
p->heap_bottom = 0;
6569
memset(&p->context, 0, sizeof(p->context));
66-
memset(p->trapframe, 0, PAGE_SIZE);
67-
memset((void *)p->kstack, 0, PAGE_SIZE);
70+
memset((void *)p->kstack, 0, KSTACK_SIZE);
71+
memset((void *)p->trapframe, 0, TRAP_PAGE_SIZE);
6872
p->context.ra = (uint64)usertrapret;
69-
p->context.sp = p->kstack + PAGE_SIZE;
73+
p->context.sp = p->kstack + KSTACK_SIZE;
7074
return p;
7175
}
7276

@@ -114,12 +118,40 @@ void yield(void)
114118
sched();
115119
}
116120

121+
void freeproc(struct proc *p)
122+
{
123+
p->state = UNUSED;
124+
// uvmfree(p->pagetable, p->max_page);
125+
}
126+
117127
// Exit the current process.
118128
void exit(int code)
119129
{
120130
struct proc *p = curr_proc();
121131
infof("proc %d exit with %d", p->pid, code);
122-
p->state = UNUSED;
132+
freeproc(p);
123133
finished();
124134
sched();
125135
}
136+
137+
// Grow or shrink user memory by n bytes.
138+
// Return 0 on succness, -1 on failure.
139+
int growproc(int n)
140+
{
141+
uint64 program_brk;
142+
struct proc *p = curr_proc();
143+
program_brk = p->program_brk;
144+
int new_brk = program_brk + n - p->heap_bottom;
145+
if(new_brk < 0){
146+
return -1;
147+
}
148+
if(n > 0){
149+
if((program_brk = uvmalloc(p->pagetable, program_brk, program_brk + n, PTE_W)) == 0) {
150+
return -1;
151+
}
152+
} else if(n < 0){
153+
program_brk = uvmdealloc(p->pagetable, program_brk, program_brk + n);
154+
}
155+
p->program_brk = program_brk;
156+
return 0;
157+
}

os/proc.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef PROC_H
22
#define PROC_H
33

4+
#include "riscv.h"
45
#include "types.h"
56

67
#define NPROC (16)
@@ -31,10 +32,14 @@ enum procstate { UNUSED, USED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
3132
struct proc {
3233
enum procstate state; // Process state
3334
int pid; // Process ID
34-
uint64 ustack; // Virtual address of user stack
35+
pagetable_t pagetable; // User page table
36+
uint64 ustack;
3537
uint64 kstack; // Virtual address of kernel stack
3638
struct trapframe *trapframe; // data page for trampoline.S
3739
struct context context; // swtch() here to run process
40+
uint64 max_page;
41+
uint64 program_brk;
42+
uint64 heap_bottom;
3843
/*
3944
* LAB1: you may need to add some new fields here
4045
*/
@@ -54,4 +59,6 @@ struct proc *allocproc();
5459
// swtch.S
5560
void swtch(struct context *, struct context *);
5661

57-
#endif // PROC_H
62+
int growproc(int n);
63+
64+
#endif // PROC_H

os/riscv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ static inline void sfence_vma()
291291

292292
#define PGROUNDUP(sz) (((sz) + PGSIZE - 1) & ~(PGSIZE - 1))
293293
#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE - 1))
294+
#define PGALIGNED(a) (((a) & (PGSIZE - 1)) == 0)
294295

295296
#define PTE_V (1L << 0) // valid
296297
#define PTE_R (1L << 1)
@@ -317,6 +318,7 @@ static inline void sfence_vma()
317318
#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))
318319

319320
typedef uint64 pte_t;
321+
typedef uint64 pde_t;
320322
typedef uint64 *pagetable_t; // 512 PTEs
321323

322324
#endif // RISCV_H

0 commit comments

Comments
 (0)