[freeldr]
authorGabriel Ilardi <gabrielilardi@hotmail.it>
Sat, 31 Jul 2010 21:00:40 +0000 (21:00 +0000)
committerGabriel Ilardi <gabrielilardi@hotmail.it>
Sat, 31 Jul 2010 21:00:40 +0000 (21:00 +0000)
- Patch by Carlo Bramini reviewed by lassy:
The CF must be tested when reading time because the legacy DS12x87
chip shows a condition where it's updating its time registers and if it's the
case then the call should be retried later. Now the time is valid when both CF flags for date and time are good at the same time.
It's better to send the correct value of CF with the proper field to the REGS structure instead of hoping that the flag won't be changed by compiled code.
In the Int386() function I did the fix for acquiring the status flags to send to the software interrupt.
I also think it is also a good idea to always clear the direction flag before
doing movsb/movsw/movsd in this function. Since we are working with DOS stuff,
the state of the direction register could be unknown, who knows what happens
after those INT opcodes. Afterall I don't think that adding these two "cld"
would be a big problem.
See issue #2786 for more details.

svn path=/trunk/; revision=48383

reactos/boot/freeldr/freeldr/arch/i386/int386.S
reactos/boot/freeldr/freeldr/arch/i386/pcrtc.c
reactos/boot/freeldr/freeldr/include/arch.h

index 3b467e5..14086bf 100644 (file)
 #define ASM
 #include <arch.h>
 
+/* Only these flags are propagated into Int386() */
+#define FLAGS_PROP     (I386FLAG_CF | \
+                     I386FLAG_ZF | \
+                     I386FLAG_SF)
 
 Int386_REGS:
 
@@ -85,6 +89,7 @@ EXTERN(_Int386)
        movl    $Int386_REGS,%edi
        movl    Int386_regsin,%esi
        movl    $0x24,%ecx
+       cld
        rep
        movsb
 
@@ -101,6 +106,16 @@ EXTERN(_Int386)
        movw    %cs:Int386_gs,%ax
        movw    %ax,%gs                                 /* GS register */
 
+       /* Prepare EFLAGS for recover */
+       pushf
+       movw    %cs:Int386_eflags, %ax
+       popw    %cx
+       andw    $FLAGS_PROP, %ax
+       andw    $~FLAGS_PROP, %cx
+       orw             %cx, %ax
+       pushw   %ax
+
+       /* Recover general purpose registers */
        movl    %cs:Int386_eax,%eax             /* EAX register */
        movl    %cs:Int386_ebx,%ebx             /* EBX register */
        movl    %cs:Int386_ecx,%ecx             /* ECX register */
@@ -109,6 +124,9 @@ EXTERN(_Int386)
        movl    %cs:Int386_esi,%esi             /* ESI register */
        movl    %cs:Int386_edi,%edi             /* EDI register */
 
+       /* Recover previously prepared flags */
+       popf
+
        /* Do not set the flags register */
        /* only return its value in regsout */
        //pushl Int386_eflags
@@ -149,6 +167,7 @@ Int386_vector_opcode:
        movl    $Int386_REGS,%esi
        movl    Int386_regsout,%edi
        movl    $0x24,%ecx
+       cld
        rep
        movsb
 
index 1141753..6b53da8 100644 (file)
@@ -27,56 +27,66 @@ PcGetTime(VOID)
     static TIMEINFO TimeInfo;
     REGS Regs;
 
-    /* Some BIOSes, such as the 1998/07/25 system ROM
-     * in the Compaq Deskpro EP/SB, leave CF unchanged
-     * if successful, so CF should be cleared before
-     * calling this function. */
-    __writeeflags(__readeflags() & ~EFLAGS_CF);
+    for (;;)
+    {
+        /* Some BIOSes, such as the 1998/07/25 system ROM
+         * in the Compaq Deskpro EP/SB, leave CF unchanged
+         * if successful, so CF should be cleared before
+         * calling this function. */
+        Regs.x.eflags = 0;
+//        __writeeflags(__readeflags() & ~EFLAGS_CF);
 
-    /* Int 1Ah AH=04h
-     * TIME - GET REAL-TIME CLOCK DATE (AT,XT286,PS)
-     *
-     * AH = 04h
-     * CF clear to avoid bug
-     * Return:
-     * CF clear if successful
-     * CH = century (BCD)
-     * CL = year (BCD)
-     * DH = month (BCD)
-     * DL = day (BCD)
-     * CF set on error
-     */
-    Regs.b.ah = 0x04;
-    Int386(0x1A, &Regs, &Regs);
+        /* Int 1Ah AH=04h
+         * TIME - GET REAL-TIME CLOCK DATE (AT,XT286,PS)
+         *
+         * AH = 04h
+         * CF clear to avoid bug
+         * Return:
+         * CF clear if successful
+         * CH = century (BCD)
+         * CL = year (BCD)
+         * DH = month (BCD)
+         * DL = day (BCD)
+         * CF set on error
+         */
+        Regs.b.ah = 0x04;
+        Int386(0x1A, &Regs, &Regs);
 
-    TimeInfo.Year = 100 * BCD_INT(Regs.b.ch) + BCD_INT(Regs.b.cl);
-    TimeInfo.Month = BCD_INT(Regs.b.dh);
-    TimeInfo.Day = BCD_INT(Regs.b.dl);
+        if (!INT386_SUCCESS(Regs)) continue;
 
-    /* Some BIOSes leave CF unchanged if successful,
-     * so CF should be cleared before calling this function. */
-    __writeeflags(__readeflags() & ~EFLAGS_CF);
+        TimeInfo.Year = 100 * BCD_INT(Regs.b.ch) + BCD_INT(Regs.b.cl);
+        TimeInfo.Month = BCD_INT(Regs.b.dh);
+        TimeInfo.Day = BCD_INT(Regs.b.dl);
 
-    /* Int 1Ah AH=02h
-     * TIME - GET REAL-TIME CLOCK TIME (AT,XT286,PS)
-     *
-     * AH = 02h
-     * CF clear to avoid bug
-     * Return:
-     * CF clear if successful
-     * CH = hour (BCD)
-     * CL = minutes (BCD)
-     * DH = seconds (BCD)
-     * DL = daylight savings flag (00h standard time, 01h daylight time)
-     * CF set on error (i.e. clock not running or in middle of update)
-     */
-    Regs.b.ah = 0x02;
-    Int386(0x1A, &Regs, &Regs);
+        /* Some BIOSes leave CF unchanged if successful,
+         * so CF should be cleared before calling this function. */
+        Regs.x.eflags = 0;
+//        __writeeflags(__readeflags() & ~EFLAGS_CF);
 
-    TimeInfo.Hour = BCD_INT(Regs.b.ch);
-    TimeInfo.Minute = BCD_INT(Regs.b.cl);
-    TimeInfo.Second = BCD_INT(Regs.b.dh);
+        /* Int 1Ah AH=02h
+         * TIME - GET REAL-TIME CLOCK TIME (AT,XT286,PS)
+         *
+         * AH = 02h
+         * CF clear to avoid bug
+         * Return:
+         * CF clear if successful
+         * CH = hour (BCD)
+         * CL = minutes (BCD)
+         * DH = seconds (BCD)
+         * DL = daylight savings flag (00h standard time, 01h daylight time)
+         * CF set on error (i.e. clock not running or in middle of update)
+         */
+        Regs.b.ah = 0x02;
+        Int386(0x1A, &Regs, &Regs);
 
+        if (!INT386_SUCCESS(Regs)) continue;
+
+        TimeInfo.Hour = BCD_INT(Regs.b.ch);
+        TimeInfo.Minute = BCD_INT(Regs.b.cl);
+        TimeInfo.Second = BCD_INT(Regs.b.dh);
+
+        break;
+    }
     return &TimeInfo;
 }
 
index b9a6cc0..ec374f4 100644 (file)
@@ -58,6 +58,19 @@ extern ULONG gDiskReadBuffer, gFileSysBuffer;
 #define EXTERN(x)      .global x; x:
 
 
+// Flag Masks
+#define I386FLAG_CF            0x0001          // Carry Flag
+#define I386FLAG_RESV1 0x0002          // Reserved - Must be 1
+#define I386FLAG_PF            0x0004          // Parity Flag
+#define I386FLAG_RESV2 0x0008          // Reserved - Must be 0
+#define I386FLAG_AF            0x0010          // Auxiliary Flag
+#define I386FLAG_RESV3 0x0020          // Reserved - Must be 0
+#define I386FLAG_ZF            0x0040          // Zero Flag
+#define I386FLAG_SF            0x0080          // Sign Flag
+#define I386FLAG_TF            0x0100          // Trap Flag (Single Step)
+#define I386FLAG_IF            0x0200          // Interrupt Flag
+#define I386FLAG_DF            0x0400          // Direction Flag
+#define I386FLAG_OF            0x0800          // Overflow Flag
 
 
 #ifndef ASM
@@ -148,20 +161,6 @@ typedef union
 // specifically handles linear addresses.
 int            Int386(int ivec, REGS* in, REGS* out);
 
-// Flag Masks
-#define I386FLAG_CF            0x0001          // Carry Flag
-#define I386FLAG_RESV1 0x0002          // Reserved - Must be 1
-#define I386FLAG_PF            0x0004          // Parity Flag
-#define I386FLAG_RESV2 0x0008          // Reserved - Must be 0
-#define I386FLAG_AF            0x0010          // Auxiliary Flag
-#define I386FLAG_RESV3 0x0020          // Reserved - Must be 0
-#define I386FLAG_ZF            0x0040          // Zero Flag
-#define I386FLAG_SF            0x0080          // Sign Flag
-#define I386FLAG_TF            0x0100          // Trap Flag (Single Step)
-#define I386FLAG_IF            0x0200          // Interrupt Flag
-#define I386FLAG_DF            0x0400          // Direction Flag
-#define I386FLAG_OF            0x0800          // Overflow Flag
-
 // This macro tests the Carry Flag
 // If CF is set then the call failed (usually)
 #define INT386_SUCCESS(regs)   ((regs.x.eflags & I386FLAG_CF) == 0)