aarch64EL0模式和用户空间范围



我目前正在Aarch64体系结构上移植SO3操作系统。我使用QEMU/virt64仿真来实现这一点。只要我在内核空间运行EL1中的代码,一切都很顺利。但当我开始处理用户空间方面的问题时,我遇到了一些问题,并发现了各种各样的东西。我想确保我能正确地适应。

(SO3机制在非常简化的形式上与Linux非常相似。我们考虑48位VA寻址,ttbr0/ttbr1_el1目前使用相同的页表(。

首先,不可能在EL0模式下运行内核代码(因此代码位于地址>0xffff00.(,对吧?(目前,第一个用户线程prolog在内核空间开始执行,但在用户模式下,所以我需要在应用程序区域重新映射一些页面(或我错过了armv8支持的一些功能?

其次,我注意到在EL0中,任何使用位47访问VA的内存位置都会导致异常(在EL1中((我将堆栈顶部放在用户范围的最后几页中(知道它为什么失败了吗?(SCTRL/TCR的配置方式与Linux略有相同(

两种情况都会导致esr_el1:0x92000044(MMU故障(

ADDINGS

翻译有四个层次。

此外,奇怪的是:如果我在块描述符的TTE中设置了位6(AP1(,当MMU切换到L0页表时,它会失败。它只适用于页面TTE(级别3(。

以下是系统寄存器的值:

  • TCR_EL1:0x15b5503510
  • SCTLR_EL1:0x34f4d91d

TCR对应于:

#define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA
#define TCR_TG_FLAGS    TCR_TG0_4K | TCR_TG1_4K
#define TCR_SMP_FLAGS   (TCR_SH0_INNER | TCR_SH1_INNER)
tcr = TCR_CACHE_FLAGS | TCR_SMP_FLAGS | TCR_TG_FLAGS | TCR_ASID16 | TCR_A1;
tcr |= TCR_TxSZ(48) | (TCR_PS_BITS_256TB << TCR_IPS_SHIFT);

和SCTLR到:

#define SCTLR_EL1_SET   (SCTLR_ELx_M    | SCTLR_ELx_C    | SCTLR_ELx_SA   |
SCTLR_EL1_SA0  | SCTLR_EL1_SED  | SCTLR_ELx_I    |
SCTLR_EL1_DZE  | SCTLR_EL1_UCT           |
SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |
ENDIAN_SET_EL1 | SCTLR_EL1_UCI  | SCTLR_EL1_RES1)

内存区域属性取自Linux:

#define MT_NORMAL       0
#define MT_NORMAL_TAGGED    1
#define MT_NORMAL_NC        2
#define MT_NORMAL_WT        3
#define MT_DEVICE_nGnRnE    4
#define MT_DEVICE_nGnRE     5
#define MT_DEVICE_GRE       6
/* MAIR_ELx memory attributes (used by Linux) */
#define MAIR_ATTR_DEVICE_nGnRnE     UL(0x00)
#define MAIR_ATTR_DEVICE_nGnRE      UL(0x04)
#define MAIR_ATTR_DEVICE_GRE        UL(0x0c)
#define MAIR_ATTR_NORMAL_NC     UL(0x44)
#define MAIR_ATTR_NORMAL_WT     UL(0xbb)
#define MAIR_ATTR_NORMAL_TAGGED     UL(0xf0)
#define MAIR_ATTR_NORMAL        UL(0xff)
#define MAIR_ATTR_MASK          UL(0xff)
/* Position the attr at the correct index */
#define MAIR_ATTRIDX(attr, idx)     ((attr) << ((idx) * 8))
#define MAIR_EL1_SET                            
(MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) |  
MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) |    
MAIR_ATTRIDX(MAIR_ATTR_DEVICE_GRE, MT_DEVICE_GRE) |        
MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) |      
MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) |            
MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT) |      
MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED))

内核代码映射为MT_NORMAL

TTE配置有以下功能:

static inline void set_pte_table(u64 *pte, enum dcache_option option)
{
u64 attrs = PTE_TABLE_NS;
*pte |= PTE_TYPE_TABLE;
*pte |= attrs;
}
static inline void set_pte_block(u64 *pte, enum dcache_option option)
{
u64 attrs = PTE_BLOCK_MEMTYPE(option);
/* Set the PTE with R/W permissions for both kernel and user mode */
*pte |= PTE_TYPE_BLOCK | PTE_BLOCK_AF | PTE_BLOCK_INNER_SHARE | PTE_BLOCK_NS;
*pte |= attrs;
}
static inline void set_pte_page(u64 *pte, enum dcache_option option)
{
u64 attrs = PTE_BLOCK_MEMTYPE(option);
/* Set the PTE with R/W permissions for both kernel and user mode */
*pte |= PTE_TYPE_PAGE | PTE_BLOCK_AF | PTE_BLOCK_INNER_SHARE | PTE_BLOCK_NS | PTE_BLOCK_AP1;
*pte |= attrs;
}

如果我试图在set_PTE_BLOCK函数中设置PTE_BLOCK_AP1,它将失败。

适用于EL1和EL0的翻译机制是相同的。因此,如果您正确配置了内存系统,那么您绝对可以在内核模式下运行代码。你要确保:

TTE中的
  • AP[1](比特6(是1
  • 如果页面应可执行,则TTE中的UXN(位54(为0
  • 没有一个页面表的APTableUXNTable位设置为不允许将页面映射为userland可访问/userland可执行的值
  • 如果您使用的是ARMv8.1或更高版本,则PAN将被禁用。为此,请运行msr pan, 0并将SCTLR_EL1.SPAN(位23(设置为1(否则将在每个异常条目上重新启用PAN(
  • 如果您的目标具有FEAT_E0PD(在ARMv8.5中是必需的,在ARMv8.4中是可选的(,请确保TCR_EL1.E0PD1(位56(是0(假设您的内核位于地址空间的上半部分,否则是E0PD0,位55(

(位从0开始编号,与ARMv8参考手册中的相同。(

对于您的第二个问题,我们需要知道您加载到TCR_EL1中的确切值,但我的猜测是T0SZ的值使TTBR0映射的地址空间小于48位。在任何一种情况下,当在异常向量处读取时,ESR_EL1都将保持异常综合症。

相关内容

  • 没有找到相关文章

最新更新