Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
bloodline wrote:I’m new to x86 asm, but as I understand it, ESP is the stack pointer, EBP is just the stack frame pointer. If the function doesn’t require its own stack frame, then the compiler can use the register for other things like passing in the address of the return variable/structure (I’ve seen gcc do this).
As I understand, x86 uses EBP as stack bottom, or the start of stack. ESP is the top of stack. For a new stack frame, the existing EBP is pushed onto the stack, then EBP is reset to ESP, then whatever you want is then pushed and popped.
When leaving the stack, contents located at EBP is moved to EBP, and ESP is decremented by 1, restoring the previous stack frame.
A beginner developer/student. Likes to know stuff. Don't have an OS to put here.
bloodline wrote:I’m new to x86 asm, but as I understand it, ESP is the stack pointer, EBP is just the stack frame pointer. If the function doesn’t require its own stack frame, then the compiler can use the register for other things like passing in the address of the return variable/structure (I’ve seen gcc do this).
As I understand, x86 uses EBP as stack bottom, or the start of stack. ESP is the top of stack. For a new stack frame, the existing EBP is pushed onto the stack, then EBP is reset to ESP, then whatever you want is then pushed and popped.
When leaving the stack, contents located at EBP is moved to EBP, and ESP is decremented by 1, restoring the previous stack frame.
Apologies, I edited my post after you had answered and I didn’t realise (my browser hadn’t refreshed). Check back and see if I’ve answered your question.
-edit- The point is you can’t trust what is in EBP, once an exception has occurred, push any information you need to determine what has gone wrong somewhere safe, and then switch to a new context, the old one is done!
nullplan wrote:
But in most cases, you cannot handle an exception by simply returning, as the fault will just re-occur. Most faults in kernel space should probably be handled by a kernel panic. That means: Print as much information about the fault that occurred as you can (exception number, EIP and ESP of the failing context, maybe the other registers, and a stack trace is always helpful), and then stop the system. If you support multiple CPUs, send IPIs to them to stop them, then execute HLT in an endless loop. The reason is that in that case the kernel is faulty and must be stopped.
I'm a bit more selective in when generating kernel panics. Generally, I will only generate a panic if the fault happens in the scheduler or an interrupt. Other cases are handled as userspace faults, but won't call the exception handing stuff in usermode. This is a bit more convinient since then I can inspect the fault in the kernel debugger, and I can also see it in the usermode debugger if it's active and the faulting thread is in the debugged process. For panics, I have a monitor that can interactively inspect core state and even emulate instructions. When I run in unattended mode, faults and panics will be logged instead and the computer is restarted automatically with no "blue screens".
My OS design is a bit different than standard OS, primarily because most of this was implemented when I didn't have interrupts. So I was forced into a traditional programming approach, so my OS is a giant program than other standard OS. It is not modular(although it is just the kernel).
My kernel, therefore is not designed to run userspace binary(although I can extend it to do so if I had a way to load actual binary as user program), my kernel runs something like BASIC which I invented out of thin air(which, for now is very limited and inefficient because my lack of efficient C programming skills). The actual use of this exception is to catch when the interpreter tries to do division by zero. As it actually is a user error, I don't want to completely reset but drop back to command interface from which interpreter is called I don't want to write checks for everytime, as my code is already terrible.
I could specifically do something for it to work with that, but I need a more general approach. But I don't have any idea about it.
A beginner developer/student. Likes to know stuff. Don't have an OS to put here.
pranavappu007 wrote:The actual use of this exception is to catch when the interpreter tries to do division by zero. As it actually is a user error, I don't want to completely reset but drop back to command interface from which interpreter is called I don't want to write checks for everytime, as my code is already terrible.
I could specifically do something for it to work with that, but I need a more general approach. But I don't have any idea about it.
Do the Div/0 error check in your interpreter... no point using an interpreter if you don’t take advantage of runtime checking!!
Octocontrabass wrote:
What will happen when other_function() returns? What will it return to? Will it be able to restore the callee-saved registers properly?
I was thinking, instead of calling a function, if I can discard the stack of the function causing the exception, access the parent's stack frame, and use the return address saved on to the stack when the erroneous function is called, and return to that as if the function returned by itself? As my entire kernel runs in flat segment, it hould work as a normal function return..
I think something like:
mov esp, ebp ;clearing the current stack frame(assuming interrupt doesn't automatically set new frame)
mov ebp, [ebp] ;getting the bottom of parent stack frame
pop ebx ;this should be the return address stored when the erroneous function is called
pushf
push cs ;OR mov ax, cs, push eax
push ebx
iretd
Does this work with necessary corrections? Or is there something I am missing? It shouldn't have that return problem, and should work once I get the stack right..
A beginner developer/student. Likes to know stuff. Don't have an OS to put here.
bloodline wrote:
Do the Div/0 error check in your interpreter... no point using an interpreter if you don’t take advantage of runtime checking!!
So it's better to check at runtime and reset in exception? Is it possible to safely exit out of the function if a function caused an exception?
In your interpreter, you will have some code to perform a division operation on two variables. All you need to do is check if the divisor is equal to zero, if it is, then the BASIC program should terminate and throw a div/0 error, often helpful to print the line number which caused the error as useful feedback to the user.
Don’t let the interpreter actually perform an operation which you know will cause a CPU exception as that will be VERY difficult to debug and of no use to anyone!
Octocontrabass wrote:
Does this work with necessary corrections? Or is there something I am missing? It shouldn't have that return problem, and should work once I get the stack right..
If you return from a function which has caused an exception, you have no idea what you will be returning to the calling function... so then that function might generate an exception, which could cause its caller to fault, and so on... the reason why you halt at an exception is because your code has failed, you cannot realistically expect to continue execution. The best you can do is provide good feed back to the user who can debug what went wrong.
-edit- Put simply if something goes wrong, you can’t just push it to one side and carry on, if you do that then you will have more problems and no idea if those other problems were caused by this one or are problems in their own right!
pranavappu007 wrote:If I didn't do 'iret', doesn't the entire program code then be treated as part of ISR?
The CPU doesn't treat ISRs any differently from normal code (except NMI).
True, without the iret, you are just losing a bit of stack, unless the interrupt is at a higher privilege level than your normal running code, where ISR code has access to more CPU features... minor quibble, and one that I don’t think is relevant in this case, but pranavappu007 will need to know about this stuff.