日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

虚拟地址如何访问到物理地址

發(fā)布時(shí)間:2023/12/18 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 虚拟地址如何访问到物理地址 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

環(huán)境:32bit CPU
一、通過(guò)二級(jí)頁(yè)表映射的方式訪問物理地址

1、取一級(jí)頁(yè)表的基地址Abase1
2、取虛擬地址的前12bit[31:20]地址O1
3、計(jì)算得到新地址Apgd=(Abase1&0xFFFFF000)+O1,此地址是PGD頁(yè)表上的地址,取此地址中的數(shù)據(jù)Abase2
4、取虛擬地址的中間8bit[19:12]地址O2
5、計(jì)算得到新地址Apte=(Abase2&0xFFFFFF00)+O2,此地址是PTE頁(yè)表上的地址,取此地址中的數(shù)據(jù)Abase3
6、取虛擬地址的后12bit[11:0]地址O3
7、計(jì)算得到新地址Aphy=(Abase3&0xFFFFF000)+O3,此地址就是實(shí)實(shí)在在的物理地址
以上的計(jì)算和查找過(guò)程有MMU模塊實(shí)現(xiàn),同時(shí)會(huì)把映射信息存放在MMU中的TLB中,類似于cache,方便下次快速的查找。
二、疑問
1、一級(jí)頁(yè)表的基地址存放在什么地方?
2、如何找到存放在物理地址的信息?
三、分析問題
1、操作系統(tǒng)有個(gè)專門的結(jié)構(gòu)體負(fù)責(zé)進(jìn)程的內(nèi)存使用情況,task_struct里面的mm_struct

struct task_struct {......int on_rq;int prio, static_prio, normal_prio;unsigned int rt_priority;const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt;......struct mm_struct *mm, *active_mm;struct mm_struct {......unsigned long mmap_base; /* base of mmap area */unsigned long mmap_legacy_base; /* base of mmap area in bottom-up allocations */unsigned long task_size; /* size of task vm space */unsigned long highest_vm_end; /* highest vma end address */pgd_t * pgd;atomic_t mm_users; /* How many users with user space? */atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */atomic_long_t nr_ptes; /* PTE page table pages */......

其中pgd保存的就是一級(jí)頁(yè)表的基地址。進(jìn)程切換時(shí),會(huì)把TTBRx寄存器(上圖所示)保存起來(lái),把下一個(gè)進(jìn)程的pgd內(nèi)容寫到TTBRx寄存器中。
2、寫段程序,找到存放信息的物理地址
2.1、內(nèi)核態(tài)代碼
根據(jù)上面所描述的頁(yè)表映射方式,查找到虛擬地址對(duì)應(yīng)的物理地址
需要在內(nèi)核態(tài)下面運(yùn)行,內(nèi)核態(tài)下可以獲取當(dāng)前進(jìn)程的PCB task_struct進(jìn)而獲取mm_struct內(nèi)存管理模塊

#include <linux/init_task.h> unsigned int get_phy_addr(struct mm_struct *mm, unsigned long addr) {pgd_t *pgd = NULL;pud_t *pud = NULL;pmd_t *pmd = NULL;pte_t *pte = NULL;unsigned int phy_addr = 0;printk("pgd_base = %p\n",mm->pgd);pgd = pgd_offset(mm, addr); //一級(jí)頁(yè)表項(xiàng)的地址printk("vaddr=[0x%08x] *pgd=%08x\n", addr, pgd_val(*pgd));if (pgd_none(*pgd))goto out;if (pgd_bad(*pgd)) {printk("pgd bad\n");goto out;}pud = pud_offset(pgd, addr);printk("pud=0x%08x,*pud=%08x\n", pud, pud_val(*pud));if (pud_none(*pud))goto out;if (pud_bad(*pud)) {printk("pud bad");goto out;}pmd = pmd_offset(pud, addr);printk("pmd=0x%08x,*pmd=%08x\n", pmd, pmd_val(*pmd));if (pmd_none(*pmd))goto out;if (pmd_bad(*pmd)) {printk("(bad)");goto out;}//二級(jí)映射,pmd等于pgd。函數(shù)中實(shí)現(xiàn)兩個(gè)功能:1、根據(jù)pgd地址查找二級(jí)頁(yè)表基地址;2、二級(jí)頁(yè)表基地址和addr算出二級(jí)頁(yè)表地址pte = pte_offset_map(pmd, addr); printk("pte=0x%08x, *pte=%08x\n", pte, pte_val(*pte));if(!pte_none(*pte) && pte_present(*pte)) {phy_addr = (pte_val(*pte) & 0xFFFFF000) | (addr & 0xFFF);printk("phy_addr is 0x%x\n", phy_addr);}else{printk("pte is not present\n") ;}pte_unmap(pte);return phy_addr; out:return -1; }

2.2、/dev/mem節(jié)點(diǎn)說(shuō)明
知道虛擬地址對(duì)應(yīng)的物理地址,我們就可以借助/dev/mem節(jié)點(diǎn)訪問對(duì)應(yīng)的物理地址查看是否是虛擬地址存放的數(shù)據(jù)。
/dev/mem是系統(tǒng)物理內(nèi)存的映像文件,這里的物理內(nèi)存是指我們插在內(nèi)存槽上的內(nèi)存條嗎?當(dāng)然是,但物理內(nèi)存不單單指內(nèi)存條。
物理內(nèi)存嚴(yán)格來(lái)講應(yīng)該是指 物理地址空間 ,內(nèi)存條只是映射到這個(gè)地址空間的一部分,其余的還有各種PCI設(shè)備,IO端口等。
我們可以從/proc/iomem中看到這個(gè)映射:

cat /proc/iomem


其中 內(nèi)存分配的物理地址是0x80000000~0x83FFFFFF 64M
事實(shí)上,它就是一個(gè)活著的Linux系統(tǒng)實(shí)時(shí)映像,所有的進(jìn)程task_struct結(jié)構(gòu)體,sock結(jié)構(gòu)體,sk_buff結(jié)構(gòu)體,進(jìn)程數(shù)據(jù)等等都在里面的某個(gè)位置:

如果能定位它們?cè)?dev/mem里的位置,我們就能得到系統(tǒng)中這些數(shù)據(jù)結(jié)構(gòu)的實(shí)時(shí)值,所謂的調(diào)試工具所做的也不過(guò)如此。其實(shí)我們?cè)谡{(diào)試內(nèi)核轉(zhuǎn)儲(chǔ)文件的時(shí)候,vmcore也是一個(gè)物理內(nèi)存映像,和/dev/mem不同的是,它是一具尸體。
無(wú)論是活體,還是尸體,均五臟俱全,分析它們的手段是一致。和靜態(tài)分析vmcore不同的是,/dev/mem是一個(gè)動(dòng)態(tài)的內(nèi)存映像,有時(shí)候借助它可以做一些正經(jīng)的事情。
2.3、應(yīng)用層獲取/dev/mem的映射

#include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h>int main(int argc, char *argv[]) {int i = 0, fd = 0;unsigned int addr = 0, content = 0;unsigned int page_size = getpagesize();unsigned int taddr = 0;unsigned int *map_base = NULL;unsigned int offset_in_page = 0;printf("page_size=0x%x\n", page_size);fd = open("/dev/mem", O_RDWR|O_SYNC);if (fd == -1) {printf("open /dev/mem error.\n");return -1;}taddr = strtoll(argv[1], NULL, 16);offset_in_page = taddr & (page_size - 1);//map_base = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, taddr & (~(unsigned int)(page_size - 1)));map_base = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, fd, taddr & (~(unsigned int)(page_size - 1)));if (-1 == (int)map_base) {printf("mmap failed!, errno=%d\n", errno);close(fd);return -1;}printf("map_base=0x%x\n", map_base);addr = (unsigned int)(((unsigned char *)map_base) + offset_in_page);printf("addressx:0x%x\n", addr);printf("content 0x%x\n\n", *(unsigned int *)(addr));//*(unsigned int *)(addr) = 0x6f6a6944;close(fd);munmap(map_base, page_size);return 1; }

2.4、測(cè)試程序

測(cè)試程序: int main(int argc, char** argv) {int fd = -1;struct param_s param;char *buf = "Chinaxxxxx.\n";memset(&param, 0x00, sizeof(struct ty_motor_param_s));fd = open("/dev/motor", O_RDWR);if (fd < 0) {printf("open error.\n");return 0;}printf("buf=0x%x", buf);param.addr = buf;ioctl(fd, IOCTL_SET, &param);close(fd);sleep(10);printf("buf=0x%x", buf);return 0; }

2.5、實(shí)驗(yàn)開始
2.5.1、運(yùn)行2.4程序,通過(guò)ioctl運(yùn)行內(nèi)核代碼,執(zhí)行2.3程序get_phy_addr函數(shù),獲取物理地址。
2.5.2、通過(guò)傳入獲取到的物理地址,運(yùn)行2.2程序,打印物理地址的信息。

其中0x83e6573c是獲取的物理地址
ARM處理器小端存儲(chǔ)數(shù)據(jù),因此0x43 0x68 0x69 0x6e 剛好對(duì)應(yīng)著Chinaxxxxx中的Chin的Ascii碼值
2.6、擴(kuò)展
2.6.1、既然知道物理地址了,是不是可以修改物理地址里面的內(nèi)容?
2.6.2、打開2.3代碼的注釋 *(unsigned int *)(addr) = 0x6f6a6944;
2.6.3、再操作2.5中的步驟,發(fā)現(xiàn)原先的Chinaxxxxx被修改了

3、遇到的問題
3.1.1、2.3中的代碼mmap一直返回-1,錯(cuò)誤碼一直是1(errno 1 Operation not permitted)
3.1.2、解決方法
在.config文件中設(shè)置CONFIG_STRICT_DEVMEM is not set

正如上面描述的,通過(guò)獲取物理地址修改物理地址里面的數(shù)據(jù),這對(duì)系統(tǒng)來(lái)說(shuō)就毫無(wú)安全可言。因此內(nèi)核通過(guò)CONFIG_STRICT_DEVMEM配置項(xiàng)禁止內(nèi)存空間實(shí)現(xiàn)映射。

總結(jié)

以上是生活随笔為你收集整理的虚拟地址如何访问到物理地址的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。