Hello guys,
I am in the process of adding user mode support to my OS. I am able to switch to user mode:
(gdb) c
Continuing.
(gdb) l
111 // lock_scheduler();
112 // schedule();
113 // unlock_scheduler();
114 switch_usr_mode();
115 // printf("Back to kernel_main..\n");
116 for(;;) {
117
118 }
119 }
120
But if I add a break point at any place in my switch_user_mode assembly code, the jump to user mode fails:
(gdb) b switch_usr_mode
Breakpoint 5 at 0x103ad2: file task_sw.s, line 38.
(gdb) c
Continuing.
Breakpoint 5, switch_usr_mode () at task_sw.s:38
38 cli
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
isr6 () at idt_flush.s:34
34 ISR_NOERR 6<---------------??
Weird thing is, if I modify my assembly code to look like this:
global switch_usr_mode
extern task_user
switch_usr_mode:
cli
mov ax, 0x23
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push long 0x23
push eax
pushf
pop eax
or eax, 0x200
push eax
push long 0x1B
push task_user
iret
cont:
ret
That is, jump to task_user(), then I don't fault even if I put a break point in my switch_user_mode code.
(gdb)
task_user () at kernel.c:67
67 void task_user () {
I am not sure why this is happening. Has anyone else experienced this. Really appreciate it if anyone could give any sort of pointers on this.
Link to my repo: https://github.com/Crescent92/testOS/bl ... k_sw.s#L53
ISR6 when switching to user mode on adding a breakpoint
Re: ISR6 when switching to user mode on adding a breakpoint
Did you sti ?crescent wrote: global switch_usr_mode
extern task_user
switch_usr_mode:
cli
mov ax, 0x23
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push long 0x23
push eax
pushf
pop eax
or eax, 0x200
push eax
push long 0x1B
push task_user
iret
cont:
ret
-
- Member
- Posts: 148
- Joined: Sun Aug 23, 2020 4:35 pm
Re: ISR6 when switching to user mode on adding a breakpoint
Iman,
I'm pretty sure Is how they are enabling interrupts.
They modify the values that the iret will instruction will use so that they are enabled on entry.
crescent,
Have you mapped your kernel (especially your stack) to be usermode readable?
This possibly might be combined with a PIT interrupt happening in usermode and trying to access a disallowed page (which might be why the breakpoints are being problematic)?
Maybe as a test, remove the code above and just run it without interrupts and see if it gives the exception.
And what exception are you getting? Is ISR6 an exception (if so, which one), an IRQ, or a software interrupt?
I'm pretty sure
Code: Select all
pushf
pop eax
or eax,0x200
push eax
They modify the values that the iret will instruction will use so that they are enabled on entry.
crescent,
Have you mapped your kernel (especially your stack) to be usermode readable?
This possibly might be combined with a PIT interrupt happening in usermode and trying to access a disallowed page (which might be why the breakpoints are being problematic)?
Maybe as a test, remove the code above and just run it without interrupts and see if it gives the exception.
And what exception are you getting? Is ISR6 an exception (if so, which one), an IRQ, or a software interrupt?
My OS: TritiumOS
https://github.com/foliagecanine/tritium-os
void warranty(laptop_t laptop) { if (laptop.broken) return laptop; }
I don't get it: Why's the warranty void?
https://github.com/foliagecanine/tritium-os
void warranty(laptop_t laptop) { if (laptop.broken) return laptop; }
I don't get it: Why's the warranty void?
Re: ISR6 when switching to user mode on adding a breakpoint
Iman,
As foliagecanine has pointed out, I've been enabling it by or-ing eflags with 0x200.
foliagecanine,
ISR6 is invalid opcode exception. As to your question whether I've pages accessible from user space or not, that's not an issue as I have PIT triggering without causing any page faults. It's only when I put a break point somewhere in the switch_user_mode code that I get an invalid opcode exception. It specifically happens when pushing the return address( push $cont).
As foliagecanine has pointed out, I've been enabling it by or-ing eflags with 0x200.
foliagecanine,
ISR6 is invalid opcode exception. As to your question whether I've pages accessible from user space or not, that's not an issue as I have PIT triggering without causing any page faults. It's only when I put a break point somewhere in the switch_user_mode code that I get an invalid opcode exception. It specifically happens when pushing the return address( push $cont).
-
- Member
- Posts: 148
- Joined: Sun Aug 23, 2020 4:35 pm
Re: ISR6 when switching to user mode on adding a breakpoint
Hmm...
So I just compiled your kernel and did a bunch of debugging.
I did almost excactly what you did and got this:
DDD (GDB) seems to think that you're getting isr0 (which I would assume is the Divide By Zero exception).
Either way, I found that when your isr returns (it apparently qualifies neither as an interrupt nor as an exception handler and therefore returns; check your interrupts code), it returns to 0x00000029 which (at least on QEMU) is "aam 0", which restarts the Divide By Zero exception (is that even right? I've never used aam before). Something (especially interrupts!) could be corrupting the stack, causing a return to jump into nowhere.
Then I stepped through your entire function with just "si", it succeeded. I even hit the continue button to make sure, but it was fine.
When I did a few si's and then hit continue in the middle of your function, it gave me the error above.
Something like this generally happens when an interrupt happens in unstable code, but you definitely used cli, so...
I really have no clue. Its very annoying when something happens either only in debug (so you can't debug right) or only in production (so it looks fine when you debug it)
It works if you step all the way through it, but breaks if you continue on any line "mov esp,eax" or below.
You can either look through most of your code to try to fix it, or leave it as is. It looks like you're sort-of-using James Molloy's OS tutorial. You might be able to download the code, rename a few files, and do a diff to compare it. If you do choose to leave it, be careful. It could be a symptom of a much larger problem (i.e. incorrect GDT, idt, etc)
Good luck!
So I just compiled your kernel and did a bunch of debugging.
I did almost excactly what you did and got this:
DDD (GDB) seems to think that you're getting isr0 (which I would assume is the Divide By Zero exception).
Either way, I found that when your isr returns (it apparently qualifies neither as an interrupt nor as an exception handler and therefore returns; check your interrupts code), it returns to 0x00000029 which (at least on QEMU) is "aam 0", which restarts the Divide By Zero exception (is that even right? I've never used aam before). Something (especially interrupts!) could be corrupting the stack, causing a return to jump into nowhere.
Then I stepped through your entire function with just "si", it succeeded. I even hit the continue button to make sure, but it was fine.
When I did a few si's and then hit continue in the middle of your function, it gave me the error above.
Something like this generally happens when an interrupt happens in unstable code, but you definitely used cli, so...
I really have no clue. Its very annoying when something happens either only in debug (so you can't debug right) or only in production (so it looks fine when you debug it)
It works if you step all the way through it, but breaks if you continue on any line "mov esp,eax" or below.
You can either look through most of your code to try to fix it, or leave it as is. It looks like you're sort-of-using James Molloy's OS tutorial. You might be able to download the code, rename a few files, and do a diff to compare it. If you do choose to leave it, be careful. It could be a symptom of a much larger problem (i.e. incorrect GDT, idt, etc)
Good luck!
My OS: TritiumOS
https://github.com/foliagecanine/tritium-os
void warranty(laptop_t laptop) { if (laptop.broken) return laptop; }
I don't get it: Why's the warranty void?
https://github.com/foliagecanine/tritium-os
void warranty(laptop_t laptop) { if (laptop.broken) return laptop; }
I don't get it: Why's the warranty void?