KallistiOS git master
Independent SDK for the Sega Dreamcast
|
Driver for the SH4's MMU (disabled by default). More...
Topics | |
Cacheability Settings | |
SH4 MMU page cachability settings values | |
Page size settings | |
SH4 MMU page sizes | |
Protection Settings | |
SH4 MMU page protection settings values | |
Files | |
file | mmu.h |
Memory Management Unit and Translation Lookaside Buffer handling. | |
Data Structures | |
struct | mmupage_t |
MMU TLB entry for a single page. More... | |
struct | mmusubcontext_t |
MMU sub-context type. More... | |
struct | mmucontext_t |
MMU context type. More... | |
Macros | |
#define | MMU_SUB_PAGES 512 |
The number of pages in a sub-context. | |
Typedefs | |
typedef mmupage_t *(* | mmu_mapfunc_t) (mmucontext_t *context, int virtpage) |
MMU mapping handler. | |
Functions | |
void | mmu_use_table (mmucontext_t *context) |
Set the "current" page tables for TLB handling. | |
mmucontext_t * | mmu_context_create (int asid) |
Allocate a new MMU context. | |
void | mmu_context_destroy (mmucontext_t *context) |
Destroy an MMU context when a process is being destroyed. | |
int | mmu_virt_to_phys (mmucontext_t *context, int virtpage) |
Using the given page tables, translate the virtual page ID to a physical page ID. | |
int | mmu_phys_to_virt (mmucontext_t *context, int physpage) |
Using the given page tables, translate the physical page ID to a virtual page ID. | |
void | mmu_switch_context (mmucontext_t *context) |
Switch to the given context. | |
void | mmu_page_map (mmucontext_t *context, int virtpage, int physpage, int count, page_prot_t prot, page_cache_t cache, bool share, bool dirty) |
Set the given virtual page to map to the given physical page. | |
int | mmu_copyin (mmucontext_t *context, uint32_t srcaddr, uint32_t srccnt, void *buffer) |
Copy a chunk of data from a process' address space into a kernel buffer, taking into account page mappings. | |
int | mmu_copyv (mmucontext_t *context1, struct iovec *iov1, int iovcnt1, mmucontext_t *context2, struct iovec *iov2, int iovcnt2) |
Copy a chunk of data from one process' address space to another process' address space, taking into account page mappings. | |
mmu_mapfunc_t | mmu_map_get_callback (void) |
Get the current mapping function. | |
mmu_mapfunc_t | mmu_map_set_callback (mmu_mapfunc_t newfunc) |
Set a new MMU mapping handler. | |
int | mmu_page_map_static (uintptr_t virt, uintptr_t phys, page_size_t page_size, page_prot_t page_prot, bool cached) |
Create a static virtual memory maping. | |
void | mmu_init (void) |
Initialize MMU support. | |
void | mmu_init_basic (void) |
Initialize basic MMU support. | |
void | mmu_shutdown (void) |
Shutdown MMU support. | |
void | mmu_shutdown_basic (void) |
Shutdown basic MMU support. | |
void | mmu_reset_itlb (void) |
Reset ITLB. | |
bool | mmu_enabled (void) |
Check if MMU translation is enabled. | |
void | mmu_set_sq_addr (void *addr) |
Reset the base target address for store queues. | |
Driver for the SH4's MMU (disabled by default).
Since the software has to handle TLB misses on the SH-4, we have freedom to use any page table format we want (and thus save space), but we must make it quick to access. The SH-4 can address a maximum of 512M of address space per "area", but we only care about one area, so this is the total maximum addressable space. With 4K pages, that works out to 2^17 pages that must be mappable, or 17 bits. We use 18 bits just to be sure (there are a few left over).
Page tables (per-process) are a sparse two-level array. The virtual address space is actually 2^30 bytes, or 2^(30-12)=2^18 pages, so there must be a possibility of having that many page entries per process space. A full page table for a process would be 1M, so this is obviously too big!! Thus the sparse array.
The bottom layer of the page tables consists of a sub-context array for 512 pages, which translates into 2K of storage space. The process then has the possibility of using one or more of the 512 top-level slots. For a very small process (using one page for code/data and one for stack), it should be possible to achieve a page table footprint of one page. The tables can grow from there as necessary.
Virtual addresses are broken up as follows:
#define MMU_SUB_PAGES 512 |
The number of pages in a sub-context.
typedef mmupage_t *(* mmu_mapfunc_t) (mmucontext_t *context, int virtpage) |
MMU mapping handler.
This type is used for functions that will take over the mapping for the kernel. In general, there shouldn't be much use for taking this over yourself, unless you want to change the size of the page table entries or something of the like.
context | The context in use. |
virtpage | The virtual page to map. |
mmucontext_t * mmu_context_create | ( | int | asid | ) |
Allocate a new MMU context.
Each process should have exactly one of these, and these should not exist without a process. Since KOS doesn't actually have a process model of its own, that means you will only ever have one of these, if any.
asid | The address space ID of this process. |
void mmu_context_destroy | ( | mmucontext_t * | context | ) |
Destroy an MMU context when a process is being destroyed.
This function cleans up a MMU context, deallocating any memory its using.
context | The context to clean up after. |
int mmu_copyin | ( | mmucontext_t * | context, |
uint32_t | srcaddr, | ||
uint32_t | srccnt, | ||
void * | buffer ) |
Copy a chunk of data from a process' address space into a kernel buffer, taking into account page mappings.
context | The context to use. |
srcaddr | Source, in the mapped memory space. |
srccnt | The number of bytes to copy. |
buffer | The kernel buffer to copy into (should be in P1). |
int mmu_copyv | ( | mmucontext_t * | context1, |
struct iovec * | iov1, | ||
int | iovcnt1, | ||
mmucontext_t * | context2, | ||
struct iovec * | iov2, | ||
int | iovcnt2 ) |
Copy a chunk of data from one process' address space to another process' address space, taking into account page mappings.
context1 | The source's context. |
iov1 | The scatter/gather array to copy from. |
iovcnt1 | The number of entries in iov1. |
context2 | The destination's context. |
iov2 | The scatter/gather array to copy to. |
iovcnt2 | The number of entries in iov2. |
bool mmu_enabled | ( | void | ) |
Check if MMU translation is enabled.
void mmu_init | ( | void | ) |
Initialize MMU support.
Unlike most things in KOS, the MMU is not initialized by a normal startup. This is because for most homebrew, its not needed.
This implies mmu_init_basic().
void mmu_init_basic | ( | void | ) |
Initialize basic MMU support.
This function can be used to initialize the very minimum for MMU to work with static mappings. Dynamic mapping (and mmu_page_map()) will not work. If you need dynamic mapping, use mmu_init() instead.
mmu_mapfunc_t mmu_map_get_callback | ( | void | ) |
Get the current mapping function.
mmu_mapfunc_t mmu_map_set_callback | ( | mmu_mapfunc_t | newfunc | ) |
Set a new MMU mapping handler.
This function will allow you to set a new function to handle mapping for memory pages. There's not much of a reason to do this unless you really do not like the way KOS handles the page mapping internally.
newfunc | The new function to handle mapping. |
void mmu_page_map | ( | mmucontext_t * | context, |
int | virtpage, | ||
int | physpage, | ||
int | count, | ||
page_prot_t | prot, | ||
page_cache_t | cache, | ||
bool | share, | ||
bool | dirty ) |
Set the given virtual page to map to the given physical page.
This implies turning on the "valid" bit. Also sets the other named attributes as specified.
context | The context to modify. |
virtpage | The first virtual page to map. |
physpage | The first physical page to map. |
count | The number of sequential pages to map. |
prot | Memory protection for page (see Protection Settings). |
cache | Cache scheme for page (see Cacheability Settings). |
share | Set to share between processes (meaningless). |
dirty | Set to mark the page as dirty. |
int mmu_page_map_static | ( | uintptr_t | virt, |
uintptr_t | phys, | ||
page_size_t | page_size, | ||
page_prot_t | page_prot, | ||
bool | cached ) |
Create a static virtual memory maping.
This function reserves one TLB entry to create a static mapping from a virtual memory address to a physical memory address. Static mappings are never flushed out of the TLB, and are sometimes useful when the whole MMU function is not necesary. Static memory mappings can also use different page sizes.
Note that the only way to undo static mappings is to call mmu_shutdown_basic().
virt | The virtual address for the memory mapping. |
phys | The physical address for the memory mapping. |
page_size | The size of the memory page used. |
page_prot | The memory protection usef for that mapping. |
cached | True if the mapped memory area is cached, false otherwise. |
0 | On success. |
-1 | When the virtual or physical addresses are not aligned to the page size. |
int mmu_phys_to_virt | ( | mmucontext_t * | context, |
int | physpage ) |
Using the given page tables, translate the physical page ID to a virtual page ID.
context | The context to look in. |
physpage | The physical page number to look for. |
void mmu_reset_itlb | ( | void | ) |
Reset ITLB.
void mmu_set_sq_addr | ( | void * | addr | ) |
Reset the base target address for store queues.
addr | The base address to reset to |
void mmu_shutdown | ( | void | ) |
Shutdown MMU support.
Turn off MMU support after it was initialized with mmu_init(). You should try to make sure this gets done if you initialize the MMU in your program, so as to play nice with loaders and the like (that will not expect that its on, in general).
void mmu_shutdown_basic | ( | void | ) |
Shutdown basic MMU support.
Turn off basic MMU support after it was initialized with mmu_init_basic(). You should try to make sure this gets done if you initialize the MMU in your program, so as to play nice with loaders and the like (that will not expect that its on, in general).
void mmu_switch_context | ( | mmucontext_t * | context | ) |
Switch to the given context.
This function switches to the given context's address space ID. The context should have already been made current with mmu_use_table(). You are responsible for invalidating any caches as necessary, as well as invalidating any stale TLB entries.
context | The context to make current. |
void mmu_use_table | ( | mmucontext_t * | context | ) |
Set the "current" page tables for TLB handling.
This function is useful if you're trying to implement a process model or something of the like on top of KOS. Essentially, this allows you to completely boot the MMU context in use out and replace it with another. You will need to call the mmu_switch_context() function afterwards to set the address space id.
context | The context to make current. |
int mmu_virt_to_phys | ( | mmucontext_t * | context, |
int | virtpage ) |
Using the given page tables, translate the virtual page ID to a physical page ID.
context | The context to look in. |
virtpage | The virtual page number to look for. |