253 lines
8.4 KiB
C
253 lines
8.4 KiB
C
|
/* Copyright (C) 2004 David Decotigny
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||
|
USA.
|
||
|
*/
|
||
|
#ifndef _SOS_PAGING_H_
|
||
|
#define _SOS_PAGING_H_
|
||
|
|
||
|
/**
|
||
|
* @file paging.h
|
||
|
*
|
||
|
* MMU management routines (arch-dependent). Setup the MMU without
|
||
|
* identity-mapping physical<->virtual addresses over the whole
|
||
|
* physical address space: a single, restricted and known, area is
|
||
|
* identity-mapped, the remaining kernel/user space is not. To access
|
||
|
* and manage the MMU translation tables (PD/PT on x86), we rely on a
|
||
|
* particular configuration, called "mirroring", where the top-level
|
||
|
* translation table (PD on x86) maps itself at a known and fixed (virtual)
|
||
|
* address. The only assumption for this to be possible is that the
|
||
|
* structure of the translation table entries are compatible at the
|
||
|
* different levels of vadddr->paddr translation process (PDE and PTE
|
||
|
* on x86 are Ok). Credits go to Christophe Avoinne for that.
|
||
|
*/
|
||
|
|
||
|
#include <sos/types.h>
|
||
|
#include <sos/errno.h>
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Basic SOS virtual memory organization
|
||
|
*
|
||
|
* - Kernel space starts at the lower 4kB address (first page is not
|
||
|
* mapped in order to catch invalid pointers)
|
||
|
* - User space starts at the 1GB address
|
||
|
*/
|
||
|
#define SOS_PAGING_BASE_USER_ADDRESS (0x40000000) /* 1GB (must be 4MB-aligned) */
|
||
|
#define SOS_PAGING_UPPER_USER_ADDRESS (0xFFFFFFFF) /* 4GB - 1B */
|
||
|
#define SOS_PAGING_USER_SPACE_SIZE (SOS_PAGING_UPPER_USER_ADDRESS - \
|
||
|
SOS_PAGING_BASE_USER_ADDRESS + 1) /* 3GB */
|
||
|
#define SOS_PAGING_IS_USER_AREA(base_addr, length) \
|
||
|
( (SOS_PAGING_BASE_USER_ADDRESS <= (base_addr)) \
|
||
|
&& ((length) <= SOS_PAGING_USER_SPACE_SIZE) )
|
||
|
|
||
|
/** Length of the space reserved for the mirroring in the kernel
|
||
|
virtual space */
|
||
|
#define SOS_PAGING_MIRROR_SIZE (1 << 22) /* 1 PD = 1024 Page Tables = 4MB */
|
||
|
|
||
|
/** Virtual address where the mirroring takes place */
|
||
|
#define SOS_PAGING_MIRROR_VADDR \
|
||
|
(SOS_PAGING_BASE_USER_ADDRESS - SOS_PAGING_MIRROR_SIZE)
|
||
|
|
||
|
#define SOS_PAGING_BASE_KERNEL_ADDRESS (0x00004000) /* 16kB */
|
||
|
#define SOS_PAGING_UPPER_KERNEL_ADDRESS (SOS_PAGING_MIRROR_VADDR - 1) /* 1GB - 4MB - 1B */
|
||
|
#define SOS_PAGING_KERNEL_SPACE_SIZE (SOS_PAGING_UPPER_KERNEL_ADDRESS - \
|
||
|
SOS_PAGING_BASE_KERNEL_ADDRESS + 1) /* 1GB - 4MB - 16kB */
|
||
|
#define SOS_PAGING_IS_KERNEL_AREA(base_addr, length) \
|
||
|
( (SOS_PAGING_BASE_KERNEL_ADDRESS <= (base_addr)) \
|
||
|
&& ((length) <= SOS_PAGING_KERNEL_SPACE_SIZE) )
|
||
|
|
||
|
|
||
|
/**
|
||
|
* sos_paging_map flags
|
||
|
*/
|
||
|
/** Usual virtual memory access rights */
|
||
|
#define SOS_VM_MAP_PROT_NONE 0
|
||
|
#define SOS_VM_MAP_PROT_READ (1<<0)
|
||
|
#define SOS_VM_MAP_PROT_WRITE (1<<1)
|
||
|
#define SOS_VM_MAP_PROT_EXEC (1<<2) /* Not supported on IA32 */
|
||
|
|
||
|
/** Mapping a page may involve an physical page allocation (for a new
|
||
|
PT), hence may potentially block */
|
||
|
#define SOS_VM_MAP_ATOMIC (1<<31)
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Setup initial page directory structure where the kernel is
|
||
|
* identically-mapped, and the mirroring. This routine also
|
||
|
* identity-maps the BIOS and video areas, to allow some debugging
|
||
|
* text to be printed to the console. Finally, this routine installs
|
||
|
* the whole configuration into the MMU.
|
||
|
*/
|
||
|
sos_ret_t sos_paging_subsystem_setup(sos_paddr_t identity_mapping_base,
|
||
|
sos_paddr_t identity_mapping_top);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Map the given physical page at the given virtual address in the
|
||
|
* current address space.
|
||
|
*
|
||
|
* @note *IMPORTANT*: The physical page ppage_paddr *MUST* have been
|
||
|
* referenced by the caller through either a call to
|
||
|
* sos_physmem_ref_physpage_new() or sos_physmem_ref_physpage_at(). It
|
||
|
* would work if this were untrue, but this would be INCORRECT (it is
|
||
|
* expected that one is owning the page before mapping it, or
|
||
|
* otherwise the page could have been stolen by an interrupt or
|
||
|
* another thread).
|
||
|
*
|
||
|
* @param ppage_paddr The address of a physical page (page-aligned)
|
||
|
* @param vpage_vaddr The address of the virtual page (page-aligned)
|
||
|
* @param is_user_page TRUE when the page is available from user space
|
||
|
* @param flags A mask made of SOS_VM_* bits
|
||
|
*
|
||
|
* @note Unless the SOS_VM_MAP_ATOMIC bit is set in the flags, the
|
||
|
* function may potentially block, because a physical page may be
|
||
|
* allocated for a new PT.
|
||
|
*/
|
||
|
sos_ret_t sos_paging_map(sos_paddr_t ppage_paddr,
|
||
|
sos_vaddr_t vpage_vaddr,
|
||
|
sos_bool_t is_user_page,
|
||
|
sos_ui32_t flags);
|
||
|
|
||
|
/**
|
||
|
* Undo the mapping from vaddr to the underlying physical page (if any)
|
||
|
* @param vpage_vaddr The address of the virtual page (page-aligned)
|
||
|
*
|
||
|
* @return >= 0 when OK (the number of bytes of RAM unmapped), < 0 on error
|
||
|
*/
|
||
|
sos_ret_t sos_paging_unmap(sos_vaddr_t vpage_vaddr);
|
||
|
|
||
|
/**
|
||
|
* Undo the mapping from [vaddr .. vaddr + size[ to the underlying
|
||
|
* physical pages (if any)
|
||
|
* @param vpage_vaddr The address of the virtual page (page-aligned)
|
||
|
* @param size The size (in bytes) to unmap. MUST be page-aligned
|
||
|
*/
|
||
|
sos_ret_t sos_paging_unmap_interval(sos_vaddr_t base_vpage_vaddr,
|
||
|
sos_size_t size);
|
||
|
|
||
|
/**
|
||
|
* Return the page protection flags (SOS_VM_MAP_PROT_*) associated
|
||
|
* with the address, or SOS_VM_MAP_PROT_NONE when page is not mapped
|
||
|
*/
|
||
|
sos_ui32_t sos_paging_get_prot(sos_vaddr_t vaddr);
|
||
|
|
||
|
/**
|
||
|
* Change the page access rights
|
||
|
*/
|
||
|
sos_ret_t sos_paging_set_prot(sos_vaddr_t vaddr,
|
||
|
sos_ui32_t new_prot);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get the "dirty" status of the page
|
||
|
*/
|
||
|
sos_bool_t sos_paging_is_dirty(sos_vaddr_t vaddr);
|
||
|
|
||
|
/**
|
||
|
* Change the "dirty" status of the page
|
||
|
*/
|
||
|
sos_ret_t sos_paging_set_dirty(sos_vaddr_t vaddr,
|
||
|
sos_bool_t is_dirty);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Change the access rights of the mapping from [vaddr .. vaddr +
|
||
|
* size[ to the underlying physical pages (if any)
|
||
|
* @param vpage_vaddr The address of the virtual page (page-aligned)
|
||
|
* @param size The size (in bytes) to unmap. MUST be page-aligned
|
||
|
*/
|
||
|
sos_ret_t sos_paging_set_prot_of_interval(sos_vaddr_t vaddr,
|
||
|
sos_size_t size,
|
||
|
sos_ui32_t new_prot);
|
||
|
|
||
|
/**
|
||
|
* Return the physical address of the given virtual address. Since page
|
||
|
* at physical addr 0 is not mapped, the NULL result means "page not
|
||
|
* mapped".
|
||
|
*/
|
||
|
sos_paddr_t sos_paging_get_paddr(sos_vaddr_t vaddr);
|
||
|
|
||
|
/**
|
||
|
* Tell whether the address is physically mapped
|
||
|
*/
|
||
|
#define sos_paging_check_present(vaddr) \
|
||
|
(sos_paging_get_paddr(vaddr) != NULL)
|
||
|
|
||
|
|
||
|
/* *************************************************
|
||
|
* Functions restricted to mm_context module
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Release the references to all the referenced pages (and PT on
|
||
|
* x86). On x86, this applies only to the USER pages and PT.
|
||
|
*/
|
||
|
sos_ret_t sos_paging_dispose(sos_vaddr_t vaddr_PD);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Copy the MMU configuration related to the kernel virtual area
|
||
|
*/
|
||
|
sos_ret_t sos_paging_copy_kernel_space(sos_vaddr_t dest_vaddr_PD,
|
||
|
sos_vaddr_t src_vaddr_PD);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Copy the MMU configuration related to the user virtual area
|
||
|
*/
|
||
|
sos_ret_t sos_paging_copy_user_space(sos_vaddr_t dest_vaddr_PD,
|
||
|
sos_vaddr_t src_vaddr_PD);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Prepare the *current* address space for COW on the given *private*
|
||
|
* mapping
|
||
|
*/
|
||
|
sos_ret_t sos_paging_prepare_COW(sos_uaddr_t base_address,
|
||
|
sos_size_t length);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Try to resolve the given page fault exception by a COW.
|
||
|
*
|
||
|
* @param uaddr The user-space address (of the current MMU context) of
|
||
|
* the faulting access
|
||
|
*
|
||
|
* @return TRUE if the page fault was a real COW and could be handled,
|
||
|
* FALSE if the page fault is not subject to COW (no physical mem
|
||
|
* mapped at this address). <0 in case the given address is subject to
|
||
|
* COW BUT could not be resolved due to runtime errors
|
||
|
*/
|
||
|
sos_ret_t sos_paging_try_resolve_COW(sos_uaddr_t uaddr);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Retrieve the current physical address of the PD
|
||
|
*/
|
||
|
sos_paddr_t sos_paging_get_current_PD_paddr(void);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Change the current MMU configuration.
|
||
|
*
|
||
|
* @note DANGEROUS. Don't use it unless you know exactly what you're
|
||
|
* doing !
|
||
|
*/
|
||
|
sos_ret_t sos_paging_set_current_PD_paddr(sos_paddr_t paddr_PD);
|
||
|
|
||
|
#endif /* _SOS_PAGING_H_ */
|