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

1.3k views Asked by At

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.

2

There are 2 answers

0
adrianmcmenamin On BEST ANSWER

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)
5
dkz On

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.