gpt4 book ai didi

arm - 什么是更新 MMU 转换表的正确方法

转载 作者:行者123 更新时间:2023-12-01 12:45:31 27 4
gpt4 key购买 nike

我在我的 s3c2440 板上启用了 MMU(3G - 4G 内存::故障属性),当我没有读/写 3G - 4G 内存时一切都很好。所以为了测试页面错误向量,我写信给一个 0xFF 到 3G 地址,正如我所料,我从 FSR 得到了正确的值,所以我在 _do_page_fault() 中做了这个,步骤是这样的:

.....                 // set new page to translation table 
.....
invlidate_icache (); // clear icache
clr_dcache (); // wb is used ,clear dcache
invalidate_ttb (); // invalidate translation table

然后ISR_dataabort返回,我读取3G地址得到我之前写入的0xFF。不幸的是我又遇到了数据中止。(我确定我设置的转换表值没问题)

那么更新 MMU 转换表的正确方法是什么。任何帮助都非常感谢!谢谢

这是我使用的主要代码(只是为了一些测试),(我对 ARM ARCH 有点陌生,所以这段代码可能很粗糙)

/* MMU TTB 0 BASE ATTR */
#define TTB0_FAULT (0|(1<<4)) /* TTB FAULT */
#define TTB0_COARSE (1|(1<<4)) /* COARSE PAGE BASE ADDR */
#define TTB0_SEG (2|(1<<4)) /* SEG BASE ADDR */
#define TTB0_FINE (3|(1<<4)) /* FINE PAGE BASE ADDR */

/* MMU TTB 1 BASE ATTR */
#define TTB1_FAULT (0)
#define TTB1_LPG (1) /* Large page */
#define TTB1_SPG (2) /* small page */
#define TTB1_TPG (3) /* tiny page */

/* domain access priority level */
#define FAULT_PL (0x0) /* domain fault */
#define USR_PL (0x1) /* usr mode */
#define RSV_PL (0x2) /* reserved */
#define SYS_PL (0x3) /* sys mode */

#define DOMAIN_FAULT (0x0<<5) /* fault 0*/
#define DOMAIN_SYS (0x1<<5) /* sys 1*/
#define DOMAIN_USR (0x2<<5) /* usr 2*/

/* C,B bit */
#define CB (3<<2) /* cache_on, write_back */
#define CNB (2<<2) /* cache_on, write_through */
#define NCB (1<<2) /* cache_off,WR_BUF on */
#define NCNB (0<<2) /* cache_off,WR_BUF off */

/* ap 2 bits */
#define AP_FAULT (0<<10) /* access deny */
#define AP_SU_ONLY (1<<10) /* rw su only */
#define AP_USR_RO (2<<10) /* sup=RW, user=RO */
#define AP_RW (3<<10) /* su=RW, user=RW */

/* page dir 1 ap0 */
#define AP0_SU_ONLY (1<<4) /* rw su only */
#define AP0_USR_RO (2<<4) /* sup=RW, user=RO */
#define AP0_RW (3<<4) /* su=RW, user=RW */

/* page dir 1 ap1 */
#define AP1_SU_ONLY (1<<6) /* rw su only */
#define AP1_USR_RO (2<<6) /* sup=RW, user=RO */
#define AP1_RW (3<<6) /* su=RW, user=RW */


/* page dir 1 ap2 */
#define AP2_SU_ONLY (1<<8) /* rw su only */
#define AP2_USR_RO (2<<8) /* sup=RW, user=RO */
#define AP2_RW (3<<8) /* su=RW, user=RW */

/* page dir 1 ap3 */
#define AP3_SU_ONLY (1<<10) /* rw su only */
#define AP3_USR_RO (2<<10) /* sup=RW, user=RO */
#define AP3_RW (3<<10) /* su=RW, user=RW */


#define RAM_START (0x30000000)
#define KERNEL_ENTRY (0x30300000) /* BANK 6 (3M) */
#define KERNEL_STACK (0x3001A000) /* BANK 6 (16K + 64K + 16K + 8K) (8k kernel stack) */
#define IRQ_STACK (0x3001B000) /* 4K IRQ STACK */
#define KERNEL_IMG_SIZE (0x20000)

#define IRQ_STACK (0x3001B000)

/* 16K aignment */
#define TTB_BASE (0x30000000)
#define PAGE_DIR0 (TTB_BASE)
#define TTB_FULL_SIZE (0x4000)
#define PAGE_DIR1 (TTB_BASE+TTB_FULL_SIZE)

#define PAGE_DIR0_SIZE (0x4000) /* 16k */


void _do_page_fault (void)
{
//
...........
//
// read the FSR && get the vaddr && type here
volatile unsigned *page_dir = (volatile unsigned*)(TTB_BASE);
unsigned index = vaddr >> 20,i = 0, j = 0;
unsigned page = 0;

if (!(page_dir[index] & ~(0x3FF) && (type == 0x0B))) { /* page_dir empty */
i = index & ~0x03;
if ( (page_dir[i+0] & ~(0x3FF)) || (page_dir [i+1] & ~(0x3FF))
|| (page_dir[i+2] & ~(0x3FF)) || (page_dir [i+3] & ~(0x3FF)) )
{
panic ( "page dir is bad !\n" ); /* 4 continuous page_dir must be 0 */
}

if (!(page = find_free_page ()))
panic ( "no more free page !\n" ); /* alloc a page page dir*/

page_dir[i+0] = (page + 0x000) | DOMAIN_USR | TTB0_COARSE ; /* small page 1st 1KB */
page_dir[i+1] = (page + 0x400) | DOMAIN_USR | TTB0_COARSE ; /* small page 2nd 1KB */
page_dir[i+2] = (page + 0x800) | DOMAIN_USR | TTB0_COARSE ; /* small page 3rd 1KB */
page_dir[i+3] = (page + 0xC00) | DOMAIN_USR | TTB0_COARSE ; /* small page 4th 1KB */

if (!(page = find_free_page ()))
panic ( "no more free page !\n" ); /* alloc a page page table*/

volatile unsigned *page_tbl = (volatile unsigned*) (page_dir[index] & ~(0x3FF));

*page_tbl = page|AP0_RW|AP1_RW|AP2_RW|AP3_RW| NCNB|TTB1_SPG;/* small page is used */


invalidate_icache ();

for (i = 0; i < 64; i++)
{
for (j = 0;j < 8;j ++)
clr_invalidate_dcache ( (i<<26)|(j<<5) );
}


invalidate_tlb ();
}
........
//

}

/* here is the macros */

#define invalidate_tlb() \
{\
__asm__ __volatile__ (\
"mov r0,#0\n"\
"mcr p15,0,r0,c8,c7,0\n"\
:::"r0" \
);\
}

#define clr_invalidate_dcache(index) \
{\
__asm__ __volatile__ (\
"mcr p15,0,%[i],c7,c14,2\n"\
:: [i]"r"(index)\
);\
}


#define invalidate_icache() \
{\
__asm__ __volatile__ (\
"mov r0,#0\n"\
"mcr p15,0,r0,c7,c5,0\n"\
::: "r0"\
);\
}

#define invalidate_dcache() \
{\
__asm__ __volatile__ (\
"mov r0,#0\n"\
"mcr p15,0,r0,c7,c6,0\n"\
::: "r0"\
);\
}



#define invalidate_idcache() \
{\
__asm__ __volatile__ (\
"mov r0,#0\n"\
"mcr p15,0,r0,c7,c7,0\n"\
:::"r0"\
);\
}\

最佳答案

注意:我假设 TTB_BASE 是主要的 ARM L1 页表。如果它是一些阴影,您需要根据 unixsmurf 显示更多代码.这是我最好的猜测...

您的 page_dir 既作为主要的 L1 条目,也作为 L2 精细页表。 TTB_BASE 应该只包含部分、 super 部分或指向子页表的指针。您需要为 L2 页表分配更多的物理内存。

我猜你的 page_dir[i+0]page_dir[i+1] 等正在覆盖其他 L1 部分条目和 您的 invalidate_tlb() 使它对 CPU 具体。您应该使用 L2 page_tbl 指针来设置/索引小/精细页面。也许您的内核代码位于 3G-4G 空间,并且您正在那里覆盖一些关键的 L1 映射;可能会发生许多奇怪的事情。 page_tbl 的当前用途不清楚。

您不能 双重使用主要 L1 表,因为它们对硬件有意义。我想这只是一个错误?

L1 主页表中只有三种类型的条目,

  1. Sections - 一个 1MB 内存直接映射 virt 到 phys,没有第 2nd 页表。
  2. Super-sections - 每个部分 4MB 内存映射,但最小化 TLB 压力。
  3. 第 2nd 页表。条目可以是 1k、4k 和 64k。 精细页表 的表大小为 4k,并且不在现代 ARM 设计中。每个条目是精细页表中的 1k 地址。

主页表必须位于16k 对齐 的物理地址上,这也是它的大小。 16k/(4bytes/entry)*1MB 给出 L1 表的 4GB 地址范围。所以主 L1 页表中的每个条目总是引用一个 1MB 条目。 页表是较新 ARM 上的唯一选项,它们指的是 1K L2 表。

1K_L2_size * 4K_entry / (4bytes_per_entry) gives 1MB address space.
1K_L2_size * 64K_entry / (16bytes_per_entry) gives 1MB address space.

在 super 部分的主要 L1 中有四个 1MB 的条目。 L2 表中的 64k large page 各有四个条目。如果您使用的是 super-sections,则您没有 L2 条目。

我认为您可能混淆了 super 部分大页面?对于某些格式不正确的页表,只会出现在 TLB 无效,以便通过遍历从表中重新获取 MMU 映射。

最后,您应该刷新D 缓存清空 写入缓冲区 以确保与内存的一致性。您可能还希望有一个内存屏障

static inline void dcache_clean(void)
{
const int zero = 0;
asm volatile ("" ::: "memory"); /* barrier */
/* clean entire D cache -> push to external memory. */
asm volatile ("1: mrc p15, 0, r15, c7, c10, 3\n"
" bne 1b\n" ::: "cc");
/* drain the write buffer */
asm volatile ("mcr 15, 0, %0, c7, c10, 4"::"r" (zero));
}

还有协处理器命令可以使单个 TLB 条目无效,因为您只是更改数据错误中的 vaddr/paddr 映射的一部分。

另请参阅:ARM MMU tutorial , Virtual Memory structures ,以及您的 ARM 架构引用手册

关于arm - 什么是更新 MMU 转换表的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16383007/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com