I am wondering if there is any difference between the MIPS syscall and trap instructions. I can't find anything involving this, so I am not sure if there is a difference. Traps seem to just be a conditional syscall, but some clarifying can be helpful.
The SYSCALL and TRAP instructions both trigger exceptions, but the resulting exception is of a different type (SystemCall versus Trap), and the operating system will likely handle them differently.
A Trap is an exception switches to kernel mode by invoking a kernel sub-routine (any system call). Usually trap creates any kind of control transfer to operating system. Where as SYSCALL is synchronous and planned user process to kernel mode.
Related
In an assembly program, the .text section is loaded at 0x08048000; the .data and the .bss section comes after that.
What would happen if I don't put an exit syscall in the .text section? Would it lead to the .data and the .bss section being interpreted as code causing "unpredictable" behavior? When will the program terminate -- probably after every "instruction" is executed?
I can easily write a program without the exit syscall, but testing if .data and .bss gets executed is something I don't know because I guess I would have to know the real machine code that is generated under-the-hoods to understand that.
I think this question is more about "How would OS and CPU handle such a scenario?" than assembly language, but it is still interesting to know for assembly programmers etc.
The processor does not know where your code ends. It faithfully executes one instruction after another until execution is redirected elsewhere (e.g. by a jump, call, interrupt, system call, or similar).
If your code ends without jumping elsewhere, the processor continues executing whatever is in memory after your code. It is fairly unpredictable what exactly happens, but eventually, your code typically crashes because it tries to execute an invalid instruction or tries to access memory that it is not allowed to access.
If neither happens and no jump occurs, eventually the processor tries to execute unmapped memory or memory that is marked as “not executable” as code, causing a segmentation violation. On Linux, this raises a SIGSEGV or SIGBUS. When unhandled, these terminate your process and optionally produce core dumps.
If you're curious, run under a debugger and look at disassembly of the faulting instruction.
My understanding : An interrupt (hardware interrupt) occurs asynchronously generally been caused by an external event directly interrupting the CPU. The CPU will then vector to the particular ISR to handle the interrupt.
Obviously an ISR cannot have a return value or have parameters passed because the event happen at anytime at any point of execution in our code.
With exceptions however, my understanding is that this is a software interrupt which is caused by a special instruction pd within the software.
I've heard that exceptions are handled in a similar fashion to handling an ISR. Can an exception handler in that case behave differently to an ISR , by taking arguments from the code and return a value, because we know where we were in our code when it was executed?
Thanks in advance
A hardware exception is not a software interrupt, you do not explicitly call it - it occurs on some hardware detectable error such as:
invalid address
invalid instruction
invalid alignment
divide-by-zero
You can of course write code to deliberately cause any of these and therefore use them as software interrupts, but then you may loose the utility of them as genuine error traps. Exceptions are in some cases used for this purpose - for example in a processor without an FPU on an architecture where and FPU is an option, the invalid instruction handler can be used to implement software emulation of an FPU so that the compiler does not need to generate different code for FPU and non-FPU variants. Similarly an invalid address exception can invoke a memory manager to implement a virtual memory swap-file (on devices with an MMU).
A software interrupt is explicitly called by an SWI instruction. It's benefit over a straightforward function call is that the application does not need to know the location of the handler - that is determined by the vector table, and is often used to make operating system or BIOS calls in simple operating systems can dynamically load code, but that do not support dynamic-linking (MS-DOS for example worked in this way).
What hardware interrupts, software interrupts and exceptions all have in common is that they execute in different processor context that normal code - typically switching to an independent stack and automatically pushing registers (or using an alternate register bank). They all operate via a vector table, and you cannot pass or return parameters via formal function parameter passing and return. With SWI and forced-exceptions, it is possible to load values into specific registers or memory locations known to the handler.
The above are general principles - the precise details will vary between different architectures. Consult technical reference for the specific device used.
The term "exception" can mean completely different things.
There are "software exceptions" in the form of exception handling, as a high-level language feature in languages like C++. An "exception handler" in this context would be something like a try { } catch block.
And there are "hardware exceptions" which is a term used by some CPU cores like PowerPC. These are a form of critical interrupts corresponding to an error state. An "exception handler" in this context would be similar to an interrupt vector table, although when a hardware exception occurs, there is usually nothing the software can do about it.
Hardware exceptions take no arguments and return no data, just like interrupts. Architectures like PowerPC separate hardware exceptions from hardware interrupts, where the former are various error states, and the later are interrupts from the application-specific hardware.
It isn't all that meaningful for a hardware exception to communicate with the software, as they would be generated from critical failures like wrong OP code executed, CPU clock gone bad, runaway code etc etc. That is, the execution environment has been compromised so there is nothing meaningful that the software executing in that environment can possibly do.
I'm working with PIC32 MCUs (MIPS M4K core), I'm trying to understand how do interrupts work in MIPS; I'm armed with "See MIPS Run" book, official MIPS reference and Google. No one of them can help me understand the following:
I have interrupt declared like this:
void __ISR(_CORE_TIMER_VECTOR) my_int_handler(void)
I look at disassembly, and I see that RDPGPR SP, SP is called in the ISR prologue (first instruction, actually); and balancing WRPGPR SR, SR instruction is called in the ISR epilogue (before writing previously-saved Status register to CP0 and calling ERET).
I see that these instruction purposes are to read from and save to previous shadow register set, so, RDPGPR SP, SP reads $sp from shadow register set and WRPGPR SR, SR writes it back, but I can't understand the reason for this. This ISR intended not to use shadow register set, and actually in disassembly I see that context is saved to the stack. But, for some reason, $sp is read from and written to shadow $sp. Why is this?
And, related question: is there some really comprehensive resource (book, or something) on MIPS assembly language? "See MIPS Run" seems really good, it's great starting point for me to dig into MIPS architecture, but it does not cover several topics good enough, several things off the top of my head:
Very little information about EIC (external interrupt controller) mode: it has the diagram with Cause register that shows that in EIC mode we have RIPL instead of IP7-2, but there is nothing about how does it work (say, that interrupt is caused if only Cause->RIPL is more than Status->IPL. There's even no explanation what RIPL does mean ("Requested Interrupt Priority Level", well, Google helped). I understand that EIC is implementation-dependent, but the things I just mentioned are generic.
Assembly language is covered not completely enough: say, nothing about macro (.macro, .endm directives), I couldn't find anything about some assembler directives I've seen in the existing code, say, .set mips32r2, and so on.
I cant find anything about using rdpgpr/wrpgpr in the ISR, it covers these instructions (and shadow register sets in general) very briefly
Official MIPS reference doesn't help much in these topics as well. Is there really good book that covers all possible assembly directives, and so on?
When the MIPS core enters an ISR it can swap the interrupted code's active register set with a new one (there can be several different shadow register sets), specific for that interrupt priority.
Usually the interrupt routines don't have a stack of their own, and because the just switched-in shadow register set certainly have its sp register with a different value than the interrupted code's, the ISR copies the sp value from the just switched-out shadow register set to its own, to be able to use the interrupted code's stack.
If you wish, you could set your ISR's stack to a previously allocated stack of its own, but that is usually not useful.
I am giving very limited information, I know, but it is probably enough.
System specs: MIPS 64-bit processor with 8 cores running 4 virtual cpus each.
OS: Some proprietary Linux based on the 2.6.32.9 kernel
Process: a simple user-land process running 7 posix threads. This specific application is running on core 0, which does not have any cpu affinity by any process.
The crash is almost impossible to reproduce. There is no specific scenario. We know that, if we perform some minor activity with the application it might crash once a day.
The specific thread that's crashing wakes up every 5 milliseconds, reads information from one shared memory area and updates another. That's it.
There is not too much activity. The process is not working too hard.
Now: When I open the core and load a symbol-less image of the application, gdb points to instruction 100661e0. Instruction 100661e0 looks like this (viewing with an objdump view of the non-stripped image):
void class::foo(uint8_t factor)
{
100661d8: ffbf0018 sd ra,24(sp)
100661dc: 0080802d move s0,a0
bar(factor, shared_memory_a->profiles[PROFILE_1]);
100661e0: 0c019852 jal 10066148 <_ZN28class35barEhR30profile_t>
100661e4: 64c673c8 daddiu a2,a2,29640
bar(factor, shared_memory_a->profiles[PROFILE_2]);
100661e8: de060010 ld a2,16(s0)
The line that shows as the exception line is
100661e0: 0c019852 jal 10066148 <_ZN28class35barEhR30profile_t>
Note that 10066148 is a valid instruction.
The Bad register contains the following address, which is aligned, but does not look valid as far as the instruction address space is concerned: c0000003ddc5dd90
The cause register contains this value: 0000000000800014
I don't understand why the Bad registers shows the value it does, where the instruction specifically states a valid instruction. I am a little concerned about branch delay slot issues, but I shouldn't be concerned about those when I am running a userland application using simple C++.
I'd appreciate any thoughts.
I am working on a MIPS32 like CPU and I am wondering how the MIPS32 exception and interrupt handling works exactly. The MIPS32 Privileged Resource Architecture guide doesn't give much information. I am wondering about several things which are:
What happens if there is an exception or interrupt in an exception or interrupt handler?
MIPS32 has 5 hardware interrupts and 2 software interrupts in the cause register. Are the software interrupts exceptions or are exceptions just shown in the exception code value?
Is there a different interrupt and exception vector?
What happens if there are 2 exceptions that go off in the pipeline before it clears itself for the exception? For example there is an overflow exception followed by another exception, and an interrupt. What happens?
Links to any useful resources will be appreciated.
Exception handlers should not re-enable exceptions until after they have saved EPC, SR etc.
The software interrupts are exceptions.
Some MIPS CPUs have been built with different interrupt and exception vectors, but this turns out not to be very useful.
MIPS has precise exceptions: i.e. exceptions appear in instruction sequence and only the first exception in the pipeline will be architecturally visible.
See MIPS Run Linux is the best and most readable reference for MIPS exceptions and the MIPS PRA.