Posté le 14/02/2021 13:35
Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 142 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements
Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd
Citer : Posté le 14/02/2021 13:39 | #
Hi Stage0! I'll answer your other question here as I'd like to keep the thread you posted it on (Tutoriels d'utilisation de gint) clean for the tutorials.
There are several potential "risks" to changing the VBR. I'm not sure which exactly you have in mind, so here are the main ones (and how gint handles them).
• Breaking the OS by running OS code without providing it with the interrupts that it expects
gint handles the interrupts with its own drivers and APIs, so OS code does not run at all (except maybe one or two pieces that I validated beforehand). It is possible to catch some interrupts and redirect the others (in an add-in that just wants to use a single interrupt and still use the OS), but this is not gint's approach; gint replaces the OS entirely.
• Being interrupted during the installation of the new interrupt handler
The VBR-changing function (src/kernel/cpu.s) blocks all interrupts during the change, and configures peripheral modules to disable interrupt signals that gint cannot handle before restoring them. TLB misses are still enabled during the change to ensure virtualization, so the code has to check that the old TLB miss handler works the instruction before changing VBR and that the new works immediately after changing VBR (which isn't too difficult).
• Setting VBR to an address that is unsuitable for interrupt handlers
Interrupt handlers run with SR.BL=1, meaning that exceptions, TLB misses, and interrupts are all disabled. Because TLB misses are disabled, virtualization cannot be ensured, hence the interrupt handler has to be loaded at a virtual address that is not managed by the MMU. Originally I used areas unused by the OS that worked from experience, but as problems consistently occurred with new models I switched to using some of the user data segment (dubbed "user RAM" or "uram"). The data segment is virtualized, but the non-virtualized address can be found by querying the MMU (src/kernel/kernel.c).
• Being unable to safely change back to the OS's VBR when leaving the add-in
gint's main integration with the OS is through a "world switch" the saves the whole state of relevant hardware at startup and restores it before giving control back to the OS when leaving. It is stable enough that it can even be used to leave mid-execution to invoke the main menu or perform operations on the file system (which require DMA access and thus cannot run in gint).
Ajouté le 14/02/2021 à 13:43 :
This jump looks incorrect:
jmp @r0
rts
nop
.stop:
sleep
jmp @r0
"mov.l .stop, r0" loads 4 bytes at .stop into r0; the value of r0 after that instruction is a combination of the opcodes of "sleep" and "jmp @r0". What you need instead to jump is the address of .stop.
The general way of loading the address of a symbol into a register is like this:
jmp @r0
nop
# later...
address_of_stop:
.long .stop
But in this case, because .stop is in the same file and close to the jump, and the target register is r0, you can use the mova instruction which does the same thing.
jmp @r0
nop
Of course, this type of jump is extremely common, so there is a shorter instruction to do this. This is bra, one of the very few instructions that are common enough to have 12 bits of parameters. It allows you to jump to a nearby symbol:
nop
Citer : Posté le 14/02/2021 14:18 | #
I fixed the code error, but I got the same result.
Citer : Posté le 14/02/2021 14:25 | #
You also need to change the final jump to a bra and add a nop at the end for the last delay slot.
Additionally, your code would need some context; namely, how are you compiling it and what linker script are you using?
Citer : Posté le 14/02/2021 14:41 | #
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(sh4)
ENTRY(_start)
MEMORY
{
rom (rx) : o = 0x00300000, l = 2M
ram (rwx) : o = 0x88000000, l = 2M
}
SECTIONS
{
.text : {
*(.text)
*(.text.*)
} > rom
.rodata : {
*(.rodata)
*(.rodata.*)
} > rom
.data : ALIGN(4) {
_datald = LOADADDR(.data) ;
_sdata = . ;
*(.data)
*(.data.*);
_edata = . ;
} >ram AT>rom
.bss : ALIGN(4) {
_bbss = . ;
*(.bss)
*(.bss*)
*(COMMON)
_ebss = . ;
} >ram
}
ld script
Citer : Posté le 14/02/2021 15:25 | # | Fichier joint
Oh no you can't do that - you will (eventually) overwrite OS data! This is the start of the RAM, but not the bit allocated to add-ins. The bit allocated to add-ins is virtualized at 0x08100000 (and is 512k and doesn't have execution permissions):
This is not a problem right now, but it will be soon.
Other than that, your program is fine. I tested it successfully on my fx-CG 50. I assume something in your build process is incorrect, so I'm attaching an archive of a minimal working example.
Citer : Posté le 15/02/2021 00:50 | #
Thanks for your help
Ajouté le 18/02/2021 à 07:39 :
I get restart error when I try to switch from privileged mode to user mode.
start.c
#include "init.h"
extern unsigned int DATA_LMA,DATA_VMA,DATA_SIZE;
extern unsigned int BSS_LMA,BSS_SIZE;
extern unsigned int VBR_Address;
static void regcpy(unsigned * restrict l, int s, unsigned * restrict r) {
while(s > 0)
{
*r++ = *l++;
*r++ = *l++;
*r++ = *l++;
*r++ = *l++;
s -= 16;
}
}
static void regclr(unsigned *r, int s) {
while(s > 0)
{
*r++ = 0;
*r++ = 0;
*r++ = 0;
*r++ = 0;
s -= 16;
}
}
__attribute__((section(".text.entry")))
int start(void){
Init_Hardware();
regcpy(&DATA_LMA, (int)&DATA_SIZE, &DATA_VMA);
regclr(&BSS_LMA, (int)&BSS_SIZE);
__asm__ volatile ("ldc %0, vbr\n"::"r"((unsigned)&VBR_Address));
CPU_SetSR(0x1000);
while (1){__asm__ volatile ("sleep\n");}
}
init.s
.global _Init_Hardware
.global _CPU_SetSR
_Init_Hardware:
! SR.MD = 1
! SR.BL = 1
! SR.RB = 1
! SR.IMASK = 0b1111
mov.l SR_Configure, r1
ldc r1, sr
mov.l Stack_Address, r15
rts
nop
_CPU_SetSR:
ldc r4, sr
rts
nop
.align 4
Stack_Address:
.long 0x8180000
SR_Configure:
.long 0x700000f0
ld
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(sh4)
ENTRY(_start)
MEMORY
{
rom (rx) : o = 0x00300000, l = 2M
ram (rw) : o = 0x08100000, l = 512k
}
SECTIONS
{
.text : {
*(.text.entry)
*(.text)
*(.text.*)
. = ALIGN(0x100);
_VBR_Address = . ;
. = _VBR_Address + 0x100 ;
_EXH_BEGIN = ABSOLUTE(.) ;
*(.exh) ;
. = _VBR_Address + 0x400 ;
_TLBH_BEGIN = ABSOLUTE(.) ;
*(.tlbh) ;
. = _VBR_Address + 0x600 ;
_INTH_BEGIN = ABSOLUTE(.) ;
*(.inth) ;
} > rom
.rodata : {
*(.rodata)
*(.rodata.*)
} > rom
. = ORIGIN(ram);
.bss (NOLOAD) : {
_BSS_LMA = . ;
*(.bss.vram)
*(.bss COMMON)
. = ALIGN(16);
} >ram :NONE
_BSS_SIZE = SIZEOF(.bss) ;
.data ALIGN(4) : ALIGN(4) {
_DATA_LMA = LOADADDR(.data) ;
_DATA_VMA = . ;
*(.data)
*(.data.*);
. = ALIGN(16);
} >ram AT>rom
_DATA_SIZE = SIZEOF(.data) ;
/DISCARD/ : {
*(.debug_info .debug_abbrev .debug_loc .debug_aranges
.debug_ranges .debug_line .debug_str)
*(.jcr)
*(.eh_frame_hdr)
*(.eh_frame)
*(.comment)
}
}
The current exception handling(.exh .tlbh, .inth) module is almost the same now,modify them later
mov.l .addr, r1
jmp @r1
.align 4
.addr:
.long 0x80000000
Why does it happen?
Citer : Posté le 18/02/2021 08:43 | #
There are a couple of things of note here.
First of all, you don't need to enable privileged mode because it is already enabled. In fact, if you were in user mode, there would be no escape and making a kernel would be impossible. The separation between user mode and privileged mode is designed specifically so that you can't break out of user mode without help from the code that put you in it. Fortunately, the fx-CG 50 OS runs add-ins in privileged mode, which makes this whole adventure possible.
If you want to leave the add-in and return to the main menu later, you can't override SR and VBR and not restore them. Specifically if you ever attempt to leave the add-in with your own VBR this is a guaranteed crash. You might simply decide to reboot (as FiXOS does), which frees you from the burden of monitoring everything the OS might need for a successful return.
Your stack address change is very suspicious. The address you use, 0x08180000, is exactly at the end of the data block, which is good. But you can absolutely not change the stack in the middle of a C function such as start(), and the compiler will never produce code that can have its stack changed. In fact, 0x08180000 is already the stack pointer on fx-CG 50, except that a couple of values are stored before the add-in starts. By changing the stack address here, you confuse your own start() function into a crash and you override data that the OS has placed on the stack before calling you.
The crash likely occurs because start() tries to pop off the stack values that were put there before calling InitHardware(), except that the stack pointer has now moved. While attempting this operation, the stack exceeds 0x08180000 and thus a TLB miss occurs, which crashes at that stage.
If you ever make it to the VBR change without crashing because of the stack, the program will still crash as soon as you set SR.BL=0 because you will be assaulted with interrupts from timers, the RTC, and other mechanisms, and your interrupt handler doesn't handle them yet.
Your exception, TLB miss and interrupt handlers cannot simply be in the code section because that section is virtualized and the handlers run with SR.BL=1, which disables the MMU. You need to load the interrupt handlers into an area of RAM accessed through P1 or P2 (that are non-virtualized). This is the most tricky problem in your case.
Finally, in your rebooting event handler, you have forgotten a nop after the jmp (which is a delay slot instruction) and you should jump to 0xa0000000 (which is the same as 0x80000000 but with cache disabled) for a guaranteed successful reboot.
I know it's a lot, but you clearly know where you're going, so good luck!
Citer : Posté le 18/02/2021 09:09 | #
Thanks for your prompt reply I found the error:I need to handle interrupts
Ajouté le 23/02/2021 à 04:53 :
I have a problem again...
When I run this code,The emulator crashed again:
memcpy((void*)0x88000100,exh,(uint32_t)EXH_SIZE);
memcpy((void*)0x88000400,tlbh,(uint32_t)TLBH_SIZE);
memcpy((void*)0x88000600,inth,(uint32_t)INTH_SIZE);
(I don't care about breaking OS data )
Citer : Posté le 23/02/2021 08:28 | #
How are exh and EXH_SIZE provided? Particulary EXH_SIZE. If it's set in the linker script, then the size of the exception handler is the value of the symbol _EXH_SIZE, which is (uint32_t)&EXH_SIZE from the program.
Generally speaking, if you create a global variable x then it is compiled into a symbol _x (the _ is a convention on this architecture) and the linker stores the address of the variable to _x. In the C program, if you reference &x, the compiler inserts code to obtain the value of the symbol, but if you reference x, the code also accesses memory at the address obtained from the symbol.
Hence the (admittedly confusing) result that symbols specified in the linker are just addresses of non-existing variables. If you use EXH_SIZE as a variable then you're doing a memory access with your exception handler's size as the address, which fails of course.
Citer : Posté le 23/02/2021 09:32 | #
I'm so careless.I forgot to add &
Ajouté le 05/03/2021 à 10:52 :
I occasionally noticed that RC (https://bible.planet-casio.com/lephenixnoir/resource-compendium.html) says
On the fx-CG 50 RAM starts at 8c000000 so the main process' stack is from
8c0f0000 to 8c15ffff and the child's is from 8c160000 to 0x8c1dffff.
and what is the address 0x88000000?I have been using this address before and tested well.I may have a misunderstanding?
Citer : Posté le 05/03/2021 10:55 | #
Traditionally, address 0x88000000 is RAM. Every model except the fx-CG 50 uses this address.
By contrast, fx-CG 50 has RAM at 0x8c000000. It works the same in every other aspect but all addresses are offset by 0x04000000.
Only one of the two addresses will work, if your program works with 0x88000000 then that is what your model uses.
gint currently detects the base address from the value in r15 at the start of the program, but I believe it can be queried in the BSC.
Citer : Posté le 05/03/2021 11:06 | #
Than I think this may be a problem with the simulator, I have not tested it on a real machine.I want to confirm that the ROM address of FXCG50 is 0x84000000?
Citer : Posté le 05/03/2021 11:07 | #
The ROM address of every single model is 0x80000000 (P1) or 0xa0000000 (P2).
Please note, the fx-CG 50 emulator is *not* the same as the actual fx-CG 50 and it uses 0x88000000 for the RAM even though the fx-CG 50 uses 0x8c000000.
Citer : Posté le 05/03/2021 11:36 | #
And are the files in the ROM scattered or concentrated in a certain block?Does the user's 16MB ROM start from 0x8000000+16MB?
Citer : Posté le 05/03/2021 11:39 | #
There is a block roughly at the end yes, but the address and format change depending on the OS version. Using the filesystem on your own is (very) difficult and Yatis has spent some months investigating that so far. Yatis is the only one to use a custom read-only filesystem driver (on older models I believe?), even gint relies on BFile.
Citer : Posté le 05/03/2021 11:46 | #
I probably understand. I will investigate as much as possible.