Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
X
xv6-public
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
问题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
银宸时代
OS Lab Group
奖励实验
xv6-public
提交
f25a3f9a
提交
f25a3f9a
9月 02, 2010
创建
作者:
Austin Clements
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Rearrange vm.c so it's in logical order and prints nicely. Shorten a few…
Rearrange vm.c so it's in logical order and prints nicely. Shorten a few functions in uninteresting ways to make them fit.
上级
f53e6110
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
137 行增加
和
137 行删除
+137
-137
runoff.spec
runoff.spec
+8
-2
vm.c
vm.c
+129
-135
没有找到文件。
runoff.spec
浏览文件 @
f25a3f9a
...
@@ -42,8 +42,14 @@ odd: proc.h
...
@@ -42,8 +42,14 @@ odd: proc.h
left: proc.c # VERY important
left: proc.c # VERY important
odd: proc.c # VERY important
odd: proc.c # VERY important
# setjmp.S either
# A few more action packed spreads
# vm.c either
# page table creation and process loading
# walkpgdir mappages setupkvm vmenable switch[ku]vm inituvm loaduvm
# process memory management
# allocuvm deallocuvm freevm
right: vm.c
odd: vm.c
# kalloc.c either
# kalloc.c either
# syscall.h either
# syscall.h either
...
...
vm.c
浏览文件 @
f25a3f9a
...
@@ -6,33 +6,38 @@
...
@@ -6,33 +6,38 @@
#include "proc.h"
#include "proc.h"
#include "elf.h"
#include "elf.h"
// The mappings from logical to linear are one to one (i.e.,
// segmentation doesn't do anything).
// There is one page table per process, plus one that's used
// when a CPU is not running any process (kpgdir).
// A user process uses the same page table as the kernel; the
// page protection bits prevent it from using anything other
// than its 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..end : mapped direct (for the kernel's text and data)
// end..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).
// The virtual address space of each user program includes the kernel
// (which is inaccessible in user mode). The user program addresses
// range from 0 till 640KB (USERTOP), which where the I/O hole starts
// (both in physical memory and in the kernel's virtual address
// space).
#define USERTOP 0xA0000
#define USERTOP 0xA0000
static
pde_t
*
kpgdir
;
// for use in scheduler()
static
pde_t
*
kpgdir
;
// for use in scheduler()
// Set up CPU's kernel segment descriptors.
// Run once at boot time on each CPU.
void
ksegment
(
void
)
{
struct
cpu
*
c
;
// Map virtual addresses to linear addresses using identity map.
// Cannot share a CODE descriptor for both kernel and user
// because it would have to have DPL_USR, but the CPU forbids
// an interrupt from CPL=0 to DPL=3.
c
=
&
cpus
[
cpunum
()];
c
->
gdt
[
SEG_KCODE
]
=
SEG
(
STA_X
|
STA_R
,
0
,
0xffffffff
,
0
);
c
->
gdt
[
SEG_KDATA
]
=
SEG
(
STA_W
,
0
,
0xffffffff
,
0
);
c
->
gdt
[
SEG_UCODE
]
=
SEG
(
STA_X
|
STA_R
,
0
,
0xffffffff
,
DPL_USER
);
c
->
gdt
[
SEG_UDATA
]
=
SEG
(
STA_W
,
0
,
0xffffffff
,
DPL_USER
);
// map cpu, and curproc
c
->
gdt
[
SEG_KCPU
]
=
SEG
(
STA_W
,
&
c
->
cpu
,
8
,
0
);
lgdt
(
c
->
gdt
,
sizeof
(
c
->
gdt
));
loadgs
(
SEG_KCPU
<<
3
);
// Initialize cpu-local storage.
cpu
=
c
;
proc
=
0
;
}
// 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,
// create any required page table pages.
// create any required page table pages.
...
@@ -50,10 +55,8 @@ walkpgdir(pde_t *pgdir, const void *va, int create)
...
@@ -50,10 +55,8 @@ walkpgdir(pde_t *pgdir, const void *va, int create)
return
0
;
return
0
;
else
{
else
{
pgtab
=
(
pte_t
*
)
r
;
pgtab
=
(
pte_t
*
)
r
;
// Make sure all those PTE_P bits are zero.
// Make sure all those PTE_P bits are zero.
memset
(
pgtab
,
0
,
PGSIZE
);
memset
(
pgtab
,
0
,
PGSIZE
);
// The permissions here are overly generous, but they can
// The permissions here are overly generous, but they can
// be further restricted by the permissions in the page table
// be further restricted by the permissions in the page table
// entries, if necessary.
// entries, if necessary.
...
@@ -68,9 +71,9 @@ walkpgdir(pde_t *pgdir, const void *va, int create)
...
@@ -68,9 +71,9 @@ walkpgdir(pde_t *pgdir, const void *va, int create)
static
int
static
int
mappages
(
pde_t
*
pgdir
,
void
*
la
,
uint
size
,
uint
pa
,
int
perm
)
mappages
(
pde_t
*
pgdir
,
void
*
la
,
uint
size
,
uint
pa
,
int
perm
)
{
{
char
*
first
=
PGROUNDDOWN
(
la
);
char
*
a
=
PGROUNDDOWN
(
la
);
char
*
last
=
PGROUNDDOWN
(
la
+
size
-
1
);
char
*
last
=
PGROUNDDOWN
(
la
+
size
-
1
);
char
*
a
=
first
;
while
(
1
){
while
(
1
){
pte_t
*
pte
=
walkpgdir
(
pgdir
,
a
,
1
);
pte_t
*
pte
=
walkpgdir
(
pgdir
,
a
,
1
);
if
(
pte
==
0
)
if
(
pte
==
0
)
...
@@ -86,32 +89,75 @@ mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
...
@@ -86,32 +89,75 @@ mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
return
1
;
return
1
;
}
}
// Set up CPU's kernel segment descriptors.
// The mappings from logical to linear are one to one (i.e.,
// Run once at boot time on each CPU.
// segmentation doesn't do anything).
// There is one page table per process, plus one that's used
// when a CPU is not running any process (kpgdir).
// A user process uses the same page table as the kernel; the
// page protection bits prevent it from using anything other
// than its 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..end : mapped direct (for the kernel's text and data)
// end..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).
// The virtual address space of each user program includes the kernel
// (which is inaccessible in user mode). The user program addresses
// range from 0 till 640KB (USERTOP), which where the I/O hole starts
// (both in physical memory and in the kernel's virtual address
// space).
// Allocate one page table for the machine for the kernel address
// space for scheduler processes.
void
void
k
segment
(
void
)
k
vmalloc
(
void
)
{
{
struct
cpu
*
c
;
kpgdir
=
setupkvm
();
}
// Map virtual addresses to linear addresses using identity map.
// Set up kernel part of a page table.
// Cannot share a CODE descriptor for both kernel and user
pde_t
*
// because it would have to have DPL_USR, but the CPU forbids
setupkvm
(
void
)
// an interrupt from CPL=0 to DPL=3.
{
c
=
&
cpus
[
cpunum
()];
pde_t
*
pgdir
;
c
->
gdt
[
SEG_KCODE
]
=
SEG
(
STA_X
|
STA_R
,
0
,
0xffffffff
,
0
);
c
->
gdt
[
SEG_KDATA
]
=
SEG
(
STA_W
,
0
,
0xffffffff
,
0
);
c
->
gdt
[
SEG_UCODE
]
=
SEG
(
STA_X
|
STA_R
,
0
,
0xffffffff
,
DPL_USER
);
c
->
gdt
[
SEG_UDATA
]
=
SEG
(
STA_W
,
0
,
0xffffffff
,
DPL_USER
);
// map cpu, and curproc
// Allocate page directory
c
->
gdt
[
SEG_KCPU
]
=
SEG
(
STA_W
,
&
c
->
cpu
,
8
,
0
);
if
(
!
(
pgdir
=
(
pde_t
*
)
kalloc
()))
return
0
;
memset
(
pgdir
,
0
,
PGSIZE
);
if
(
// Map IO space from 640K to 1Mbyte
!
mappages
(
pgdir
,
(
void
*
)
USERTOP
,
0x60000
,
USERTOP
,
PTE_W
)
||
// Map kernel and free memory pool
!
mappages
(
pgdir
,
(
void
*
)
0x100000
,
PHYSTOP
-
0x100000
,
0x100000
,
PTE_W
)
||
// Map devices such as ioapic, lapic, ...
!
mappages
(
pgdir
,
(
void
*
)
0xFE000000
,
0x2000000
,
0xFE000000
,
PTE_W
))
return
0
;
return
pgdir
;
}
lgdt
(
c
->
gdt
,
sizeof
(
c
->
gdt
));
// Turn on paging.
loadgs
(
SEG_KCPU
<<
3
);
void
vmenable
(
void
)
// Initialize cpu-local storage.
{
cpu
=
c
;
uint
cr0
;
proc
=
0
;
switchkvm
();
// load kpgdir into cr3
cr0
=
rcr0
();
cr0
|=
CR0_PG
;
lcr0
(
cr0
);
}
// Switch h/w page table register to the kernel-only page table, for when
// no process is running.
void
switchkvm
()
{
lcr3
(
PADDR
(
kpgdir
));
// Switch to the kernel page table
}
}
// Switch h/w page table and TSS registers to point to process p.
// Switch h/w page table and TSS registers to point to process p.
...
@@ -134,36 +180,6 @@ switchuvm(struct proc *p)
...
@@ -134,36 +180,6 @@ switchuvm(struct proc *p)
popcli
();
popcli
();
}
}
// Switch h/w page table register to the kernel-only page table, for when
// 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
*
setupkvm
(
void
)
{
pde_t
*
pgdir
;
// Allocate page directory
if
(
!
(
pgdir
=
(
pde_t
*
)
kalloc
()))
return
0
;
memset
(
pgdir
,
0
,
PGSIZE
);
// Map IO space from 640K to 1Mbyte
if
(
!
mappages
(
pgdir
,
(
void
*
)
USERTOP
,
0x60000
,
USERTOP
,
PTE_W
))
return
0
;
// Map kernel and free memory pool
if
(
!
mappages
(
pgdir
,
(
void
*
)
0x100000
,
PHYSTOP
-
0x100000
,
0x100000
,
PTE_W
))
return
0
;
// Map devices such as ioapic, lapic, ...
if
(
!
mappages
(
pgdir
,
(
void
*
)
0xFE000000
,
0x2000000
,
0xFE000000
,
PTE_W
))
return
0
;
return
pgdir
;
}
// return the physical address that a given user address
// return the physical address that a given user address
// maps to. the result is also a kernel logical address,
// maps to. the result is also a kernel logical address,
// since the kernel maps the physical memory allocated to user
// since the kernel maps the physical memory allocated to user
...
@@ -177,6 +193,37 @@ uva2ka(pde_t *pgdir, char *uva)
...
@@ -177,6 +193,37 @@ uva2ka(pde_t *pgdir, char *uva)
return
(
char
*
)
pa
;
return
(
char
*
)
pa
;
}
}
void
inituvm
(
pde_t
*
pgdir
,
char
*
init
,
uint
sz
)
{
char
*
mem
=
kalloc
();
if
(
sz
>=
PGSIZE
)
panic
(
"inituvm: more than a page"
);
memset
(
mem
,
0
,
PGSIZE
);
mappages
(
pgdir
,
0
,
PGSIZE
,
PADDR
(
mem
),
PTE_W
|
PTE_U
);
memmove
(
mem
,
init
,
sz
);
}
int
loaduvm
(
pde_t
*
pgdir
,
char
*
addr
,
struct
inode
*
ip
,
uint
offset
,
uint
sz
)
{
uint
i
,
pa
,
n
;
pte_t
*
pte
;
if
((
uint
)
addr
%
PGSIZE
!=
0
)
panic
(
"loaduvm: addr must be page aligned
\n
"
);
for
(
i
=
0
;
i
<
sz
;
i
+=
PGSIZE
){
if
(
!
(
pte
=
walkpgdir
(
pgdir
,
addr
+
i
,
0
)))
panic
(
"loaduvm: address should exist
\n
"
);
pa
=
PTE_ADDR
(
*
pte
);
if
(
sz
-
i
<
PGSIZE
)
n
=
sz
-
i
;
else
n
=
PGSIZE
;
if
(
readi
(
ip
,
(
char
*
)
pa
,
offset
+
i
,
n
)
!=
n
)
return
0
;
}
return
1
;
}
// allocate sz bytes more memory for a process starting at the
// allocate sz bytes more memory for a process starting at the
// given user address; allocates physical memory and page
// given user address; allocates physical memory and page
// table entries. addr and sz need not be page-aligned.
// table entries. addr and sz need not be page-aligned.
...
@@ -187,10 +234,9 @@ allocuvm(pde_t *pgdir, char *addr, uint sz)
...
@@ -187,10 +234,9 @@ allocuvm(pde_t *pgdir, char *addr, uint sz)
{
{
if
(
addr
+
sz
>
(
char
*
)
USERTOP
)
if
(
addr
+
sz
>
(
char
*
)
USERTOP
)
return
0
;
return
0
;
char
*
first
=
PGROUNDDOWN
(
addr
);
char
*
a
=
PGROUNDDOWN
(
addr
);
char
*
last
=
PGROUNDDOWN
(
addr
+
sz
-
1
);
char
*
last
=
PGROUNDDOWN
(
addr
+
sz
-
1
);
char
*
a
;
for
(;
a
<=
last
;
a
+=
PGSIZE
){
for
(
a
=
first
;
a
<=
last
;
a
+=
PGSIZE
){
pte_t
*
pte
=
walkpgdir
(
pgdir
,
a
,
0
);
pte_t
*
pte
=
walkpgdir
(
pgdir
,
a
,
0
);
if
(
pte
==
0
||
(
*
pte
&
PTE_P
)
==
0
){
if
(
pte
==
0
||
(
*
pte
&
PTE_P
)
==
0
){
char
*
mem
=
kalloc
();
char
*
mem
=
kalloc
();
...
@@ -213,10 +259,9 @@ deallocuvm(pde_t *pgdir, char *addr, uint sz)
...
@@ -213,10 +259,9 @@ deallocuvm(pde_t *pgdir, char *addr, uint sz)
{
{
if
(
addr
+
sz
>
(
char
*
)
USERTOP
)
if
(
addr
+
sz
>
(
char
*
)
USERTOP
)
return
0
;
return
0
;
char
*
first
=
(
char
*
)
PGROUNDUP
((
uint
)
addr
);
char
*
a
=
(
char
*
)
PGROUNDUP
((
uint
)
addr
);
char
*
last
=
PGROUNDDOWN
(
addr
+
sz
-
1
);
char
*
last
=
PGROUNDDOWN
(
addr
+
sz
-
1
);
char
*
a
;
for
(;
a
<=
last
;
a
+=
PGSIZE
){
for
(
a
=
first
;
a
<=
last
;
a
+=
PGSIZE
){
pte_t
*
pte
=
walkpgdir
(
pgdir
,
a
,
0
);
pte_t
*
pte
=
walkpgdir
(
pgdir
,
a
,
0
);
if
(
pte
&&
(
*
pte
&
PTE_P
)
!=
0
){
if
(
pte
&&
(
*
pte
&
PTE_P
)
!=
0
){
uint
pa
=
PTE_ADDR
(
*
pte
);
uint
pa
=
PTE_ADDR
(
*
pte
);
...
@@ -246,37 +291,6 @@ freevm(pde_t *pgdir)
...
@@ -246,37 +291,6 @@ freevm(pde_t *pgdir)
kfree
((
void
*
)
pgdir
);
kfree
((
void
*
)
pgdir
);
}
}
int
loaduvm
(
pde_t
*
pgdir
,
char
*
addr
,
struct
inode
*
ip
,
uint
offset
,
uint
sz
)
{
uint
i
,
pa
,
n
;
pte_t
*
pte
;
if
((
uint
)
addr
%
PGSIZE
!=
0
)
panic
(
"loaduvm: addr must be page aligned
\n
"
);
for
(
i
=
0
;
i
<
sz
;
i
+=
PGSIZE
){
if
(
!
(
pte
=
walkpgdir
(
pgdir
,
addr
+
i
,
0
)))
panic
(
"loaduvm: address should exist
\n
"
);
pa
=
PTE_ADDR
(
*
pte
);
if
(
sz
-
i
<
PGSIZE
)
n
=
sz
-
i
;
else
n
=
PGSIZE
;
if
(
readi
(
ip
,
(
char
*
)
pa
,
offset
+
i
,
n
)
!=
n
)
return
0
;
}
return
1
;
}
void
inituvm
(
pde_t
*
pgdir
,
char
*
init
,
uint
sz
)
{
char
*
mem
=
kalloc
();
if
(
sz
>=
PGSIZE
)
panic
(
"inituvm: more than a page"
);
memset
(
mem
,
0
,
PGSIZE
);
mappages
(
pgdir
,
0
,
PGSIZE
,
PADDR
(
mem
),
PTE_W
|
PTE_U
);
memmove
(
mem
,
init
,
sz
);
}
// given a parent process's page table, create a copy
// given a parent process's page table, create a copy
// of it for a child.
// of it for a child.
pde_t
*
pde_t
*
...
@@ -307,23 +321,3 @@ bad:
...
@@ -307,23 +321,3 @@ bad:
return
0
;
return
0
;
}
}
// Allocate one page table for the machine for the kernel address
// space for scheduler processes.
void
kvmalloc
(
void
)
{
kpgdir
=
setupkvm
();
}
// Turn on paging.
void
vmenable
(
void
)
{
uint
cr0
;
switchkvm
();
// load kpgdir into cr3
cr0
=
rcr0
();
cr0
|=
CR0_PG
;
lcr0
(
cr0
);
}
编写
预览
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论