Why does access to an unmapped location not generate a hardware exception (Microblaze)
Asked Answered
V

2

6

I want to write my code that will handle TLB misses on the Microblaze and through that, of course, the page tables etc. This is all being done on OVPsim.

As I am learning as I go I wrote this little piece of assembly to reference an unmapped location (0x1000000) - I am running this as privileged code with VM on:

ori r20, r0, 0
ori r12, r0, 0x1000000
/* next line should break it */
sw  r20, r12, r0

(I.e., write the contents of r20 == 0 out to the address formed by ORing r12 == 0x1000000 and r0 == 0 => 0x1000000 obviously.)

But instead of jumping to the exception vector, GDB reports "Program received SIGSEV" - what did I get wrong? I haven't got the enable hardware exceptions bit on in the MSR but the manual says you cannot mask these exceptions in any case so that shouldn't be the issue.

Further information I cannot get any (eg, including misalignment exceptions) of the exception handling code to execute, (unless I explicitly call it), whether or not I am using the debugger. With the debugger off I get this output from OVPsim (NB I merely changed the test address - there is no significance in the difference between 0xA000000 and 0x100000 above):

Processor Exception (PC_PRX) Processor 'platform/cpu0' 0x248: sw       r20, r12, r0
Processor Exception (PC_WPX) No write access at 0xa000000

This is all code being run in privileged mode, so I can see no overt reason for it not to call the handlers, unless I have not configured the Microblaze properly. I have these turned on:

icmAddStringAttr(cpu1_attr, "endian", "big");
icmAddDoubleAttr(cpu1_attr, "mips", 100.000000);
icmAddStringAttr(cpu1_attr, "variant", "V8_20");
icmAddBoolAttr(cpu1_attr, "verbose", "true");
icmAddUns32Attr(cpu1_attr, "C_PVR", 2);
icmAddUns32Attr(cpu1_attr, "C_USE_MMU", 3);
icmAddStringAttr(cpu1_attr, "C_USE_BARREL", "1");
icmAddStringAttr(cpu1_attr, "C_USE_DIV", "1");
icmAddUns32Attr(cpu1_attr, "C_USE_INTERRUPT", 1);
icmAddUns32Attr(cpu1_attr, "C_MMU_TLB_ACCESS", 3);
icmAddUns32Attr(cpu1_attr, "C_UNALIGNED_EXCEPTIONS", 1);
icmAddUns32Attr(cpu1_attr, "C_ILL_OPCODE_EXCEPTION", 1);
icmAddUns32Attr(cpu1_attr, "C_DIV_ZERO_EXCEPTION", 1);
icmAddUns32Attr(cpu1_attr, "C_OPCODE_0x0_ILLEGAL", 1);
icmAddUns32Attr(cpu1_attr, "C_DEBUG_ENABLED", 1);

There is no reason to believe this won't work as OVPsim will run Linux on the Microblaze.

Veg answered 17/11, 2014 at 23:20 Comment(4)
You Microblaze configuration looks OK. The output of the emulator looks a bit odd. The "No write access" exception could mean that the corresponding page was found in TLB but it has no write access enabled. You should see an exception even in this case. Try setting EE bit in MSR, although , just in case its OVPsim implementation is wrong.Randell
I have the EE bit set already :( MSR is 0x2502Veg
Just one more suggestion is to set Microblaze parameter C_MMU_ZONES = 2. Even if you're not using protection zones, when this parameter is 0 Microblaze does not generate code or data access exception.Randell
Didn't make any difference I'm afraid. The default is 16 in any case.Veg
V
2

With thanks to Jamie Garside at the York University Real-Time Systems group: the OVP simulator's default setting is to trap exceptions and exit the simulation, this is why no sort of exception was being executed in the way I expected - instead they were simply being reported as some sort of error and the simulation was being halted.

However, if ICM_ATTR_SIMEX is defined for the simulation then the simulation will execute the exception handlers in just the way the real processor would - so adding ICM_ATTR_SIMEX to my instance's attributes - e.g., by ORing it in as shown below, puts everything in its rightful place:

#define SIM_ATTRS (ICM_ATTR_DEFAULT|ICM_ATTR_SIMEX)
Veg answered 20/11, 2014 at 19:43 Comment(0)
R
3

Your TLB exception is generated, it's GDB who blocks you from getting into the handler.

Debugging VM mode is a tricky thing. I'm not familiar of OVPsim and how well it's integrated with GDB, but there are several ways to work your way through it:

  1. Explicit software breakpoint. Just use brk r16, 0x18 instruction where you want to set a breakpoint in the code and let GDB go with continue command. It will stop once it executes this break, no matter if its VM user code, or exception handler.

    The downside of this, there's no easy way to continue from GDB, once it reaches this kind of break. You'd need to either modify r16 to the next instruction address, or replace your brk instruction with nop from GDB.

  2. Hardware breakpoint. This one is the easiest break you can use to debug both exception side and VM-side code without worrying about TLB page presence. But hardware breakpoints requires hardware support from Microblaze (not sure if OSPsim supports them). To use it in GDB just use hbreak (or hb) instead of break command.

  3. GDB soft-breakpoints. You're still may be able to use regular style GDB breakpoints if you know how they work and your VM-model is simple enough. Basically GDB needs write access to the code page where you want to break (in order to write brk instruction). So in VM mode you must ensure that the page is present in TLB and has write access.

    It is even trickier to set break from non-VM mode into VM-code when your virtual address differs from physical. You'd need to be sure the page you want to put your breakpoint is loaded in physical memory and manually translate virtual address to physical and set breakpoint. So unless you have 1:1 mapping (and all code and data is inside the memory) or you wrote your own GDB stub, it's a paint to use GDB breakpoints.

Unfortunately, stepping through the code in GDB is almost is as using GDB soft-breakpoints all the time. I.e. you're OK stepping inside non-VM code, or inside single loaded VM-page having write permissions. But once you need to deal with something outside of TLB or access VM code from non-VM, it can become really frustrating.

Randell answered 19/11, 2014 at 19:1 Comment(5)
Thanks for the answer. But if I turn debugging off it just breaks the simulation. I know there must be a way to get this to work, as you can run a Linux kernel on OVP and plainly that relies on demand paging. Have I missed some possible setting for the Microblaze out when I have set it up do you think?Veg
You don't have to completely let debugger go, you just need to use it more carefully. GDB is OK on debugging plain code either VM or non-VM, but if you're trying to step through TLB exception, GDB becomes to smart or too unpredictable. Another think is emulator itself. E.g. QEMU MMU implementation was not full and good enough just to host Linux kernel. I would suggest running real Microblaze design with debug module and debugging it with Xilinx' XMD tool, which is plain, simple and predictable.Randell
I just believe I am getting the TLB exception, or indeed any exceptions, at all because the debugger isn't the issue here. I think this is a setup issue - ie I have missed some sort of setting when either configuring or booting the thing.Veg
Just add a forever loop in your exception handler and let the program go either with GDB or without. If debugger was connected hit Ctrl+Break, if not, connecting to emulator will stop its execution and by checking rpc you will know you were stuck in the main loop. I'm sure there's also a way to simply output to stdout from the emulator. You need to find virtual register corresponding to UART output and define outbyte() to put bytes into this register. This will let you printf() from the handler.Randell
I have a forever loop in my exception handler. The exception handler is never called, that's the issue.Veg
V
2

With thanks to Jamie Garside at the York University Real-Time Systems group: the OVP simulator's default setting is to trap exceptions and exit the simulation, this is why no sort of exception was being executed in the way I expected - instead they were simply being reported as some sort of error and the simulation was being halted.

However, if ICM_ATTR_SIMEX is defined for the simulation then the simulation will execute the exception handlers in just the way the real processor would - so adding ICM_ATTR_SIMEX to my instance's attributes - e.g., by ORing it in as shown below, puts everything in its rightful place:

#define SIM_ATTRS (ICM_ATTR_DEFAULT|ICM_ATTR_SIMEX)
Veg answered 20/11, 2014 at 19:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.