Chinaunix
标题:
更改 page table entry屬性,卻未生效
[打印本页]
作者:
wth0722
时间:
2014-06-06 22:31
标题:
更改 page table entry屬性,卻未生效
本帖最后由 wth0722 于 2014-06-06 22:39 编辑
各位先進好,
小弟用ioremap()要了一塊記憶體使用
ioreamp()初始化是要了一塊non-cache的記憶體
我後來有去找該address所在的page table entry
找到 ptep = pte_offset_map(pmd, addr);
把ptep的prot改為 PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED
上面即為ioremap_cached的屬性
改完之後,以為那一塊記憶體就有cache了,但還是沒有
請教各位大大有什麼想法嗎? 謝謝
作者:
wth0722
时间:
2014-06-06 22:42
本帖最后由 wth0722 于 2014-06-06 22:43 编辑
還是我需要用下列這方式
set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
去set那page table entry的屬性才是真正寫入成功???
作者:
humjb_1983
时间:
2014-06-07 13:13
怎么确认没成功的呢?
作者:
wth0722
时间:
2014-06-07 14:46
我有一個測試程式利用dma
不去做flush cache就可以看到不一樣結果
作者:
humjb_1983
时间:
2014-06-09 09:04
wth0722 发表于 2014-06-07 14:46
我有一個測試程式利用dma
不去做flush cache就可以看到不一樣結果
修改后,再把相应pte的内容打出来看看呢~
作者:
wth0722
时间:
2014-06-09 13:19
已經找出原因了
單純只是去修改記憶體上的page table並沒有用
必需要使用set_pte_at()設定page table entry才有用
作者:
wth0722
时间:
2014-06-09 15:13
看了一下 set_pte_at()之後
發現為什麼直接改memory上的page table entry是無效了
因為set_pte_at()有去變更h/w pte,而上面的變更只是linux pte
作者:
humjb_1983
时间:
2014-06-09 15:48
你的内核是啥版本?
作者:
wth0722
时间:
2014-06-09 16:49
Linux 3.4.5
作者:
humjb_1983
时间:
2014-06-09 18:32
我看3.10代码中么有set_pte_at()接口的定义。
作者:
l4rmbr
时间:
2014-06-09 22:42
本帖最后由 l4rmbr 于 2014-06-09 22:54 编辑
看了楼主的表述,楼主你应该是在更新页表项后忘了冲刷tlb缓存。正确用法应该像这样:
flush_cache_page(vma, addr, pfn); <--- 冲刷数据/指令缓存
set_pte(pte_pointer, new_pte_val); <--- 更新页表项
flush_tlb_page(vma, addr); <--- 冲刷tlb缓存
此外,多说两点.
1.
set_pte_at() 与 set_pte()功能基本相同,不过前者用来实现钩子,用以
冲刷相应的数据/指令缓存。
在大多数体系架构下,这两个函数一样。不过arm是个例外。因为它是vivt
架构(virtual indexed and virtual tagged), 所以更新了虚拟地址的页表项,
也要相应地刷新缓存。 x86就不用,因为它是pipi(physical indexed and physical tagged)
缓存一致性由cpu内在地保证,不需要程序员干预。
2.
我大概翻了下代码,发现set_pte一般用在第一次创建一个表项时,此时无所谓“更新”一说。
如果是要更新一个旧页表项,则用的是set_pte_at。
这也符合这两个接口的设计目的。
作者:
l4rmbr
时间:
2014-06-09 22:43
本帖最后由 l4rmbr 于 2014-06-09 22:54 编辑
[非常抱歉,网络原因发了相同内容两次,麻烦版主删除这个帖子吧。谢谢!]
看了楼主的表述,楼主你应该是在更新页表项后忘了冲刷tlb缓存。正确用法应该像这样:
flush_cache_page(vma, addr, pfn); <--- 冲刷数据/指令缓存
set_pte(pte_pointer, new_pte_val); <--- 更新页表项
flush_tlb_page(vma, addr); <--- 冲刷tlb缓存
此外,多说两点.
1.
set_pte_at() 与 set_pte()功能基本相同,不过前者用来实现钩子,用以
冲刷相应的数据/指令缓存。
在大多数体系架构下,这两个函数一样。不过arm是个例外。因为它是vivt
架构(virtual indexed and virtual tagged), 所以更新了虚拟地址的页表项,
也要相应地刷新缓存。 x86就不用,因为它是pipi(physical indexed and physical tagged)
缓存一致性由cpu内在地保证,不需要程序员干预。
2.
我大概翻了下代码,发现set_pte一般用在第一次创建一个表项时,此时无所谓“更新”一说。
如果是要更新一个旧页表项,则用的是set_pte_at。
这也符合这两个接口的设计目的。
作者:
wth0722
时间:
2014-06-10 10:21
回复
12#
l4rmbr
先感謝你的回應
flush_cache_page(vma, addr, pfn); <--- 沖刷數據/指令緩存
set_pte(pte_pointer, new_pte_val); <--- 更新頁表項
flush_tlb_page(vma, addr); <--- 沖刷tlb緩存
我無法用上面那些,因為ioremap()後,那塊記憶體是沒有vma的
我試過find_vma()是找不到的
我這邊是ARM arch,並沒有set_pte(),只有set_pte_at()
再來其實一開始我是有flush all cache 以及 鎖TLB,但還是沒有解決問題
後來才知道是因為我是只有更改Linux pte,並沒有改道h/w pte
所以才會需要set_pte_at()幫我去修改他
還有其實ARM arch的d-cache 是VIPT non-aliasing
i-cache才是VIVT
作者:
chenyu105
时间:
2014-06-10 11:33
奇怪,我看的内核是3.13,如果照楼主的流程,用set_pte_at并不会刷cache。
对于set_pte_at,如果是用户态的地址,则尝试刷cache:
static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pteval)
{
unsigned long ext = 0;
if (addr < TASK_SIZE && pte_present_user(pteval)) {
__sync_icache_dcache(pteval);
ext |= PTE_EXT_NG;
}
}
复制代码
如果是用户态的地址,并且有可执行属性,就算vipt 没有cache aliase,也需刷icache和dcache:
void __sync_icache_dcache(pte_t pteval)
{
unsigned long pfn;
struct page *page;
struct address_space *mapping;
if (cache_is_vipt_nonaliasing() && !pte_exec(pteval))
/* only flush non-aliasing VIPT caches for exec mappings */
return;
复制代码
#define pte_exec(pte) (!(pte_val(pte) & L_PTE_XN))
复制代码
由于楼主的ioremap带PROT_PTE_DEVICE属性,
#define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
因此pte_exec返回0,从而__sync_icache_dcache直接返回了。
也就是说,不会刷cache,这个跟楼主的描述有点矛盾。
作者:
l4rmbr
时间:
2014-06-10 11:47
回复
13#
wth0722
你好。我看了下ioremap的实现,确实是没关联vma的。
还有,你说的hw pte是怎么回事? 页表项不就是在内存中的数据结构吗?还有硬件页表项这一说?不知是什么架构。能不能解释下?谢谢!
最后,关于vivt, 多谢指正 :)
作者:
wth0722
时间:
2014-06-10 11:51
回复
14#
chenyu105
不好意思,請問跟我講哪一點有矛盾?
set_pte_at() -> cpu_v7_set_pte_ext() 這邊若是UP則會flush cache
我從頭到尾就一直說問題的點是在於只有寫入到Linux pte,並沒有寫到h/w pte
TLB、cache的問題我不認為問題點在那邊阿,因為我試過flush也沒用
作者:
wth0722
时间:
2014-06-10 11:58
回复
15#
l4rmbr
我用是ARM arch的,這邊是有兩份pte的
原因是Linux所要的pte資訊,ARM並沒有提供,所以要多一份保存
請參考arch/arm/include/asm/pgtable-2level.h
31 * This leads to the page tables having the following layout:
32 *
33 * pgd pte
34 * | |
35 * +--------+
36 * | | +------------+ +0
37 * +- - - - + | Linux pt 0 |
38 * | | +------------+ +1024
39 * +--------+ +0 | Linux pt 1 |
40 * | |-----> +------------+ +2048
41 * +- - - - + +4 | h/w pt 0 |
42 * | |-----> +------------+ +3072
43 * +--------+ +8 | h/w pt 1 |
44 * | | +------------+ +4096
45 *
作者:
l4rmbr
时间:
2014-06-10 12:06
回复
17#
wth0722
多谢。明白了。 这也是为了弥补linux通用多级页表和硬件支持页表之间的差异。
作者:
chenyu105
时间:
2014-06-10 12:17
本帖最后由 chenyu105 于 2014-06-10 12:20 编辑
回复
16#
wth0722
明白了。
如果设置了软件pte,应该也会有什么时候会把软件pte更新到硬件pte吧
作者:
wth0722
时间:
2014-06-10 13:08
回复
19#
chenyu105
set_pte_at() ---> cpu_v7_set_pte_ext()
cpu_v7_set_pte_ext()這裡面會去寫入到h/w pte
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2