gint/src/mmu/mmu.c

235 lines
5.0 KiB
C
Raw Normal View History

//---
// gint:mmu:mmu - MMU driver definition and context management
//---
#include <gint/mmu.h>
#include <gint/drivers.h>
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
#include <gint/drivers/states.h>
#include <gint/hardware.h>
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
//---
// Unified interface
//---
/* mmu_translate(): Get the physical address for a virtual page */
uint32_t mmu_translate(uint32_t page, uint32_t *size)
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
{
return isSH3() ? tlb_translate(page,size) : utlb_translate(page,size);
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
}
/* mmu_uram(): Get pointer to physical start of user RAM */
void *mmu_uram(void)
{
/* Use P1 access */
return (void *)(mmu_translate(0x08100000, NULL) | 0x80000000);
}
/* mmu_uram_size(): Get size of user RAM area */
uint32_t mmu_uram_size(void)
{
uint32_t size = 0;
uint32_t pagesize;
while(mmu_translate(0x08100000 + size, &pagesize) != (uint32_t)-1)
{
size += pagesize;
}
return size;
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
}
/* mmu_is_rom(): Determine if an address points to ROM */
bool mmu_is_rom(void const *ptr)
{
uint32_t a = (uint32_t)ptr;
if(a >= 0x80000000 && a < 0x88000000)
return true;
if(a >= 0xa0000000 && a < 0xa8000000)
return true;
if(a >= 0x00300000 && a < 0x00800000)
return true;
return false;
}
//---
// SH7705 TLB
//---
#ifdef FX9860G
/* tlb_addr() - get the P4 address of a TLB address entry */
GINLINE const tlb_addr_t *tlb_addr(uint way, uint E)
{
uint32_t addr = 0xf2000000 | (E << 12) | (way << 8);
return (void *)addr;
}
/* tlb_data() - get the P4 address of a TLB data entry */
GINLINE const tlb_data_t *tlb_data(uint way, uint E)
{
uint32_t addr = 0xf3000000 | (E << 12) | (way << 8);
return (void *)addr;
}
/* tlb_mapped_memory() - count amount of mapped memory */
void tlb_mapped_memory(uint32_t *p_rom, uint32_t *p_ram)
{
uint32_t rom = 0, ram = 0;
for(int way = 0; way < 4; way++)
for(int E = 0; E < 32; E++)
{
const tlb_addr_t *addr = tlb_addr(way, E);
const tlb_data_t *data = tlb_data(way, E);
if(!addr->V || !data->V) continue;
int size = data->SZ ? 4096 : 1024;
uint32_t src;
if(data->SZ) src = (((addr->VPN >> 2) | E) << 12);
else src = (addr->VPN | (E << 2)) << 10;
if(src >= 0x00300000 && src < 0x00380000) rom += size;
if(src >= 0x08100000 && src < 0x08180000) ram += size;
}
if(p_rom) *p_rom = rom;
if(p_ram) *p_ram = ram;
gint[HWURAM] = ram;
}
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
/* tlb_translate(): Get the physical address for a virtual page */
uint32_t tlb_translate(uint32_t page, uint32_t *size)
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
{
for(int way = 0; way < 4; way++)
for(int E = 0; E < 32; E++)
{
const tlb_addr_t *addr = tlb_addr(way, E);
const tlb_data_t *data = tlb_data(way, E);
if(!addr->V || !data->V) continue;
uint32_t src;
if(data->SZ) src = (((addr->VPN >> 2) | E) << 12);
else src = (addr->VPN | (E << 2)) << 10;
if(src == page)
{
if(size) *size = (data->SZ ? 4096 : 1024);
return data->PPN << 10;
}
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
}
return -1;
}
#endif
//---
// SH7305 Unified TLB
//---
GINLINE const utlb_addr_t *utlb_addr(uint E)
{
uint32_t addr = 0xf6000000 | ((E & 0x3f) << 8);
return (void *)addr;
}
GINLINE const utlb_data_t *utlb_data(uint E)
{
uint32_t addr = 0xf7000000 | ((E & 0x3f) << 8);
return (void *)addr;
}
void utlb_mapped_memory(uint32_t *p_rom, uint32_t *p_ram)
{
uint32_t rom = 0, ram = 0;
for(int E = 0; E < 64; E++)
{
const utlb_addr_t *addr = utlb_addr(E);
const utlb_data_t *data = utlb_data(E);
if(!addr->V || !data->V) continue;
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
/* Magic formula to get the size without using an array since
this code is used even before global data is initialized */
int sz = ((data->SZ1 << 1) | data->SZ2) << 3;
int size = 1 << ((0x14100c0a >> sz) & 0xff);
uint32_t src = addr->VPN << 10;
if(src >= 0x00300000 && src < 0x00700000) rom += size;
if(src >= 0x08100000 && src < 0x08180000) ram += size;
}
if(p_rom) *p_rom = rom;
if(p_ram) *p_ram = ram;
gint[HWURAM] = ram;
}
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
uint32_t utlb_translate(uint32_t page, uint32_t *size)
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
{
for(int E = 0; E < 64; E++)
{
const utlb_addr_t *addr = utlb_addr(E);
const utlb_data_t *data = utlb_data(E);
if(!addr->V || !data->V) continue;
if((uint32_t)addr->VPN << 10 == page)
{
/* Same magic formula as utlb_mapped_memory() */
int sz = ((data->SZ1 << 1) | data->SZ2) << 3;
if(size) *size = 1 << ((0x14100c0a >> sz) & 0xff);
return data->PPN << 10;
}
kernel: dynamic loading of GMAPPED functions to user RAM This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
2020-09-17 14:48:54 +02:00
}
return -1;
}
2023-02-02 14:23:03 +01:00
itlb_addr_t const *itlb_addr(uint E)
{
uint32_t addr = 0xf2000000 | ((E & 3) << 8);
return (void *)addr;
}
itlb_data_t const *itlb_data(uint E)
{
uint32_t addr = 0xf3000000 | ((E & 3) << 8);
return (void *)addr;
}
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void configure(void)
{
/* Make writes to the control register area synchronous; this is needed
for the SPU to operate properly */
if(isSH4()) SH7305_MMU.PASCR.UBC = 1;
}
//---
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
// State and driver metadata
//---
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void hsave(mmu_state_t *s)
{
if(isSH3()) return;
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
s->PASCR = SH7305_MMU.PASCR.lword;
s->IRMCR = SH7305_MMU.IRMCR.lword;
}
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void hrestore(mmu_state_t const *s)
{
if(isSH3()) return;
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
SH7305_MMU.PASCR.lword = s->PASCR;
SH7305_MMU.IRMCR.lword = s->IRMCR;
}
gint_driver_t drv_mmu = {
.name = "MMU",
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
.configure = configure,
.hsave = (void *)hsave,
.hrestore = (void *)hrestore,
.state_size = sizeof(mmu_state_t),
};
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
GINT_DECLARE_DRIVER(02, drv_mmu);