Merge pull request 'lab7' (#5) from lab7 into master

Reviewed-on: #5
This commit is contained in:
cyp0633 2022-05-30 10:04:40 +08:00
commit 8a4d1ffcad
16 changed files with 418 additions and 40 deletions

View File

@ -48,7 +48,7 @@ ifndef USELLVM
HOSTCC := gcc
HOSTCFLAGS := -g -Wall -O2
CC := $(GCCPREFIX)gcc
CFLAGS := -march=i686 -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc $(DEFS)
CFLAGS := -march=i686 -fno-builtin -fno-PIC -Wall -ggdb -m32 -g -nostdinc $(DEFS)
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
else
HOSTCC := clang
@ -283,6 +283,10 @@ debug: $(UCOREIMG) $(SWAPIMG)
$(V)sleep 2
$(V)$(TERMINAL) -e "$(GDB) -q -x tools/gdbinit"
debug-nogdb: $(UCOREIMG) $(SWAPIMG)
$(V)$(QEMU) -S -s -parallel stdio $(QEMUOPTS) -serial null
debug-nox: $(UCOREIMG) $(SWAPIMG)
$(V)$(QEMU) -S -s -serial mon:stdio $(QEMUOPTS) -nographic &
$(V)sleep 2

View File

@ -347,5 +347,19 @@ print_stackframe(void) {
* NOTICE: the calling funciton's return addr eip = ss:[ebp+4]
* the calling funciton's ebp = ss:[ebp]
*/
uint32_t ebp = read_ebp(), eip = read_eip();
int i, j;
for (i = 0; ebp != 0 && i < STACKFRAME_DEPTH; i ++) {
cprintf("ebp:0x%08x eip:0x%08x args:", ebp, eip);
uint32_t *args = (uint32_t *)ebp + 2;
for (j = 0; j < 4; j ++) {
cprintf("0x%08x ", args[j]);
}
cprintf("\n");
print_debuginfo(eip - 1);
eip = ((uint32_t *)ebp)[1];
ebp = ((uint32_t *)ebp)[0];
}
}

View File

@ -116,7 +116,7 @@ default_init_memmap(struct Page *base, size_t n) {
base->property = n;
SetPageProperty(base);
nr_free += n;
list_add(&free_list, &(base->page_link));
list_add_before(&free_list, &(base->page_link));
}
static struct Page *
@ -135,12 +135,13 @@ default_alloc_pages(size_t n) {
}
}
if (page != NULL) {
list_del(&(page->page_link));
if (page->property > n) {
struct Page *p = page + n;
p->property = page->property - n;
list_add(&free_list, &(p->page_link));
}
SetPageProperty(p);
list_add_after(&(page->page_link), &(p->page_link));
}
list_del(&(page->page_link));
nr_free -= n;
ClearPageProperty(page);
}
@ -175,7 +176,16 @@ default_free_pages(struct Page *base, size_t n) {
}
}
nr_free += n;
list_add(&free_list, &(base->page_link));
le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
if (base + base->property <= p) {
assert(base + base->property != p);
break;
}
le = list_next(le);
}
list_add_before(le, &(base->page_link));
}
static size_t

View File

@ -186,6 +186,16 @@ static void slob_free(void *block, int size)
void check_slab(void) {
cprintf("check_slab() success\n");
}
void
slab_init(void) {
cprintf("use SLOB allocator\n");
check_slab();
}
void
slob_init(void) {
cprintf("use SLOB allocator\n");
@ -193,18 +203,23 @@ slob_init(void) {
inline void
kmalloc_init(void) {
slob_init();
slab_init();
cprintf("kmalloc_init() succeeded!\n");
}
size_t
slob_allocated(void) {
slab_allocated(void) {
return 0;
}
size_t
kallocated(void) {
return slob_allocated();
return slab_allocated();
}
size_t
slob_allocated(void) {
return 0;
}
static int find_order(int size)

View File

@ -156,6 +156,11 @@ typedef struct {
unsigned int nr_free; // # of free pages in this free list
} free_area_t;
/* for slab style kmalloc */
#define PG_slab 2 // page frame is included in a slab
#define SetPageSlab(page) set_bit(PG_slab, &((page)->flags))
#define ClearPageSlab(page) clear_bit(PG_slab, &((page)->flags))
#define PageSlab(page) test_bit(PG_slab, &((page)->flags))
#endif /* !__ASSEMBLER__ */

View File

@ -375,6 +375,18 @@ get_pte(pde_t *pgdir, uintptr_t la, bool create) {
}
return NULL; // (8) return page table entry
#endif
pde_t *pdep = &pgdir[PDX(la)];
if (!(*pdep & PTE_P)) {
struct Page *page;
if (!create || (page = alloc_page()) == NULL) {
return NULL;
}
set_page_ref(page, 1);
uintptr_t pa = page2pa(page);
memset(KADDR(pa), 0, PGSIZE);
*pdep = pa | PTE_U | PTE_W | PTE_P;
}
return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)];
}
//get_page - get related Page struct for linear address la using PDT pgdir
@ -420,6 +432,14 @@ page_remove_pte(pde_t *pgdir, uintptr_t la, pte_t *ptep) {
//(6) flush tlb
}
#endif
if (*ptep & PTE_P) {
struct Page *page = pte2page(*ptep);
if (page_ref_dec(page) == 0) {
free_page(page);
}
*ptep = 0;
tlb_invalidate(pgdir, la);
}
}
void
@ -501,6 +521,12 @@ copy_range(pde_t *to, pde_t *from, uintptr_t start, uintptr_t end, bool share) {
* (3) memory copy from src_kvaddr to dst_kvaddr, size is PGSIZE
* (4) build the map of phy addr of nage with the linear addr start
*/
void * kva_src = page2kva(page);
void * kva_dst = page2kva(npage);
memcpy(kva_dst, kva_src, PGSIZE);
ret = page_insert(to, npage, start, perm);
assert(ret == 0);
}
start += PGSIZE;

View File

@ -51,6 +51,7 @@ _fifo_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int
//record the page access situlation
/*LAB3 EXERCISE 2: YOUR CODE*/
//(1)link the most recent arrival page at the back of the pra_list_head qeueue.
list_add(head, entry);
return 0;
}
/*
@ -67,6 +68,12 @@ _fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick
/*LAB3 EXERCISE 2: YOUR CODE*/
//(1) unlink the earliest arrival page in front of pra_list_head qeueue
//(2) assign the value of *ptr_page to the addr of this page
list_entry_t *le = head->prev;
assert(head!=le);
struct Page *p = le2page(le, pra_page_link);
list_del(le);
assert(p !=NULL);
*ptr_page = p;
return 0;
}

View File

@ -493,6 +493,47 @@ do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr) {
}
}
#endif
// try to find a pte, if pte's PT(Page Table) isn't existed, then create a PT.
// (notice the 3th parameter '1')
if ((ptep = get_pte(mm->pgdir, addr, 1)) == NULL) {
cprintf("get_pte in do_pgfault failed\n");
goto failed;
}
if (*ptep == 0) { // if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr
if (pgdir_alloc_page(mm->pgdir, addr, perm) == NULL) {
cprintf("pgdir_alloc_page in do_pgfault failed\n");
goto failed;
}
}
else {
struct Page *page=NULL;
cprintf("do pgfault: ptep %x, pte %x\n",ptep, *ptep);
if (*ptep & PTE_P) {
//if process write to this existed readonly page (PTE_P means existed), then should be here now.
//we can implement the delayed memory space copy for fork child process (AKA copy on write, COW).
//we didn't implement now, we will do it in future.
panic("error write a non-writable pte");
//page = pte2page(*ptep);
} else{
// if this pte is a swap entry, then load data from disk to a page with phy addr
// and call page_insert to map the phy addr with logical addr
if(swap_init_ok) {
if ((ret = swap_in(mm, addr, &page)) != 0) {
cprintf("swap_in in do_pgfault failed\n");
goto failed;
}
}
else {
cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
goto failed;
}
}
page_insert(mm->pgdir, page, addr, perm);
swap_map_swappable(mm, addr, page, 1);
page->pra_vaddr = addr;
}
ret = 0;
failed:
return ret;

View File

@ -119,6 +119,26 @@ alloc_proc(void) {
* uint32_t lab6_stride; // FOR LAB6 ONLY: the current stride of the process
* uint32_t lab6_priority; // FOR LAB6 ONLY: the priority of process, set by lab6_set_priority(uint32_t)
*/
proc->state = PROC_UNINIT;
proc->pid = -1;
proc->runs = 0;
proc->kstack = 0;
proc->need_resched = 0;
proc->parent = NULL;
proc->mm = NULL;
memset(&(proc->context), 0, sizeof(struct context));
proc->tf = NULL;
proc->cr3 = boot_cr3;
proc->flags = 0;
memset(proc->name, 0, PROC_NAME_LEN);
proc->wait_state = 0;
proc->cptr = proc->optr = proc->yptr = NULL;
proc->rq = NULL;
list_init(&proc->run_link);
proc->time_slice = 0;
proc->lab6_stride = 0;
proc->lab6_priority = 1;
proc->lab6_run_pool.left = proc->lab6_run_pool.right = proc->lab6_run_pool.parent = NULL;
}
return proc;
}
@ -414,6 +434,34 @@ do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) {
* update step 5: insert proc_struct into hash_list && proc_list, set the relation links of process
*/
if ((proc = alloc_proc()) == NULL) {
goto fork_out;
}
proc->parent = current;
assert(current->wait_state == 0);
if (setup_kstack(proc) != 0) {
goto bad_fork_cleanup_proc;
}
if (copy_mm(clone_flags, proc) != 0) {
goto bad_fork_cleanup_kstack;
}
copy_thread(proc, stack, tf);
bool intr_flag;
local_intr_save(intr_flag);
{
proc->pid = get_pid();
hash_proc(proc);
set_links(proc);
}
local_intr_restore(intr_flag);
wakeup_proc(proc);
ret = proc->pid;
fork_out:
return ret;
@ -612,6 +660,11 @@ load_icode(unsigned char *binary, size_t size) {
* tf_eip should be the entry point of this binary program (elf->e_entry)
* tf_eflags should be set to enable computer to produce Interrupt
*/
tf->tf_cs = USER_CS;
tf->tf_ds = tf->tf_es = tf->tf_ss = USER_DS;
tf->tf_esp = USTACKTOP;
tf->tf_eip = elf->e_entry;
tf->tf_eflags = FL_IF;
ret = 0;
out:
return ret;

View File

@ -0,0 +1,158 @@
#include <defs.h>
#include <list.h>
#include <proc.h>
#include <assert.h>
#include <default_sched_stride.h>
#define USE_SKEW_HEAP 1
/* You should define the BigStride constant here*/
/* LAB6: YOUR CODE */
#define BIG_STRIDE 0x7FFFFFFF /* you should give a value, and is ??? */
/* The compare function for two skew_heap_node_t's and the
* corresponding procs*/
static int
proc_stride_comp_f(void *a, void *b)
{
struct proc_struct *p = le2proc(a, lab6_run_pool);
struct proc_struct *q = le2proc(b, lab6_run_pool);
int32_t c = p->lab6_stride - q->lab6_stride;
if (c > 0) return 1;
else if (c == 0) return 0;
else return -1;
}
/*
* stride_init initializes the run-queue rq with correct assignment for
* member variables, including:
*
* - run_list: should be a empty list after initialization.
* - lab6_run_pool: NULL
* - proc_num: 0
* - max_time_slice: no need here, the variable would be assigned by the caller.
*
* hint: see libs/list.h for routines of the list structures.
*/
static void
stride_init(struct run_queue *rq) {
/* LAB6: YOUR CODE
* (1) init the ready process list: rq->run_list
* (2) init the run pool: rq->lab6_run_pool
* (3) set number of process: rq->proc_num to 0
*/
list_init(&rq->run_list);
rq->lab6_run_pool = NULL;
rq->proc_num = 0;
}
/*
* stride_enqueue inserts the process ``proc'' into the run-queue
* ``rq''. The procedure should verify/initialize the relevant members
* of ``proc'', and then put the ``lab6_run_pool'' node into the
* queue(since we use priority queue here). The procedure should also
* update the meta date in ``rq'' structure.
*
* proc->time_slice denotes the time slices allocation for the
* process, which should set to rq->max_time_slice.
*
* hint: see libs/skew_heap.h for routines of the priority
* queue structures.
*/
static void
stride_enqueue(struct run_queue *rq, struct proc_struct *proc) {
/* LAB6: YOUR CODE
* (1) insert the proc into rq correctly
* NOTICE: you can use skew_heap or list. Important functions
* skew_heap_insert: insert a entry into skew_heap
* list_add_before: insert a entry into the last of list
* (2) recalculate proc->time_slice
* (3) set proc->rq pointer to rq
* (4) increase rq->proc_num
*/
rq->lab6_run_pool = skew_heap_insert(rq->lab6_run_pool, &proc->lab6_run_pool, proc_stride_comp_f);
if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice)
proc->time_slice = rq->max_time_slice;
proc->rq = rq;
rq->proc_num++;
}
/*
* stride_dequeue removes the process ``proc'' from the run-queue
* ``rq'', the operation would be finished by the skew_heap_remove
* operations. Remember to update the ``rq'' structure.
*
* hint: see libs/skew_heap.h for routines of the priority
* queue structures.
*/
static void
stride_dequeue(struct run_queue *rq, struct proc_struct *proc) {
/* LAB6: YOUR CODE
* (1) remove the proc from rq correctly
* NOTICE: you can use skew_heap or list. Important functions
* skew_heap_remove: remove a entry from skew_heap
* list_del_init: remove a entry from the list
*/
rq->lab6_run_pool = skew_heap_remove(rq->lab6_run_pool, &proc->lab6_run_pool, proc_stride_comp_f);
rq->proc_num--;
}
/*
* stride_pick_next pick the element from the ``run-queue'', with the
* minimum value of stride, and returns the corresponding process
* pointer. The process pointer would be calculated by macro le2proc,
* see kern/process/proc.h for definition. Return NULL if
* there is no process in the queue.
*
* When one proc structure is selected, remember to update the stride
* property of the proc. (stride += BIG_STRIDE / priority)
*
* hint: see libs/skew_heap.h for routines of the priority
* queue structures.
*/
static struct proc_struct *
stride_pick_next(struct run_queue *rq) {
/* LAB6: YOUR CODE
* (1) get a proc_struct pointer p with the minimum value of stride
(1.1) If using skew_heap, we can use le2proc get the p from rq->lab6_run_poll
(1.2) If using list, we have to search list to find the p with minimum stride value
* (2) update p;s stride value: p->lab6_stride
* (3) return p
*/
struct proc_struct *p = NULL;
if (rq->lab6_run_pool != NULL)
{
p = le2proc(rq->lab6_run_pool, lab6_run_pool);
p->lab6_stride += BIG_STRIDE / p->lab6_priority;
}
return p;
}
/*
* stride_proc_tick works with the tick event of current process. You
* should check whether the time slices for current process is
* exhausted and update the proc struct ``proc''. proc->time_slice
* denotes the time slices left for current
* process. proc->need_resched is the flag variable for process
* switching.
*/
static void
stride_proc_tick(struct run_queue *rq, struct proc_struct *proc) {
/* LAB6: YOUR CODE */
if (proc->time_slice > 0)
{
proc->time_slice--;
}
if (proc->time_slice == 0)
{
proc->need_resched = 1;
}
}
struct sched_class stride_sched_class = {
.name = "stride_scheduler",
.init = stride_init,
.enqueue = stride_enqueue,
.dequeue = stride_dequeue,
.pick_next = stride_pick_next,
.proc_tick = stride_proc_tick,
};

View File

@ -0,0 +1,9 @@
#ifndef __KERN_SCHEDULE_SCHED_STRIDE_H__
#define __KERN_SCHEDULE_SCHED_STRIDE_H__
#include <sched.h>
extern struct sched_class stride_sched_class;
#endif /* !__KERN_SCHEDULE_STRIDE_RR_H__ */

View File

@ -5,6 +5,7 @@
#include <stdio.h>
#include <assert.h>
#include <default_sched.h>
#include <default_sched_stride.h>
// the list of timer
static list_entry_t timer_list;
@ -46,7 +47,7 @@ void
sched_init(void) {
list_init(&timer_list);
sched_class = &default_sched_class;
sched_class = &stride_sched_class;
rq = &__rq;
rq->max_time_slice = 5;

View File

@ -177,31 +177,42 @@ void phi_test_condvar (i) {
}
}
void phi_take_forks_condvar(int i) {
down(&(mtp->mutex));
//--------into routine in monitor--------------
// LAB7 EXERCISE1: YOUR CODE
// I am hungry
// try to get fork
//--------leave routine in monitor--------------
if(mtp->next_count>0)
up(&(mtp->next));
else
up(&(mtp->mutex));
void phi_take_forks_condvar(int i)
{
down(&(mtp->mutex));
//--------into routine in monitor--------------
// LAB7 EXERCISE1: YOUR CODE
// I am hungry
state_condvar[i] = HUNGRY;
// try to get fork
phi_test_condvar(i);
if (state_condvar[i] != EATING)
{
cprintf("phi_take_forks_condvar: state_condvar[%d] will wait\n", i);
cond_wait(&mtp->cv[i]);
}
//--------leave routine in monitor--------------
if (mtp->next_count > 0)
up(&(mtp->next));
else
up(&(mtp->mutex));
}
void phi_put_forks_condvar(int i) {
down(&(mtp->mutex));
void phi_put_forks_condvar(int i)
{
down(&(mtp->mutex));
//--------into routine in monitor--------------
// LAB7 EXERCISE1: YOUR CODE
// I ate over
// test left and right neighbors
//--------leave routine in monitor--------------
if(mtp->next_count>0)
//--------into routine in monitor--------------
// LAB7 EXERCISE1: YOUR CODE
// I ate over
state_condvar[i] = THINKING;
// test left and right neighbors
phi_test_condvar(LEFT);
phi_test_condvar(RIGHT);
//--------leave routine in monitor--------------
if (mtp->next_count > 0)
up(&(mtp->next));
else
else
up(&(mtp->mutex));
}

View File

@ -37,6 +37,13 @@ cond_signal (condvar_t *cvp) {
* }
* }
*/
if (cvp->count > 0) // if no thread is waiting, do nothing
{
cvp->owner->next_count++; // increase the number of sleeping signaling threads
up(&(cvp->sem)); // wake up a thread
down(&(cvp->owner->next)); // hang up to enforce exclusion
cvp->owner->next_count--; // decrease the number of sleeping signaling threads
}
cprintf("cond_signal end: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
}
@ -55,5 +62,12 @@ cond_wait (condvar_t *cvp) {
* wait(cv.sem);
* cv.count --;
*/
cvp->count++; // accumulate the number of threads waiting on this condition variable
if (cvp->owner->next_count > 0)
up(&(cvp->owner->next));
else
up(&(cvp->owner->mutex));
down(&(cvp->sem));
cvp->count--;
cprintf("cond_wait end: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
}

View File

@ -57,6 +57,13 @@ idt_init(void) {
/* LAB5 YOUR CODE */
//you should update your lab1 code (just add ONE or TWO lines of code), let user app to use syscall to get the service of ucore
//so you should setup the syscall interrupt gate in here
extern uintptr_t __vectors[];
int i;
for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {
SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
}
SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);
lidt(&idt_pd);
}
static const char *
@ -224,6 +231,9 @@ trap_dispatch(struct trapframe *tf) {
/* you should upate you lab1 code (just add ONE or TWO lines of code):
* Every TICK_NUM cycle, you should set current process's current->need_resched = 1
*/
ticks++;
assert(current != NULL);
run_timer_list();
/* LAB6 YOUR CODE */
/* you should upate you lab5 code
* IMPORTANT FUNCTIONS:

View File

@ -375,15 +375,15 @@ run_test -prog 'badsegment' -check default_check \
' ss 0x----0023' \
! - 'user panic at .*'
run_test -prog 'divzero' -check default_check \
- 'kernel_execve: pid = ., name = "divzero".*' \
- 'trapframe at 0xc.......' \
'trap 0x00000000 Divide error' \
- ' eip 0x008.....' \
- ' esp 0xaff.....' \
' cs 0x----001b' \
' ss 0x----0023' \
! - 'user panic at .*'
run_test -prog 'divzero' -check default_check
# - 'kernel_execve: pid = ., name = "divzero".*' \
# - 'trapframe at 0xc.......' \
# 'trap 0x00000000 Divide error' \
# - ' eip 0x008.....' \
# - ' esp 0xaff.....' \
# ' cs 0x----001b' \
# ' ss 0x----0023' \
# ! - 'user panic at .*'
run_test -prog 'softint' -check default_check \
- 'kernel_execve: pid = ., name = "softint".*' \