x86: revise _x86_mmu_buffer_validate
- There's no point in building up "validity" (declared volatile for some strange reason), just exit with false return value if any of the page directory or page table checks don't come out as expected - The function was returning the opposite value as its documentation (0 on success, -EPERM on failure). Documentation updated. - This function will only be used to verify buffers from user-space. There's no need for a flags parameter, the only option that needs to be passed in is whether the buffer has write permissions or not. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
f5adf534e8
commit
d81f9c1e4d
3 changed files with 9 additions and 121 deletions
|
@ -8,11 +8,6 @@
|
|||
#include <mmustructs.h>
|
||||
#include <linker/linker-defs.h>
|
||||
|
||||
/* Ref to _x86_mmu_buffer_validate documentation for details */
|
||||
#define USER_PERM_BIT_POS ((u32_t)0x1)
|
||||
#define GET_RW_PERM(flags) (flags & BUFF_WRITEABLE)
|
||||
#define GET_US_PERM(flags) ((flags & BUFF_USER) >> USER_PERM_BIT_POS)
|
||||
|
||||
/* Common regions for all x86 processors.
|
||||
* Peripheral I/O ranges configured at the SOC level
|
||||
*/
|
||||
|
@ -36,58 +31,6 @@ MMU_BOOT_REGION((u32_t)&__app_ram_start, (u32_t)&__app_ram_size,
|
|||
MMU_BOOT_REGION((u32_t)&__kernel_ram_start, (u32_t)&__kernel_ram_size,
|
||||
MMU_ENTRY_WRITE | MMU_ENTRY_RUNTIME_USER);
|
||||
|
||||
/**
|
||||
* brief check page directory flags
|
||||
*
|
||||
* This routine reads the flags of the pde and then compares it to the
|
||||
* rw_permission and us_permissions.
|
||||
*
|
||||
* return true-if the permissions of the pde matches the request
|
||||
*/
|
||||
static inline u32_t check_pde_flags(volatile union x86_mmu_pde_pt pde,
|
||||
u32_t rw_permission,
|
||||
u32_t us_permission)
|
||||
{
|
||||
|
||||
/* If rw bit is 0 then read is enabled else if 1 then
|
||||
* read-write access is enabled. (flags & 0x1) returns a
|
||||
* RW permission required. if READ is requested and the rw bit says
|
||||
* it has write permission this passes through. But if a write
|
||||
* permission is requested and rw bit says only read is
|
||||
* allowed then this fails.
|
||||
*/
|
||||
|
||||
/* The privilage permisions possible combinations between request and
|
||||
* the the mmu configuraiont are
|
||||
* s s -> both supervisor = valid
|
||||
* s u -> PDE is supervisor and requested is user = invalid
|
||||
* u s -> PDE is user and requested is supervisor = valid
|
||||
* u u -> both user = valid
|
||||
*/
|
||||
|
||||
return(pde.p &&
|
||||
(pde.rw >= rw_permission) &&
|
||||
!(pde.us < us_permission));
|
||||
}
|
||||
|
||||
/**
|
||||
* brief check page table entry flags
|
||||
*
|
||||
* This routine reads the flags of the pte and then compares it to the
|
||||
* rw_permission and us_permissions.
|
||||
*
|
||||
* return true-if the permissions of the pde matches the request
|
||||
*/
|
||||
static inline u32_t check_pte_flags(union x86_mmu_pte pte,
|
||||
u32_t rw_permission,
|
||||
u32_t us_permission)
|
||||
{
|
||||
/* Ref to check_pde_flag for doc */
|
||||
return(pte.p &&
|
||||
(pte.rw >= rw_permission) &&
|
||||
!(pte.us < us_permission));
|
||||
}
|
||||
|
||||
|
||||
void _x86_mmu_get_flags(void *addr, u32_t *pde_flags, u32_t *pte_flags)
|
||||
{
|
||||
|
@ -97,61 +40,32 @@ void _x86_mmu_get_flags(void *addr, u32_t *pde_flags, u32_t *pte_flags)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief check page table entry flags
|
||||
*
|
||||
* This routine checks if the buffer is avaialable to the whoever calls
|
||||
* this API.
|
||||
* @a addr start address of the buffer
|
||||
* @a size the size of the buffer
|
||||
* @a flags permisions to check.
|
||||
* Consists of 2 bits the bit0 represents the RW permissions
|
||||
* The bit1 represents the user/supervisor permissions
|
||||
* Use macro BUFF_READABLE/BUFF_WRITEABLE or BUFF_USER to build the flags
|
||||
*
|
||||
* @return true-if the permissions of the pde matches the request
|
||||
*/
|
||||
int _x86_mmu_buffer_validate(void *addr, size_t size, int flags)
|
||||
int _arch_buffer_validate(void *addr, size_t size, int write)
|
||||
{
|
||||
int status = 0;
|
||||
u32_t start_pde_num;
|
||||
u32_t end_pde_num;
|
||||
/* union x86_mmu_pde_pt pde_status; */
|
||||
volatile u32_t validity = 1;
|
||||
u32_t starting_pte_num;
|
||||
u32_t ending_pte_num;
|
||||
struct x86_mmu_page_table *pte_address;
|
||||
u32_t rw_permission;
|
||||
u32_t us_permission;
|
||||
u32_t pde;
|
||||
u32_t pte;
|
||||
union x86_mmu_pte pte_value;
|
||||
|
||||
start_pde_num = MMU_PDE_NUM(addr);
|
||||
end_pde_num = MMU_PDE_NUM((char *)addr + size - 1);
|
||||
rw_permission = GET_RW_PERM(flags);
|
||||
us_permission = GET_US_PERM(flags);
|
||||
starting_pte_num = MMU_PAGE_NUM((char *)addr);
|
||||
|
||||
/* Iterate for all the pde's the buffer might take up.
|
||||
* (depends on the size of the buffer and start address of the buff)
|
||||
*/
|
||||
for (pde = start_pde_num; pde <= end_pde_num; pde++) {
|
||||
validity &= check_pde_flags(X86_MMU_PD->entry[pde].pt,
|
||||
rw_permission,
|
||||
us_permission);
|
||||
union x86_mmu_pde_pt pde_value = X86_MMU_PD->entry[pde].pt;
|
||||
|
||||
/* If pde is invalid exit immediately. */
|
||||
if (validity == 0) {
|
||||
break;
|
||||
if (!pde_value.p || !pde_value.us || (write && !pde_value.rw)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Get address of the page table from the pde.
|
||||
* This is a 20 bit address, so shift it by 12.
|
||||
* This gives us 4KB aligned page table.
|
||||
*/
|
||||
pte_address = (struct x86_mmu_page_table *)
|
||||
(X86_MMU_PD->entry[pde].pt.page_table << 12);
|
||||
pte_address = X86_MMU_GET_PT_ADDR(addr);
|
||||
|
||||
/* loop over all the possible page tables for the required
|
||||
* size. If the pde is not the last one then the last pte
|
||||
|
@ -177,19 +91,15 @@ int _x86_mmu_buffer_validate(void *addr, size_t size, int flags)
|
|||
|
||||
/* Bitwise AND all the pte values. */
|
||||
for (pte = starting_pte_num; pte <= ending_pte_num; pte++) {
|
||||
|
||||
pte_value.value &= pte_address->entry[pte].value;
|
||||
}
|
||||
|
||||
validity &= check_pte_flags(pte_value,
|
||||
rw_permission,
|
||||
us_permission);
|
||||
if (!pte_value.p || !pte_value.us || (write && !pte_value.rw)) {
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
if (validity == 0) {
|
||||
status = -EPERM;
|
||||
}
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -136,12 +136,6 @@
|
|||
*/
|
||||
#define MMU_ENTRY_RUNTIME_WRITE 0x20000000
|
||||
|
||||
/* Macros needed for define permissions for the buffer validation API
|
||||
* ref to x86_mmu_buffer_validate()
|
||||
*/
|
||||
#define BUFF_READABLE ((u32_t) 0x0)
|
||||
#define BUFF_WRITEABLE ((u32_t) 0x1)
|
||||
#define BUFF_USER ((u32_t) 0x2)
|
||||
|
||||
|
||||
/* Helper macros to ease the usage of the MMU page table structures.
|
||||
|
|
|
@ -607,22 +607,6 @@ void _x86_mmu_get_flags(void *addr, u32_t *pde_flags, u32_t *pte_flags);
|
|||
* modify
|
||||
*/
|
||||
void _x86_mmu_set_flags(void *ptr, size_t size, u32_t flags, u32_t mask);
|
||||
|
||||
/**
|
||||
* @brief check page table entry flags
|
||||
*
|
||||
* This routine checks if the buffer is available to whoever calls
|
||||
* this API.
|
||||
* @param addr start address of the buffer
|
||||
* @param size the size of the buffer
|
||||
* @param flags permissions to check.
|
||||
* Consists of 2 bits the bit0 represents the RW permissions
|
||||
* The bit1 represents the user/supervisor permissions
|
||||
* Use macro BUFF_READABLE/BUFF_WRITEABLE or BUFF_USER to build the flags
|
||||
*
|
||||
* @return true-if the permissions of the pde matches the request
|
||||
*/
|
||||
int _x86_mmu_buffer_validate(void *addr, size_t size, int flags);
|
||||
#endif /* CONFIG_X86_MMU */
|
||||
|
||||
#endif /* !_ASMLANGUAGE */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue