From ffc722f4e81e2de9ec72776ce7e351f24dda16d5 Mon Sep 17 00:00:00 2001 From: Stanislav Shwartsman Date: Fri, 1 Dec 2023 23:55:35 +0200 Subject: [PATCH] Porting #SF patch #565 Real Time Clock /CMOS fix (#4) by Michele Giacomone Detailed description: -Observed issues Due to some limitations only dates between 1980 and 2038 can be used in a reliable way. Also, bochs incorrectly assumes a linear correspondence between the data returned by the functions localtime() and mktime(), and isn't setting the latter properly. Bochs keeps its internal time value dependent to these functions after setup, assuming that their internal settings won't change on the go - which is not the case. In my OS, and in my timezone, this leads to incorrect startup values for 5 months each year and unreliable values if the simulation is kept going for a long time. (a feedback between localtime() and mktime() is created which keeps shifting back the time) Also, the RTC simulation is not realistic since the clock fixes itself across DST changes, without updating any DST related flag, a behavior that no guest OS expects. -Proposed fix This is implemented in such way that no bochs' previous behavior is changed, a part from the broken ones, with legacy in mind == the user can keep using bochs exactly as before knowing nothing of this patch +Make the internal s.timeval variable a Bit64s, so it can fit all values that the cmos can correctly represent, reported below: MIN setting -62167219200 => 0000/01/01 SAT 0:00:00 MAX BCD setting 253402300799 => 9999/12/31 FRI 23:59:59 MAX BIN setting 745690751999 => 25599/12/31 FRI 23:59:59 And then fix each reference to these so it can handle such values And make bochs correctly wrap around for under/overflows, so that only the most significant bits of the century are lost. +Do the same thing to the bochs time0 parameter, so all the above values can be chosen at startup (despite being now legal values, 1 and 2 will still be treated as "local" and "utc"). Note that normally only BCD settings are valid since bochs' CMOS defaults to such operating mode - the only way to use the binary range is by loading a cmos memory map. +Make the internal s.timeval variable independent from external factors. This means providing a small set of time handling functions, contained in "iodev/utctime.h", which must work in any environment in which bochs compiles, accessing no external resource. This also means that after startup, s.timeval will only be changed internally, and no call to the OS time functions will be made. +Make the internal s.timeval variable timezone independent, to have a linear correlation between its values and valid CMOS settings. To make it easier, s.timeval is gonna be treated as if the current timezone was UTC: so, - if the user selects UTC as time0, s.timeval will become current time(NULL) - if the user selects localtime, s.timeval will be computed as the value which will display the same broken down time as localtime(&now) - if the user inputs a time formatted string the proper s.timeval to displayed will be easily calculated, - if the user inputs a starting time value, s.timeval will be computed as the value which will display the same broken down time as localtime(&user_input) to ensure the same operation as before. A "tz=utc" is displayed when bochs prints out the current time value, to warn users about the difference in meaning between the internally kept time value and the value they can set through the "time0=" parameter. This might be changed to communicate instead the time value they can input to get the same setting, but performing such calculation (except for the startup time) suffers from all the mktime()/localtime() problems listed above so I did not do it. The range of "time0" is automatically adjusted so all users in all time zones can set any legal value despite "time0=" having a local meaning. A thorough explanation of what I did and why can be found in the "iodev/utctime.h" library header. --------- Co-authored-by: Stanislav Shwartsman Co-authored-by: Volker Ruppert --- .gitignore | 7 ++ bochs/bios/BIOS-bochs-latest | Bin 131072 -> 131072 bytes bochs/bios/BIOS-bochs-legacy | Bin 65536 -> 65536 bytes bochs/bios/Makefile.in | 7 +- bochs/bios/rombios.c | 171 +++++++++++++++++++++---- bochs/config.cc | 42 +++++-- bochs/config.h.in | 2 - bochs/configure | 36 ------ bochs/configure.ac | 2 - bochs/gui/textconfig.cc | 33 +++-- bochs/iodev/Makefile.in | 6 +- bochs/iodev/cmos.cc | 101 ++++++++------- bochs/iodev/cmos.h | 7 +- bochs/iodev/utctime.h | 234 +++++++++++++++++++++++++++++++++++ 14 files changed, 505 insertions(+), 143 deletions(-) create mode 100644 bochs/iodev/utctime.h diff --git a/.gitignore b/.gitignore index 8213cccd9..328eeafab 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,13 @@ bochs-msvc-src.zip # /bochs/bios/ /bochs/bios/Makefile +/bochs/bios/_rombios*_.c +/bochs/bios/biossums +/bochs/bios/rombios*.s +/bochs/bios/rombios*.sym +/bochs/bios/rombios*.txt +/bochs/bios/rombios*.bin +/bochs/bios/rombios32.out # /bochs/build/linux/ /bochs/build/linux/DOC-linux.html diff --git a/bochs/bios/BIOS-bochs-latest b/bochs/bios/BIOS-bochs-latest index 413672564b45a7c1a9a74c5001f76aa5dd475ba3..44ba3aadb7c6ff8389de3de8a9f506ad181d0016 100644 GIT binary patch delta 15537 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 delta 14721 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 X#|HhKTsrdcF!*iI%)=f+^}YWGqzkSa diff --git a/bochs/bios/BIOS-bochs-legacy b/bochs/bios/BIOS-bochs-legacy index f9f04d4cedd45d97e9ba8a9258846534180bddfc..bd82bbd8295216060204bde2b048966b473362d2 100644 GIT binary patch delta 14364 zcmaib31CcD_xQY*#ga)Ti7c|OB8iYh2qj2l`fNcoZ4s5?Be7GG(3VWdA~R!b$5O3b zt6%Hae(}XJ3>Ac;)>74?f|NVP5)q-<=6CLWZ^r2N{r>-s%-plwbI(2J+;i_e@3pYd zzOc}~dUwRUM)1Mvs$%6vo@=hOo!!d zG8Cp)8R=TVQJd9PSMZAb0#Dj_b6df&ZBc62tN9UHp;nt!rz@x@U0$h$SL&=ru`}iM zK@1gV3f2ns+N=g$K`nXuGT+_8QA=LJxwd}XNg!>Pwb|T+;~N4h^4ksLc&-6Xw9n

2`Mf?aM;tv33Y~fm8H@I)#s% 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 delta 13608 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 diff --git a/bochs/bios/Makefile.in b/bochs/bios/Makefile.in index e09956439..5770d3c48 100644 --- a/bochs/bios/Makefile.in +++ b/bochs/bios/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2020 The Bochs Project +# Copyright (C) 2001-2023 The Bochs Project # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -45,8 +45,9 @@ IASL = @IASL@ BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev LOCAL_CXXFLAGS = -UPSTREAM_RELEASE_DATE = $(shell grep "Updated:" ../README | sed 's/Updated://') -BUILDDATE = `date -u -d '$(UPSTREAM_RELEASE_DATE)' '+%m/%d/%y'` +# UPSTREAM_RELEASE_DATE = $(shell grep "Updated:" ../README | sed 's/Updated://') +# BUILDDATE = `date -u -d '$(UPSTREAM_RELEASE_DATE)' '+%m/%d/%y'` +BUILDDATE = `date -u '+%m/%d/%y'` BIOS_BUILD_DATE = "-DBIOS_BUILD_DATE=\"$(BUILDDATE)\"" # # -------- end configurable options -------------------------- diff --git a/bochs/bios/rombios.c b/bochs/bios/rombios.c index 76b654382..f08066f02 100644 --- a/bochs/bios/rombios.c +++ b/bochs/bios/rombios.c @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2001-2021 The Bochs Project +// Copyright (C) 2001-2023 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -573,6 +573,12 @@ typedef unsigned long Bit32u; shr ebx, #16 ret + imodu: + div bl + mov al, ah + xor ah, ah + ret + ASM_END // for access to RAM area which is used by interrupt vectors @@ -841,6 +847,8 @@ static Bit16u inw(); static void outw(); static void init_rtc(); static bx_bool rtc_updating(); +static Bit8u bin2bcd(); +static Bit8u bcd2bin(); static Bit8u _read_byte(); static Bit16u _read_word(); @@ -928,7 +936,7 @@ Bit16u cdrom_boot(); #endif // BX_ELTORITO_BOOT -static char bios_svn_version_string[] = "$Revision$ $Date$"; +// static char bios_svn_version_string[] = "$Revision$ $Date$"; #define BIOS_COPYRIGHT_STRING "(c) 2001-2021 The Bochs Project" @@ -1255,6 +1263,51 @@ rtc_updating() return(1); // update-in-progress never transitioned to 0 } + Bit8u +bin2bcd(value) + Bit8u value; +{ +ASM_START + push bp + mov bp, sp + + push dx + mov dh, ah + xor ah, ah + mov al, 4[bp] + mov dl, #10 + div dl + shl al, #4 + add al, ah + mov ah, dh + pop dx + + pop bp +ASM_END +} + + Bit8u +bcd2bin(value) + Bit8u value; +{ +ASM_START + push bp + mov bp, sp + + push dx + mov al, 4[bp] + mov dh, al + and dh, #0x0f + shr al, #4 + mov dl, #10 + mul dl + add al, dh + pop dx + + pop bp +ASM_END +} + #define read_byte(seg, offset) _read_byte(offset, seg) Bit8u @@ -2011,8 +2064,7 @@ void s3_resume_panic() void print_bios_banner() { - printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", - BIOS_BUILD_DATE, bios_svn_version_string); + printf(BX_APPNAME" BIOS - build: %s\nOptions: ", BIOS_BUILD_DATE); printf( #if BX_APM "apmbios " @@ -2264,7 +2316,7 @@ log_bios_start() #if BX_DEBUG_SERIAL outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */ #endif - BX_INFO("%s\n", bios_svn_version_string); + BX_INFO("BIOS BUILD DATE: %s\n", BIOS_BUILD_DATE); } bx_bool @@ -8461,7 +8513,7 @@ int1a_function(regs, ds, iret_addr) Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call { - Bit8u val8; + Bit8u val8,hr; BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds); @@ -8506,10 +8558,24 @@ int1a_function(regs, ds, iret_addr) break; } - regs.u.r8.dh = inb_cmos(0x00); // Seconds - regs.u.r8.cl = inb_cmos(0x02); // Minutes - regs.u.r8.ch = inb_cmos(0x04); // Hours - regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B + val8 = inb_cmos(0x0b); + if(val8&0x04){ + regs.u.r8.dh = bin2bcd(inb_cmos(0x00)); // Seconds + regs.u.r8.cl = bin2bcd(inb_cmos(0x02)); // Minutes + hr = inb_cmos(0x04); + if(!(val8&0x02)&&(hr&0x80)) hr = (hr & 0x7f) + 12; + if(!(val8&0x02)&&(!(hr%12))) hr -= 12; + regs.u.r8.ch = bin2bcd(hr); // Hours + }else{ + regs.u.r8.dh = inb_cmos(0x00); // Seconds + regs.u.r8.cl = inb_cmos(0x02); // Minutes + hr = inb_cmos(0x04); + if(!(val8&0x02)&&(hr&0x80)) hr = (hr & 0x7f) + 0x12; + if(!(val8&0x02)&&(!(hr%0x12))) hr -= 0x12; + regs.u.r8.ch = hr; // Hours + } + + regs.u.r8.dl = val8 & 0x01; // Stat Reg B regs.u.r8.ah = 0; regs.u.r8.al = regs.u.r8.ch; ClearCF(iret_addr.flags); // OK @@ -8530,11 +8596,29 @@ int1a_function(regs, ds, iret_addr) init_rtc(); // fall through as if an update were not in progress } - outb_cmos(0x00, regs.u.r8.dh); // Seconds - outb_cmos(0x02, regs.u.r8.cl); // Minutes - outb_cmos(0x04, regs.u.r8.ch); // Hours + + val8 = inb_cmos(0x0b); + + if(val8 & 0x04){ + hr = bcd2bin(regs.u.r8.ch); + if(!(val8&0x02)&&(hr>=12)) hr |= 0x80; + if(!(val8&0x02)&&(hr>12)) hr -= 12; + if(!(val8&0x02)&&(hr==00)) hr = 12; + outb_cmos(0x00, bcd2bin(regs.u.r8.dh)); // Seconds + outb_cmos(0x02, bcd2bin(regs.u.r8.cl)); // Minutes + outb_cmos(0x04, hr); // Hours + }else{ + hr = regs.u.r8.ch; + if(!(val8&0x02)&&(hr>=0x12)) hr |= 0x80; + if(!(val8&0x02)&&(hr>0x12)) hr -= 0x12; + if(!(val8&0x02)&&(hr==0x00)) hr = 0x12; + outb_cmos(0x00, regs.u.r8.dh); // Seconds + outb_cmos(0x02, regs.u.r8.cl); // Minutes + outb_cmos(0x04, hr); // Hours + } + // Set Daylight Savings time enabled bit to requested value - val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01); + val8 = (val8 & 0x66) | (regs.u.r8.dl & 0x01); // (reg B already selected) outb_cmos(0x0b, val8); regs.u.r8.ah = 0; @@ -8548,10 +8632,21 @@ int1a_function(regs, ds, iret_addr) SetCF(iret_addr.flags); break; } - regs.u.r8.cl = inb_cmos(0x09); // Year - regs.u.r8.dh = inb_cmos(0x08); // Month - regs.u.r8.dl = inb_cmos(0x07); // Day of Month - regs.u.r8.ch = inb_cmos(0x32); // Century + + val8 = inb_cmos(0x0b); + + if(val8 & 0x04){ + regs.u.r8.cl = bin2bcd(inb_cmos(0x09)); // Year + regs.u.r8.dh = bin2bcd(inb_cmos(0x08)); // Month + regs.u.r8.dl = bin2bcd(inb_cmos(0x07)); // Day of Month + regs.u.r8.ch = bin2bcd(inb_cmos(0x32)); // Century + }else{ + regs.u.r8.cl = inb_cmos(0x09); // Year + regs.u.r8.dh = inb_cmos(0x08); // Month + regs.u.r8.dl = inb_cmos(0x07); // Day of Month + regs.u.r8.ch = inb_cmos(0x32); // Century + } + regs.u.r8.al = regs.u.r8.ch; ClearCF(iret_addr.flags); // OK break; @@ -8572,11 +8667,21 @@ int1a_function(regs, ds, iret_addr) SetCF(iret_addr.flags); break; } - outb_cmos(0x09, regs.u.r8.cl); // Year - outb_cmos(0x08, regs.u.r8.dh); // Month - outb_cmos(0x07, regs.u.r8.dl); // Day of Month - outb_cmos(0x32, regs.u.r8.ch); // Century - val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit + + val8=inb_cmos(0x0b); + + if(val8&0x04){ + outb_cmos(0x09, bcd2bin(regs.u.r8.cl)); // Year + outb_cmos(0x08, bcd2bin(regs.u.r8.dh)); // Month + outb_cmos(0x07, bcd2bin(regs.u.r8.dl)); // Day of Month + outb_cmos(0x32, bcd2bin(regs.u.r8.ch)); // Century + }else{ + outb_cmos(0x09, regs.u.r8.cl); // Year + outb_cmos(0x08, regs.u.r8.dh); // Month + outb_cmos(0x07, regs.u.r8.dl); // Day of Month + outb_cmos(0x32, regs.u.r8.ch); // Century + } + val8 = val8 & 0x7f; // clear halt-clock bit outb_cmos(0x0b, val8); regs.u.r8.ah = 0; regs.u.r8.al = val8; // AL = val last written to Reg B @@ -8605,9 +8710,23 @@ int1a_function(regs, ds, iret_addr) init_rtc(); // fall through as if an update were not in progress } - outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm - outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm - outb_cmos(0x05, regs.u.r8.ch); // Hours alarm + + if(val8&0x04){ + hr = bcd2bin(regs.u.r8.ch); + outb_cmos(0x01, bcd2bin(regs.u.r8.dh)); // Seconds alarm + outb_cmos(0x03, bcd2bin(regs.u.r8.cl)); // Minutes alarm + if((val8&0x02)&&(hr>=12)) hr |= 0x80; + if((val8&0x02)&&(hr==00)) hr = 12; + outb_cmos(0x05, hr); // Hours alarm + }else{ + hr = regs.u.r8.ch; + outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm + outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm + if((val8&0x02)&&(hr>=0x12)) hr |= 0x80; + if((val8&0x02)&&(hr==0x00)) hr = 0x12; + outb_cmos(0x05, hr); // Hours alarm + } + outb(PORT_PIC2_DATA, inb(PORT_PIC2_DATA) & 0xfe); // enable IRQ 8 // enable Status Reg B alarm bit, clear halt clock bit outb_cmos(0x0b, (val8 & 0x7f) | 0x20); diff --git a/bochs/config.cc b/bochs/config.cc index aba94e58a..9068df553 100644 --- a/bochs/config.cc +++ b/bochs/config.cc @@ -984,6 +984,27 @@ void bx_init_options() // clock & cmos options static const char *clock_sync_names[] = { "none", "realtime", "slowdown", "both", NULL }; + Bit64s mintime,maxtime; + struct tm mtim,xtim; + + mtim.tm_year =0000 -1900; + mtim.tm_mon = 1 - 1; + mtim.tm_mday = 1 ; + mtim.tm_hour = 00 ; + mtim.tm_min = 00 ; + mtim.tm_sec = 00 ; + mtim.tm_isdst = -1 ; + + xtim.tm_year =9999 -1900; + xtim.tm_mon = 12 - 1; + xtim.tm_mday = 31 ; + xtim.tm_hour = 23 ; + xtim.tm_min = 59 ; + xtim.tm_sec = 59 ; + xtim.tm_isdst = -1 ; + + mintime=mktime(&mtim); //Find which epoch corresponds to the upper limit expressed in local time + maxtime=mktime(&xtim); //Find which epoch corresponds to the lower limit expressed in local time bx_param_enum_c *clock_sync = new bx_param_enum_c(clock_cmos, "clock_sync", "Synchronisation method", @@ -995,7 +1016,7 @@ void bx_init_options() "time0", "Initial CMOS time for Bochs\n(1:localtime, 2:utc, other:time in seconds)", "Initial time for Bochs CMOS clock, used if you really want two runs to be identical", - 0, BX_MAX_BIT32U, + mintime, maxtime, BX_CLOCK_TIME0_LOCAL); bx_param_bool_c *rtc_sync = new bx_param_bool_c(clock_cmos, "rtc_sync", "Sync RTC speed with realtime", @@ -1025,7 +1046,7 @@ void bx_init_options() deplist->add(rtc_init); use_cmosimage->set_dependent_list(deplist); - time0->set_ask_format("Enter Initial CMOS time (1:localtime, 2:utc, other:time in seconds): [%d] "); + time0->set_ask_format("Enter Initial CMOS time (1:localtime, 2:utc, other:time in seconds): [" FMT_LL "d] "); clock_sync->set_ask_format("Enter Synchronisation method: [%s] "); clock_cmos->set_options(clock_cmos->SHOW_PARENT); cmosimage->set_options(cmosimage->SHOW_PARENT); @@ -3107,9 +3128,9 @@ static int parse_line_formatted(const char *context, int num_params, char *param for (i=1; iget_param_bool(BXPN_CMOSIMAGE_RTC_INIT)->set(0); - } else if (!strcmp(params[i], "rtc_init=image")) { + } else if (!strncmp(params[i], "rtc_init=image",14)) { SIM->get_param_bool(BXPN_CMOSIMAGE_RTC_INIT)->set(1); } else { BX_ERROR(("%s: unknown parameter for cmosimage ignored.", context)); @@ -3139,17 +3160,19 @@ static int parse_line_formatted(const char *context, int num_params, char *param else if (!strncmp(params[i], "time0=", 6)) { if (isalpha(params[i][6])) { memset(&tm_time, 0, sizeof(tm_time)); - n = sscanf(¶ms[i][6], "%3s %3s%3d %2d:%2d:%2d %d", wday, mon, &tm_time.tm_mday, + n = sscanf(¶ms[i][6], "%3s %3s %2d %2d:%2d:%2d %d", wday, mon, &tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min, &tm_time.tm_sec, &year); - if ((n == 7) && (year >= 1980) && (strstr(months, mon) != NULL)) { + if ((n == 7) && (strstr(months, mon) != NULL)) { tm_time.tm_year = year - 1900; tm_time.tm_mon = 12 - ((int)strlen(strstr(months, mon)) / 4); + tm_time.tm_isdst = -1; SIM->get_param_num(BXPN_CLOCK_TIME0)->set(mktime(&tm_time)); } else { PARSE_ERR(("%s: time0 string format malformed.", context)); } } else { - SIM->get_param_num(BXPN_CLOCK_TIME0)->set(atoi(¶ms[i][6])); + Bit64s tmptm=atol(¶ms[i][6]); + SIM->get_param_num(BXPN_CLOCK_TIME0)->set(tmptm); } } else { @@ -3438,8 +3461,7 @@ int bx_write_clock_cmos_options(FILE *fp) { fprintf(fp, "clock: sync=%s", SIM->get_param_enum(BXPN_CLOCK_SYNC)->get_selected()); - switch (SIM->get_param_num(BXPN_CLOCK_TIME0)->get()) { - case 0: break; + switch (SIM->get_param_num(BXPN_CLOCK_TIME0)->get64()) { case BX_CLOCK_TIME0_LOCAL: fprintf(fp, ", time0=local"); break; @@ -3447,7 +3469,7 @@ int bx_write_clock_cmos_options(FILE *fp) fprintf(fp, ", time0=utc"); break; default: - fprintf(fp, ", time0=%u", SIM->get_param_num(BXPN_CLOCK_TIME0)->get()); + fprintf(fp, ", time0=" FMT_LL "d", SIM->get_param_num(BXPN_CLOCK_TIME0)->get64()); } fprintf(fp, ", rtc_sync=%d\n", SIM->get_param_bool(BXPN_CLOCK_RTC_SYNC)->get()); diff --git a/bochs/config.h.in b/bochs/config.h.in index 1f7af797e..413f9d487 100644 --- a/bochs/config.h.in +++ b/bochs/config.h.in @@ -138,8 +138,6 @@ #define BX_HAVE_SYS_MMAN_H 0 #define BX_HAVE_XPM_H 0 #define BX_HAVE_XRANDR_H 0 -#define BX_HAVE_TIMELOCAL 0 -#define BX_HAVE_GMTIME 0 #define BX_HAVE_MKTIME 0 #define BX_HAVE_TMPFILE64 0 #define BX_HAVE_FSEEK64 0 diff --git a/bochs/configure b/bochs/configure index 7c0a03153..60a441e7e 100755 --- a/bochs/configure +++ b/bochs/configure @@ -22106,42 +22106,6 @@ then : fi - for ac_func in timelocal -do : - ac_fn_c_check_func "$LINENO" "timelocal" "ac_cv_func_timelocal" -if test "x$ac_cv_func_timelocal" = xyes -then : - printf "%s\n" "#define HAVE_TIMELOCAL 1" >>confdefs.h - printf "%s\n" "#define BX_HAVE_TIMELOCAL 1" >>confdefs.h - -fi - -done - - for ac_func in gmtime -do : - ac_fn_c_check_func "$LINENO" "gmtime" "ac_cv_func_gmtime" -if test "x$ac_cv_func_gmtime" = xyes -then : - printf "%s\n" "#define HAVE_GMTIME 1" >>confdefs.h - printf "%s\n" "#define BX_HAVE_GMTIME 1" >>confdefs.h - -fi - -done - - for ac_func in mktime -do : - ac_fn_c_check_func "$LINENO" "mktime" "ac_cv_func_mktime" -if test "x$ac_cv_func_mktime" = xyes -then : - printf "%s\n" "#define HAVE_MKTIME 1" >>confdefs.h - printf "%s\n" "#define BX_HAVE_MKTIME 1" >>confdefs.h - -fi - -done - # Check whether --enable-largefile was given. if test ${enable_largefile+y} then : diff --git a/bochs/configure.ac b/bochs/configure.ac index 1413c3ea3..0107b2f9e 100644 --- a/bochs/configure.ac +++ b/bochs/configure.ac @@ -234,8 +234,6 @@ AC_CHECK_FUNCS(nanosleep, AC_DEFINE(BX_HAVE_NANOSLEEP)) AC_CHECK_FUNCS(abort, AC_DEFINE(BX_HAVE_ABORT)) AC_CHECK_MEMBER(struct sockaddr_in.sin_len, AC_DEFINE(BX_HAVE_SOCKADDR_IN_SIN_LEN), , [#include #include ]) -AC_CHECK_FUNCS(timelocal, AC_DEFINE(BX_HAVE_TIMELOCAL)) -AC_CHECK_FUNCS(gmtime, AC_DEFINE(BX_HAVE_GMTIME)) AC_CHECK_FUNCS(mktime, AC_DEFINE(BX_HAVE_MKTIME)) dnl As of autoconf 2.53, the standard largefile test fails for Linux/gcc. diff --git a/bochs/gui/textconfig.cc b/bochs/gui/textconfig.cc index 94be08a69..374aa935c 100644 --- a/bochs/gui/textconfig.cc +++ b/bochs/gui/textconfig.cc @@ -182,10 +182,10 @@ int ask_uint(const char *prompt, const char *help, Bit32u min, Bit32u max, Bit32 } } -// identical to ask_uint, but uses signed comparisons -int ask_int(const char *prompt, const char *help, Bit32s min, Bit32s max, Bit32s the_default, Bit32s *out) +// Identical to ask_uint but uses 64 bits signed integers +int ask_int(const char *prompt, const char *help, Bit64s min, Bit64s max, Bit64s the_default, Bit64s *out) { - int n = max + 1; + Bit64s n = max + 1; char buffer[1024]; char *clean; int illegal; @@ -202,12 +202,12 @@ int ask_int(const char *prompt, const char *help, Bit32s min, Bit32s max, Bit32s } if ((clean[0] == '?') && (strlen(help) > 0)) { bx_printf("\n%s\n", help); - bx_printf("Your choice must be an integer between %u and %u.\n\n", min, max); + bx_printf("Your choice must be an integer between " FMT_LL "d and " FMT_LL "d.\n\n", min, max); continue; } - illegal = (1 != sscanf(buffer, "%d", &n)); + illegal = (1 != sscanf(buffer, "%ld", &n)); if (illegal || nmax) { - bx_printf("Your choice (%s) was not an integer between %d and %d.\n\n", + bx_printf("Your choice (%s) was not an integer between " FMT_LL "d and " FMT_LL "d.\n\n", clean, min, max); } else { // choice is okay @@ -616,7 +616,8 @@ void bx_log_options(int individual) int done = 0; while (!done) { bx_print_log_action_table(); - Bit32s id, level, action; + Bit64s id; + Bit32s level, action; Bit32s maxid = SIM->get_n_log_modules(); if (ask_int(log_options_prompt1, "", -1, maxid-1, -1, &id) < 0) return; @@ -864,11 +865,11 @@ void text_print(bx_param_c *param) if (base == 16) format = "%s: 0x%x"; else - format = "%s: %d"; + format = "%s: %ld"; if (nparam->get_label()) { - bx_printf(format, nparam->get_label(), (Bit32s)nval); + bx_printf(format, nparam->get_label(), (Bit64s)nval); } else { - bx_printf(format, nparam->get_name(), (Bit32s)nval); + bx_printf(format, nparam->get_name(), (Bit64s)nval); } } } @@ -950,10 +951,18 @@ int text_ask(bx_param_c *param) prompt = "Enter new value or '?' for help: [%d] "; } Bit32u n = nparam->get(); - status = ask_uint(prompt, help, (Bit32u)nparam->get_min(), + Bit64s m = nparam->get64(); + + if(nparam->get_base() != 10){ + status = ask_uint(prompt, help, (Bit32u)nparam->get_min(), (Bit32u)nparam->get_max(), n, &n, nparam->get_base()); + }else{ + status = ask_int(prompt, help, (Bit64s)nparam->get_min(), + (Bit64s)nparam->get_max(), m, &m); + } if (status < 0) return status; - nparam->set(n); + if(nparam->get_base() != 10) nparam->set(n); + else nparam->set(m); } break; case BXT_PARAM_BOOL: diff --git a/bochs/iodev/Makefile.in b/bochs/iodev/Makefile.in index d04d90c7c..3722a1427 100644 --- a/bochs/iodev/Makefile.in +++ b/bochs/iodev/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2021 The Bochs Project +# Copyright (C) 2001-2023 The Bochs Project # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -200,7 +200,7 @@ cmos.o: cmos.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \ ../misc/bswap.h ../plugin.h \ ../extplugin.h ../param_names.h ../pc_system.h ../bx_debug/debug.h \ ../config.h ../osdep.h ../memory/memory-bochs.h ../gui/siminterface.h \ - ../gui/gui.h cmos.h virt_timer.h + ../gui/gui.h cmos.h virt_timer.h utctime.h devices.o: devices.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \ ../gui/paramtree.h ../logio.h \ ../instrument/stubs/instrument.h ../misc/bswap.h ../plugin.h \ @@ -371,7 +371,7 @@ cmos.lo: cmos.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \ ../misc/bswap.h ../plugin.h \ ../extplugin.h ../param_names.h ../pc_system.h ../bx_debug/debug.h \ ../config.h ../osdep.h ../memory/memory-bochs.h ../gui/siminterface.h \ - ../gui/gui.h cmos.h virt_timer.h + ../gui/gui.h cmos.h virt_timer.h utctime.h devices.lo: devices.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \ ../gui/paramtree.h ../logio.h \ ../misc/bswap.h ../plugin.h \ diff --git a/bochs/iodev/cmos.cc b/bochs/iodev/cmos.cc index 5baf410d9..8feb32df9 100644 --- a/bochs/iodev/cmos.cc +++ b/bochs/iodev/cmos.cc @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2002-2021 The Bochs Project +// Copyright (C) 2002-2023 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,6 +27,7 @@ #include "iodev.h" #include "cmos.h" #include "virt_timer.h" +#include "utctime.h" #define LOG_THIS theCmosDevice-> @@ -127,9 +128,9 @@ bx_cmos_c::~bx_cmos_c(void) { save_image(); char *tmptime; - if ((tmptime = strdup(ctime(&(BX_CMOS_THIS s.timeval)))) != NULL) { + if ((tmptime = strdup(ascutc(utctime(&(BX_CMOS_THIS s.timeval))))) != NULL) { tmptime[strlen(tmptime)-1]='\0'; - BX_INFO(("Last time is %u (%s)", (unsigned) get_timeval(), tmptime)); + BX_INFO(("Last time: " FMT_LL "d tz=utc (%s)", get_timeval(), tmptime)); free(tmptime); } SIM->get_bochs_root()->remove("cmos"); @@ -170,36 +171,26 @@ void bx_cmos_c::init(void) 244, 0, 0, "cmos"); // one-shot, not-active } - if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get() == BX_CLOCK_TIME0_LOCAL) { + if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get64() == BX_CLOCK_TIME0_LOCAL) { + time_t tmptime; + struct tm *tmptm;; + BX_INFO(("Using local time for initial clock")); - BX_CMOS_THIS s.timeval = time(NULL); - } else if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get() == BX_CLOCK_TIME0_UTC) { - bool utc_ok = 0; + tmptime = time(NULL); //Calculate which timeval will display the local time + tmptm = localtime(&tmptime); + BX_CMOS_THIS s.timeval = timeutc(pushtm(tmptm)); + + } else if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get64() == BX_CLOCK_TIME0_UTC) { BX_INFO(("Using utc time for initial clock")); - - BX_CMOS_THIS s.timeval = time(NULL); - -#if BX_HAVE_GMTIME -#if BX_HAVE_MKTIME - struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval); - utc_holder->tm_isdst = -1; - utc_ok = 1; - BX_CMOS_THIS s.timeval = mktime(utc_holder); -#elif BX_HAVE_TIMELOCAL - struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval); - utc_holder->tm_isdst = 0; // XXX Is this correct??? - utc_ok = 1; - BX_CMOS_THIS s.timeval = timelocal(utc_holder); -#endif //BX_HAVE_MKTIME -#endif //BX_HAVE_GMTIME - - if (!utc_ok) { - BX_ERROR(("UTC time is not supported on your platform. Using current time(NULL)")); - } + BX_CMOS_THIS s.timeval = (Bit64s)time(NULL); } else { + Bit64s tmpintime; + struct tm *tmptmtime; BX_INFO(("Using specified time for initial clock")); - BX_CMOS_THIS s.timeval = SIM->get_param_num(BXPN_CLOCK_TIME0)->get(); + tmpintime = SIM->get_param_num(BXPN_CLOCK_TIME0)->get64(); + tmptmtime = localtime(&tmpintime); + BX_CMOS_THIS s.timeval = timeutc(pushtm(tmptmtime)); } // load CMOS from image file if requested. @@ -264,11 +255,11 @@ void bx_cmos_c::init(void) } char *tmptime; - while((tmptime = strdup(ctime(&(BX_CMOS_THIS s.timeval)))) == NULL) { + while((tmptime = strdup(ascutc(utctime(&(BX_CMOS_THIS s.timeval))))) == NULL) { BX_PANIC(("Out of memory.")); } tmptime[strlen(tmptime)-1]='\0'; - BX_INFO(("Setting initial clock to: %s (time0=%u)", tmptime, (Bit32u)BX_CMOS_THIS s.timeval)); + BX_INFO(("Setting initial clock to: %s tz=utc (time0=" FMT_LL "d)", tmptime, (Bit64s)BX_CMOS_THIS s.timeval)); free(tmptime); BX_CMOS_THIS s.timeval_change = 0; @@ -442,8 +433,25 @@ void bx_cmos_c::write(Bit32u address, Bit32u value, unsigned io_len) case REG_MIN_ALARM: // minutes alarm case REG_HOUR_ALARM: // hours alarm BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value; - BX_DEBUG(("alarm time changed to %02x:%02x:%02x", BX_CMOS_THIS s.reg[REG_HOUR_ALARM], - BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM])); + if(BX_CMOS_THIS s.rtc_mode_12hour) { + if(BX_CMOS_THIS s.rtc_mode_binary) { + BX_DEBUG(("alarm time changed to %02u:%02u:%02u %s", BX_CMOS_THIS s.reg[REG_HOUR_ALARM] & 0x7F, + BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM], + (BX_CMOS_THIS s.reg[REG_HOUR_ALARM] & 0x80)?"pm":"am")); + } else { + BX_DEBUG(("alarm time changed to %02x:%02x:%02x %s", BX_CMOS_THIS s.reg[REG_HOUR_ALARM] & 0x7F, + BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM], + (BX_CMOS_THIS s.reg[REG_HOUR_ALARM] & 0x80)?"pm":"am")); + } + } else { + if(BX_CMOS_THIS s.rtc_mode_binary) { + BX_DEBUG(("alarm time changed to %02u:%02u:%02u", BX_CMOS_THIS s.reg[REG_HOUR_ALARM], + BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM])); + } else { + BX_DEBUG(("alarm time changed to %02x:%02x:%02x", BX_CMOS_THIS s.reg[REG_HOUR_ALARM], + BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM])); + } + } break; case REG_SEC: // seconds @@ -766,19 +774,20 @@ void bx_cmos_c::uip_timer() void bx_cmos_c::update_clock() { - struct tm *time_calendar; + struct utctm *time_calendar; unsigned year, month, day, century; Bit8u val_bcd, hour; + Bit64s mintvalset=-62167219200,maxtvalset[2]={253402300799, 745690751999}; - time_calendar = localtime(& BX_CMOS_THIS s.timeval); + while(BX_CMOS_THIS s.timeval>maxtvalset[BX_CMOS_THIS s.rtc_mode_binary?1:0]) {BX_CMOS_THIS s.timeval-=(maxtvalset[BX_CMOS_THIS s.rtc_mode_binary?1:0]-mintvalset+1);} + while(BX_CMOS_THIS s.timevaltm_sec, - BX_CMOS_THIS s.rtc_mode_binary); + BX_CMOS_THIS s.reg[REG_SEC] = bin_to_bcd(time_calendar->tm_sec, BX_CMOS_THIS s.rtc_mode_binary); // update minutes - BX_CMOS_THIS s.reg[REG_MIN] = bin_to_bcd(time_calendar->tm_min, - BX_CMOS_THIS s.rtc_mode_binary); + BX_CMOS_THIS s.reg[REG_MIN] = bin_to_bcd(time_calendar->tm_min, BX_CMOS_THIS s.rtc_mode_binary); // update hours if (BX_CMOS_THIS s.rtc_mode_12hour) { @@ -789,8 +798,7 @@ void bx_cmos_c::update_clock() val_bcd |= bin_to_bcd(hour, BX_CMOS_THIS s.rtc_mode_binary); BX_CMOS_THIS s.reg[REG_HOUR] = val_bcd; } else { - BX_CMOS_THIS s.reg[REG_HOUR] = bin_to_bcd(time_calendar->tm_hour, - BX_CMOS_THIS s.rtc_mode_binary); + BX_CMOS_THIS s.reg[REG_HOUR] = bin_to_bcd(time_calendar->tm_hour, BX_CMOS_THIS s.rtc_mode_binary); } // update day of the week @@ -826,7 +834,8 @@ void bx_cmos_c::update_clock() void bx_cmos_c::update_timeval() { - struct tm time_calendar; + struct utctm time_calendar; + Bit16s val_yr; Bit8u val_bin, pm_flag; // update seconds @@ -862,14 +871,14 @@ void bx_cmos_c::update_timeval() BX_CMOS_THIS s.rtc_mode_binary) - 1; // update year - val_bin = bcd_to_bin(BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE], + val_yr = bcd_to_bin(BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE], BX_CMOS_THIS s.rtc_mode_binary); - val_bin = (val_bin - 19) * 100; - val_bin += bcd_to_bin(BX_CMOS_THIS s.reg[REG_YEAR], + val_yr = (val_yr - 19) * 100; + val_yr += bcd_to_bin(BX_CMOS_THIS s.reg[REG_YEAR], BX_CMOS_THIS s.rtc_mode_binary); - time_calendar.tm_year = val_bin; + time_calendar.tm_year = val_yr; - BX_CMOS_THIS s.timeval = mktime(& time_calendar); + BX_CMOS_THIS s.timeval = timeutc(& time_calendar); } #if BX_DEBUGGER diff --git a/bochs/iodev/cmos.h b/bochs/iodev/cmos.h index 9c1e4bfb4..9009778b6 100644 --- a/bochs/iodev/cmos.h +++ b/bochs/iodev/cmos.h @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2002-2021 The Bochs Project +// Copyright (C) 2002-2023 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -52,7 +52,7 @@ public: virtual void set_reg(Bit8u reg, Bit32u val) { s.reg[reg] = val; } - virtual time_t get_timeval() { + virtual Bit64s get_timeval() { return s.timeval; } virtual void enable_irq(bool enabled) { @@ -64,7 +64,7 @@ public: Bit32u periodic_interval_usec; int one_second_timer_index; int uip_timer_index; - time_t timeval; + Bit64s timeval; //Changed this from time_t to Bit64s - this struct seems to not be referenced ouside of this class despite being public Bit8u cmos_mem_address; Bit8u cmos_ext_mem_addr; bool timeval_change; @@ -80,6 +80,7 @@ public: } s; // state information private: + static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len); static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len); #if !BX_USE_CMOS_SMF diff --git a/bochs/iodev/utctime.h b/bochs/iodev/utctime.h new file mode 100644 index 000000000..cf488e74b --- /dev/null +++ b/bochs/iodev/utctime.h @@ -0,0 +1,234 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: utctime.h +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2023 The Bochs Project +// +// Portable gmtime()/timegm() clones by Michele Giacomone +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +///////////////////////////////////////////////////////////////////////// + +#ifndef UTCTIME_H +#define UTCTIME_H + +/* + + I wanted a couple of functions that could mimic the behavior of localtime()/mktime() but being linear (no timezone or DST issues) and portable. + For convenience I wrote them so that they behave as if the local timezone was UTC, which means that my "localtime" function - which will be utctime() - must provide identical results as gmtime(), and my "mktime" function - which will be timeutc() - must act exactly as the non-standard function timegm() or mktime() called with TZ set to UTC. + This allows a more realistic rtc/cmos simulation since the internally kept time value can no longer bounce around due to external factors. + Also, by doing this, across every system, a given internal value will always mean the same time and date setting. + If the user selects the cmos to be set up with their local time, the calculated difference between the current epoch value and bochs internal value could be communicated to them in the "startup time" debug message. The same goes if they choose to specify an epoch value, since that has to be interpreted as the epoch value which would set their corresponding local time, to ensure compatibility with previous bochs' behavior. If the user selects to set the current UTC time value instead, the value returned by time(NULL) is already what needed. + +A few considerations on operand sizes: + +These are the contents of "struct tm": + +tm_sec int seconds after the minute 0-61* +tm_min int minutes after the hour 0-59 +tm_hour int hours since midnight 0-23 +tm_mday int day of the month 1-31 +tm_mon int months since January 0-11 +tm_year int years since 1900 +tm_wday int days since Sunday 0-6 +tm_yday int days since January 1 0-365 +tm_isdst int Daylight Saving Time flag + +*60 in C11. Technically to account for leap seconds. Since they have the same epoch value as the (normal) following second, and my functions can treat out of range values correctly, I can safely assume 0-59. + +I use Bit64s instead of time_t to represent the number of seconds since 1970-1-1 00:00:00 (which I just call "epoch") since the latter is not well defined, and 32bits won't fully cover dates that a human might want to input (==at least a few hundred years both ways). + +I also need to redefine "struct tm" to protect against different "int" sizes. As said below, to get everything to work properly the size of its elements has to be less than the size of the epoch, but must allow all in-range values, so Bit32s and Bit16s are the options. I choose Bit16s since bochs can't handle years less than 0 or more than 25599 (valid values: -1900 to 23699, included). + +The following will work if division does round towards zero. +Everything will operate correctly for all the valid (values in range, or convertible to in range values) struct tm settings. +Despite the fact that "invalid" (values out of range and not convertible to in range values) struct tm settings could be used to get otherwise unreachable epoch values through timeutc() (but the reverse operation through utctime() would not be allowed since it can only return in-range values), timeutc() has to return -1 to properly mimic timegm()/mktime(). I'm not too happy with this since -1 means a possibly useful date (last second of 1969), and a better value would have been (1<<63), so that can be changed in the future if this -1 behavior is not used by bochs. + +With the above considerations I tested that: + +utctime() supports all values that can be converted to a VALID struct configuration (as gmtime() does): +MIN utctime() value: -1036267257600 => -30868/01/01 FRI 0:00:00 +MAX utctime() value: 1031849193599 => 34667/12/31 TUE 23:59:59 +Values out of this range will not set anything and a NULL pointer will be returned. + +timeutc() supports all the same values, making it the exact inverse of utctime(): +MIN utctime() value: -1036267257600 => -30868/01/01 FRI 0:00:00 +MAX utctime() value: 1031849193599 => 34667/12/31 TUE 23:59:59 +Out of range or not set values will be fixed through a call to utcime() before returning. +Invalid struct settings will cause timeutc() to return -1 and the struct not to be set. + +A utctime_ext() function is provided. It is identical to utctime() but allows to use an external structure (in fact, it is called by utctime() to set the globally available struct utctm). + +An ascutc() function is provided. It serves as an ascitime() clone. It makes up a string with no additional checks. + +A pushtm() function is provided. It's used to copy a struct tm into the struct uctm globally available. + +Bochs current CMOS code can only handle properly the following range (Gregorian calendar): +MIN setting -62167219200 => 0/01/01 SAT 0:00:00 +MAX BCD setting 253402300799 => 9999/12/31 FRI 23:59:59 +MAX BIN setting 745690751999 => 25599/12/31 FRI 23:59:59 +With binary mode only accessible by loading a cmos memory map file +Either way, settings out of the currently valid range must wrap around correctly, giving the impression of a simple overflow. Luckily the valid range starts on a Saturday and ends on a Friday. +The allowed epoch values could all fit in 40bits +*/ + +struct utctm { + Bit16s tm_sec; // seconds after the minute 0-59 + Bit16s tm_min; // minutes after the hour 0-59 + Bit16s tm_hour; // hours since midnight 0-23 + Bit16s tm_mday; // day of the month 1-31 + Bit16s tm_mon; // months since January 0-11 + Bit16s tm_year; // years since 1900 + Bit16s tm_wday; // days since Sunday 0-6 + Bit16s tm_yday; // days since January 1 0-365 +}; + +char *ascutc(struct utctm *src) +{ + static const char wdaystr[8][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "N/D"}; + static const char monstr[13][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "N/D"}; + static char timestr[28]; + sprintf(timestr,"%.3s %.3s %2d %2d:%02d:%02d %6d\n", wdaystr[((src->tm_wday>=0)&&(src->tm_wday<7))?src->tm_wday:7], monstr[((src->tm_mon>=0)&&(src->tm_mon<12))?src->tm_mon:12], ((Bit16u)src->tm_mday)%100, ((Bit16u)src->tm_hour)%100, ((Bit16u)src->tm_min)%100, ((Bit16u)src->tm_sec)%100, (Bit32s)src->tm_year+1900); //Set the string up using extra caution to protect against bogus values, since snprintf() might not be available + return (char*) ×tr; +} + +struct utctm *utctime_ext(const Bit64s *a,struct utctm *trgt) +{ + static const Bit32s monthlydays[2][13]={{0,31,59,90,120,151,181,212,243,273,304,334,365},{0,31,60,91,121,152,182,213,244,274,305,335,366}}; //Days elapsed between the start of the selected month and the start of the year + Bit8u isleap=0; //Leap year flag + struct utctm bdt; //Structure to temporary store the output + Bit64s etmp=*a; //Temporary variable, epoch since 1970 + Bit64s tsec; //Temporary variable, seconds + Bit64s eyear=2001; //Temporary variable, year + + tsec=etmp%(24*60*60); //Get time of day + etmp/=(24*60*60); //Get days number + etmp-=11323; //Use 2001-01-01 as the base of the days number, it being the nearest first non-leap year of a 400yrs cycle + if(tsec<0){etmp--;tsec+=(24*60*60);}; //Get a positive time_of_day number and a properly rounded days number + + bdt.tm_sec=tsec%60; //Set the seconds value + tsec/=60; + bdt.tm_min=tsec%60; //Set the minutes value + tsec/=60; + bdt.tm_hour=tsec; //Set the hour value + + bdt.tm_wday=(etmp-6)%7; + if(bdt.tm_wday<0) bdt.tm_wday+=7; //Set the day of the week value + + if(etmp<0){eyear+=400*(etmp/146097-1);etmp%=146097;etmp+=146097;}; //Years before 2001 accounted for + + eyear+=400*(etmp/146097); //Add the number of 400yr cycles + etmp%=146097; + eyear+=100*(etmp/36524); //Add the number of 100yr cycles + etmp%=36524; + eyear+=4*(etmp/1461); //Add the number of 4yr cycles + etmp%=1461; + while((eyear%4)&&(etmp>=365)){eyear++;etmp-=365;} //Add the number of remaining years; + + isleap|=((eyear%400)? 0: 2); + isleap|=((eyear% 4)? 0: 1); + isleap&=((eyear%100)?~0:~1); + isleap=(isleap?1:0); //Find out if the year is leap + + eyear-=1900; + bdt.tm_year=eyear; //Set the year value + + bdt.tm_yday=etmp; //Set the day of the year value + bdt.tm_mon=0; + while(etmp>=monthlydays[isleap][bdt.tm_mon+1]) bdt.tm_mon++; //Set the month value + etmp-=monthlydays[isleap][bdt.tm_mon]; + bdt.tm_mday=etmp+1; //Set the day of the month value + + if(eyear != bdt.tm_year) return NULL; //If the calculated year is too high fail + + trgt->tm_sec=bdt.tm_sec; //Else write back in the structure proper values + trgt->tm_min=bdt.tm_min; //And return its address + trgt->tm_hour=bdt.tm_hour; + trgt->tm_wday=bdt.tm_wday; + trgt->tm_yday=bdt.tm_yday; + trgt->tm_mday=bdt.tm_mday; + trgt->tm_mon=bdt.tm_mon; + trgt->tm_year=bdt.tm_year; + return trgt; +} + +Bit64s timeutc(struct utctm *bdt) +{ + static const Bit32s monthlydays[2][13]={{0,31,59,90,120,151,181,212,243,273,304,334,365},{0,31,60,91,121,152,182,213,244,274,305,335,366}}; //Days elapsed between the start of the selected month and the start of the year + Bit8u isleap=3; //Leap year flag + Bit32s tmon; //Temporary month value + Bit64s epoch=0; //Value to return + Bit64s etmp; //Temporary variable + + etmp=bdt->tm_year; + tmon=bdt->tm_mon; + + etmp+=tmon/12; + tmon%=12; + if(tmon<0){etmp--;tmon+=12;}; //Broken month value accounted for + + etmp-=101; //Years passed since 2001 + if(etmp<0){epoch+=(146097*(etmp/400 - 1)); etmp%=400; etmp+=400;}; //Years before 2001 accounted for + + epoch+=(etmp/400)*146097; //Add in epoch the number of days corresponding to completed 400yr cycles + etmp%=400; + isleap&=((etmp==399)?~0:~2); //Clear bit1 if the year can not be divided by 400 + epoch+=(etmp/100)*36524; //Add in epoch the number of days corresponding to completed 100yr cycles + etmp%=100; + isleap&=((etmp==99)?~1:~0); //Clear bit0 if the year can be divided by 100 + epoch+=(etmp/4)*1461; //Add in epoch the number of days corresponding to completed 4yr cycles + etmp%=4; + isleap&=((etmp==3)?~0:~1); //Clear bit0 if the year can not divided by 4 + isleap=(isleap?1:0); //Shrink the flag to a single bit + epoch+=etmp*365; //Add in epoch the number of days corresponding to completed years + + //Now we have in epoch the number (positive or negative) of days between the start of the current year and the start of 2001 and isleap set if the year is leap + + epoch+=monthlydays[isleap][tmon]; + epoch+=bdt->tm_mday-1; //Now we have in epoch the number of entire days between the current date and 2001-01-01 00:00 + epoch*=24; + epoch+=bdt->tm_hour; //Now we have in epoch the number of hours + epoch*=60; + epoch+=bdt->tm_min; //Now we have in epoch the number of minutes + epoch*=60; + epoch+=bdt->tm_sec; //Now we have a positive or negative number of seconds between the input time and 2001-01-01 00:00:00 + epoch+=978307200; //Now we have a positive or negative number of seconds between the input time and 1970-01-01 00:00:00 + + if(utctime_ext(&epoch,bdt)) return epoch; //Set if possible all fields so they are in their proper ranges + else return -1; +} + +static struct utctm timedata; + +struct utctm *utctime(const Bit64s *a) +{ + return utctime_ext(a,&timedata); +} + +struct utctm *pushtm(struct tm *src) +{ + timedata.tm_sec=src->tm_sec; + timedata.tm_min=src->tm_min; + timedata.tm_hour=src->tm_hour; + timedata.tm_wday=src->tm_wday; + timedata.tm_yday=src->tm_yday; + timedata.tm_mday=src->tm_mday; + timedata.tm_mon=src->tm_mon; + timedata.tm_year=src->tm_year; + return &timedata; +} + +#endif // UTCTIME_H