/*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;