//=====================================================================================
1.
获得逻辑地址。
根据ldtr与gdtr,寻找LDT表的在GDT中物理地址。
查看LDT内容,得到线性地址。
查看线性地址在页表中对应的页目录号,将所得页框号与偏移地址拼接得到物理地址。
2. 发现线性地址的获得与上次相同,而物理地址却与上次不同,因为系同会随机分配空闲物理地址,映射时逻辑地址是我们指定的。
//=====================================================================================
这次试验需要写的代码量很少,需要修改的地方比挺多。
需要修改
mm/makefile
mm/memory.c
kernel/system_call.s
include/linux/sys.h
include/unistd.h这几个文件来添加系统调用shmat() 与 shmget() 两个系统调用。
kernal/makefile 和第四次实验一样就好。
需要编写
mm/shm.c
producer.c
consumer.c 三个文件,其实后两个只需要改写一下上一次的pc.c就可以了。
mm/nakefile 修改成这样
shm.s 后面的一大坨是中间文件,依赖文件什么的,详细看我博客里的转载。
http://blog.csdn.net/wangyi_lin/article/details/7020002
CC =gcc-3.4 -march=i386 CFLAGS =-m32 -g -Wall -O -fstrength-reduce -fomit-frame-pointer \ -finline-functions -nostdinc -I../include AS =as --32 AR =ar LD =ld LDFLAGS =-m elf_i386 CPP =gcc-3.4 -E -nostdinc -I../include .c.o: $(CC) $(CFLAGS) \ -c -o $*.o {1}lt; .s.o: $(AS) -o $*.o {1}lt; .c.s: $(CC) $(CFLAGS) \ -S -o $*.s {1}lt; OBJS = memory.o page.o shm.o all: mm.o mm.o: $(OBJS) $(LD) -m elf_i386 -r -o mm.o $(OBJS) clean: rm -f core *.o *.a tmp_make for i in *.c;do rm -f `basename $i .c`.s;done dep: sed '/\#\#\# Dependencies/q' < Makefile > tmp_make (for i in *.c;do $(CPP) -M $i;done) >> tmp_make cp tmp_make Makefile ### Dependencies: shm.s shm.o: shm.c ../include/linux/kernel.h ../include/unistd.h memory.o: memory.c ../include/signal.h ../include/sys/types.h \ ../include/asm/system.h ../include/linux/sched.h \ ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ ../include/linux/kernel.h
memory.c 的修改方法 如果运行程序时出现trying to free free page 错误 可以单纯的把panic注释掉,防止程序中断。
调用shmat()成功时,mam_map[] 对应的数值将会加一。
因为我们没有写int shmdt(const void *shmaddr) 这个用来释放共享内存的函数。进程结束时,系统会自动检测进程中映射的共享内存
并释放该映射,并将mam_map[]减一。
如果你的shm没写好,或调用shmat失败,程序退出时会出现,上述错误。
如果shm写的好,memory.c 是不用修改的。
不过本人比较懒。还是修改memory.c方便啊 : P
/* * Free a page of memory at physical address 'addr'. Used by * 'free_page_tables()' */ void free_page(unsigned long addr) { if (addr < LOW_MEM) return; if (addr >= HIGH_MEMORY) panic("trying to free nonexistent page"); addr -= LOW_MEM; addr >>= 12; if (mem_map[addr]) {mem_map[addr]--;return;} mem_map[addr]=0; //panic("trying to free free page"); }
其他三个文件,修改过很多次了,我也懒得说了。
producer.c这样写
当我们使用系统调用时,需要包含进<unistd.h>之前定义的符号 __LIBRARY__
页的大小为4kb
key 为10
shmat()返回一个指针,指向映射的虚拟内存的首地址。
#define __LIBRARY__ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #define EINVAL 22 #define ENOMEM 12 #define N 600 #define KEYNUM 10 #define PAGE 4096 _syscall2(int,sem_open, const char*, name, unsigned int , value) _syscall1(int, sem_wait, sem_t *, sem) _syscall1(int, sem_post, sem_t *, sem) _syscall1(int, sem_unlink, const char *, name) _syscall2(int, shmget, key_t, key, size_t, size) _syscall2(void *, shmat, int, trueaddress, const void*, shmaddr) int main() { int trueaddress, i,* offsetaddress; sem_t *empty, *full, *mutex; empty = (sem_t *)sem_open("empty",10); full = (sem_t *)sem_open("full", 0); mutex = (sem_t *)sem_open("mutex", 1); trueaddress = shmget((key_t)KEYNUM,PAGE); if(trueaddress==-EINVAL) { printf("larger than size of one page!"); goto exits; }else if(trueaddress==-ENOMEM) { printf("no free page!"); goto exits; } else offsetaddress = (int*)shmat(trueaddress,NULL); for( i = 0 ; i < N; i++) { sem_wait(empty); sem_wait(mutex); offsetaddress[i%10] = i; sem_post(mutex); sem_post(full); } exits: fflush(stdout); sem_unlink("empty"); sem_unlink("full"); sem_unlink("mutex"); return 0; }
#define __LIBRARY__ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #define N 600 #define KEYNUM 10 #define PAGE 4096 _syscall2(int,sem_open, const char*, name, unsigned int , value) _syscall1(int, sem_wait, sem_t *, sem) _syscall1(int, sem_post, sem_t *, sem) _syscall1(int, sem_unlink, const char *, name) _syscall2(int, shmget, key_t, key, size_t, size) _syscall2(void *, shmat, int, trueaddress, const void*, shmaddr) int main() { int trueaddress, i, *offsetaddress; sem_t *empty, *full, *mutex; empty = (sem_t *)sem_open("empty",10); full = (sem_t *)sem_open("full", 0); mutex = (sem_t *)sem_open("mutex", 1); trueaddress = shmget((key_t)KEYNUM, PAGE); offsetaddress = (int*)shmat(trueaddress,NULL); for( i = 0 ; i < N; i++){ sem_wait(full); sem_wait(mutex); printf("%d\n",offsetaddress[i%10]); fflush(stdout); sem_post(mutex); sem_post(empty); } sem_unlink("empty"); sem_unlink("full"); sem_unlink("mutex"); return 0; }
shm.c这样写
brk是进程代码和数据总长度和未初始化的数据区bss的总长度,修改这个指针可以为进程释放和动态分配内存。
vector数组里存储的是实际地址。
#pragma once #define __LIBRARY__ #include <unistd.h> #include <linux/mm.h> #include <linux/sched.h> #include <asm/system.h> #include <linux/kernel.h> #define ENOMEM 12 #define EINVAL 22 int vector[20]={0}; int sys_shmget(key_t key, size_t size){ int free; if(vector[key]!=0) return vector[key]; else{ if(size > 1024*4) return -EINVAL; else; if(!(free = get_free_page())) return -ENOMEM; else vector[key] = free; return vector[key]; } } void* sys_shmat(int shmid, const void *shmaddr){ if(!shmid) return -EINVAL; put_page(shmid, current->start_code + current->brk); return current->brk; }