Page 1 of 2

Interrupts in user mode

Posted: Sun Mar 11, 2012 9:04 pm
by yoshi65
Okay guys I have followed the tutorial at http://www.jamesmolloy.co.uk/ and at the last tutorial I can't do anything with interrupts. I have a get_ticks function that is supposed to get the number of ticks that have passed and they all return 2 because the interrupt is never called, I would like to get this working so I can use the keyboard. Can anyone help me?

Re: Interrupts in user mode

Posted: Sun Mar 11, 2012 9:47 pm
by Jezze
How can we help when you provide no code or anything other than "it does not work"?

Re: Interrupts in user mode

Posted: Sun Mar 11, 2012 9:56 pm
by VolTeK
yoshi65 wrote: I have a get_ticks function that is supposed to get the number of ticks that have passed and they all return 2 because the interrupt is never called
And why is it never called?

Re: Interrupts in user mode

Posted: Sun Mar 11, 2012 11:13 pm
by yoshi65
Sorry guys for the lack of code. I don't have it with me right now but all I know is that in user mode I cannot receive any interrupts. Why does entering user mode get rid of the interrupts?

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 12:08 am
by piranha
Do you receive interrupts before you switch to ring 3? Have you enabled interrupts in the switch to user mode function? Have you triple checked your code?

-JL

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 4:05 am
by JamesM
(1) Are interrupts enabled?
(2) Can you call syscalls from user mode? I.e. do you have a correct kernel stack and DPL in the IDT entries?

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 4:14 am
by turdus
Use my patch to bochs 2.5.1, it will help you tracking down the bug.
It suppresses the first debugger prompt if called with -q, otherwise it will show you helpful messages, also in debugger you'll be able to see dpls for gdt and idt. Also note that if you enable trace, it will show you whenever an interrupt is called.

Code: Select all

diff -r bochs-2.5.1/bx_debug/dbg_main.cc bochs-2.5.1new/bx_debug/dbg_main.cc
300a301
> int firstcommand=1;
327a329,333
>     if (firstcommand && SIM->get_param_enum(BXPN_BOCHS_START)->get()==BX_QUICK_START) {
>       firstcommand=0;
>       strcat(tmp_buf, "c\n");
>       charptr_ret = &tmp_buf[0];
>     } else {
336a343
>     }
2855c2862
<       dbg_printf("Code segment, base=0x%08x, limit=0x%08x, %s%s%s, %d-bit\n",
---
>       dbg_printf("Code segment, base=0x%08x, limit=0x%08x, %s%s%s, %d-bit, dpl=%d\n",
2860c2867
<         d_b ? 32 : 16);
---
>         d_b ? 32 : 16, dpl);
2862c2869
<       dbg_printf("Data segment, base=0x%08x, limit=0x%08x, %s%s%s\n",
---
>       dbg_printf("Data segment, base=0x%08x, limit=0x%08x, %s%s%s, dpl=%d\n",
2866c2873
<         (type&1)? ", Accessed" : "");
---
>         (type&1)? ", Accessed" : "", dpl);
2892c2899
<       dbg_printf("descriptor hi=0x%08x, lo=0x%08x", hi, lo);
---
>       dbg_printf("descriptor hi=0x%08x, lo=0x%08x, dpl=%d", hi, lo, dpl);
diff -r bochs-2.5.1/cpu/access.cc bochs-2.5.1new/cpu/access.cc
43c43
<     BX_DEBUG(("write_virtual_checks(): segment descriptor not valid"));
---
>     BX_DEBUG(("write_virtual_checks(): segment %d descriptor not valid", seg->selector.index));
48c48
<     BX_ERROR(("write_virtual_checks(): segment not present"));
---
>     BX_ERROR(("write_virtual_checks(): segment %d not present", seg->selector.index));
59c59
<       BX_ERROR(("write_virtual_checks(): no write access to seg"));
---
>       BX_ERROR(("write_virtual_checks(): no write access to seg %d", seg->selector.index));
66c66
<         BX_ERROR(("write_virtual_checks(): write beyond limit, r/w"));
---
>         BX_ERROR(("write_virtual_checks(): write beyond limit, r/w, seg %d", seg->selector.index));
89c89
<         BX_ERROR(("write_virtual_checks(): write beyond limit, r/w ED"));
---
>         BX_ERROR(("write_virtual_checks(): write beyond limit, r/w ED, seg %d", seg->selector.index));
95c95
<       BX_PANIC(("write_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
---
>       BX_PANIC(("write_virtual_checks(): unknown descriptor type=%d seg %d", seg->cache.type, seg->selector.index));
107c107
<     BX_DEBUG(("read_virtual_checks(): segment descriptor not valid"));
---
>     BX_DEBUG(("read_virtual_checks(): segment %d descriptor not valid", seg->selector.index));
112c112
<     BX_ERROR(("read_virtual_checks(): segment not present"));
---
>     BX_ERROR(("read_virtual_checks(): segment %d not present", seg->selector.index));
124c124
<         BX_ERROR(("read_virtual_checks(): read beyond limit"));
---
>         BX_ERROR(("read_virtual_checks(): read beyond limit seg %d", seg->selector.index));
143c143
<         BX_ERROR(("read_virtual_checks(): read beyond limit ED"));
---
>         BX_ERROR(("read_virtual_checks(): read beyond limit ED seg %d", seg->selector.index));
155c155
<       BX_PANIC(("read_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
---
>       BX_PANIC(("read_virtual_checks(): unknown descriptor type=%d seg %d", seg->cache.type, seg->selector.index));
167c167
<     BX_DEBUG(("execute_virtual_checks(): segment descriptor not valid"));
---
>     BX_DEBUG(("execute_virtual_checks(): segment %d descriptor not valid", seg->selector.index));
172c172
<     BX_ERROR(("execute_virtual_checks(): segment not present"));
---
>     BX_ERROR(("execute_virtual_checks(): segment %d not present", seg->selector.index));
184c184
<         BX_ERROR(("execute_virtual_checks(): read beyond limit"));
---
>         BX_ERROR(("execute_virtual_checks(): read beyond limit seg %d", seg->selector.index));
199c199
<         BX_ERROR(("execute_virtual_checks(): read beyond limit execute only"));
---
>         BX_ERROR(("execute_virtual_checks(): read beyond limit execute only seg %d", seg->selector.index));
213c213
<         BX_ERROR(("execute_virtual_checks(): read beyond limit ED"));
---
>         BX_ERROR(("execute_virtual_checks(): read beyond limit ED seg %d", seg->selector.index));
219c219
<       BX_PANIC(("execute_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
---
>       BX_PANIC(("execute_virtual_checks(): unknown descriptor type=%d seg %d", seg->cache.type, seg->selector.index));
234c234
<     BX_PANIC(("undefined segment passed to strseg()!"));
---
>     BX_PANIC(("undefined segment %d passed to strseg()!", seg->selector.index));
268c268
<     BX_ERROR(("system_read_byte(): canonical failure"));
---
>     BX_ERROR(("system_read_byte(): canonical failure %lx", laddr));
298c298
<     BX_ERROR(("system_read_word(): canonical failure"));
---
>     BX_ERROR(("system_read_word(): canonical failure %lx", laddr));
328c328
<     BX_ERROR(("system_read_dword(): canonical failure"));
---
>     BX_ERROR(("system_read_dword(): canonical failure %lx", laddr));
358c358
<     BX_ERROR(("system_read_qword(): canonical failure"));
---
>     BX_ERROR(("system_read_qword(): canonical failure %lx", laddr));
391c391
<     BX_ERROR(("system_write_byte(): canonical failure"));
---
>     BX_ERROR(("system_write_byte(): canonical failure %lx", laddr));
423c423
<     BX_ERROR(("system_write_word(): canonical failure"));
---
>     BX_ERROR(("system_write_word(): canonical failure %lx", laddr));
455c455
<     BX_ERROR(("system_write_dword(): canonical failure"));
---
>     BX_ERROR(("system_write_dword(): canonical failure %lx", laddr));
diff -r bochs-2.5.1/cpu/ctrl_xfer_pro.cc bochs-2.5.1new/cpu/ctrl_xfer_pro.cc
138c138
<       BX_ERROR(("branch_far64: canonical RIP violation"));
---
>       BX_ERROR(("branch_far64: canonical RIP violation %lx", rip));
149c149
<       BX_ERROR(("branch_far64: RIP > limit"));
---
>       BX_ERROR(("branch_far64: RIP(%lx) > limit(%lx)", rip, descriptor->u.segment.limit_scaled));
diff -r bochs-2.5.1/cpu/exception.cc bochs-2.5.1new/cpu/exception.cc
46c46
<     BX_ERROR(("interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit));
---
>     BX_ERROR(("interrupt(long mode): vector %d must be within IDT table limits, IDT.limit = 0x%x", vector, BX_CPU_THIS_PTR idtr.limit));
54c54
<     BX_ERROR(("interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0"));
---
>     BX_ERROR(("interrupt(long mode): IDT entry %d extended attributes DWORD4 TYPE != 0", vector));
66c66
<     BX_ERROR(("interrupt(long mode): gate descriptor is not valid sys seg"));
---
>     BX_ERROR(("interrupt(long mode): gate descriptor %d is not valid sys seg", vector));
75,76c75,76
<     BX_ERROR(("interrupt(long mode): unsupported gate type %u",
<         (unsigned) gate_descriptor.type));
---
>     BX_ERROR(("interrupt(long mode): unsupported gate type %u vector %d",
>         (unsigned) gate_descriptor.type, vector));
84c84
<     BX_ERROR(("interrupt(long mode): soft_int && gate.dpl < CPL"));
---
>     BX_ERROR(("interrupt(long mode): soft_int(%d) && gate.dpl(%d) < CPL(%d)", vector, gate_descriptor.dpl, CPL));
103c103
<     BX_ERROR(("int_trap_gate(long mode): selector null"));
---
>     BX_ERROR(("int_trap_gate(long mode): selector null vector %d",vector));
120c120
<     BX_ERROR(("interrupt(long mode): not accessible or not code segment"));
---
>     BX_ERROR(("interrupt(long mode): not accessible or not code segment vector %d", vector));
127c127
<     BX_ERROR(("interrupt(long mode): must be 64 bit segment"));
---
>     BX_ERROR(("interrupt(long mode): must be 64 bit segment vector %d", vector));
133c133
<     BX_ERROR(("interrupt(long mode): segment not present"));
---
>     BX_ERROR(("interrupt(long mode): segment not present vector %d", vector));
253c253
<     BX_ERROR(("interrupt(): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit));
---
>     BX_ERROR(("interrupt(): vector %d must be within IDT table limits, IDT.limit = 0x%x", vector, BX_CPU_THIS_PTR idtr.limit));
279,280c279,280
<     BX_ERROR(("interrupt(): gate.type(%u) != {5,6,7,14,15}",
<       (unsigned) gate_descriptor.type));
---
>     BX_ERROR(("interrupt(): gate.type(%u) != {5,6,7,14,15} vector %d",
>       (unsigned) gate_descriptor.type, vector));
287c287
<     BX_ERROR(("interrupt(): soft_int && (gate.dpl < CPL)"));
---
>     BX_ERROR(("interrupt(): soft_int(%d) && (gate.dpl(%d) < CPL(%d))", vector, gate_descriptor.dpl, CPL));
293c293
<     BX_ERROR(("interrupt(): gate not present"));
---
>     BX_ERROR(("interrupt(): gate not present vector %d", vector));
306c306
<       BX_ERROR(("interrupt(): tss_selector.ti=1 from gate descriptor - #GP(tss_selector)"));
---
>       BX_ERROR(("interrupt(): tss_selector.ti=1 from gate descriptor - #GP(tss_selector) vector %d",vector));
318c318
<       BX_ERROR(("interrupt(): TSS selector points to invalid or bad TSS - #GP(tss_selector)"));
---
>       BX_ERROR(("interrupt(): TSS selector points to invalid or bad TSS - #GP(tss_selector) vector %d seg %d", vector, tss_selector.index));
325c325
<       BX_ERROR(("interrupt(): TSS selector points to bad TSS - #GP(tss_selector)"));
---
>       BX_ERROR(("interrupt(): TSS selector points to bad TSS - #GP(tss_selector) vector %d seg %d", vector, tss_selector.index));
331c331
<       BX_ERROR(("interrupt(): TSS descriptor.p == 0"));
---
>       BX_ERROR(("interrupt(): TSS descriptor.p == 0 vector %d seg", vector, tss_selector.index));
354c354
<       BX_ERROR(("interrupt(): EIP > CS.limit"));
---
>       BX_ERROR(("interrupt(): EIP(%x) > CS.limit(%x)",EIP,BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled));
437c437
<         BX_ERROR(("interrupt(): SS.rpl != CS.dpl"));
---
>         BX_ERROR(("interrupt(): SS.rpl(%d) != CS.dpl(%d)", ss_selector.rpl, cs_descriptor.dpl));
444c444
<         BX_ERROR(("interrupt(): SS.dpl != CS.dpl"));
---
>         BX_ERROR(("interrupt(): SS.dpl(%d) != CS.dpl(%d)", ss_descriptor.dpl, cs_descriptor.dpl));
diff -r bochs-2.5.1/cpu/segment_ctrl_pro.cc bochs-2.5.1new/cpu/segment_ctrl_pro.cc
56c56
<         BX_ERROR(("load_seg_reg(SS): rpl != CPL"));
---
>         BX_ERROR(("load_seg_reg(SS): rpl(%d) != CPL(%d)", ss_selector.rpl, CPL));
77c77
<         BX_ERROR(("load_seg_reg(SS): dpl != CPL"));
---
>         BX_ERROR(("load_seg_reg(SS): dpl(%d) != CPL(%d)", descriptor.dpl, CPL));
134c134
<           BX_ERROR(("load_seg_reg(%s, 0x%04x): RPL & CPL must be <= DPL", strseg(seg), new_value));
---
>           BX_ERROR(("load_seg_reg(%s, 0x%04x): RPL(%d) & CPL(%d) must be <= DPL(%d)", strseg(seg), new_value, selector.rpl, CPL, descriptor.dpl));

Happy hunting!

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 6:03 am
by yoshi65
(1) Are interrupts enabled?
They were before I got into ring 3.
(2) Can you call syscalls from user mode? I.e. do you have a correct kernel stack and DPL in the IDT entries?
Yeah. I can successfully make syscalls without a problem.

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 12:42 pm
by AJ
yoshi65 wrote:
(1) Are interrupts enabled?
They were before I got into ring 3
And what is the value of EFLAGS that's on the stack before you IRET?

Cheers,
Adam

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 6:18 pm
by yoshi65
My code ors the correct flag as follows from my under standing...

Code: Select all

pop %eax ; Get EFLAGS back into EAX. The only way to read EFLAGS is to pushf then pop.
or %eax, $0x200 ; Set the IF flag.
push %eax ; Push the new EFLAGS value back onto the stack.
My code is pretty much exactly the same as what is on the website mentioned accept I have a system function that returns the "ticks" variable from the timer.

Thanks, for all of your guys' time so far. You guys are great.

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 7:18 pm
by Nessphoro
yoshi65 wrote:Yeah. I can successfully make syscalls without a problem.
yoshi65 wrote:...I have a system function that returns the "ticks" variable from the timer...

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 7:22 pm
by yoshi65
Hey again,
Sorry for the double post but apparently that last code segment wasn't in
the tutorials code but just in the tutorial. So I inserted it in

Code: Select all

void switch_to_user_mode()
{
   // Set up a stack structure for switching to user mode.
   asm volatile("  \ 
     cli; \ 
     mov $0x23, %ax; \ 
     mov %ax, %ds; \ 
     mov %ax, %es; \ 
     mov %ax, %fs; \ 
     mov %ax, %gs; \ 
                   \ 
     mov %esp, %eax; \ 
     pushl $0x23; \ 
     pushl %eax; \ 
     pushf; \ 
     pushl $0x1B; \ 
     push $1f; \ 
     iret; \ 
   1: \ 
     ");
}
After the "pushf" like it said but my compiler gives me in invalid operand error upon compilation.
I am so close thanks for the EFLAG suggestion hopefully this is the last hurdle.

Thanks again!

Re: Interrupts in user mode

Posted: Mon Mar 12, 2012 8:48 pm
by yoshi65
Sorry for the double post again but an update:

I added those lines but it needs to be

Code: Select all

or $0x200, %eax;
instead but now when I try to call a system function it says "Un handled interrupt 13"
in my console so I am guessing this has to do with incorrect stack placement?

Re: Interrupts in user mode

Posted: Tue Mar 13, 2012 4:27 am
by Jezze
Verify:

1, All your pages you are using have the usermode and present bit set.
2, You have set up the tss with the esp0 correctly.
3, The idt entry for the system call you are trying to use also has the usermode bit set.

Re: Interrupts in user mode

Posted: Tue Mar 13, 2012 5:33 am
by yoshi65
Thanks, that brings me to my next thing I found. When the TSS is installed there is a 0x0 for the esp0 entry. How can I get the stack for the kernel to put it in there? (That is assuming that is what I need to do anyway)