/*TempleOS runs exclusively in ring 0.
Ring 0 is part of the Charter.
This demo is for you to play around
with ring 3. TempleOS 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_stk,*new_rip;

asm {
INT_TO_RING0:: //Set to handle general protection 0xD fault temporarily.
INC U64 [SYS_PROGRESS1]
PUSH U32 CGDT.ds //STKSEG
MOV RAX,U64 [&old_stk]
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,0);

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

asm {
MOV U64 [&old_stk],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 //STKSEG
PUSH U64 [&old_stk]
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);
SetRAX(Gs->tss->tr);
LTR AX

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

Ring3Demo;