Maybe it should be initialized to a known state and then enable or disable NMIs without trying to read the current contents of byte at port 0x70 to preserve a probably invalid state from dummy data.
Is it an obsolete bit usable only in very old systems, 8088, 286, 386...?
This is the code I'm using:
http://devel.archefire.org/downfile.php ... ame=01.zip
This is what I get from my execution log:
Code: Select all
main.119: Point in a variable to absolute offset 0x46C, where the BIOS tick timer resides
How to properly keep it updated from our OS at all times???
main.065: Clear the screen, print what this program does
and set the function to be executed by the run time at exit (atexit).
main.076: Use the SMSW, store machine status word instruction,
and if bit 0 is 1, exit the program
as the CPU is currently in protected mode.
Bit 0 of CR0 is currently 0
main.101: Execute CLI.
main.112: Disable NMIs -- call this log with parameters computed outside the function since x86 code calls it
backwards on stack and then it will fail to be set properly to display our numbers.
Port 0x70 currently contains 0xff -- 11111111b
bmain.121: Bit 7 of port 0x70 (CMOS Memory Index) is 1
so NMIs are disabled.
main.137: We simply enable protected mode by setting
bit 0 of CR0 to 1 (mov eax,cr0 -- inc eax -- mov cr0,eax), but after that we still need to set it up properly.
delay_RTC.053 -- We will iterate for 5 seconds.
delay_RTC.059 -- STEP 1. Get current seconds count, 68, BCD 0x44, in x. The BIOS timer at 0x46C is now 1462296.
delay_RTC.064 -- STEP 2. Wait until the new seconds in the CMOS memory index 0 become different than the cached x second.
delay_RTC.072 -- STEP 3 (debug only). We iterated 108234 times to wait for 1 second change. The BIOS timer at 0x46C is no 1462300 (4 ticks total difference)
delay_RTC.059 -- STEP 1. Get current seconds count, 69, BCD 0x45, in x. The BIOS timer at 0x46C is now 1462300.
delay_RTC.064 -- STEP 2. Wait until the new seconds in the CMOS memory index 0 become different than the cached x second.
delay_RTC.072 -- STEP 3 (debug only). We iterated 720653 times to wait for 1 second change. The BIOS timer at 0x46C is now 1462318 (18 ticks total difference)
delay_RTC.059 -- STEP 1. Get current seconds count, 70, BCD 0x46, in x. The BIOS timer at 0x46C is now 1462318.
delay_RTC.064 -- STEP 2. Wait until the new seconds in the CMOS memory index 0 become different than the cached x second.
delay_RTC.072 -- STEP 3 (debug only). We iterated 910483 times to wait for 1 second change. The BIOS timer at 0x46C is now 1462336 (18 ticks total difference)
delay_RTC.059 -- STEP 1. Get current seconds count, 71, BCD 0x47, in x. The BIOS timer at 0x46C is now 1462336.
delay_RTC.064 -- STEP 2. Wait until the new seconds in the CMOS memory index 0 become different than the cached x second.
delay_RTC.072 -- STEP 3 (debug only). We iterated 947023 times to wait for 1 second change. The BIOS timer at 0x46C is now 1462355 (19 ticks total difference)
delay_RTC.059 -- STEP 1. Get current seconds count, 72, BCD 0x48, in x. The BIOS timer at 0x46C is now 1462355.
delay_RTC.064 -- STEP 2. Wait until the new seconds in the CMOS memory index 0 become different than the cached x second.
delay_RTC.072 -- STEP 3 (debug only). We iterated 882140 times to wait for 1 second change. The BIOS timer at 0x46C is now 1462373 (18 ticks total difference)
delay_RTC.080 -- Here we could improve the accuracy of our timer some more
if we made an average of all the counts, except the first one,
then we subtracted the first count from the average, got
the absolute value, or subtracted the smaller from the bigger value
and then we simply iterated one more time in a second loop only for the
amount of the subtraction to complete an obviously partial amount of time
to complete a whole second, as long as that count is smaller than the bigger count so far.
The only drawback is that it would be very CPU intensive, not suited for every multitasking application
and even less for a multitasking kernel and libraries.
main.147: We simply disable protected mode by clearing
bit 0 of CR0 to 0 (mov eax,cr0 -- dec eax, mov cr0,eax). We didn't set up anything further so we don't need to
reconfigure anything to return to Real Mode, but we can't call any Turbo C library functions or Real-Mode specific
code during that time or we will crash in a badly-enabled protected mode.
main.233: Enable NMIs -- call this log with parameters computed outside the function since x86 code calls it
backwards on stack and then it will fail to be set properly to display our numbers.
Port 0x70 currently contains 0xff -- 11111111b
main.121: Bit 7 of port 0x70 (CMOS Memory Index) is 1
so NMIs are disabled.
main.259: Now port 0x70 contains 0xff -- 11111111b
main.235: Execute STI.
main.291: WARNING: Port 0x70 is stuck on reads to 11111111b, so we can't enable/disable NMIs
It must be a machine with an invalid port 0x70 on reads and write-only NMI enabled/disabled state at write-only byte port 0x70.
my_exit.047 -- Just print a message right before the program terminates.
NOTE: I see that this topic has cooled down properly, as it should. The question, although can develop a much more complete answer, has been fully answered. I have also given myself time to evaluate the suggestion from LtG for simplifying my book editing automation function, but now that everything has been cooled down and the conversation has been processed mentally in depth, now I see that LtG's suggestion isn't convenient because it simply does not allow for complex documentation, just for extremely basic logging, which is useless for what I want to achieve. My function is thought to generate many kinds of data in the future (image files for graphical memory snapshots, sound chunks, video or GIF loops, HTML, and anything that I could need), so my function is OK as it is. After all, it's intended to write a book, so it cannot be much more simple that it already is here. I need to leave it like that as a minimum.