ISR6 when switching to user mode on adding a breakpoint

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.
Post Reply
crescent
Posts: 7
Joined: Thu May 14, 2020 9:23 pm

ISR6 when switching to user mode on adding a breakpoint

Post by crescent »

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
User avatar
iman
Member
Member
Posts: 84
Joined: Wed Feb 06, 2019 10:41 am
Libera.chat IRC: ImAn

Re: ISR6 when switching to user mode on adding a breakpoint

Post by iman »

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
Did you sti ?
Iman Abdollahzadeh
Github
Codeberg
foliagecanine
Member
Member
Posts: 148
Joined: Sun Aug 23, 2020 4:35 pm

Re: ISR6 when switching to user mode on adding a breakpoint

Post by foliagecanine »

Iman,
I'm pretty sure

Code: Select all

pushf
pop eax
or eax,0x200
push eax
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?
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?
crescent
Posts: 7
Joined: Thu May 14, 2020 9:23 pm

Re: ISR6 when switching to user mode on adding a breakpoint

Post by crescent »

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).
foliagecanine
Member
Member
Posts: 148
Joined: Sun Aug 23, 2020 4:35 pm

Re: ISR6 when switching to user mode on adding a breakpoint

Post by foliagecanine »

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!
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?
Post Reply