diff --git a/Kernel/.bochsrc b/Kernel/.bochsrc index 8027057545..03643f30f3 100644 --- a/Kernel/.bochsrc +++ b/Kernel/.bochsrc @@ -35,7 +35,8 @@ cpuid: smap=false, mwait=true print_timestamps: enabled=0 port_e9_hack: enabled=1 private_colormap: enabled=0 -clock: sync=none, time0=local, rtc_sync=0 +#clock: sync=realtime, time0=local, rtc_sync=1 +clock: sync=none, time0=local, rtc_sync=1 # no cmosimage log: - logprefix: %t%e%d diff --git a/Kernel/Makefile b/Kernel/Makefile index 3fc318e9de..e74007fe1d 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -19,7 +19,8 @@ KERNEL_OBJS = \ Console.o \ IRQHandler.o \ kprintf.o \ - ProcFileSystem.o + ProcFileSystem.o \ + RTC.o VFS_OBJS = \ ../VirtualFileSystem/DiskDevice.o \ diff --git a/Kernel/RTC.cpp b/Kernel/RTC.cpp new file mode 100644 index 0000000000..ef0734390a --- /dev/null +++ b/Kernel/RTC.cpp @@ -0,0 +1,90 @@ +#include "RTC.h" +#include "CMOS.h" + +namespace RTC { + +static time_t s_bootTime; + +void initialize() +{ + byte cmosMode = CMOS::read(0x0b); + cmosMode |= 2; // 24 hour mode + cmosMode |= 4; // No BCD mode + CMOS::write(0x0b, cmosMode); + + s_bootTime = now(); +} + +time_t bootTime() +{ + return s_bootTime; +} + +static bool updateInProgress() +{ + return CMOS::read(0x0a) & 0x80; +} + +inline bool isLeapYear(unsigned year) +{ + return ((year % 4 == 0) && ((year % 100 != 0) || (year % 400) == 0)); +} + +static unsigned daysInMonthsSinceStartOfYear(unsigned month, unsigned year) +{ + switch (month) { + case 11: return 30; + case 10: return 31; + case 9: return 30; + case 8: return 31; + case 7: return 31; + case 6: return 30; + case 5: return 31; + case 4: return 30; + case 3: return 31; + case 2: + if (isLeapYear(year)) + return 29; + return 28; + case 1: return 31; + default: return 0; + } +} + +static unsigned daysInYearsSinceEpoch(unsigned year) +{ + unsigned days = 0; + while (year > 1969) { + days += 365; + if (isLeapYear(year)) + ++days; + --year; + } + return days; +} + +time_t now() +{ + // FIXME: We should probably do something more robust here. + // Perhaps read all the values twice and verify that they were identical. + // We don't want to be caught in the middle of an RTC register update. + while (updateInProgress()) + ; + + unsigned year = (CMOS::read(0x32) * 100) + CMOS::read(0x09); + unsigned month = CMOS::read(0x08); + unsigned day = CMOS::read(0x07); + unsigned hour = CMOS::read(0x04); + unsigned minute = CMOS::read(0x02); + unsigned second = CMOS::read(0x00); + + return daysInYearsSinceEpoch(year - 1) * 86400 + + daysInMonthsSinceStartOfYear(month - 1, year) * 86400 + + day * 86400 + + hour * 3600 + + minute * 60 + + second; +} + +} + diff --git a/Kernel/RTC.h b/Kernel/RTC.h new file mode 100644 index 0000000000..77b1e5ef7f --- /dev/null +++ b/Kernel/RTC.h @@ -0,0 +1,12 @@ +#pragma once + +#include "types.h" + +namespace RTC { + +void initialize(); +time_t now(); +time_t bootTime(); + +} + diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 762008e84f..4524f72682 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -61,8 +61,9 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) Console::the().putChar(arg1 & 0xff); break; case Syscall::Sleep: - current->sys$sleep(arg1); - break; + return current->sys$sleep(arg1); + case Syscall::PosixGettimeofday: + return current->sys$gettimeofday((timeval*)arg1); case Syscall::Spawn: return current->sys$spawn((const char*)arg1); case Syscall::GetDirEntries: diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index bef6d5ff36..3569c91f44 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -29,6 +29,7 @@ enum Function { GetDirEntries = 0x1997, PosixLstat = 0x1998, PosixGetcwd = 0x1999, + PosixGettimeofday = 0x2000, }; void initialize(); diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 9612a24cb9..28ed1981a1 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -11,6 +11,7 @@ #include "MemoryManager.h" #include "errno.h" #include "i8253.h" +#include "RTC.h" //#define DEBUG_IO //#define TASK_DEBUG @@ -728,6 +729,15 @@ int Task::sys$sleep(unsigned seconds) return 0; } +int Task::sys$gettimeofday(timeval* tv) +{ + InterruptDisabler disabler; + auto now = RTC::now(); + tv->tv_sec = now; + tv->tv_usec = 0; + return 0; +} + uid_t Task::sys$getuid() { return m_uid; diff --git a/Kernel/Task.h b/Kernel/Task.h index 13435fc528..3f855f6d2e 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -99,6 +99,7 @@ public: int sys$get_dir_entries(int fd, void*, size_t); int sys$getcwd(char*, size_t); int sys$sleep(unsigned seconds); + int sys$gettimeofday(timeval*); static void initialize(); diff --git a/Kernel/_fs_contents b/Kernel/_fs_contents index da330ef7e3..9dd078d965 100644 Binary files a/Kernel/_fs_contents and b/Kernel/_fs_contents differ diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 92026a036c..06593b518b 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -25,6 +25,7 @@ #include #include "Console.h" #include "ProcFileSystem.h" +#include "RTC.h" #define TEST_VFS //#define STRESS_TEST_SPAWNING @@ -179,6 +180,7 @@ void init() auto console = make(); + RTC::initialize(); PIC::initialize(); gdt_init(); idt_init(); @@ -191,6 +193,7 @@ void init() PIT::initialize(); memset(&system, 0, sizeof(system)); + WORD base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15); WORD ext_memory = (CMOS::read(0x18) << 8) | CMOS::read(0x17); diff --git a/Kernel/kprintf.cpp b/Kernel/kprintf.cpp index 2234967e59..b80fcc2e0b 100644 --- a/Kernel/kprintf.cpp +++ b/Kernel/kprintf.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "kprintf.h" #include "Console.h" #include diff --git a/Kernel/sync-sh b/Kernel/sync-sh index b19da4ba8f..4053a3ab20 100755 --- a/Kernel/sync-sh +++ b/Kernel/sync-sh @@ -6,5 +6,6 @@ cp ../Userland/ps mnt/bin/ps cp ../Userland/ls mnt/bin/ls cp ../Userland/pwd mnt/bin/pwd cp ../Userland/sleep mnt/bin/sleep +cp ../Userland/date mnt/bin/date umount mnt sync diff --git a/Kernel/types.h b/Kernel/types.h index 3b4b609454..ac5a4feedd 100644 --- a/Kernel/types.h +++ b/Kernel/types.h @@ -23,8 +23,14 @@ typedef DWORD uid_t; typedef DWORD gid_t; typedef int pid_t; typedef DWORD time_t; +typedef DWORD suseconds_t; typedef DWORD size_t; +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + struct FarPtr { DWORD offset { 0 }; WORD selector { 0 }; diff --git a/LibC/Makefile b/LibC/Makefile index 3f28724fd9..c958788553 100644 --- a/LibC/Makefile +++ b/LibC/Makefile @@ -6,6 +6,7 @@ OBJS = \ mman.o \ dirent.o \ stdlib.o \ + time.o \ entry.o LIBRARY = LibC.a diff --git a/LibC/time.cpp b/LibC/time.cpp new file mode 100644 index 0000000000..43efb2f364 --- /dev/null +++ b/LibC/time.cpp @@ -0,0 +1,21 @@ +#include "time.h" +#include "errno.h" +#include + +extern "C" { + +time_t time(time_t* tloc) +{ + timeval tv; + if (gettimeofday(&tv) < 0) + return (time_t)-1; + return tv.tv_sec; +} + +int gettimeofday(timeval* tv) +{ + int rc = Syscall::invoke(Syscall::PosixGettimeofday, (dword)tv); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +} diff --git a/LibC/time.h b/LibC/time.h new file mode 100644 index 0000000000..acce4816bd --- /dev/null +++ b/LibC/time.h @@ -0,0 +1,11 @@ +#pragma once + +#include "types.h" + +extern "C" { + +int gettimeofday(timeval*); +time_t time(time_t*); + +} + diff --git a/LibC/types.h b/LibC/types.h index 23f532c938..d8aacd8728 100644 --- a/LibC/types.h +++ b/LibC/types.h @@ -26,6 +26,12 @@ typedef dword nlink_t; typedef dword blksize_t; typedef dword blkcnt_t; typedef dword time_t; +typedef dword suseconds_t; + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; struct stat { dev_t st_dev; /* ID of device containing file */ diff --git a/Userland/.gitignore b/Userland/.gitignore index 9effb83fcc..e17fc11729 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -4,4 +4,5 @@ ps ls pwd sleep +date *.o diff --git a/Userland/Makefile b/Userland/Makefile index 20e729d999..1615f689b5 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -4,7 +4,8 @@ OBJS = \ ps.o \ ls.o \ pwd.o \ - sleep.o + sleep.o \ + date.o APPS = \ id \ @@ -12,7 +13,8 @@ APPS = \ ps \ ls \ pwd \ - sleep + sleep \ + date ARCH_FLAGS = STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib @@ -50,6 +52,9 @@ pwd: pwd.o sleep: sleep.o $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a +date: date.o + $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a + .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Userland/date.cpp b/Userland/date.cpp new file mode 100644 index 0000000000..00738773c5 --- /dev/null +++ b/Userland/date.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main(int c, char** v) +{ + time_t now = time(nullptr); + printf("%u\n", now); + return 0; +} +