feat: add time syscall & command in shell

This commit is contained in:
2026-02-18 17:34:36 +01:00
parent ea0d909f68
commit dfa86b272c
14 changed files with 171 additions and 3 deletions
+16 -1
View File
@@ -5,6 +5,7 @@
*/ */
#include "Syscall.hpp" #include "Syscall.hpp"
#include <Timekeeping/Time.hpp>
#include <Terminal/Terminal.hpp> #include <Terminal/Terminal.hpp>
#include <Fs/Vfs.hpp> #include <Fs/Vfs.hpp>
#include <Memory/Heap.hpp> #include <Memory/Heap.hpp>
@@ -256,6 +257,17 @@ namespace Zenith {
return (rows << 32) | (cols & 0xFFFFFFFF); return (rows << 32) | (cols & 0xFFFFFFFF);
} }
static void Sys_GetTime(DateTime* out) {
if (out == nullptr) return;
Timekeeping::DateTime dt = Timekeeping::GetDateTime();
out->Year = dt.Year;
out->Month = dt.Month;
out->Day = dt.Day;
out->Hour = dt.Hour;
out->Minute = dt.Minute;
out->Second = dt.Second;
}
static void Sys_Reset() { static void Sys_Reset() {
/* /*
Triple fault for now; TODO: implement UEFI runtime function for clean reboot. Triple fault for now; TODO: implement UEFI runtime function for clean reboot.
@@ -349,6 +361,9 @@ namespace Zenith {
case SYS_SHUTDOWN: case SYS_SHUTDOWN:
/* Unimplemented */ /* Unimplemented */
return -1; return -1;
case SYS_GETTIME:
Sys_GetTime((DateTime*)frame->arg1);
return 0;
default: default:
return -1; return -1;
} }
@@ -375,7 +390,7 @@ namespace Zenith {
Hal::WriteMSR(Hal::IA32_FMASK, 0x200); Hal::WriteMSR(Hal::IA32_FMASK, 0x200);
Kt::KernelLogStream(Kt::OK, "Syscall") << "SYSCALL/SYSRET initialized (LSTAR=" Kt::KernelLogStream(Kt::OK, "Syscall") << "SYSCALL/SYSRET initialized (LSTAR="
<< kcp::hex << (uint64_t)SyscallEntry << kcp::dec << ", 26 syscalls)"; << kcp::hex << (uint64_t)SyscallEntry << kcp::dec << ", 29 syscalls)";
} }
} }
+10
View File
@@ -39,6 +39,16 @@ namespace Zenith {
static constexpr uint64_t SYS_GETARGS = 25; static constexpr uint64_t SYS_GETARGS = 25;
static constexpr uint64_t SYS_RESET = 26; static constexpr uint64_t SYS_RESET = 26;
static constexpr uint64_t SYS_SHUTDOWN = 27; static constexpr uint64_t SYS_SHUTDOWN = 27;
static constexpr uint64_t SYS_GETTIME = 28;
struct DateTime {
uint16_t Year;
uint8_t Month;
uint8_t Day;
uint8_t Hour;
uint8_t Minute;
uint8_t Second;
};
struct FbInfo { struct FbInfo {
uint64_t width; uint64_t width;
+66
View File
@@ -4,12 +4,70 @@
*/ */
#include "Time.hpp" #include "Time.hpp"
#include "ApicTimer.hpp"
#include <Terminal/Terminal.hpp> #include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp> #include <CppLib/Stream.hpp>
using namespace Kt; using namespace Kt;
static int64_t g_bootEpoch = 0;
static bool IsLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
static int DaysInMonth(int month, int year) {
static const int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (month == 2 && IsLeapYear(year)) return 29;
return days[month];
}
static int64_t DateToEpoch(int year, int month, int day, int hour, int minute, int second) {
int64_t days = 0;
for (int y = 1970; y < year; y++) {
days += IsLeapYear(y) ? 366 : 365;
}
for (int m = 1; m < month; m++) {
days += DaysInMonth(m, year);
}
days += day - 1;
return days * 86400 + hour * 3600 + minute * 60 + second;
}
static Timekeeping::DateTime EpochToDate(int64_t epoch) {
Timekeeping::DateTime dt = {};
int64_t rem = epoch;
int year = 1970;
while (true) {
int64_t daysInYear = IsLeapYear(year) ? 366 : 365;
if (rem < daysInYear * 86400) break;
rem -= daysInYear * 86400;
year++;
}
dt.Year = (uint16_t)year;
int dayOfYear = (int)(rem / 86400);
rem -= (int64_t)dayOfYear * 86400;
int month = 1;
while (month <= 12) {
int dim = DaysInMonth(month, year);
if (dayOfYear < dim) break;
dayOfYear -= dim;
month++;
}
dt.Month = (uint8_t)month;
dt.Day = (uint8_t)(dayOfYear + 1);
dt.Hour = (uint8_t)(rem / 3600);
rem %= 3600;
dt.Minute = (uint8_t)(rem / 60);
dt.Second = (uint8_t)(rem % 60);
return dt;
}
void Timekeeping::Init(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour, uint8_t Minute, uint8_t Second) { void Timekeeping::Init(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour, uint8_t Minute, uint8_t Second) {
g_bootEpoch = DateToEpoch(Year, Month, Day, Hour, Minute, Second);
/* Hardcode CET for now */ /* Hardcode CET for now */
TimeZone CET = { TimeZone CET = {
"Central European Time", "Central European Time",
@@ -64,3 +122,11 @@ void Timekeeping::Init(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour,
UpdatePanelBar(dateString); UpdatePanelBar(dateString);
} }
int64_t Timekeeping::GetUnixTimestamp() {
return g_bootEpoch + (int64_t)(Timekeeping::GetMilliseconds() / 1000);
}
Timekeeping::DateTime Timekeeping::GetDateTime() {
return EpochToDate(GetUnixTimestamp());
}
+11
View File
@@ -41,5 +41,16 @@ namespace Timekeeping {
"December" "December"
}; };
struct DateTime {
uint16_t Year;
uint8_t Month;
uint8_t Day;
uint8_t Hour;
uint8_t Minute;
uint8_t Second;
};
void Init(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour, uint8_t Minute, uint8_t Second); void Init(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour, uint8_t Minute, uint8_t Second);
int64_t GetUnixTimestamp();
DateTime GetDateTime();
}; };
Binary file not shown.
Binary file not shown.
+10
View File
@@ -39,6 +39,16 @@ namespace Zenith {
static constexpr uint64_t SYS_GETARGS = 25; static constexpr uint64_t SYS_GETARGS = 25;
static constexpr uint64_t SYS_RESET = 26; static constexpr uint64_t SYS_RESET = 26;
static constexpr uint64_t SYS_SHUTDOWN = 27; static constexpr uint64_t SYS_SHUTDOWN = 27;
static constexpr uint64_t SYS_GETTIME = 28;
struct DateTime {
uint16_t Year;
uint8_t Month;
uint8_t Day;
uint8_t Hour;
uint8_t Minute;
uint8_t Second;
};
struct FbInfo { struct FbInfo {
uint64_t width; uint64_t width;
+3
View File
@@ -176,6 +176,9 @@ namespace zenith {
if (rows) *rows = (int)(r >> 32); if (rows) *rows = (int)(r >> 32);
} }
// Timekeeping (wall-clock)
inline void gettime(Zenith::DateTime* out) { syscall1(Zenith::SYS_GETTIME, (uint64_t)out); }
// Power management // Power management
[[noreturn]] inline void reset() { [[noreturn]] inline void reset() {
syscall0(Zenith::SYS_RESET); syscall0(Zenith::SYS_RESET);
+3
View File
@@ -47,6 +47,9 @@
round-trip times. Timeout is 3 seconds per request. round-trip times. Timeout is 3 seconds per request.
Example: ping 10.0.2.2 Example: ping 10.0.2.2
.SS date
Display the current date and time in UTC.
.SS uptime .SS uptime
Display the system uptime in minutes, seconds, and milliseconds. Display the system uptime in minutes, seconds, and milliseconds.
+16 -1
View File
@@ -3,7 +3,7 @@
syscalls - overview of ZenithOS system calls syscalls - overview of ZenithOS system calls
.SH DESCRIPTION .SH DESCRIPTION
ZenithOS provides 26 system calls (numbers 0-25) for userspace ZenithOS provides 29 system calls (numbers 0-28) for userspace
programs. Syscalls use the x86-64 SYSCALL instruction with the programs. Syscalls use the x86-64 SYSCALL instruction with the
following register convention: following register convention:
@@ -91,6 +91,12 @@
Get milliseconds elapsed since boot. Get milliseconds elapsed since boot.
uint64_t zenith::get_milliseconds(); uint64_t zenith::get_milliseconds();
.B SYS_GETTIME (28)
Get the current wall-clock date and time (UTC).
Fills a Zenith::DateTime struct with Year, Month, Day,
Hour, Minute, and Second fields.
void zenith::gettime(Zenith::DateTime* out);
.SH SYSTEM .SH SYSTEM
.B SYS_GETINFO (15) .B SYS_GETINFO (15)
Get OS name, version, and configuration. Get OS name, version, and configuration.
@@ -133,5 +139,14 @@
Get the argument string passed to this process at spawn time. Get the argument string passed to this process at spawn time.
int zenith::getargs(char* buf, uint64_t maxLen); int zenith::getargs(char* buf, uint64_t maxLen);
.SH POWER MANAGEMENT
.B SYS_RESET (26)
Reboot the system.
[[noreturn]] void zenith::reset();
.B SYS_SHUTDOWN (27)
Shut down the system (currently unimplemented).
[[noreturn]] void zenith::shutdown();
.SH SEE ALSO .SH SEE ALSO
spawn(2), file(2), framebuffer(2), malloc(3) spawn(2), file(2), framebuffer(2), malloc(3)
Binary file not shown.
Binary file not shown.
+35
View File
@@ -94,6 +94,7 @@ static void cmd_help() {
zenith::print(" cat <file> Display file contents\n"); zenith::print(" cat <file> Display file contents\n");
zenith::print(" run <file> Spawn a new process from an ELF file\n"); zenith::print(" run <file> Spawn a new process from an ELF file\n");
zenith::print(" ping <ip> Send ICMP echo requests\n"); zenith::print(" ping <ip> Send ICMP echo requests\n");
zenith::print(" date Show current date and time\n");
zenith::print(" uptime Show uptime in milliseconds\n"); zenith::print(" uptime Show uptime in milliseconds\n");
zenith::print(" clear Clear the screen\n"); zenith::print(" clear Clear the screen\n");
zenith::print(" reset Reboot the system\n"); zenith::print(" reset Reboot the system\n");
@@ -390,6 +391,38 @@ static void cmd_man(const char* arg) {
} }
} }
static void print_int_padded(uint64_t n) {
if (n < 10) zenith::putchar('0');
print_int(n);
}
static const char* month_name(int m) {
static const char* months[] = {
"", "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
if (m >= 1 && m <= 12) return months[m];
return "?";
}
static void cmd_date() {
Zenith::DateTime dt;
zenith::gettime(&dt);
print_int(dt.Day);
zenith::putchar(' ');
zenith::print(month_name(dt.Month));
zenith::putchar(' ');
print_int(dt.Year);
zenith::print(", ");
print_int(dt.Hour);
zenith::putchar(':');
print_int_padded(dt.Minute);
zenith::putchar(':');
print_int_padded(dt.Second);
zenith::print(" UTC\n");
}
static void cmd_clear() { static void cmd_clear() {
zenith::print("\033[2J"); // Clear entire screen zenith::print("\033[2J"); // Clear entire screen
zenith::print("\033[H"); // Move cursor to top-left zenith::print("\033[H"); // Move cursor to top-left
@@ -428,6 +461,8 @@ static void process_command(const char* line) {
cmd_ping(line + 5); cmd_ping(line + 5);
} else if (streq(line, "ping")) { } else if (streq(line, "ping")) {
cmd_ping(""); cmd_ping("");
} else if (streq(line, "date")) {
cmd_date();
} else if (streq(line, "uptime")) { } else if (streq(line, "uptime")) {
cmd_uptime(); cmd_uptime();
} else if (streq(line, "clear")) { } else if (streq(line, "clear")) {
BIN
View File
Binary file not shown.