Undocumented Corner

by Robert R. Collins



Listing One

CLI {                   /* v86 mode                          */

    if (EFLAGS.IOPL == 3) {

    then EFLAGS.IF = 0;

    else if (CR4.VME == 0) {    /* IOPL < 3                  */

        then #GP(0);        /* ERROR CODE = 0                */

        else EFLAGS.VIF = 0;

        }

    }

}

STI {                   /* v86 mode                          */

    if (EFLAGS.IOPL == 3) {

    then EFLAGS.IF = 1;

    else if (CR4.VME == 0) {    /* IOPL < 3                  */

        #GP(0);         /* ERROR CODE = 0                    */

            else {

        if (EFLAGS.VIP == 1) {  /* if VIP already=1, #GP(?)  */

            then #GP(0);    /* ERROR CODE = 0                */

                    /* Processor never set VIF               */

                    /*   before #GP()                        */

            else EFLAGS.VIF = 1;

                }

            }

        }

    }

}

PUSHF {                 /* v86 mode                          */

    if (EFLAGS.IOPL == 3) {

    then

    if (OperandSize == 32) {

        then push(EFLAGS & 0xFCFFFF);   /* Clear VM & RF     */

        else push(FLAGS);

    }

                    /* IOPL < 3                              */

    else if ((CR4.VME == 0) || (OperandSize == 32)) { /* IOPL < 3  */

        then #GP(0);        /* ERROR CODE = 0                 */

        else {

                TEMP = FLAGS;

        TEMP = TEMP OR 0x3000;  /* Set IOPL=3 on stack (dumb?) */

        TEMP.IF = EFLAGS.VIF;

        push(TEMP);

            }

        }

    }

}

POPF {                  /* v86 mode                            */

    if (EFLAGS.IOPL == 3) {     /* IOPL = 3                    */

    then if (OperandSize == 32) {

        then {

       TEMP = pop();

        /* Clear these fields from EFLAGS stack image:         */

        TEMP = TEMP AND NOT 0x1BB02A;   /* VIP VIF VM RF IOPL  */

        /* Keep these fields from current EFLAGS register:     */

        EFLAGS = EFLAGS AND 0x1B3002;   /* VIP VIF VM RF IOPL  */

        EFLAGS = EFLAGS OR TEMP;

        }

        else {

        TEMP = pop();

        /* Clear these fields from EFLAGS stack image:         */

        TEMP = TEMP AND NOT 0xB02A; /* IOPL                    */

        /* Keep these fields from current EFLAGS register:     */

        FLAGS = FLAGS AND 0x3002;   /* IOPL                    */

        FLAGS = FLAGS OR TEMP;

        }

    }

    else if ((CR4.VME == 0) || (OperandSize == 32)) { /* IOPL < 3    */

            then #GP(0);

        else if ([SP].TF) {     /* If stack image TF=1, then #GP     */

                then #GP(0);

        else if ((VIP == 1) && [SP.IF]) {

                    then #GP(0);

                    else {

                        TEMP = pop();

            EFLAGS.VIF = TEMP.IF;

            /* Clear these fields from EFLAGS stack image:             */

            TEMP = AND NOT 0xB22A;  /* IOPL, IF                        */

            /* Keep these fields from current EFLAGS reg               */

            FLAGS = FLAGS AND 0x3202;/* IOPL, IF                       */

            FLAGS = FLAGS OR TEMP;

                    }

                }

            }

        }

    }

}

IRET {                                /* v86 mode                       */

    if (EFLAGS.IOPL == 3)             /* IOPL = 3                       */

        then if (OperandSize == 32) {

            then {

                EIP = pop();

                CS = pop();

                TEMP = pop();

                /* Clear these fields from EFLAGS stack image:            */

                TEMP = TEMP AND NOT 0x1BB02A;   /* VIP VIF VM RF IOPL     */

                /* Keep these fields from current EFLAGS register:        */

                EFLAGS = EFLAGS AND 0x1B3002;   /* VIP VIF VM RF IOPL     */

        EFLAGS = EFLAGS OR TEMP;

            }

            else {

                IP = pop();

                CS = pop();

                TEMP = pop();

                /* Clear these fields from EFLAGS stack image:            */

                TEMP = TEMP AND NOT 0xB02A;     /* IOPL                   */

                /* Keep these fields from current EFLAGS register:        */

                FLAGS = FLAGS AND 0x3002;       /* IOPL                   */

                FLAGS = FLAGS OR TEMP;

        }

        }

        else if ((CR4.VME == 0) || (OperandSize == 32)) { /* IOPL < 3     */

            then #GP(0);

            else if ([SP].TF) {         /* If stack image TF=1, then #GP  */

                then #GP(0);

        else if ((VIP == 1) && [SP.IF]) {

            then #GP(0);

            else {

            IP = pop();

            CS = pop();

            TEMP = pop();

            EFLAGS.VIF = TEMP.IF;

            /* Clear these fields from EFLAGS stack image:      */

            TEMP = AND NOT 0xB22A;  /* IOPL, IF                 */

            /****************************************************/

            /* ** NOTE ** The following treatment of TF flag    */

            /* ********** *MAY BE A BUG* in the Pentium.        */

            /* POPF uses the FLAGS mask of 0x3202, but IRET     */

            /* uses 0x3302.  Consider that POPF and IRET        */

            /* #GP on a condition involving TF.  So is it       */

            /* just coincidence that IRET has further           */

            /* special treatment of TF on IRET, where POPF      */

            /* does not?                                        */

            /****************************************************/

            /* Keep these fields from current EFLAGS reg        */

            FLAGS = FLAGS AND 0x3302;/* IOPL, IF, TF            */

            FLAGS = FLAGS OR TEMP;

            }

          }

        }

      }

   }

}



3



