Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
X
xv6-public
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
问题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
银宸时代
OS Lab Group
奖励实验
xv6-public
提交
c4cc10da
提交
c4cc10da
8月 06, 2010
创建
作者:
Robert Morris
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix corner cases in exec of ELF
put an invalid page below the stack have fork() handle invalid pages
上级
1afc9d3f
隐藏空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
84 行增加
和
37 行删除
+84
-37
defs.h
defs.h
+2
-1
exec.c
exec.c
+5
-2
kalloc.c
kalloc.c
+2
-3
mmu.h
mmu.h
+0
-1
proc.c
proc.c
+5
-5
proc.h
proc.h
+3
-2
usertests.c
usertests.c
+24
-0
vm.c
vm.c
+43
-23
没有找到文件。
defs.h
浏览文件 @
c4cc10da
...
@@ -163,7 +163,8 @@ void freevm(pde_t*);
...
@@ -163,7 +163,8 @@ void freevm(pde_t*);
void
inituvm
(
pde_t
*
,
char
*
,
char
*
,
uint
);
void
inituvm
(
pde_t
*
,
char
*
,
char
*
,
uint
);
int
loaduvm
(
pde_t
*
,
char
*
,
struct
inode
*
ip
,
uint
,
uint
);
int
loaduvm
(
pde_t
*
,
char
*
,
struct
inode
*
ip
,
uint
,
uint
);
pde_t
*
copyuvm
(
pde_t
*
,
uint
);
pde_t
*
copyuvm
(
pde_t
*
,
uint
);
void
loadvm
(
struct
proc
*
);
void
switchuvm
(
struct
proc
*
);
void
switchkvm
();
// number of elements in fixed-size array
// number of elements in fixed-size array
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
exec.c
浏览文件 @
c4cc10da
...
@@ -43,13 +43,16 @@ exec(char *path, char **argv)
...
@@ -43,13 +43,16 @@ exec(char *path, char **argv)
goto
bad
;
goto
bad
;
if
(
!
allocuvm
(
pgdir
,
(
char
*
)
ph
.
va
,
ph
.
memsz
))
if
(
!
allocuvm
(
pgdir
,
(
char
*
)
ph
.
va
,
ph
.
memsz
))
goto
bad
;
goto
bad
;
sz
+=
PGROUNDUP
(
ph
.
memsz
);
if
(
ph
.
va
+
ph
.
memsz
>
sz
)
sz
=
ph
.
va
+
ph
.
memsz
;
if
(
!
loaduvm
(
pgdir
,
(
char
*
)
ph
.
va
,
ip
,
ph
.
offset
,
ph
.
filesz
))
if
(
!
loaduvm
(
pgdir
,
(
char
*
)
ph
.
va
,
ip
,
ph
.
offset
,
ph
.
filesz
))
goto
bad
;
goto
bad
;
}
}
iunlockput
(
ip
);
iunlockput
(
ip
);
// Allocate and initialize stack at sz
// Allocate and initialize stack at sz
sz
=
PGROUNDUP
(
sz
);
sz
+=
PGSIZE
;
// leave an invalid page
if
(
!
allocuvm
(
pgdir
,
(
char
*
)
sz
,
PGSIZE
))
if
(
!
allocuvm
(
pgdir
,
(
char
*
)
sz
,
PGSIZE
))
goto
bad
;
goto
bad
;
mem
=
uva2ka
(
pgdir
,
(
char
*
)
sz
);
mem
=
uva2ka
(
pgdir
,
(
char
*
)
sz
);
...
@@ -95,7 +98,7 @@ exec(char *path, char **argv)
...
@@ -95,7 +98,7 @@ exec(char *path, char **argv)
proc
->
tf
->
eip
=
elf
.
entry
;
// main
proc
->
tf
->
eip
=
elf
.
entry
;
// main
proc
->
tf
->
esp
=
sp
;
proc
->
tf
->
esp
=
sp
;
load
vm
(
proc
);
switchu
vm
(
proc
);
freevm
(
oldpgdir
);
freevm
(
oldpgdir
);
...
...
kalloc.c
浏览文件 @
c4cc10da
// Physical memory allocator, intended to allocate
// Physical memory allocator, intended to allocate
// memory for user processes. Allocates in 4096-byte
"pages"
.
// memory for user processes. Allocates in 4096-byte
pages
.
// Free list is kept sorted and combines adjacent pages into
// Free list is kept sorted and combines adjacent pages into
// long runs, to make it easier to allocate big segments.
// long runs, to make it easier to allocate big segments.
// One reason the page size is 4k is that the x86 segment size
// This combining is not useful now that xv6 uses paging.
// granularity is 4k.
#include "types.h"
#include "types.h"
#include "defs.h"
#include "defs.h"
...
...
mmu.h
浏览文件 @
c4cc10da
...
@@ -129,7 +129,6 @@ struct segdesc {
...
@@ -129,7 +129,6 @@ struct segdesc {
#define PTE_ADDR(pte) ((uint) (pte) & ~0xFFF)
#define PTE_ADDR(pte) ((uint) (pte) & ~0xFFF)
typedef
uint
pte_t
;
typedef
uint
pte_t
;
extern
pde_t
*
kpgdir
;
// Control Register flags
// Control Register flags
#define CR0_PE 0x00000001 // Protection Enable
#define CR0_PE 0x00000001 // Protection Enable
...
...
proc.c
浏览文件 @
c4cc10da
...
@@ -145,7 +145,7 @@ growproc(int n)
...
@@ -145,7 +145,7 @@ growproc(int n)
if
(
!
allocuvm
(
proc
->
pgdir
,
(
char
*
)
proc
->
sz
,
n
))
if
(
!
allocuvm
(
proc
->
pgdir
,
(
char
*
)
proc
->
sz
,
n
))
return
-
1
;
return
-
1
;
proc
->
sz
+=
n
;
proc
->
sz
+=
n
;
load
vm
(
proc
);
switchu
vm
(
proc
);
return
0
;
return
0
;
}
}
...
@@ -214,9 +214,10 @@ scheduler(void)
...
@@ -214,9 +214,10 @@ scheduler(void)
// to release ptable.lock and then reacquire it
// to release ptable.lock and then reacquire it
// before jumping back to us.
// before jumping back to us.
proc
=
p
;
proc
=
p
;
load
vm
(
p
);
switchu
vm
(
p
);
p
->
state
=
RUNNING
;
p
->
state
=
RUNNING
;
swtch
(
&
cpu
->
scheduler
,
proc
->
context
);
swtch
(
&
cpu
->
scheduler
,
proc
->
context
);
switchkvm
();
// Process is done running for now.
// Process is done running for now.
// It should have changed its p->state before coming back.
// It should have changed its p->state before coming back.
...
@@ -242,7 +243,6 @@ sched(void)
...
@@ -242,7 +243,6 @@ sched(void)
panic
(
"sched running"
);
panic
(
"sched running"
);
if
(
readeflags
()
&
FL_IF
)
if
(
readeflags
()
&
FL_IF
)
panic
(
"sched interruptible"
);
panic
(
"sched interruptible"
);
lcr3
(
PADDR
(
kpgdir
));
// Switch to the kernel page table
intena
=
cpu
->
intena
;
intena
=
cpu
->
intena
;
swtch
(
&
proc
->
context
,
cpu
->
scheduler
);
swtch
(
&
proc
->
context
,
cpu
->
scheduler
);
cpu
->
intena
=
intena
;
cpu
->
intena
=
intena
;
...
@@ -414,8 +414,8 @@ wait(void)
...
@@ -414,8 +414,8 @@ wait(void)
// Found one.
// Found one.
pid
=
p
->
pid
;
pid
=
p
->
pid
;
kfree
(
p
->
kstack
,
KSTACKSIZE
);
kfree
(
p
->
kstack
,
KSTACKSIZE
);
p
->
kstack
=
0
;
p
->
kstack
=
0
;
freevm
(
p
->
pgdir
);
freevm
(
p
->
pgdir
);
p
->
state
=
UNUSED
;
p
->
state
=
UNUSED
;
p
->
pid
=
0
;
p
->
pid
=
0
;
p
->
parent
=
0
;
p
->
parent
=
0
;
...
...
proc.h
浏览文件 @
c4cc10da
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
// Contexts are stored at the bottom of the stack they
// Contexts are stored at the bottom of the stack they
// describe; the stack pointer is the address of the context.
// describe; the stack pointer is the address of the context.
// The layout of the context matches the layout of the stack in swtch.S
// The layout of the context matches the layout of the stack in swtch.S
// at
"Switch stacks" comment. Switch itself
doesn't save eip explicitly,
// at
the "Switch stacks" comment. Switch
doesn't save eip explicitly,
// but it is on the stack and allocproc() manipulates it.
// but it is on the stack and allocproc() manipulates it.
struct
context
{
struct
context
{
uint
edi
;
uint
edi
;
...
@@ -31,7 +31,7 @@ enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
...
@@ -31,7 +31,7 @@ enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
// Per-process state
// Per-process state
struct
proc
{
struct
proc
{
uint
sz
;
// Size of process memory (bytes)
uint
sz
;
// Size of process memory (bytes)
pde_t
*
pgdir
;
//
l
inear address of proc's pgdir
pde_t
*
pgdir
;
//
L
inear address of proc's pgdir
char
*
kstack
;
// Bottom of kernel stack for this process
char
*
kstack
;
// Bottom of kernel stack for this process
enum
procstate
state
;
// Process state
enum
procstate
state
;
// Process state
volatile
int
pid
;
// Process ID
volatile
int
pid
;
// Process ID
...
@@ -48,6 +48,7 @@ struct proc {
...
@@ -48,6 +48,7 @@ struct proc {
// Process memory is laid out contiguously, low addresses first:
// Process memory is laid out contiguously, low addresses first:
// text
// text
// original data and bss
// original data and bss
// invalid page
// fixed-size stack
// fixed-size stack
// expandable heap
// expandable heap
...
...
usertests.c
浏览文件 @
c4cc10da
...
@@ -1261,6 +1261,29 @@ sbrktest(void)
...
@@ -1261,6 +1261,29 @@ sbrktest(void)
printf
(
stdout
,
"sbrk test OK
\n
"
);
printf
(
stdout
,
"sbrk test OK
\n
"
);
}
}
void
stacktest
(
void
)
{
printf
(
stdout
,
"stack test
\n
"
);
char
dummy
=
1
;
char
*
p
=
&
dummy
;
int
ppid
=
getpid
();
int
pid
=
fork
();
if
(
pid
<
0
){
printf
(
stdout
,
"fork failed
\n
"
);
exit
();
}
if
(
pid
==
0
){
// should cause a trap:
p
[
-
4096
]
=
'z'
;
kill
(
ppid
);
printf
(
stdout
,
"stack test failed: page before stack was writeable
\n
"
);
exit
();
}
wait
();
printf
(
stdout
,
"stack test OK
\n
"
);
}
int
int
main
(
int
argc
,
char
*
argv
[])
main
(
int
argc
,
char
*
argv
[])
{
{
...
@@ -1272,6 +1295,7 @@ main(int argc, char *argv[])
...
@@ -1272,6 +1295,7 @@ main(int argc, char *argv[])
}
}
close
(
open
(
"usertests.ran"
,
O_CREATE
));
close
(
open
(
"usertests.ran"
,
O_CREATE
));
stacktest
();
sbrktest
();
sbrktest
();
opentest
();
opentest
();
...
...
vm.c
浏览文件 @
c4cc10da
...
@@ -8,13 +8,20 @@
...
@@ -8,13 +8,20 @@
// The mappings from logical to linear are one to one (i.e.,
// The mappings from logical to linear are one to one (i.e.,
// segmentation doesn't do anything).
// segmentation doesn't do anything).
// The mapping from linear to physical are one to one for the kernel.
// There is one page table per process, plus one that's used
// The mappings for the kernel include all of physical memory (until
// when a CPU is not running any process (kpgdir).
// PHYSTOP), including the I/O hole, and the top of physical address
// A user process uses the same page table as the kernel; the
// space, where additional devices are located.
// page protection bits prevent it from using anything other
// The kernel itself is linked to be at 1MB, and its physical memory
// than its memory.
// is also at 1MB.
//
// Physical memory for user programs is allocated from physical memory
// setupkvm() and exec() set up every page table like this:
// 0..640K : user memory (text, data, stack, heap)
// 640K..1M : mapped direct (for IO space)
// 1M..kernend : mapped direct (for the kernel's text and data)
// kernend..PHYSTOP : mapped direct (kernel heap and user pages)
// 0xfe000000..0 : mapped direct (devices such as ioapic)
//
// The kernel allocates memory for its heap and for user memory
// between kernend and the end of physical memory (PHYSTOP).
// between kernend and the end of physical memory (PHYSTOP).
// The virtual address space of each user program includes the kernel
// The virtual address space of each user program includes the kernel
// (which is inaccessible in user mode). The user program addresses
// (which is inaccessible in user mode). The user program addresses
...
@@ -31,7 +38,7 @@ static uint kerndata;
...
@@ -31,7 +38,7 @@ static uint kerndata;
static
uint
kerndsz
;
static
uint
kerndsz
;
static
uint
kernend
;
static
uint
kernend
;
static
uint
freesz
;
static
uint
freesz
;
pde_t
*
kpgdir
;
// One kernel page table for scheduler procs
static
pde_t
*
kpgdir
;
// for use in scheduler()
// return the address of the PTE in page table pgdir
// return the address of the PTE in page table pgdir
// that corresponds to linear address va. if create!=0,
// that corresponds to linear address va. if create!=0,
...
@@ -114,9 +121,9 @@ ksegment(void)
...
@@ -114,9 +121,9 @@ ksegment(void)
proc
=
0
;
proc
=
0
;
}
}
// S
etup address space and current process task state
.
// S
witch h/w page table and TSS registers to point to process p
.
void
void
load
vm
(
struct
proc
*
p
)
switchu
vm
(
struct
proc
*
p
)
{
{
pushcli
();
pushcli
();
...
@@ -128,14 +135,21 @@ loadvm(struct proc *p)
...
@@ -128,14 +135,21 @@ loadvm(struct proc *p)
ltr
(
SEG_TSS
<<
3
);
ltr
(
SEG_TSS
<<
3
);
if
(
p
->
pgdir
==
0
)
if
(
p
->
pgdir
==
0
)
panic
(
"
load
vm: no pgdir
\n
"
);
panic
(
"
switchu
vm: no pgdir
\n
"
);
lcr3
(
PADDR
(
p
->
pgdir
));
// switch to new address space
lcr3
(
PADDR
(
p
->
pgdir
));
// switch to new address space
popcli
();
popcli
();
}
}
// Setup kernel part of a page table. Linear adresses map one-to-one
// Switch h/w page table register to the kernel-only page table, for when
// on physical addresses.
// no process is running.
void
switchkvm
()
{
lcr3
(
PADDR
(
kpgdir
));
// Switch to the kernel page table
}
// Set up kernel part of a page table.
pde_t
*
pde_t
*
setupkvm
(
void
)
setupkvm
(
void
)
{
{
...
@@ -163,6 +177,10 @@ setupkvm(void)
...
@@ -163,6 +177,10 @@ setupkvm(void)
return
pgdir
;
return
pgdir
;
}
}
// return the physical address that a given user address
// maps to. the result is also a kernel logical address,
// since the kernel maps the physical memory allocated to user
// processes directly.
char
*
char
*
uva2ka
(
pde_t
*
pgdir
,
char
*
uva
)
uva2ka
(
pde_t
*
pgdir
,
char
*
uva
)
{
{
...
@@ -266,6 +284,8 @@ inituvm(pde_t *pgdir, char *addr, char *init, uint sz)
...
@@ -266,6 +284,8 @@ inituvm(pde_t *pgdir, char *addr, char *init, uint sz)
}
}
}
}
// given a parent process's page table, create a copy
// of it for a child.
pde_t
*
pde_t
*
copyuvm
(
pde_t
*
pgdir
,
uint
sz
)
copyuvm
(
pde_t
*
pgdir
,
uint
sz
)
{
{
...
@@ -278,17 +298,20 @@ copyuvm(pde_t *pgdir, uint sz)
...
@@ -278,17 +298,20 @@ copyuvm(pde_t *pgdir, uint sz)
for
(
i
=
0
;
i
<
sz
;
i
+=
PGSIZE
)
{
for
(
i
=
0
;
i
<
sz
;
i
+=
PGSIZE
)
{
if
(
!
(
pte
=
walkpgdir
(
pgdir
,
(
void
*
)
i
,
0
)))
if
(
!
(
pte
=
walkpgdir
(
pgdir
,
(
void
*
)
i
,
0
)))
panic
(
"copyuvm: pte should exist
\n
"
);
panic
(
"copyuvm: pte should exist
\n
"
);
pa
=
PTE_ADDR
(
*
pte
);
if
(
*
pte
&
PTE_P
){
if
(
!
(
mem
=
kalloc
(
PGSIZE
)))
pa
=
PTE_ADDR
(
*
pte
);
return
0
;
if
(
!
(
mem
=
kalloc
(
PGSIZE
)))
memmove
(
mem
,
(
char
*
)
pa
,
PGSIZE
);
return
0
;
if
(
!
mappages
(
d
,
(
void
*
)
i
,
PGSIZE
,
PADDR
(
mem
),
PTE_W
|
PTE_U
))
memmove
(
mem
,
(
char
*
)
pa
,
PGSIZE
);
return
0
;
if
(
!
mappages
(
d
,
(
void
*
)
i
,
PGSIZE
,
PADDR
(
mem
),
PTE_W
|
PTE_U
))
return
0
;
}
}
}
return
d
;
return
d
;
}
}
// Gather about physical memory layout. Called once during boot.
// Gather information about physical memory layout.
// Called once during boot.
void
void
pminit
(
void
)
pminit
(
void
)
{
{
...
@@ -307,9 +330,6 @@ pminit(void)
...
@@ -307,9 +330,6 @@ pminit(void)
kerndsz
=
ph
[
1
].
memsz
;
kerndsz
=
ph
[
1
].
memsz
;
freesz
=
PHYSTOP
-
kernend
;
freesz
=
PHYSTOP
-
kernend
;
cprintf
(
"kerntext@0x%x(sz=0x%x), kerndata@0x%x(sz=0x%x), kernend 0x%x freesz = 0x%x
\n
"
,
kerntext
,
kerntsz
,
kerndata
,
kerndsz
,
kernend
,
freesz
);
kinit
((
char
*
)
kernend
,
freesz
);
kinit
((
char
*
)
kernend
,
freesz
);
}
}
...
...
编写
预览
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论