>> I need some public domain C code to encode and decode the 4 byte BIOS >> data >> time and date at 0000:006Ch.
> If you mean on a PC isn't that one of the genuine interrupt vectors?
Your right, I'm slipping :)
Sorry 0040:006Ch
I envisage someone has written the code for their OS and its in the public domain, or they dont mind putting the time and date code into the public domain. I need non GNU no BSD, etc, code.
On 2009-06-21, Aaron Gray <ang.use...@gmail.com> wrote:
>> If you mean on a PC isn't that one of the genuine interrupt vectors?
> Your right, I'm slipping :)
> Sorry 0040:006Ch
> I envisage someone has written the code for their OS and its in the public > domain, or they dont mind putting the time and date code into the public > domain. I need non GNU no BSD, etc, code.
(Note that not everywhere you can put things in the public domain, like in the US. The only way will be to wait till the author is dead long enough. Moreover, even if I did declare so, the inalien rights would still apply, which are mostly the same as the BSD license (to be recognized as the author of the work))
Seriously, since it is an adress in dos memory space, do you want specifically realmode 16-bit code? If not, it becomes dependant on the extender too.
With Go32v2 (DJGPP,FPC), afaik the FS segment always maps to the dos space, so you can read it by reading fs:[$46C] ($46c is the linear address formed by $40 shl 16+ $6C).
Probably there is some function in the djgpp libs to copy so many bytes from there to the application space.
In FPC they are called dpmi_dosmemget and -put, I assume in DJGPP they are the same.
On Jun 21, 9:49 pm, "Aaron Gray" <ang.use...@gmail.com> wrote:
> I need some public domain C code to encode and decode the 4 byte BIOS data > time and date at 0000:006Ch.
The value at 0x0040:0x006C (or the physical address 0x0000046C) is the number of ticks since "midnight" as a plain boring 32-bit unsigned integer (which is incremented by the PIT IRQ handler at a rate of about 18.2 ticks per second) , and the value at 0x0040:0x0070 (or the physical address 0x00000470) is either a "one or more midnights have passed since boot" flag or a count of the number of midnights that have passed since boot (depending on your BIOS); which is stored as a plain boring 8-bit unsigned integer.
Now, you've posted to alt.os.development, so I'm going to assume you're a potential OS developer. With this in mind...
If you need some "genius" to provide source code so that you can encode and decode unsigned integers (that won't have endian issues), then I'm guessing you're not going to get far with OS development. The same applies if you don't know how to use pointers in C; and if you've implemented segmentation or paging (which could complicate things a little), then only you know how you've implemented segmentation or paging, and you should be able to apply what you learned while implementing these things to be able to access physical addresses.
I'd also point out that the values in these locations are almost entirely useless on their own. The first thing you'd need to worry about is *which* midnight the BIOS is talking about (local time, or UTC? It could be anything). The second thing you should've already noticed - there's no date (only the time of day).
An even better idea would be to get the time of day and the current date from the CMOS chip (and then apply drift correction and optionally convert it from whatever the user/administrator says it is into UTC). An even better idea is to (optionally) automatically do these adjustments based on feedback from the NTP network protocol so the user/administrator doesn't need to worry about setting/correcting the time and date.
It is possible that my assumption is wrong, and that you're not a potential OS developer. In this case; find a suitable C library function (e.g. the "gettimeofday()" function) or ask the OS your application/code is running on. If you're running under almost any OS (except for DOS and FreeDOS) there's almost zero chance that the value at these addresses are correct.
> On Jun 21, 9:49 pm, "Aaron Gray" <ang.use...@gmail.com> wrote: >> I need some public domain C code to encode and decode the 4 byte BIOS >> data >> time and date at 0000:006Ch.
> The value at 0x0040:0x006C (or the physical address 0x0000046C) is the > number of ticks since "midnight" as a plain boring 32-bit unsigned > integer (which is incremented by the PIT IRQ handler at a rate of > about 18.2 ticks per second) , and the value at 0x0040:0x0070 (or the > physical address 0x00000470) is either a "one or more midnights have > passed since boot" flag or a count of the number of midnights that > have passed since boot (depending on your BIOS); which is stored as a > plain boring 8-bit unsigned integer.
> Now, you've posted to alt.os.development, so I'm going to assume > you're a potential OS developer. With this in mind...
> If you need some "genius" to provide source code so that you can > encode and decode unsigned integers (that won't have endian issues), > then I'm guessing you're not going to get far with OS development. The > same applies if you don't know how to use pointers in C; and if you've > implemented segmentation or paging (which could complicate things a > little), then only you know how you've implemented segmentation or > paging, and you should be able to apply what you learned while > implementing these things to be able to access physical addresses.
> I'd also point out that the values in these locations are almost > entirely useless on their own. The first thing you'd need to worry > about is *which* midnight the BIOS is talking about (local time, or > UTC? It could be anything). The second thing you should've already > noticed - there's no date (only the time of day).
> An even better idea would be to get the time of day and the current > date from the CMOS chip (and then apply drift correction and > optionally convert it from whatever the user/administrator says it is > into UTC). An even better idea is to (optionally) automatically do > these adjustments based on feedback from the NTP network protocol so > the user/administrator doesn't need to worry about setting/correcting > the time and date.
> It is possible that my assumption is wrong, and that you're not a > potential OS developer. In this case; find a suitable C library > function (e.g. the "gettimeofday()" function) or ask the OS your > application/code is running on. If you're running under almost any OS > (except for DOS and FreeDOS) there's almost zero chance that the value > at these addresses are correct.
Hi Brendan,
Thanks for the reply. My memory has gone, I used to to AOD stuff eight years ago.
Actually I am trying to get some code to encode and decode the COFF time date stamp.
I set it to zero in an object file and it reported 'Thu Jan 01 00:00:00 1970' so thought it must be a BIOS or DOS date stamp. Anyway I am unsure now, anyway its a 32 bit value.
The PE/COFF doc says its a stamp in the same format as the C runtime library. Looking at C99 I dont see how it can be.
On Jun 22, 12:56 am, "Aaron Gray" <ang.use...@gmail.com> wrote:
> Actually I am trying to get some code to encode and decode the COFF time > date stamp.
> I set it to zero in an object file and it reported 'Thu Jan 01 00:00:00 > 1970' so thought it must be a BIOS or DOS date stamp. Anyway I am unsure > now, anyway its a 32 bit value.
> The PE/COFF doc says its a stamp in the same format as the C runtime > library. Looking at C99 I dont see how it can be.
> With Go32v2 (DJGPP,FPC), afaik the FS segment always maps to the dos > space, so you can read it by reading fs:[$46C] ($46c is the linear address > formed by $40 shl 16+ $6C).
FYI, my notes for DJGPP indicate that GS selector (not a segment) has a descriptor mapped for the "dos" space (approx. 1Mb+64k), while FS selector is used by farptr's.
Ah... Well, it seems the TimeDateStamp field is part of the COFF header common to both and is unsigned 32-bit value. FYI, the Unix epoch (used by COFF) starts Jan 1, 1970, while the DOS epoch starts Jan 1, 1980.
On 2009-06-22, Rod Pemberton <do_not_h...@nohavenot.cmm> wrote:
>> With Go32v2 (DJGPP,FPC), afaik the FS segment always maps to the dos >> space, so you can read it by reading fs:[$46C] ($46c is the linear address >> formed by $40 shl 16+ $6C).
(that should have been times 16 or shl 4 obviously)
> FYI, my notes for DJGPP indicate that GS selector (not a segment) has a > descriptor mapped for the "dos" space (approx. 1Mb+64k), while FS selector > is used by farptr's.
is that they are used in exactly the same way as I described for FPC. %fs:[seg:offs converted to linear address as seg*16+offs].
Could you explain the difference between gs and fs in your description more clearly? %gs is free on FPC (and was sometimes used for VESA LFB), so it might be a specific DJGPP thing instead of general Go32v2.
> Did he mention DJGPP somewhere?...
No. But polling these regions is rare outside operating system loader code and Dos.
In alt.os.development Rod Pemberton <do_not_h...@nohavenot.cmm> wrote:
> FYI, my notes for DJGPP indicate that GS selector (not a segment) has a > descriptor mapped for the "dos" space (approx. 1Mb+64k), while FS selector > is used by farptr's.
Where have you gotten that idea? %fs is used in farptr, correct. %gs is used by the libc (in its farptrs).
> In alt.os.development Rod Pemberton <do_not_h...@nohavenot.cmm> wrote: > > FYI, my notes for DJGPP indicate that GS selector (not a segment) has a > > descriptor mapped for the "dos" space (approx. 1Mb+64k), while FS selector > > is used by farptr's.
> Where have you gotten that idea?
I needed to know how selectors were used in DJGPP to get the selectors in my OS code working with selectors used in DJGPP code. So, I tracked down many ways, hopefully all ways, they are used.
> %fs is used in farptr, correct. %gs > is used by the libc (in its farptrs).
Yes, but the use of %gs in libc is hidden from the user. %gs is DOS memory from the user's perspective. I've found %gs is used for the following:
> On 2009-06-22, Rod Pemberton <do_not_h...@nohavenot.cmm> wrote: > >> With Go32v2 (DJGPP,FPC), afaik the FS segment always maps to the dos > >> space, so you can read it by reading fs:[$46C] ($46c is the linear > >> address formed by $40 shl 16+ $6C).
> (that should have been times 16 or shl 4 obviously)
> > FYI, my notes for DJGPP indicate that GS selector (not a segment) has a > > descriptor mapped for the "dos" space (approx. 1Mb+64k), while FS > > selector is used by farptr's.
> is that they are used in exactly the same way as I described for FPC. > %fs:[seg:offs converted to linear address as seg*16+offs].
You can use them to access DOS memory, but that's not how they work.
The example shows how to access DOS space and how to calculate a valid offset into DOS space for use with _farpeekb() function. the _farpeekb(), and other farptr functions access DOS memory from 32-bit protected-mode. The DOS memory is physically mapped. The farptr functions use selector:offset with %fs as their selector. In PM, %fs is a selector, not a segment, which points to a descriptor in a descriptor table. The descriptor sets the address range of the memory segment. By default, %fs isn't set. The farptr functions use a selector of your choice. That selector is copied into %fs. %fs is only set by the farptr functions. %gs is set to DOS memory by default. To access DOS address, you can pass in a predefined selector for DOS memory, one of which is _dos_ds. That will copy %gs into %fs.
> Could you explain the difference between gs and fs in your description > more clearly? %gs is free on FPC (and was sometimes used for VESA LFB), > so it might be a specific DJGPP thing instead of general Go32v2.
DJGPPv2 uses selectors in a certain way:
CS code selector via _my_cs(), _go32_my_cs() DS data selector via _my_ds(), _go32_my_ds() SS same as DS, via _my_ss(), _go32_my_ss() ES same as DS, used to access DOS PSP FS used for farptr's GS used for DOS memory via: _dos_ds, __djgpp_dos_sel, _go32_info_block.selector_for_lineary_memory, _go32_info_block+26, _go32_conventional_mem_selector(), libc
There is also __djgpp_ds_alias which has a different selector value, but mirrors DS' descriptor info.
> Ah... Well, it seems the TimeDateStamp field is part of the COFF header > common to both and is unsigned 32-bit value. FYI, the Unix epoch (used by > COFF) starts Jan 1, 1970, while the DOS epoch starts Jan 1, 1980.
Yaeh, that sounds more like it !
Thanks, looks like I am going to have to write some code to do it, if no one comes up with anything,
> > Ah... Well, it seems the TimeDateStamp field is part of the COFF header > > common to both and is unsigned 32-bit value. FYI, the Unix epoch (used > > by COFF) starts Jan 1, 1970, while the DOS epoch starts Jan 1, 1980.
> Yaeh, that sounds more like it !
> Thanks, looks like I am going to have to write some code to do it, if no > one comes up with anything,
First, you'll need to find out what your C compiler's epoch is. Hopefully, it's "Jan 1, 1970". AFAICT, the C standards don't have a requirement here. If it's "Jan 1, 1970" as desired, the C function ctime() probably displays the correct date and time from the COFF TimeDateStamp field. If it's a different epoch, you'll have to adjust the seconds from the 1970 epoch to your host's epoch. That'll take some work, since there are leap years involved.
This should emit the epoch.
#include <stdio.h> #include <time.h>
int main(void) { time_t epoch;
epoch=0; printf("%s\n",ctime(&epoch));
return(0);
}
FYI, this can be different for different compilers. DJGPP (uses GCC and custom DOS libc) emits "Thu Jan 1 00:00:00 1970". While, OpenWatcom emits "Wed Dec 31 19:00:00 1969".
If you don't like the format, there are other C functions that can be used to rework the time for string conversion or for timezones, e.g., strftime(), mktime(), etc.
<do_not_h...@nohavenot.cmm> wrote: > FYI, this can be different for different compilers. DJGPP (uses GCC and > custom DOS libc) emits "Thu Jan 1 00:00:00 1970". While, OpenWatcom > emits "Wed Dec 31 19:00:00 1969".
That looks like it might be a locale issue. Are you in a GMT-05:00 timezone? ctime() adjusts for local time... I had assumed that was a C requirement but perhaps it's implementation-defined. time() returns UTC, at least with my compiler's library.
> On Thu, 25 Jun 2009 20:24:57 +1000, Rod Pemberton > <do_not_h...@nohavenot.cmm> wrote:
> > FYI, this can be different for different compilers. DJGPP (uses GCC and > > custom DOS libc) emits "Thu Jan 1 00:00:00 1970". While, OpenWatcom > > emits "Wed Dec 31 19:00:00 1969".
> That looks like it might be a locale issue. Are you in a GMT-05:00 > timezone? ctime() adjusts for local time... I had assumed that was a C > requirement but perhaps it's implementation-defined. time() returns UTC, > at least with my compiler's library.
You're correct. "calendar time" isn't required to be equivalent to "local time" or GMT... So, OW is using Jan 1, 1970 GMT as the start of their epoch.
For GMT-0500 localtime, localtime() is earlier than the epoch, i.e., gmtime(), for OW. But, for DJGPP, both gmtime() and localtime() are returning the same date.. I'll have to look to see if I've got a configuration error. The timezone is probably not set or being found. So, I don't know whether it's epoch is GMT too, or local time.
Unfortunately, that means we don't know what timezone (local or GMT) is being used for COFF header. Also, since the encoding of time_t value is implementation defined, accordng to ISO C99, the values of time_t may be non-portable. That would be a problem for the OP. The COFF sources I found indicate that the TimeDateStamp field uses the time_t values returned by time() and is an unsigned 32-bit value. Poor implementation choice for COFF? Brendan's source indicate the value was in seconds. However, one must also know the timezone to decode the time_t value. Without it, does one use ctime(), or asctime(gmtime()), or something else? Should he assume GMT? or localtime?
Functionally, I see no reason why the local timezone couldn't be set to GMT (or UTC). I'd assume your time() returns UTC because the host system is using UTC as the local timezone. If not, well...
Since there is ctime(), which is equivalent to asctime(localtime()), it makes sense to me make the time_t "calendar time" values be equivalent to local time. There is no "handy" function for asctime(gmtime()). People, like me, are going to pass in zero to ctime() to get the epoch. They aren't going to use mktime() in an attempt to construct a value for the epoch when they expect the value to be zero. How do you determine the correct date to encode with mktime(), if that's what you're trying to find? In fact, I'm not sure that it's possible to determine the epoch's timezone, except possibly by visual inspection of both ctime(0) and asctime(gmtime(0)). There is no timezone information encoded in time_t values. The compiler implementor could've chosen either timezone, localtime or GMT, or neither - due to system constraints, for the epoch. So, I think one's compiler documentation should define whether the "calendar time" epoch, i.e., time(NULL) returns 0 (zero), corresponds to the local timezone, GMT, or neither...
<do_not_h...@nohavenot.cmm> wrote: > Unfortunately, that means we don't know what timezone (local or GMT) is > being used for COFF header.
Maybe it doesn't matter. I suppose it depends on what use you make of the timestamp, and the contexts in which you compare them.
> I'd assume your time() returns UTC because the host system is > using UTC as the local timezone. If not, well...
I'm in Sydney, so my local timezone is GMT+10:00. Yes, this one aspect of life was easier when I lived in Dublin!
> So, I think one's compiler > documentation should define whether the "calendar time" epoch, i.e., > time(NULL) returns 0 (zero), corresponds to the local timezone, GMT, or > neither...
Agreed, it certainly needs to be defined somewhere. Compiler/library docs seem like a good place.
> > > FYI, this can be different for different compilers. DJGPP (uses GCC and > > > custom DOS libc) emits "Thu Jan 1 00:00:00 1970". While, OpenWatcom > > > emits "Wed Dec 31 19:00:00 1969".
> > That looks like it might be a locale issue. Are you in a GMT-05:00 > > timezone? ctime() adjusts for local time... I had assumed that was a C > > requirement but perhaps it's implementation-defined. time() returns UTC, > > at least with my compiler's library.
> You're correct. "calendar time" isn't required to be equivalent to "local > time" or GMT... So, OW is using Jan 1, 1970 GMT as the start of their > epoch.
> For GMT-0500 localtime, localtime() is earlier than the epoch, i.e., > gmtime(), for OW. But, for DJGPP, both gmtime() and localtime() are > returning the same date.. I'll have to look to see if I've got a > configuration error. The timezone is probably not set or being found. So, > I don't know whether it's epoch is GMT too, or local time.
DJGPP is GMT too.
> Unfortunately, that means we don't know what timezone (local or GMT) is > being used for COFF header. Also, since the encoding of time_t value is > implementation defined, accordng to ISO C99, the values of time_t may be > non-portable. That would be a problem for the OP. The COFF sources I found > indicate that the TimeDateStamp field uses the time_t values returned by > time() and is an unsigned 32-bit value. Poor implementation choice for > COFF? Brendan's source indicate the value was in seconds. However, one > must also know the timezone to decode the time_t value. Without it, does > one use ctime(), or asctime(gmtime()), or something else? Should he assume > GMT? or localtime?
We do now...
Landon Noll's history http://www.mail-archive.com/leaps...@rom.usno.navy.mil/msg00109.html
Epoch - was "1970 Jan 1, 00:00:00 GMT" - changed to "1970 Jan 1, 00:00:00 UTC"
time_t - in seconds since the Epoch - ignores leap seconds - usually signed 32-bit int using only 31-bits... - developed formula - after 2001, 100/400 leap year rule adjustment applied to formula
"4.15 Seconds Since the Epoch", i.e., time_t - approximates seconds since the Epoch - UTC - not valid prior to 1970 - not valid if value is negative - valid if 1970 or later and value is positive - value and actual TOD relationship not specified - each day shall add 86400 seconds
For some applications this inconsistency is inconsequential, and for others it is problematic. Until the international standards communities make a clear pronouncement the inconsistencies will remain. Even after that applications which require rigorous retrospective accuracy will have to cope with the calendrical and timekeeping legacy that our predecessors have left us.
>> > > FYI, this can be different for different compilers. DJGPP (uses GCC > and >> > > custom DOS libc) emits "Thu Jan 1 00:00:00 1970". While, OpenWatcom >> > > emits "Wed Dec 31 19:00:00 1969".
>> > That looks like it might be a locale issue. Are you in a GMT-05:00 >> > timezone? ctime() adjusts for local time... I had assumed that was a C >> > requirement but perhaps it's implementation-defined. time() returns >> > UTC, >> > at least with my compiler's library.
>> You're correct. "calendar time" isn't required to be equivalent to >> "local >> time" or GMT... So, OW is using Jan 1, 1970 GMT as the start of their >> epoch.
>> For GMT-0500 localtime, localtime() is earlier than the epoch, i.e., >> gmtime(), for OW. But, for DJGPP, both gmtime() and localtime() are >> returning the same date.. I'll have to look to see if I've got a >> configuration error. The timezone is probably not set or being found. > So, >> I don't know whether it's epoch is GMT too, or local time.
> DJGPP is GMT too.
>> Unfortunately, that means we don't know what timezone (local or GMT) is >> being used for COFF header. Also, since the encoding of time_t value is >> implementation defined, accordng to ISO C99, the values of time_t may be >> non-portable. That would be a problem for the OP. The COFF sources I > found >> indicate that the TimeDateStamp field uses the time_t values returned by >> time() and is an unsigned 32-bit value. Poor implementation choice for >> COFF? Brendan's source indicate the value was in seconds. However, one >> must also know the timezone to decode the time_t value. Without it, does >> one use ctime(), or asctime(gmtime()), or something else? Should he > assume >> GMT? or localtime?
> We do now...
> Landon Noll's history > http://www.mail-archive.com/leaps...@rom.usno.navy.mil/msg00109.html
> Epoch > - was "1970 Jan 1, 00:00:00 GMT" > - changed to "1970 Jan 1, 00:00:00 UTC"
> time_t > - in seconds since the Epoch > - ignores leap seconds > - usually signed 32-bit int using only 31-bits... > - developed formula > - after 2001, 100/400 leap year rule adjustment applied to formula
> "4.15 Seconds Since the Epoch", i.e., time_t > - approximates seconds since the Epoch > - UTC > - not valid prior to 1970 > - not valid if value is negative > - valid if 1970 or later and value is positive > - value and actual TOD relationship not specified > - each day shall add 86400 seconds
> Landon Noll's history > http://www.mail-archive.com/leaps...@rom.usno.navy.mil/msg00109.html
Except for those on Google Groups, apparently. That's "leapsecs". It's not "leaps...". I can understand filtering email addresses, but filtering them out of links? Cringe... Fortunately, you can click on the ellipsis and enter a scrambled word to get the unfiltered original.