Task switching from Ring3 to ring0 (interrupt)

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
User avatar
nicesj
Member
Member
Posts: 27
Joined: Fri May 06, 2005 11:00 pm
Location: South Korea
Contact:

Task switching from Ring3 to ring0 (interrupt)

Post by nicesj »

I succeed to handle the interrupt in a same ring (ring0->ring0),

but after I change the ring to the 3 from 0, "idle_task", the bochs prints "CPU_LOOP 1" and "Error: (0) print_guard_results: guard_found ? (stop reason 0)" when occurs interrupt.

I copied below text from the bochsout.txt file (dump_cpu)
-----------------------------
00009581469e[CPU0 ] fetch_raw_descriptor: GDT: index (707)e0 > limit (47)
00009581469e[CPU0 ] fetch_raw_descriptor: GDT: index (707)e0 > limit (47)
00009581469e[CPU0 ] fetch_raw_descriptor: GDT: index (707)e0 > limit (47)
00009581469e[CPU0 ] exception(): 3rd (10) exception with no resolution, shutdown status is 00h, resetting
00009581469i[CPU0 ] protected mode
00009581469i[CPU0 ] CS.d_b = 32 bit
00009581469i[CPU0 ] SS.d_b = 32 bit
00009581469i[CPU0 ] | EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
00009581469i[CPU0 ] | ESP=0000c3fb EBP=0000c3fb ESI=00000000 EDI=00000000
00009581469i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf sf zf af pf cf
00009581469i[CPU0 ] | SEG selector base limit G D
00009581469i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00009581469i[CPU0 ] | CS:0023( 0004| 0| 3) 00000000 000fffff 1 1
00009581469i[CPU0 ] | DS:002b( 0005| 0| 3) 00000000 000fffff 1 1
00009581469i[CPU0 ] | SS:0033( 0006| 0| 3) 00000000 000fffff 1 1
00009581469i[CPU0 ] | ES:002b( 0005| 0| 3) 00000000 000fffff 1 1
00009581469i[CPU0 ] | FS:002b( 0005| 0| 3) 00000000 000fffff 1 1
00009581469i[CPU0 ] | GS:002b( 0005| 0| 3) 00000000 000fffff 1 1
00009581469i[CPU0 ] | EIP=00009cf2 (00009cf2)
00009581469i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00009581469i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00009581469i[CPU0 ] >> eb
00009581469i[CPU0 ] >> fe
00009581469i[CPU0 ] >> : jmp .+0xfffffffe
00009581469i[SYS ] bx_pc_system_c::Reset(SOFTWARE) called
00009581469i[APIC0] local apic in CPU 0 initializing
00009581469i[ ] Ctrl-C detected in signal handler.
00009581469i[ ] dbg: Quit
00009581469i[CPU0 ] real mode
00009581469i[CPU0 ] CS.d_b = 16 bit
00009581469i[CPU0 ] SS.d_b = 16 bit
00009581469i[CPU0 ] | EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000f00
00009581469i[CPU0 ] | ESP=00000000 EBP=00000000 ESI=00000000 EDI=00000000
00009581469i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
00009581469i[CPU0 ] | SEG selector base limit G D
00009581469i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00009581469i[CPU0 ] | CS:f000( 0000| 0| 0) ffff0000 0000ffff 0 0
00009581469i[CPU0 ] | DS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00009581469i[CPU0 ] | SS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00009581469i[CPU0 ] | ES:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00009581469i[CPU0 ] | FS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00009581469i[CPU0 ] | GS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00009581469i[CPU0 ] | EIP=0000fff0 (0000fff0)
00009581469i[CPU0 ] | CR0=0x00000010 CR1=0 CR2=0x00000000
00009581469i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
------------------------------------------

and, below code is reside on my kernel entry point, it will change the ring.
-----------------------------------------
// Status of CPU will store to the 0x00004E00, 0x00068(104 Bytes)
task_state_segment* tss = (task_state_segment*)0x00004E00;


// Reset the kernel stack. previous stack information isn't need anymore.
cpu_regs* regStack = (cpu_regs*)KERNEL_STACK;

regStack->eax = 0;
regStack->ebx = 0;
regStack->ecx = 0;
regStack->edx = 0;
regStack->ebp = 0;
regStack->esi = 0;
regStack->edi = 0;

regStack->cs = USER_CS;
regStack->ds = USER_DS;
regStack->es = USER_DS;
regStack->fs = USER_DS;
regStack->gs = USER_DS;
regStack->ss = USER_SS;

regStack->eip= (long)idle_task;
regStack->eflags = 0x200;
regStack->esp = (long)(g_idle_stack + 1023);

asm volatile (
// Save current kernel stack pointer to the TSS's ESP0 field
// This field will be read by CPU when interrupt occurs
"movl %%esp, %0\n"

// We should to construct a faked stack to make context switching (userlevel).
"movl $0x7c00, %%esp\n"

// We should to initialize data segments, before go into the user mode task
"popal\n"

// For the data segments
"popl %%ds\n"
"popl %%es\n"
"popl %%fs\n"
"popl %%gs\n"
"iretl\n"
: "=m"(tss->ESP0)
:
);
-------------------------------------
What am I wrong?




------------------------
http://nicesj.com
User avatar
hailstorm
Member
Member
Posts: 110
Joined: Wed Nov 02, 2005 12:00 am
Location: The Netherlands

Post by hailstorm »

Analyzing the bochs output I see a triple fault occurring. Exception number is 10. This states that the cpu is trying to access an invalid tss. The reason for this can be one of the following:
a.) gdt descriptor isn't a tss descriptor
b.) busy bit is not set (you are doing an iret)
c.) gdt index > gdt limit

Good luck!
User avatar
nicesj
Member
Member
Posts: 27
Joined: Fri May 06, 2005 11:00 pm
Location: South Korea
Contact:

thank you, but

Post by nicesj »

If I don't change to the usermode task, all works well..
(I think, that mean, gdt, gdtr sets properly, right?)

however, bochs prints CPU_LOOP if an interrupt occurs in the user mode(I succeed to change user mode and execute entry code of a first user mode task)

I try to use s/w interrupt, so I didn't touch any data in tss descriptor(just I set B=0 for initialization, i uses ltr to load "tr" at first time..)

and I checked the TSS Descriptor,
I set it like this

Code: Select all

sys_tss equ $-begin_gdt                                 ; 0x38 - 7
        dw 0x0068       ; segment_limit(104bytes)
        dw 0x4E00       ; base address_low
        db 0x00         ; base2
        db 0x89         ; P(1) DPL(00) 0 TYPE(10B1):B=0
        db 0x00         ; G(0) 00 AVL(0) SegLimit(0000) // byte addressing
        db 0x00         ; base address high
help me... I spent a month to solve this.. :cry:
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

To switch to/from ring3/ring0 you need to have SS0:ESP0 set in the current TSS (the one that is currently referenced in the task register).

The interrupt in usermode will take the SS0:ESP0 fields and then setup a temporary stack, were it can begin executing the interrupt in ring0. Once complete, the iret resets the CPU to the previous state.

Read the Intel manuals.
User avatar
hailstorm
Member
Member
Posts: 110
Joined: Wed Nov 02, 2005 12:00 am
Location: The Netherlands

Post by hailstorm »

The statement read-the-fucking-manual is not always the best response IMHO. Hardware task switching is somewhat difficult to understand. I assume that sjpark understands that both ss0:esp0 and ss3:esp3 should be set correctly.

@sjpark: Initialize the busy bit to 1 and give it another try. When the processor returns from an interrupt, it expects this bit to be set. If this doesn't work, you should review your stack settings, as pcmattman suggests.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

hailstorm wrote:The statement read-the-fucking-manual is not always the best response IMHO.
Remarks like that help nobody.

The manual is in fact where a lot of the helpers on this forum (ie. Brendan, Combuster, etc...) found the information they help us with. I think the fundamental problem is that often you just want to get coding ASAP, instead of taking the time to understand how and why something works, and you don't want to really understand a document which is relatively cryptic (but no more than any hardware datasheet, which you do need for your OS drivers).
User avatar
hailstorm
Member
Member
Posts: 110
Joined: Wed Nov 02, 2005 12:00 am
Location: The Netherlands

Post by hailstorm »

That's not the only thing I wrote, you must agree to that. I am just trying to help and remarks like "read the manual" can leave someone in the cold. Second, I didn't disagree with you, the only thing is that I often had trouble reading Intel manuals.
Certainly when it comes to pm programming, a manual can't help you each time something goes wrong, because you think you have implemented everything like you should... It is all about mindset. You also probably know that when you encounter a problem, you can stare at it for days, having a manual or not. Sometimes it is better to talk about the problem with another person. It helps you think about what you are doing (wrong).
B.t.w. you only get the big picture with your hands on it, instead of only reading manuals. Just like driving a car I think. A manual is just a text book explaining where the buttons are and what they do.
User avatar
nicesj
Member
Member
Posts: 27
Joined: Fri May 06, 2005 11:00 pm
Location: South Korea
Contact:

Post by nicesj »

thank you all.

I have the intel manual and a book for devleoping OS.
and I already read them.
I also open them when start to writing some codes.

read and read,, but I don't know What I missed... so I bagging to the other person who already developed his/her os. (or some other person like me..)

my country's first language is not the english, it makes me hard to understand what the manual said...
:?

I review's entire code what I written.. and I tried to fix something.

I make a stack space for the kernel to use it.

Code: Select all


; declaration of GDT ( I skipped this because it wasted too many lines )

bits 32
GLOBAL kstack
kstack times 1024 db 0
extern kos_entry
entry32: ; 0008:0x00008101
        cld
        ; reset all segments for executing procedure in pmode
        mov ax, kernel_ds
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax
        mov ax, kernel_ss
        mov ss, ax

        ; set up kernel stack pointer
        mov esp, kstack + 1023
        mov ebp, esp

       ; load task-register
        mov ax, sys_tss
        ltr ax           ; ltr. When occurs task switching, save current task's information

        ; jump to main entry which written in C
        jmp kos_entry

kernel stack starts from after the reserved area for "gdt"

and in the kos_entry (written in C)

Code: Select all

extern char kstack[1024]; //  I want to access kstack which I declared in the assembly codes..

char* pKStack;

void kos_entry(void) // {{{ Main function of kernel
{
        init_crt();
        printk("CRT initialized\n");

        init_int();
        printk("interrupt initialized\n");

        printk("Interrupts are enabled\n");
        outb(0x21, 0xFC);    // Enable timer/keyboard interrupts(PIC)
        enable_interrupts(); // Enable CPU interrupt

        printk("Kernel Stack : 0x%x\n", kstack);
        pKStack = kstack + 1023;
        printk("Kernel Stack : 0x%x\n", pKStack);
        printk("cpu_regs size : %d\n", sizeof(cpu_regs));

        // Reset the kernel stack. previous stack information isn't need anymore.
        cpu_regs* regStack = (cpu_regs*)(pKStack - sizeof(cpu_regs));
        printk("regStack : 0x%x\n", regStack);
        regStack->eax = 0;
        regStack->ebx = 0;
        regStack->ecx = 0;
        regStack->edx = 0;
        regStack->ebp = 0;
        regStack->esi = 0;
        regStack->edi = 0;

        regStack->cs = USER_CS;
        regStack->ds = USER_DS;
        regStack->es = USER_DS;
        regStack->fs = USER_DS;
        regStack->gs = USER_DS;
        regStack->ss = USER_SS;

        regStack->eip= (long)idle_task;
        regStack->eflags = 0x200;
        regStack->esp = (long)(g_idle_stack + 1023);

        // Status of CPU will store to the 0x00004E00, 0x00068(104 Bytes)
        task_state_segment* tss = (task_state_segment*)0x00007C00;
        tss->ESP0 = (long)pKStack;
        tss->SS0  = KERNEL_SS;

        asm volatile (
            // We should to construct a faked stack to make context switching (userlevel).
            "movl %0, %%esp\n"

            // We should to initialize data segments, before go into the user mode task
            "popal\n"

            // For the data segments
            "pop %%ds\n"
            "pop %%es\n"
            "pop %%fs\n"
            "pop %%gs\n"
            "iretl\n"
            :
            : "a"(pKStack - sizeof(cpu_regs))
        );

        while (1);
        // THERE IS NO WAY TO PASS THIS PHRASE
} // }}}
below text is debug log in the bochs

Code: Select all

Next at t=0
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b         ; ea5be000f0
b 0x8559
c
(0) Breakpoint 1, 0x0x00008559 in ?? ()
Next at t=9402029
(0) [0x00008559] 0008:0x00008559 (unk. ctxt): pop ds                    ; 1f
print-stack
   00008396 [00008396]  002b
   0000839a [0000839a]  002b
   0000839e [0000839e]  002b
   000083a2 [000083a2]  002b
   000083a6 [000083a6]  a16f
   000083aa [000083aa]  0023
   000083ae [000083ae]  0200
   000083b2 [000083b2]  7c00
   000083b6 [000083b6]  0033
   000083ba [000083ba]  b866fc00
   000083be [000083be]  d88e0010
   000083c2 [000083c2]  e08ec08e
   000083c6 [000083c6]  b866e88e
   000083ca [000083ca]  d08e0018
   000083ce [000083ce]  83babc
   000083d2 [000083d2]  66e58900
dump_cpu
eax:0x00000000, ebx:0x00000000, ecx:0x00000000, edx:0x00000000
ebp:0x00000000, esp:0x00008396, esi:0x00000000, edi:0x00000000
eip:0x00008559, eflags:0x00000202, inhibit_mask:0
cs:s=0x0008, dl=0x0000ffff, dh=0x00cf9a00, valid=1
ss:s=0x0018, dl=0x0000ffff, dh=0x00cf9200, valid=7
ds:s=0x0010, dl=0x0000ffff, dh=0x00cf9200, valid=7
es:s=0x0010, dl=0x0000ffff, dh=0x00cf9300, valid=1
fs:s=0x0010, dl=0x0000ffff, dh=0x00cf9300, valid=1
gs:s=0x0010, dl=0x0000ffff, dh=0x00cf9300, valid=1
ldtr:s=0x0000, dl=0x0000ffff, dh=0x00008200, valid=1
tr:s=0x0038, dl=0x7c000068, dh=0x00008900, valid=1
gdtr:base=0x00007f73, limit=0x47
idtr:base=0x0000b040, limit=0x800
dr0:0x00000000, dr1:0x00000000, dr2:0x00000000
dr3:0x00000000, dr6:0xffff0ff0, dr7:0x00000400
cr0:0x00000011, cr1:0x00000000, cr2:0x00000000
cr3:0x00000000, cr4:0x00000000
done
n
Error: (0) print_guard_results: guard_found ? (stop reason 0)
Next at t=9402029
(0) [0x00008559] 0008:8559 (unk. ctxt): pop ds                    ; 1f

please, give more helps to me...
your help message is a food for me, I am hungry....

thanks. :cry:
http://nicesj.com
With the software, What You Think Is What You Get.(WYTIWYG)
User avatar
nicesj
Member
Member
Posts: 27
Joined: Fri May 06, 2005 11:00 pm
Location: South Korea
Contact:

I solved this :)

Post by nicesj »

First, I made invalid stack area for the kernel.
it causes segmentation fault(bochs), when I try to change to user mode :>


so I retry to reserve stack area from the C(kernel) code. after that I succeed to change the mode between kernel and user :>

but when I call software interrupt, virtual machine generates "GP", so I checked the manual how "int" instruction works...and I found, a descriptor for a software interrupt, its DPL has to be lower than CPL, bu t my DPL of descriptor is not lower than CPL, So I fixed it..



and.....

I succeed.......... :)
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

pcmattman wrote:To switch to/from ring3/ring0 you need to have SS0:ESP0 set in the current TSS (the one that is currently referenced in the task register).

The interrupt in usermode will take the SS0:ESP0 fields and then setup a temporary stack, were it can begin executing the interrupt in ring0. Once complete, the iret resets the CPU to the previous state.

Read the Intel manuals.
I wish it was that easy... now I have a similar problem. Ironic :lol:
User avatar
inflater
Member
Member
Posts: 1309
Joined: Thu Sep 28, 2006 10:32 am
Location: Slovakia
Contact:

Post by inflater »

@pcmattman:
Hehe, see? RTFM is not the answer for problems. :) The one who is forced to read manuals by someone else, must fully understand what he is reading. Intel Manuals have around 900 pages and it must be really boring to read them; Winettou is better than these pages of hell (j/k) :lol:. For me, I prefer cleaner, and, manuals in my native language. I wish AThelp or Sysman were more bigger and updated...

I treat everybody, who is saying RTFM all over the time, as some kind of rookie that can't explain the problem his way. Really. (Notice the "all over the time" please).

inflater
My web site: http://inflater.wz.cz (Slovak)
Derrick operating system: http://derrick.xf.cz (Slovak and English :P)
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

inflater wrote:Hehe, see? RTFM is not the answer for problems. :) The one who is forced to read manuals by someone else, must fully understand what he is reading.
:lol: Actually the only problem I had was mis-interpreting the manual's explanation of the privilege level of pages...

But it is a difficult doc to understand, I'll give you that :D
Post Reply