Created
August 12, 2020 07:52
-
-
Save tsutsui/2bd10b5b91d67dedb1b251b55cc34fca to your computer and use it in GitHub Desktop.
Sun3 (not sun3x) MMU design memo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sun3 (not sun3x) MMU design memo | |
================================ | |
Written by Izumi Tsutsui (20200812) | |
Quick reversed from NetBSD/sun3 src/sys/arch/sun3/sun3/pmap.c implementation. | |
VA space | |
-------- | |
0x00000000 - 0x0FFFFFFF (256MB) | |
+-------------------------------------------------------------------------------------------------------------------------------+ | |
| 31| 30| 29| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| | |
+---------------+-----------------------------------------------------------+---------------------------------------------------| | |
| (should be 0) | <--------- segment map number ----------> | <- PTE num -> | <------------ page offset (PGOFSET) -----------> | | |
+-------------------------------------------------------------------------------------------------------------------------------+ | |
PA space | |
-------- | |
0x00000000 - 0xFFFFFFFF (whole 32bit 4GB?) | |
+-------------------------------------------------------------------------------------------------------------------------------+ | |
| 31| 30| 29| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| | |
+---------------+-----------------------------------------------------------+---------------------------------------------------| | |
| <-------------- page frame number (PG_FRAME) --------------> | <------------ page offset (PGOFSET) -----------> | | |
+-------------------------------------------------------------------------------------------------------------------------------+ | |
context (CONTEXT) | |
------------------ | |
Maybe introduced to avoid extra flush ops against pmap and cache on switching userland processes | |
- 8 hardware "context"s | |
- switched by writing context number at CONTEXT_REG (0x30000000) with SFC/DFC=0x3 | |
(see sun3/control.c and sun68k/ctrlsp.S) | |
- no other valid address? | |
- pmap.c comment says: | |
* In this pmap design, the kernel is mapped into all contexts | |
* Processes take up a known portion of the context | |
* Processes compete for the available contexts on a LRU basis | |
* each "context"'s address space is defined by the 2048 one-byte entries in the segment map. | |
* kernel ptes are in all contexts, and are always in the mmu | |
- context 0 (EMPTY_CONTEXT) is used for kernel_pmap (in current pmap.c implementation) | |
- context 1 - 7 are used for userland pmap and managed by context_free_queue TAILQ | |
- see also pmap.c comments for future "projects" | |
- All PTEs are corresponding to contexts | |
- kernel PTEs are mapped to ALL context via set_segmap_allctx() in locore.s | |
- per implementation of set_segmap_allctx(): | |
* write context number to CONTEXT_REG | |
* write SME to (SEGMAP_BASE | (va & CONTROL_ADDR_MASK)) | |
* loop above through all context (i.e. 7 to 0) | |
-> This also implies the current context number infomation is also stored | |
(or used to choose hardware SEGMAP entry) on writing SME to SEGMAP space, | |
- cache.c also has `cache_flush_context()` function | |
- (probably) VA cache also records and refers context number of the VA and hits only if the VA is in the same context | |
- allocated by context_allocate() for each userland mappings in pmap_enter_user() and static pmap_fault_reload() | |
- freed by context_free() in pmap_destroy() via static pmap_release() | |
segment map (SEGMAP) | |
-------------------- | |
PV mapping management mechanism per segement basis. | |
- 2048 one-byte entries per each context | |
- corresponding to VA bit 27-17 | |
- Accessed via address space 0x20000000 - 0x2FFFFFFC with SFC/DFC=0x3 | |
(see sun3/control.c and sun68k/ctrlsp.S) | |
- set_segmap() and get_segmap() functions are used to access | |
- Maybe lower address bits (16-0) are ignored | |
- Probably "current" context number is implicitly decoded to choose SEGMAP per context | |
- Each segment map entry has one byte "SME" (segment map entry?) corresponding to "PMEG" number | |
- actually "SME" index (segment number) is calculated from va using VA_SEGNUM() | |
``` | |
/* pmap3.h */ | |
#define SEGSHIFT 17 /* LOG2(NBSG) */ | |
/* pte3.h */ | |
#define VA_SEGNUM(x) ((u_int)(x) >> SEGSHIFT) | |
``` | |
Page Map Entry Group (PMEG) | |
--------------------------- | |
- pmap.c comment says: | |
* sun3s also have this evil "PMEG" crapola | |
* PMEG contains the mappings for that virtual segment | |
* Each PMEG maps a segment of 128Kb length, with 16 pages of 8Kb each. | |
- Up to 255 entries | |
- PMEG number 255 is used for `SEGINV` (so actually 254 entries are available?) | |
This means: | |
- 2048 * 8 segment maps are necessary to handle whole 256MB VA space for all contexts | |
- Only 256 (or 255) sets of hardware (= PMEGs) are available in MMU to handle actual PV mappings per each segment map | |
as another pmap.c comment says: | |
* As you might guess, these PMEGs are in short supply and heavy demand. | |
* PMEGs allocated to the kernel are "static" in the sense that they can't be stolen from it. | |
* PMEGs allocated to a particular segment of a pmap's virtual space will be fought over by the other pmaps. | |
page map (PGMAP) | |
---------------- | |
Contains page table entries (PTEs). | |
- Accessed via address space 0x10000000 - 0x1FFFFFFC with SFC/DFC=0x3 | |
(see sun3/control.c and sun68k/ctrlsp.S) | |
- set_pte() and get_pte() functions are used to access | |
- VA (i.e. segment map number) is used to specify PTE address | |
- Probably PMEG hardware looks up "SME" number set by set_segmap() from segment map number in VA | |
and update PTEs in the selected "PMEG" implemented as MMU hardware | |
- Maybe "PTE num" bits (16-13) in VA are also used to specify PTE number (0-15) in each PMEG hardware | |
``` | |
#define VA_PTE_NUM_SHIFT 13 | |
#define VA_PTE_NUM_MASK (0xF << VA_PTE_NUM_SHIFT) | |
#define VA_PTE_NUM(va) (((va) & VA_PTE_NUM_MASK) >> VA_PTE_NUM_SHIFT) | |
``` | |
page table entry (PTE) | |
---------------------- | |
32 bit PTE | |
- per definitions in sun3/include/pte3.h: | |
+-------------------------------------------------------------------------------------------------------------------------------+- | |
| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | | |
+---------------------------------------------------------------+-------------------------------+-------------------------------+- | |
| PG_PERM | PG_TYPE | PG_MODREF | | |
+---------------------------------------------------------------+-------------------------------+-------------------------------+ | |
| PG_VALID | PG_WRITE | PG_SYSTEM | PG_NC | (OBMEM/OBIO/VME_D16/VMED32) | PG_REF | PG_MOD | | |
+-------------------------------------------------------------------------------------------------------------------------------+- | |
-+-----------------------------------------------------------------------------------------------+ | |
| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| | |
-+-------------------+---------------------------------------------------------------------------| | |
|<--- unused ? ---> | <-------------- page frame number (PG_FRAME) --------------> | | |
-+-----------------------------------------------------------------------------------------------+ | |
(BTW, all pte variables in pmap.c should be declared as unsigned, i.e. uint32_t rather than int?) | |
PMEG management in pmap implementation | |
-------------------------------------- | |
``` | |
#define NPMEG 256 | |
``` | |
``` | |
struct pmeg_state { | |
TAILQ_ENTRY(pmeg_state) pmeg_link; /* opaque to handle PMEGs in TAILQs (free / inactive / active / kernel (wired)) */ | |
int pmeg_index; /* index # of NPMEG (0-255) */ | |
pmap_t pmeg_owner; /* which pmap owns this pmeg (kernel_pmap or user pmaps) */ | |
int pmeg_version; /* copy of pmap->pm_version; incremented on each pmap_create(9) call */ | |
vaddr_t pmeg_va; /* which VA where this PMEG belongs */ | |
int pmeg_wired; /* bitmap info of wired mapping for each PTE (0-15) XXX: should be unsigned? */ | |
int pmeg_reserved; /* indicates reserved PMEG (for PROM mappings etc.) */ | |
int pmeg_vpages; /* a number of valid PV mappings */ | |
int pmeg_qstate; /* which TAILQ this PMEG belongs (PMEGQ_FREE / PMEGQ_INACTIVE / PMEGQ_ACTIVE / PMEGQ_KERNEL / PMEGQ_NONE) */ | |
}; | |
``` | |
Consideration | |
------------- | |
I'm afraid it is a bit hard to implement wired map handling due to limited number of context.. | |
- Should we keep all context and pmeg which contain PTE mapped as wired?? | |
- Maybe I should learn and clarify definition and behavior of "wired" in MD pmap and MI uvm implementation.. | |
(keep P-V mappings in any case??) | |
- Note current `pmeg_wired` in struct pmeg_state seems only used for accounting in pmap_wired_pages(9) | |
(as exported pmap_wired_count(9) macro) | |
Random memo | |
----------- | |
- context_allocate() / context_free() pair | |
- pmeg_allocate() / pmeg_free() pair | |
- pmeg_release() is used to move pmeg from active TAILQ to inactive TAILQ as cached entries | |
when context is stolen by other process (see pmap.c comments) | |
- pv_link (PV mapping) is only managed for RAM (to handle cache alias?) | |
- get_pte_pmeg() referes "pmeg_num" as SME number and writes segmap at corresponding VA offset with pmeg_num by set_segmap() | |
- set_pte_pmeg() vice versa | |
--- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment