对于地址映射实验部分,列出你认为最重要的那几步(不超过4步),并给出你获得的实验数据。
答:第一步为找到需要的各个选择符,DS:S=0X0017,LDT:s=0x0068,GDT:BASE=0X0000 5CB8。第二步为找到数据段的基址。实验中进程的NR为4,即第5个进程,所以按照LINUX 0.11的设计,其基址应为 4*64M,转换为16进制即为0x1000 0000。实验结果也验证了这一点。第三步根据找到的线性地址,通过查看页目录表就可以找到对应页表的物理地地址。实验中页表的物理地址为0x00fa 70000。 第四步根据找到的页表所对就应的物理地址就可以找到变量所在页的物理地址。实验中变量所在页的物理地址为0x00fa6000。这里有个很有趣的现象,页表的物理地址比具体一页的物理地址高。而页表一定是先分配的内存,这也说明linux 0.11中物理内存的分配是从高到低进行的。这一点通过查看get_free_page函数得到印证。
test.c退出后,如果马上再运行一次,并再进行地址跟踪,你发现有哪些异同?为什么?
答:若马上再运行一次,则可以看到得到的线性地址为0x1400 3004,即进程的数据段基地多了0x0400 0000。就是多了一个64M。这也正是linux 0.11中对进程线性地址分配的方法即:nr*64M。因为马上运行此时进程4并没有被删除,而只是状态个性为3,所以再运行的进程正好是5。所以其分配的线性地址基址为0x1400 0000。
cd ~/oslab
tar -zxvf hit-oslab-linux-20110823.tar.gz -C /home/shiyanlou
ls -al
copy
#include <stdio.h>
int i = 0x12345678;
int main(void)
{
printf("The logical/virtual address of i is 0x%08x", &i);
fflush(stdout);
while (i)
;
return 0;
}
copy
gcc -o test test.c
./test
copy
#define SHM_SIZE 64
typedef struct shm_ds
{
unsigned int key;
unsigned int size;
unsigned long page;
}shm_ds;
int sys_shmget(unsigned int key,size_t size);
void * sys_shmat(int shmid);
copy
#define __NR_shmget 76
#define __NR_shmat 77
copy
extern int sys_shmget();
extern int sys_shmat();
/*sys_sem_unlink,*/sys_shmget, sys_shmat/*};*/
copy
#define __LIBRARY__
#include <unistd.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <errno.h>
static shm_ds shm_list[SHM_SIZE] = {{0,0,0}};
int sys_shmget(unsigned int key, size_t size)
{
int i;
void *page;
if(size > PAGE_SIZE)
return -EINVAL;
page = get_free_page();
if(!page)
return -ENOMEM;
printk("shmget get memory's address is 0x%08x\n",page);
for(i=0; i<SHM_SIZE; i++)
{
if(shm_list[i].key == key)
return i;
}
for(i=0; i<SHM_SIZE; i++)
{
if(shm_list[i].key == 0)
{
shm_list[i].page = page;
shm_list[i].key = key;
shm_list[i].size = size;
return i;
}
}
return -1;
}
void * sys_shmat(int shmid)
{
int i;
unsigned long data_base, brk;
if(shmid < 0 || SHM_SIZE <= shmid || shm_list[shmid].page==0 || shm_list[shmid].key <= 0)
return (void *)-EINVAL;
data_base = get_base(current->ldt[2]);
printk("current's data_base = 0x%08x,new page = 0x%08x\n",data_base,shm_list[shmid].page);
brk = current->brk + data_base;
current->brk += PAGE_SIZE;
if(put_page(shm_list[shmid].page, brk) == 0)
return (void *)-ENOMEM;
return (void *)(current->brk - PAGE_SIZE);
}
copy
OBJS=.......sem.o
.....
### Dependencies:
sem.s sem.o: sem.c ../include/linux/sem.h ../include/linux/kernel.h \
../include/unistd.h
shm.s shm.o:shm.c ../include/unistd.h ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/mm.h ../include/errno.h
...
copy
#define __LIBRARY__
#include <stdio.h>
#include <unistd.h>
#include <linux/kernel.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/sem.h>
_syscall2(sem_t *,sem_open,const char *,name,int,value);
_syscall1(int,sem_post,sem_t *,sem);
_syscall1(int,sem_wait,sem_t *,sem);
_syscall1(int, shmat, int, shmid);
_syscall2(int, shmget, unsigned int, key, size_t, size);
#define PRODUCE_NUM 200
#define BUFFER_SIZE 10
#define SHM_KEY 2018
int main(int argc, char* argv[])
{
sem_t *Empty,*Full,*Mutex;
int i, shm_id, location=0;
int *p;
Empty = sem_open("Empty", BUFFER_SIZE);
Full = sem_open("Full", 0);
Mutex = sem_open("Mutex", 1);
if((shm_id = shmget(SHM_KEY, BUFFER_SIZE*sizeof(int))) < 0)
printf("shmget failed!");
if((p = (int * )shmat(shm_id)) < 0)
printf("shmat error!");
for(i=0; i<PRODUCE_NUM; i++)
{
sem_wait(Empty);
sem_wait(Mutex);
p[location] = i;
sem_post(Mutex);
sem_post(Full);
location = (location+1) % BUFFER_SIZE;
}
return 0;
}
copy
#define __LIBRARY__
#include <stdio.h>
#include <unistd.h>
#include <linux/kernel.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/sem.h>
_syscall2(sem_t *,sem_open,const char *,name,int,value);
_syscall1(int,sem_post,sem_t *,sem);
_syscall1(int,sem_wait,sem_t *,sem);
_syscall1(int,sem_unlink,const char*,name);
_syscall1(int, shmat, int, shmid);
_syscall2(int, shmget, unsigned int, key, size_t, size);
#define PRODUCE_NUM 200
#define BUFFER_SIZE 10
#define SHM_KEY 2018
int main(int argc, char* argv[])
{
sem_t *Empty,*Full,*Mutex;
int used = 0, shm_id,location = 0;
int *p;
Empty = sem_open("Empty", BUFFER_SIZE);
Full = sem_open("Full", 0);
Mutex = sem_open("Mutex", 1);
if((shm_id = shmget(SHM_KEY, BUFFER_SIZE*sizeof(int))) < 0)
printf("shmget failed!\n");
if((p = (int * )shmat(shm_id)) < 0)
printf("link error!\n");
while(1)
{
sem_wait(Full);
sem_wait(Mutex);
printf("pid %d:\tconsumer consumes item %d\n", getpid(), p[location]);
fflush(stdout);
sem_post(Mutex);
sem_post(Empty);
location = (location+1) % BUFFER_SIZE;
if(++used == PRODUCE_NUM)
break;
}
sem_unlink("Mutex");
sem_unlink("Full");
sem_unlink("Empty");
return 0;
}
copy
gcc -o pro producer.c
gcc -o con consumer.c
copy
pro > proOutput &
con > conOutput &
sync
copy
这次实验使我对操作系统的段、页式内存管理,深入理解段表、页表、逻辑地址、线性地址、物理地址等概念更加理解透彻。
学习时间 301分钟
操作时间 41分钟
按键次数 251次
实验次数 12次
报告字数 7936字
是否完成 完成