• Please review our updated Terms and Rules here

How does DOS detect the presence of an RTC?

tom.storey

Experienced Member
Joined
Nov 18, 2022
Messages
104
Location
London, UK
Hi all,

Slightly obscure question, but how does DOS detect the presence of a real-time clock in the system?

I read in a document of DOS interrupt calls that from DOS 3.3 onwards, the calls that it implements that set the date and time will also update the RTC if it is present.

I spent some time today in debug trying to disassemble my way to an answer (under DOS 5.0), and I got some of the way, but then ended up in some really obscure code that I was finding quite difficult to navigate (I havent come close to being an x86 assembly guru yet).

So I thought I might ask and see if someone knows the answer - are there some variables or memory locations that it looks at that describe whether an RTC is present and where it is, or does it use some other "tricks" or methods? Is it as simple as DOS 3.3+ calling the BIOS set date/time functions which on a system with an RTC would then update said RTC? But, while I certainly seemed to be looking at code that was doing very date/time looking things, I never came across any references to int 1Ah though...

Any insight appreciated.

Thanks!
 
Keep in mind that not all RTCs are the same. They can appear at different I/O addresses and use different chipsets.

I suspect DOS is limiting itself to updating the RTC that is standard on the PC AT (and later) class of computers. Otherwise, the possibly universe of RTC variants is too large. Nor would it be necessary - those older machines would continue to use their own device drivers while newer machines could count on the AT standard.
 
There's source code available for DOS, so you can check there.

But don't confuse a real-time clock with the 18.2 msec "tick" from the timer chip, which also keeps the time of day clock. Otherwise, there are BIOS calls in later (AT BIOS) that can verify the presence of a real time clock. For earlier systems with the "CMOS" chip, one generally has to install a program to read the RTC and set the time-of-day. For later ones, look at the CLOCK$ driver source.

On AT and later systems, the RTC is the CMOS chip at I/O ports 70h and 71h.
 
I'll take a look at the CLOCK$ driver, but as is my understanding the only DOSes that have had source code released are much earlier than even 3.0?

But all of the hardware details I already know (different chips, addresses etc etc). Im building my own board with an RTC (MC146818A) for my XT, and looking at the software side of things and how to integrate it. Ive made the hardware as analog as possible to the AT implementation (down to the same dual IO port scheme to write the register address and read/write data).

My current idea (and part implementation) is simply a small utility which you can tell what IO address(es) the RTC is located at (and some jumpers on the board to configure its address, since it cant live at address 0x70/71 on a PC/XT as those addresses are decoded for another peripheral) and it will then be able to read it at boot to set the DOS time via int 21 (and maybe system time via int 1A), and write back to it to set the time. That could simply be called from autoexec.bat or some such with a flag. But I suppose I was hoping that there was some way to tell DOS where it was located so that maybe it could all be more tightly integrated and "automagic".
 
DOS 6.0 source is/was online. At least I have it.

No, short of replacing the CLOCK$ driver or installing your own TSR to patch the time-of-day BIOS services in, I don't believe that there's a way to handle this without adding programs/modifying existing code.
There have been XT-add in boards with the Motorola RTC chip--I used to have one--it required its own TSR.
 
Oh wow, yeah I just found it on github. The time stuff looks exactly like what I was seeing during disassembly earlier today., except now I have some comments to tell me what is going on. 🙃

Re utilities: cool, so Im not too far off the mark then. :)

I'll probably go down the companion utility route to begin with (not sure if I will be needing a TSR? But we'll see I guess), I need to take this all in steps and learn things as Im going. At some point after that I'll look at writing a driver that could do the work for me. It seems IBM had a driver called CMOSCLK.SYS that they included with later versions of their DOS, not sure if that ever made it into MS-DOS. Could serve as some inspiration.
 
Looking through the DOS 6.0 code, I have a feeling that it is basically calling a device driver to read and write date/time - there are references to "DEVIOCALL2" which sounds very driver'y to me. By default that may be a built in driver (havent figured out where that is yet to see what it does), but it could also be an external driver that has been loaded.

Well, this gives me some more to chew on I suppose.
 
Is it possible that "DEVIOCALL2" refers to BIOS call INT 1A, AH = 02?

Code:
Notes:    this function is also supported by the Sperry PC, which predates the
      IBM AT; the data is returned in binary rather than BCD on the Sperry,
      and DL is always 00h
    MS-DOS/PC DOS IO.SYS/IBMBIO.COM use this function to detect if a RTC
      is preset by checking if the returned values are non-zero. If they
      are, this function is called one more time, before it is assumed
      that no RTC is present.
BUG:    some BIOSes leave CF unchanged if successful, so CF should be cleared
      before calling this function
 
In general, that's the pattern with later MS-DOS. Any hardware functions are not done directly, but diverted to the driver with an IOCTL call. Linux follows this pattern also, NT/XP/2K/7... has a bit different interface (IRPs) but is generally the same idea.
 
It was probably part of the whole POSIX compatability thing. (edit: Actually, was that a DOS thing?)
 
Nah, I dont believe so. DEVIOCALL2 is defined here: https://github.com/AR1972/astro/blob/master/dos/dev.asm#L523-L597

It seems to be very much part of the device driver interface.

Okay, yeah, you're right, I guess that's a DOS device system call, it's not directly calling the BIOS functions...

That said, that just means that whatever code is setting the clock is wrapped up to *be* a device, which means it's not going to be in the MS-DOS per se source code, right? MS-DOS wraps up all the BIOS calls into drivers in IO.SYS. (or IBM dos-es call it something else, right? IBMBIO.COM?) Looking in the ../bios directory (which is referenced in the makefile) I took a random stab at msbio1.asm and 400 lines in it defines these public variables including, crucially perhaps, a flag about whether a CMOS clock is present:

Code:
; variables for real time clock setting
        public  havecmosclock
havecmosclock   db      0       ;set by msinit
        public  base_century
base_century    db      19
        public  base_year
base_year       db      80
        public  month_tab
month_tab       db      31,28,31,30,31,30,31,31,30,31,30,31

I'm going to take a wild guess if you dig around this BIOS directory long enough you'll find the code that wraps those BIOS calls into a DOS device driver.
 
Yay!

I suppose it’s possible that instead of using the BIOS calls you might find something in there that bit-bangs the hardware directly, but I’m really skeptical about that. The BIOS call is there for a reason, IE, it technically would let you use whatever hardware you want instead of having to slavishly copy the AT. (Granted most everyone did anyway, but the idea is sound.)

Since an XT doesn’t implement these calls at all I suppose it would follow that it might be technically possible to implement them in a BIOS extension? That would at first glance be the only “right” way to do auto-discovery that doesn’t require either a binary patch to DOS or a config.sys-loaded driver. Maybe you could roll it into a custom XTIDE bios build.
 
On my board I am building in a socket that I can plug a ROM or RAM into for option ROM development experiments. I could likely look at hooking int 1A and implementing my own time of day BIOS calls, but that might be going a bit far.

I think all I really need to do is just set the time within DOS so that it knows what timestamp to stick on files etc.

But in all likelihood I'll probably go a bit further and see what I can do to make it so that "DOS" can update the time in the RTC itself, as if it were running on something more like an AT with a built in RTC. That would be a pretty cool achievement I reckon. 😎
 
Recall that the AT platform uses the RTC for a lot more than time-of-day functions. For example, the Int 15h (AH=83h and 86h) comes to mind, as well as added Int 1A functionality.
 
Well, I think I found it:


It looks very simple really. Clear CX and DX, then make a call to int 1A with function 2 (read RTC time). Function 2 is not implemented in the BIOS of the PC and XT because they don't have an RTC, so the int returns with CX and DX still being clear.

If either of those registers contains a non-zero value then DOS considers a RTC to be present, and it sets that flag.

But DOS then assumes that the RTC is at IO address 70/71, which is very much only AT+ compatible, at least not without some kind of patch.


And DOS implements it's own read/write routines to interface with the RTC that actually look to be more or less copy/paste of the IBM AT BIOS routines (cmos_read and cmos_write).


So even an option ROM wouldn't help in this case I don't think, since DOS is hard coded to read/write certain IO addresses - and there's no way to intercept it because it does it directly.

Best bet then is probably a custom CLOCK$ driver for the most seamless integration.

What a great resource it is having access to the code. Hah. :)
 
Well, again, all you need is a program to read the RTC set the time of day and date through Int 1ah. You can go away after that. If the date rolls over, I think the date adjustment is handled in CLOCK$--I haven't checked, but it seems reasonable. As to what happens if the PC sits idle for two days--I think that may be a problem.
 
And DOS implements it's own read/write routines to interface with the RTC that actually look to be more or less copy/paste of the IBM AT BIOS routines (cmos_read and cmos_write).

I‘ve only skimmed it, but are you sure that hard-coded cmos routine in there is used for the simple case of just reading/setting the clock? It seems like most of the routines for that are making the INT 1A function call. The comments around the direct CMOS read/write routines read like it’s there for some kind of edge case?
 
Back
Top