Mail Archives: djgpp/2002/06/11/04:46:02
Hi all.
So, it means that some of DPMI providers may "block" sti/cli
instruction. But if your program runs under "pure" DOS & CWSDPMI
(usual DJGPP configuration), you can rely upon the fact that it works
fine with privelage instructions like sti/cli, and without any CPU
time overhead.
Since cli and sti are privileged instructions, they will cause a
protection violation and the DPMI provider will simulate the
instruction. Because of the overhead involved in processing the
exception, cli and sti should be used as little as possible. In
general, you should expect either of these instructions to require at
least 300 clocks (see below how you can test it).
As a rule (near 100% of probability) the interrupt controller on your
computer will work in FNI mode (Fully Nested Interrupt mode). It means
that when an intterupt is raised, the interrupt controller (f.e. Intel
8259 chip) is immediatelly blocked - it will not accept any interrupt
request from peripheral devices till the handler processing the
current interrupt tells NON_SPECIFIC_END_OF_INTERRUPT (=0x20) to
interrupt controller's control register (0x20 port for leading, 0xA0
port for driven IC). And the program should enable CPU to process
interrupts to set IF flag.
Of course, when the instuction "iret" is executed, it restores IF flag
of CPU (and all context previously stored to the stack when the
inturrupt was raised). But don't forget that if some of hardware
interrupt handlers, which your program establishes, may work a long
time you must give a change to others interrupts to be proccessed. It
is inadmissibly to lost some important interrupts, f.e, timer, I/O
interruprs and so on.
An interrupt handler may look like this (it is real hardware interrupt
handler for Real Time Clock to count milliseconds):
static void RTC_Interrupt_Handler (void)
{
INTERRUPT_ENTER ();
// Read status register 3 of RTC, otherwise
// the interrupt will not be enabled
readReg (RTC_STATUS_REG_3);
// Read status register 2 of RTC
// timer interrupt?
if (readReg (RTC_STATUS_REG_2) & 0x40)
++TimerCount;
INTERRUPT_LEAVE_BOTH ();
}
END_OF_STATIC_FUNCTION (RTC_Interrupt_Handler);
where:
#define INTERRUPT_ENTER(); asm ("sti"); /* enable maskable interrupts
*/
#define INTERRUPT_LEAVE(); asm ("cli"); /* disable maskable interrupts
*/ \
outportb (0x20, 0x20); /* End of interrupt
*/
#define INTERRUPT_LEAVE_BOTH(); asm ("cli"); /* disable maskable
interrupts */ \
outportb (0x20, 0x20); /* End of
interrupt */ \
outportb (0xA0, 0x20); /* End of
interrupt */
Here, we must unblock both the leading Interrupt Controller and driven
one because the RTC interrupt is mapped to the second IC.
Again, in general, you should expect that "sti" or "cli" instructions
to require many clocks under some DPMI provider. But used pure DOS it
takes only several CPU ticks. How can you test it?It is easy. Use
"rdtsc" instruction. It allows to take CPU ticks at the moment, and
returns 64-bits tick counter from the computer has rebooted. It shows
that "sti" takes only ~30 CPU ticks to be executed. It proves that a
program under DOS & CWSDMPI has enough privelage to execute "sti" or
"cli" instructions.
Best regards,
Alex
PS Here is "rdtsc" code.
-------------------------------------------
[BITS 32]
[GLOBAL _Read_TSC]
[SECTION .text]
_Read_TSC:
mov ecx, [esp+4]
rdtsc
mov [ecx], eax
mov [ecx+4], edx
ret
;_Read_TSC
-------------------------------------------
typedef unsigned long long int TICK;
extern void Read_TSC (TICK *tick);
-------------------------------------------
- Raw text -