feat: add time syscall & command in shell
This commit is contained in:
@@ -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,7 +257,18 @@ namespace Zenith {
|
|||||||
return (rows << 32) | (cols & 0xFFFFFFFF);
|
return (rows << 32) | (cols & 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Sys_Reset() {
|
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() {
|
||||||
/*
|
/*
|
||||||
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)";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -63,4 +121,12 @@ void Timekeeping::Init(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour,
|
|||||||
CString dateString = panelStr.c_str();
|
CString dateString = panelStr.c_str();
|
||||||
|
|
||||||
UpdatePanelBar(dateString);
|
UpdatePanelBar(dateString);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Timekeeping::GetUnixTimestamp() {
|
||||||
|
return g_bootEpoch + (int64_t)(Timekeeping::GetMilliseconds() / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Timekeeping::DateTime Timekeeping::GetDateTime() {
|
||||||
|
return EpochToDate(GetUnixTimestamp());
|
||||||
}
|
}
|
||||||
@@ -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.
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
@@ -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.
@@ -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
Binary file not shown.
Reference in New Issue
Block a user