arch/x86_64: add MMU interface

add MMU api for x86_64

Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
p-szafonimateusz 2024-06-17 14:04:48 +02:00 committed by Xiang Xiao
parent 53d112fa95
commit e0183927b4
7 changed files with 442 additions and 2 deletions

View File

@ -16,8 +16,8 @@ choice
config ARCH_INTEL64
bool "Intel x86_64"
select ARCH_HAVE_MPU
select ARCH_USE_MPU
select ARCH_HAVE_MMU
select ARCH_USE_MMU
select ARCH_HAVE_TICKLESS
select ARCH_HAVE_STACKCHECK
select ARCH_HAVE_RNG

View File

@ -558,6 +558,25 @@ static inline void set_pcid(uint64_t pcid)
}
}
static inline void set_cr3(uint64_t cr3)
{
asm volatile("mov %0, %%cr3" : "=rm"(cr3) : : "memory");
}
static inline uint64_t get_cr3(void)
{
uint64_t cr3;
asm volatile("mov %%cr3, %0" : "=rm"(cr3) : : "memory");
return cr3;
}
static inline uint64_t get_pml4(void)
{
/* Aligned to a 4-KByte boundary */
return get_cr3() & 0xfffffffffffff000;
}
static inline unsigned long read_msr(unsigned int msr)
{
uint32_t low;

View File

@ -41,4 +41,8 @@ if(CONFIG_ARCH_X86_64_ACPI)
list(APPEND SRCS x86_64_acpi.c)
endif()
if(CONFIG_ARCH_USE_MMU)
list(APPEND SRCS x86_64_mmu.c)
endif()
target_sources(arch PRIVATE ${SRCS})

View File

@ -32,3 +32,7 @@ endif
ifeq ($(CONFIG_ARCH_X86_64_ACPI),y)
CMN_CSRCS += x86_64_acpi.c
endif
ifeq ($(CONFIG_ARCH_USE_MMU),y)
CMN_CSRCS += x86_64_mmu.c
endif

View File

@ -0,0 +1,89 @@
/****************************************************************************
* arch/x86_64/src/common/addrenv.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_X86_64_SRC_COMMON_ADDRENV_H
#define __ARCH_X86_64_SRC_COMMON_ADDRENV_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include "x86_64_internal.h"
#ifdef CONFIG_ARCH_ADDRENV
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Aligned size of the kernel stack */
#ifdef CONFIG_ARCH_KERNEL_STACK
# define ARCH_KERNEL_STACKSIZE STACK_ALIGN_UP(CONFIG_ARCH_KERNEL_STACKSIZE)
#endif
/* Base address for address environment */
#if CONFIG_ARCH_TEXT_VBASE != 0
# define ARCH_ADDRENV_VBASE (CONFIG_ARCH_TEXT_VBASE)
#else
# define ARCH_ADDRENV_VBASE (CONFIG_ARCH_DATA_VBASE)
#endif
/* Maximum user address environment size */
#define ARCH_ADDRENV_MAX_SIZE (0x40000000)
/* User address environment end */
#define ARCH_ADDRENV_VEND (ARCH_ADDRENV_VBASE + ARCH_ADDRENV_MAX_SIZE - 1)
/* Flags for kernel page tables */
#define MMU_KPGT_FLAGS (X86_PAGE_WR)
/* Mark user memory if in kernel build */
#ifndef CONFIG_BUILD_KERNEL
# define MMU_USER_DEFAULT (X86_PAGE_USER)
#else
# define MMU_USER_DEFAULT (0)
#endif
/* Flags for user page tables */
#define MMU_UPGT_FLAGS (X86_PAGE_WR | MMU_USER_DEFAULT)
/* Flags for user FLASH (RX) and user RAM (RW) */
#define MMU_UDATA_FLAGS (X86_PAGE_WR | MMU_USER_DEFAULT)
#define MMU_UTEXT_FLAGS (X86_PAGE_WR | MMU_USER_DEFAULT)
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#endif /* CONFIG_ARCH_ADDRENV */
#endif /* __ARCH_X86_64_SRC_COMMON_ADDRENV_H */

View File

@ -0,0 +1,146 @@
/****************************************************************************
* arch/x86_64/src/common/x86_64_mmu.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include "x86_64_internal.h"
#include "x86_64_mmu.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mmu_ln_setentry
*
* Description:
* Set a level n translation table entry.
*
* Input Parameters:
* ptlevel - The translation table level, amount of levels is
* MMU implementation specific
* lnvaddr - The virtual address of the beginning of the page table at
* level n
* paddr - The physical address to be mapped
* vaddr - The virtual address to be mapped
* mmuflags - The MMU flags to use in the mapping.
*
****************************************************************************/
void mmu_ln_setentry(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr,
uintptr_t vaddr, uint32_t mmuflags)
{
uintptr_t *lntable = (uintptr_t *)lnvaddr;
uint32_t index;
DEBUGASSERT(ptlevel >= 0 && ptlevel < X86_MMU_PT_LEVELS);
/* Make sure the entry is valid */
mmuflags |= X86_PAGE_PRESENT;
/* Calculate index for lntable */
index = X86_MMU_VADDR_INDEX(vaddr, ptlevel);
/* Save it */
lntable[index] = (paddr | mmuflags);
/* Update with memory by flushing the cache(s) */
up_invalid_tlb(vaddr, vaddr + 1);
}
/****************************************************************************
* Name: mmu_ln_getentry
*
* Description:
* Get a level n translation table entry.
*
* Input Parameters:
* ptlevel - The translation table level, amount of levels is
* MMU implementation specific
* lnvaddr - The virtual address of the beginning of the page table at
* level n
* vaddr - The virtual address to get pte for
*
****************************************************************************/
uintptr_t mmu_ln_getentry(uint32_t ptlevel, uintptr_t lnvaddr,
uintptr_t vaddr)
{
uintptr_t *lntable = (uintptr_t *)lnvaddr;
uint32_t index;
DEBUGASSERT(ptlevel >= 0 && ptlevel < X86_MMU_PT_LEVELS);
index = X86_MMU_VADDR_INDEX(vaddr, ptlevel);
return lntable[index];
}
/****************************************************************************
* Name: mmu_ln_map_region
*
* Description:
* Set a translation table region for level n
*
* Input Parameters:
* ptlevel - The translation table level, amount of levels is
* MMU implementation specific
* lnvaddr - The virtual address of the beginning of the page table at
* level n
* paddr - The physical address to be mapped
* vaddr - The virtual address to be mapped
* size - The size of the region in bytes
* mmuflags - The MMU flags to use in the mapping.
*
****************************************************************************/
void mmu_ln_map_region(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr,
uintptr_t vaddr, size_t size, uint32_t mmuflags)
{
uintptr_t end_paddr = paddr + size;
size_t page_size = X86_MMU_PAGE_SIZE;
DEBUGASSERT(ptlevel >= 0 && ptlevel < X86_MMU_PT_LEVELS);
while (paddr < end_paddr)
{
mmu_ln_setentry(ptlevel, lnvaddr, paddr, vaddr, mmuflags);
paddr += page_size;
vaddr += page_size;
}
}

View File

@ -0,0 +1,178 @@
/****************************************************************************
* arch/x86_64/src/common/x86_64_mmu.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_X86_64_SRC_COMMON_X86_64_MMU_H
#define __ARCH_X86_64_SRC_COMMON_X86_64_MMU_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* 4 level paging, 4K pages */
#define X86_MMU_PT_LEVELS 4
#define X86_MMU_PAGE_SHIFT 12
#define X86_MMU_PAGE_SIZE (1 << X86_MMU_PAGE_SHIFT)
#define X86_MMU_ENTRIES_PER_PGT (X86_MMU_PAGE_SIZE / 8)
/* Get virtual address shift for a given paging level.
* NOTE: in this implementation PTL4 has index 0, PT has index 3 !
*/
#define X86_MMU_PADDR_SHIFT 12
#define X86_MMU_VPN_WIDTH 9
#define X86_MMU_VPN_MASK ((1 << X86_MMU_VPN_WIDTH) - 1)
#define X86_MMU_VADDR_SHIFT(n) (X86_MMU_PADDR_SHIFT + X86_MMU_VPN_WIDTH * \
(X86_MMU_PT_LEVELS - ((n) + 1)))
/* Get index in a given page table level for a given virtual address */
#define X86_MMU_VADDR_INDEX(vaddr, ptlevel) \
((vaddr >> X86_MMU_VADDR_SHIFT(ptlevel)) & X86_MMU_VPN_MASK)
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: mmu_cr3_reg
*
* Description:
* Utility function to build cr3 register value for input parameters
*
* Input Parameters:
* pgbase - The physical base address of the translation table base
* asid - Address space identifier. Not used now.
*
****************************************************************************/
static inline uintptr_t mmu_cr3_reg(uintptr_t pgbase, uint16_t asid)
{
uintptr_t reg;
UNUSED(asid);
reg = pgbase;
return reg;
}
/****************************************************************************
* Name: mmu_pte_to_paddr
*
* Description:
* Extract physical address from PTE
*
* Input Parameters:
* pte - Page table entry
*
* Returned Value:
* Physical address from PTE
*
****************************************************************************/
static inline uintptr_t mmu_pte_to_paddr(uintptr_t pte)
{
uintptr_t paddr = 0;
if (pte & X86_PAGE_PRESENT)
{
paddr = pte;
/* Get page addres - remove flags */
paddr &= 0x0dfffffffffff000;
}
return paddr;
}
/****************************************************************************
* Name: mmu_ln_setentry
*
* Description:
* Set a level n translation table entry.
*
* Input Parameters:
* ptlevel - The translation table level, amount of levels is
* MMU implementation specific
* lnvaddr - The virtual address of the beginning of the page table at
* level n
* paddr - The physical address to be mapped. Must be aligned to a PPN
* address boundary which is dependent on the level of the entry
* vaddr - The virtual address to be mapped. Must be aligned to a PPN
* address boundary which is dependent on the level of the entry
* mmuflags - The MMU flags to use in the mapping.
*
****************************************************************************/
void mmu_ln_setentry(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr,
uintptr_t vaddr, uint32_t mmuflags);
/****************************************************************************
* Name: mmu_ln_getentry
*
* Description:
* Get a level n translation table entry.
*
* Input Parameters:
* ptlevel - The translation table level, amount of levels is
* MMU implementation specific
* lnvaddr - The virtual address of the beginning of the page table at
* level n
* vaddr - The virtual address to get pte for. Must be aligned to a PPN
* address boundary which is dependent on the level of the entry
*
****************************************************************************/
uintptr_t mmu_ln_getentry(uint32_t ptlevel, uintptr_t lnvaddr,
uintptr_t vaddr);
/****************************************************************************
* Name: mmu_ln_map_region
*
* Description:
* Set a translation table region for level n
*
* Input Parameters:
* ptlevel - The translation table level, amount of levels is
* MMU implementation specific
* lnvaddr - The virtual address of the beginning of the page table at
* level n
* paddr - The physical address to be mapped. Must be aligned to a PPN
* address boundary which is dependent on the level of the entry
* vaddr - The virtual address to be mapped. Must be aligned to a PPN
* address boundary which is dependent on the level of the entry
* size - The size of the region in bytes
* mmuflags - The MMU flags to use in the mapping.
*
****************************************************************************/
void mmu_ln_map_region(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr,
uintptr_t vaddr, size_t size, uint32_t mmuflags);
#endif /* __ARCH_X86_64_SRC_COMMON_X86_64_MMU_H */