/*ZealOS runs exclusively in ring 0.
Ring 0 is part of the Charter.
This demo is for you to play around
with ring 3.    ZealOS is for
recreational programming, after all.

This redirects the general protection
fault, switches to ring 3, and generates
a fault to switch back.
*/

U8 *old_stack, *new_rip;

asm {
INT_TO_RING0::  //Set to handle general protection 0xD fault temporarily.
                                INC             U64 [SYS_PROGRESS1]
                                PUSH            U32 CGDT.ds             //STACKSEG
                                MOV             RAX, U64 [&old_stack]
                                PUSH            RAX
                                PUSH            U32 0                                   //FLAGS--interrupts off
                                PUSH            U32 CGDT.cs64
                                MOV             RAX, U64 [&new_rip]
                                PUSH            RAX
                                IRET
}

U0 Ring3Demo()
{
        U8 *old_vect;

        "Progress1 Before:%X\n", progress1;
        CLI
        old_vect = IntEntrySet(0x0D, INT_TO_RING0, IDTET_TRAP);

        TSSBusy(Gs->tss->tr_ring3, OFF);
        RAXSet(Gs->tss->tr_ring3 + 3);
        LTR     AX

        asm {
                MOV U64 [&old_stack], RSP

                LEA             RAX, [R3_CALLBACK]
                MOV             U64 [&new_rip], RAX

                MOV             AX, CGDT.ds_ring3 + 3
                MOV             DS, AX
                MOV             ES, AX

                PUSH    U32 CGDT.ds_ring3 + 3           //STACKSEG
                PUSH    U64 [&old_stack]
                PUSH    U32 0                                   //FLAGS--interrupts off
                PUSH    U32 CGDT.cs64_ring3 + 3
                LEA             RAX, [R3_START]
                PUSH    RAX
                IRET

                R3_START:
                INC U64 [SYS_PROGRESS1]
                CLI //This causes general protection fault #13

                R3_CALLBACK:
                MOV AX, CGDT.ds
                MOV DS, AX
                MOV ES, AX
        }

        TSSBusy(Gs->tss->tr, OFF);
        RAXSet(Gs->tss->tr);
        LTR     AX

        IntEntrySet(0x0D, old_vect, IDTET_IRQ);
        STI
        "Progress1 After :%X\n", progress1;
}

Ring3Demo;