use PIT for scheduler time; RTC driver; date conversion functions; add EsDateNowUTC

This commit is contained in:
nakst 2021-10-10 16:11:13 +01:00
parent 969ca8e4c4
commit 293f19de42
23 changed files with 314 additions and 105 deletions

View File

@ -84,16 +84,6 @@ struct EsFileStore {
};
};
struct GlobalData {
volatile int32_t clickChainTimeoutMs;
volatile float uiScale;
volatile bool swapLeftAndRightButtons;
volatile bool showCursorShadow;
volatile bool useSmartQuotes;
volatile bool enableHoverState;
volatile float animationTimeMultiplier;
};
struct ThreadLocalStorage {
// This must be the first field.
ThreadLocalStorage *self;
@ -173,6 +163,7 @@ ptrdiff_t tlsStorageOffset;
// Miscellanous forward declarations.
extern "C" void EsUnimplemented();
extern "C" uintptr_t ProcessorTLSRead(uintptr_t offset);
extern "C" uint64_t ProcessorReadTimeStamp();
void MaybeDestroyElement(EsElement *element);
const char *GetConstantString(const char *key);
void UndoManagerDestroy(EsUndoManager *manager);
@ -969,8 +960,6 @@ EsMessage *EsMessageReceive() {
EsMessageMutexCheck();
while (true) {
TS("Process message\n");
if (message.message.type == ES_MSG_INSTANCE_CREATE) {
if (message.message.createInstance.data != ES_INVALID_HANDLE) {
EsHandleClose(message.message.createInstance.data);
@ -1471,7 +1460,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) {
// Initialise the API.
_init();
EsRandomSeed(EsTimeStamp());
EsRandomSeed(ProcessorReadTimeStamp());
ThreadInitialise(&api.firstThreadLocalStorage);
EsMessageMutexAcquire();

View File

@ -55,8 +55,8 @@ _EsCRTlongjmp:
.return:
ret
[global EsTimeStamp]
EsTimeStamp:
[global ProcessorReadTimeStamp]
ProcessorReadTimeStamp:
rdtsc
shl rdx,32
or rax,rdx

View File

@ -2941,6 +2941,16 @@ void DesktopMessage(EsMessage *message) {
EsMessagePostRemote(process->handle, message);
}
}
if (message->device.type == ES_DEVICE_CLOCK) {
EsDateComponents reading;
uint64_t linear;
if (ES_SUCCESS == EsDeviceControl(message->device.handle, ES_DEVICE_CONTROL_CLOCK_READ, &reading, &linear)) {
// TODO Scheduler timer is not particularly accurate, so we should periodically resynchronize with the clock.
api.global->schedulerTimeOffset = (linear ?: DateToLinear(&reading)) - api.global->schedulerTimeMs;
}
}
} else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM || message->type == ES_MSG_DEVICE_DISCONNECTED) {
for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) {
ApplicationProcess *process = desktop.allApplicationProcesses[i];

View File

@ -1663,7 +1663,7 @@ bool EsElement::StartAnimating() {
}
void ProcessAnimations() {
uint64_t timeStamp = EsTimeStamp(); // TODO Use global time instead.
uint64_t timeStamp = ProcessorReadTimeStamp();
int64_t waitMs = -1;
for (uintptr_t i = 0; i < gui.animatingElements.Length(); i++) {
@ -5777,6 +5777,10 @@ void EsElement::Destroy(bool manual) {
}
}
if (state & UI_STATE_FOCUSED) {
UIRemoveFocusFromElement(this);
}
state |= UI_STATE_DESTROYING | UI_STATE_DESTROYING_CHILD | UI_STATE_BLOCK_INTERACTION;
if (parent) {

View File

@ -1484,7 +1484,7 @@ struct EsListView : EsElement {
EsMessageSend(this, &m);
return true;
} else if (!ctrl && !alt) {
uint64_t currentTime = EsTimeStamp() / api.startupInformation->timeStampTicksPerMs;
uint64_t currentTime = EsTimeStampMs();
if (searchBufferLastKeyTime + GetConstantNumber("listViewSearchBufferTimeout") < currentTime) {
searchBufferBytes = 0;
@ -1785,7 +1785,7 @@ struct EsListView : EsElement {
DragSelect();
}
uint64_t currentTime = EsTimeStamp() / api.startupInformation->timeStampTicksPerMs;
uint64_t currentTime = EsTimeStampMs();
int64_t remainingTime = searchBufferLastKeyTime + GetConstantNumber("listViewSearchBufferTimeout") - currentTime;
if (remainingTime < 0) {

View File

@ -1142,6 +1142,7 @@ enum EsDeviceType {
ES_DEVICE_NETWORK_CARD
ES_DEVICE_USB
ES_DEVICE_PCI_FUNCTION
ES_DEVICE_CLOCK
}
enum EsClipboardFormat {
@ -1155,6 +1156,8 @@ enum EsDeviceControlType {
ES_DEVICE_CONTROL_BLOCK_READ = 0x1002
ES_DEVICE_CONTROL_BLOCK_WRITE = 0x1003
ES_DEVICE_CONTROL_BLOCK_DETECT_FS = 0x1004 // Detect file systems. All existing file systems must have been unmounted.
ES_DEVICE_CONTROL_CLOCK_READ = 0x2001
}
function_pointer int EsUICallback(struct EsElement *element, struct EsMessage *message);
@ -1919,6 +1922,17 @@ struct EsOpenDocumentInformation {
char applicationName[128];
};
struct EsDateComponents {
uint16_t year;
uint8_t month; // 1-12.
uint8_t day; // Starting at 1.
uint8_t hour; // 0-23.
uint8_t minute; // 0-59.
uint8_t second; // 0-59.
uint8_t _unused;
uint16_t millisecond; // 0-999.
};
// Function pointer types.
function_pointer void EsThreadEntryCallback(EsGeneric argument);
@ -2106,8 +2120,6 @@ function bool EsRectangleEquals(EsRectangle a, EsRectangle b);
function bool EsRectangleContains(EsRectangle a, int32_t x, int32_t y);
function void EsSort(void *_base, size_t nmemb, size_t size, EsComparisonCallback compar, EsGeneric argument);
function void EsSortWithSwapCallback(void *_base, size_t nmemb, size_t size, EsComparisonCallback compar, EsGeneric argument, EsSwapCallback swap);
function uint64_t EsTimeStamp();
function double EsTimeStampMs();
// Graphics.
@ -2201,22 +2213,32 @@ function EsHandle EsEventCreate(bool autoReset);
function void EsEventForward(EsHandle event, EsHandle eventSink, EsGeneric data); // TODO Forwarding process/thread killed events.
function void EsEventReset(EsHandle event);
function void EsEventSet(EsHandle event);
function EsHandle EsEventSinkCreate(bool ignoreDuplicates);
function EsError EsEventSinkPop(EsHandle eventSink, EsGeneric *data); // Returns ES_ERROR_EVENT_NOT_SET if empty, and ES_ERROR_EVENT_SINK_OVERFLOW if data lost.
function EsError EsEventSinkPush(EsHandle eventSink, EsGeneric data); // Returns ES_ERROR_EVENT_SINK_DUPLICATE if duplicate, and ES_ERROR_EVENT_SINK_OVERFLOW if data lost.
function void EsMutexAcquire(EsMutex *mutex);
function void EsMutexDestroy(EsMutex *mutex);
function void EsMutexRelease(EsMutex *mutex);
function void EsPerformanceTimerPush(); // Stack size should not exceed 100 values.
function double EsPerformanceTimerPop(); // Returns value in seconds.
function void EsSchedulerYield();
function void EsSleep(uint64_t milliseconds);
function void EsSpinlockAcquire(EsSpinlock *spinlock);
function void EsSpinlockRelease(EsSpinlock *spinlock);
function EsTimer EsTimerSet(uint64_t afterMs, EsTimerCallback callback, EsGeneric argument);
function void EsTimerCancel(EsTimer id);
function void EsSleep(uint64_t milliseconds);
function uintptr_t EsWait(EsHandle *objects, size_t objectCount, uintptr_t timeoutMs);
function void EsPerformanceTimerPush(); // Stack size should not exceed 100 values.
function double EsPerformanceTimerPop(); // Returns value in seconds.
function double EsTimeStampMs(); // Current value of the performance timer, in ms.
function void EsDateNowUTC(EsDateComponents *date); // Don't rely on the accuracy of the millisecond field.
// Strings.
function char *EsCStringDuplicate(EsCString string);

View File

@ -241,7 +241,7 @@ ES_EXTERN_C void _start();
#define ES_INFINITY __builtin_inff()
#define ES_PI (3.1415926535897932384626433832795028841971693994)
// --------- Internal APIs:
// --------- Internals:
#if defined(ES_API) || defined(KERNEL) || defined(INSTALLER)
@ -279,6 +279,18 @@ struct MemoryAvailable {
size_t total;
};
struct GlobalData {
volatile int32_t clickChainTimeoutMs;
volatile float uiScale;
volatile bool swapLeftAndRightButtons;
volatile bool showCursorShadow;
volatile bool useSmartQuotes;
volatile bool enableHoverState;
volatile float animationTimeMultiplier;
volatile uint64_t schedulerTimeMs;
volatile uint64_t schedulerTimeOffset;
};
#ifdef KERNEL
#define K_BOOT_DRIVE ""
#else

View File

@ -6,10 +6,15 @@ double EsTimeStampMs() {
if (!api.startupInformation->timeStampTicksPerMs) {
return 0;
} else {
return (double) EsTimeStamp() / api.startupInformation->timeStampTicksPerMs;
return (double) ProcessorReadTimeStamp() / api.startupInformation->timeStampTicksPerMs;
}
}
void EsDateNowUTC(EsDateComponents *date) {
uint64_t linear = api.global->schedulerTimeMs + api.global->schedulerTimeOffset;
DateToComponents(linear, date);
}
void *EsMemoryReserve(size_t size, EsMemoryProtection protection, uint32_t flags) {
intptr_t result = EsSyscall(ES_SYSCALL_MEMORY_ALLOCATE, size, flags, protection, 0);

View File

@ -133,6 +133,7 @@ struct ACPI {
ACPIDescriptorTable *madt;
bool ps2ControllerUnavailable, vgaControllerUnavailable;
uint8_t centuryRegisterIndex;
KDevice *computer;
};
@ -788,20 +789,25 @@ static void DeviceAttach(KDevice *parentDevice) {
#endif
if (!acpi.vgaControllerUnavailable) {
KDeviceAttachByName(acpi.computer, "SVGA");
KDeviceAttachByName(acpi.computer, "SVGA"); // TODO Remove from the startup critical path.
}
KDeviceAttachByName(acpi.computer, "PCI");
KDeviceAttachByName(acpi.computer, "RTC"); // TODO Remove from the startup critical path.
}
KDriver driverACPI = {
.attach = DeviceAttach,
};
void *KGetRSDP() {
void *ACPIGetRSDP() {
return acpi.rsdp;
}
uint8_t ACPIGetCenturyRegisterIndex() {
return acpi.centuryRegisterIndex;
}
inline void ArchInitialise() {
acpi.Initialise();
}
@ -884,6 +890,7 @@ void ACPI::Initialise() {
fadt->Check();
if (header->length > 109) {
centuryRegisterIndex = ((uint8_t *) fadt)[108];
uint8_t bootArchitectureFlags = ((uint8_t *) fadt)[109];
ps2ControllerUnavailable = ~bootArchitectureFlags & (1 << 1);
vgaControllerUnavailable = bootArchitectureFlags & (1 << 2);
@ -1005,28 +1012,6 @@ void ACPI::Initialise() {
ProcessorEnableInterrupts();
// EsPrint("timeStampTicksPerMs = %d\n", timeStampTicksPerMs);
// Add some entropy.
{
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 0);
EsRandomAddEntropy(ProcessorIn8(0x71) << 0);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 2);
EsRandomAddEntropy(ProcessorIn8(0x71) << 1);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 4);
EsRandomAddEntropy(ProcessorIn8(0x71) << 2);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 6);
EsRandomAddEntropy(ProcessorIn8(0x71) << 3);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 7);
EsRandomAddEntropy(ProcessorIn8(0x71) << 4);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 8);
EsRandomAddEntropy(ProcessorIn8(0x71) << 5);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 9);
EsRandomAddEntropy(ProcessorIn8(0x71) << 6);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 10);
EsRandomAddEntropy(ProcessorIn8(0x71) << 7);
for (int i = 0; i < 10; i++) ProcessorOut8(0x70, 11);
EsRandomAddEntropy(ProcessorIn8(0x71) << 8);
}
// Finish processor initialisation.
// This sets up interrupts, the timer, CPULocalStorage, the GDT and TSS,
// and registers the processor with the scheduler.

93
drivers/rtc.cpp Normal file
View File

@ -0,0 +1,93 @@
#include <module.h>
#include <kernel/x86_64.h>
struct RTCDevice : KClockDevice {};
KMutex mutex;
uint8_t RTCRead(uint8_t index, bool convertFromBCD, bool convertFrom12Hour) {
KMutexAcquire(&mutex);
EsDefer(KMutexRelease(&mutex));
for (uint8_t i = 0; i < 10; i++) {
// Write the index a few times to delay before reading.
ProcessorOut8(0x70, index);
}
uint8_t value = ProcessorIn8(0x71);
if (convertFromBCD) {
value = (value >> 4) * 10 + (value & 0xF);
if (convertFrom12Hour) value -= 0x30;
}
if (convertFrom12Hour) {
if (value > 0x80) value -= 0x45;
else value -= 0x01;
}
return value;
}
void RTCReadAll(EsDateComponents *reading) {
uint8_t centuryRegisterIndex = ACPIGetCenturyRegisterIndex();
uint8_t status = RTCRead(0x0B, false, false);
reading->second = RTCRead(0x00, ~status & 4, false);
reading->minute = RTCRead(0x02, ~status & 4, ~status & 2);
reading->hour = RTCRead(0x04, ~status & 4, false);
reading->day = RTCRead(0x07, ~status & 4, false);
reading->month = RTCRead(0x08, ~status & 4, false);
reading->year = RTCRead(0x09, ~status & 4, false);
reading->year += 100 * (centuryRegisterIndex ? RTCRead(centuryRegisterIndex, ~status & 4, false) : 20);
}
EsError RTCMakeReading(KClockDevice *, EsDateComponents *reading, uint64_t *linear) {
*linear = 0; // The RTC is a componented clock.
EsMemoryZero(reading, sizeof(EsDateComponents));
// Try up to 10 times to get a consistent reading.
for (uintptr_t i = 0; i < 10; i++) {
EsDateComponents now;
RTCReadAll(&now);
bool match = 0 == EsMemoryCompare(reading, &now, sizeof(EsDateComponents));
EsMemoryCopy(reading, &now, sizeof(EsDateComponents));
if (match) break;
}
KernelLog(LOG_INFO, "RTC", "read time", "Read current time from RTC as %d/%d/%d %d:%d:%d. Status byte is 0x%X. Century register index is 0x%X.\n",
reading->year, reading->month, reading->day, reading->hour, reading->minute, reading->second,
RTCRead(0x0B, false, false), ACPIGetCenturyRegisterIndex());
// Use the time as a source of entropy.
EsRandomAddEntropy(reading->second);
EsRandomAddEntropy(reading->minute);
EsRandomAddEntropy(reading->hour);
EsRandomAddEntropy(reading->day);
EsRandomAddEntropy(reading->month);
EsRandomAddEntropy(reading->year);
return ES_SUCCESS;
}
void RTCDeviceAttached(KDevice *_parent) {
RTCDevice *device = (RTCDevice *) KDeviceCreate("RTC", _parent, sizeof(RTCDevice));
if (!device) return;
device->read = RTCMakeReading;
KDeviceSendConnectedMessage(device, ES_DEVICE_CLOCK);
#if 0
{
RTCReading start = RTCMakeReading();
KEvent e = {};
KEventWait(&e, 300000);
RTCReading end = RTCMakeReading();
KernelLog(LOG_INFO, "RTC", "delay test", "5 minute delay: %d/%d/%d %d:%d:%d; %d/%d/%d %d:%d:%d.\n",
start.year, start.month, start.day, start.hour, start.minute, start.second,
end.year, end.month, end.day, end.hour, end.minute, end.second);
}
#endif
}
KDriver driverRTC = {
.attach = RTCDeviceAttached,
};

View File

@ -36,6 +36,11 @@ source=drivers/ps2.cpp
arch=x86_common
builtin=1
[@driver RTC]
source=drivers/rtc.cpp
arch=x86_common
builtin=1
; PCI devices.
[@driver IDE]

View File

@ -222,8 +222,6 @@ const KDriver *DriverLoad(KInstalledDriver *installedDriver) {
}
void DeviceAttach(DeviceAttachData attach) {
TS("DeviceAttach to %s\n", attach.installedDriver->nameBytes, attach.installedDriver->name);
if (attach.parentDevice) {
KDeviceOpenHandle(attach.parentDevice);
}

View File

@ -99,7 +99,8 @@ void ArchShutdown(uintptr_t action);
extern "C" void ArchResetCPU();
extern "C" void ArchSpeakerBeep();
extern "C" void ArchNextTimer(size_t ms); // Receive a TIMER_INTERRUPT in ms ms.
extern "C" void ArchNextTimer(size_t ms); // Schedule the next TIMER_INTERRUPT.
extern "C" uint64_t ArchGetTimeMs(); // Called by the scheduler on the boot processor every context switch.
InterruptContext *ArchInitialiseThread(uintptr_t kernelStack, uintptr_t kernelStackSize, struct Thread *thread,
uintptr_t startAddress, uintptr_t argument1, uintptr_t argument2,
bool userland, uintptr_t stack, uintptr_t userStackSize);

View File

@ -330,6 +330,8 @@ size_t mmCoreRegionCount, mmCoreRegionArrayCommit;
LinkedList<MMSharedRegion> mmNamedSharedRegions;
KMutex mmNamedSharedRegionsMutex;
GlobalData *globalData; // Shared with all processes.
// Code!
void MMUpdateAvailablePageCount(bool increase) {
@ -2119,12 +2121,12 @@ MMSpace *MMGetCurrentProcessSpace() {
return GetCurrentThread()->process->vmm;
}
bool MMFaultRange(uintptr_t address, uintptr_t byteCount) {
bool MMFaultRange(uintptr_t address, uintptr_t byteCount, uint32_t flags = ES_FLAGS_DEFAULT) {
uintptr_t start = address & ~(K_PAGE_SIZE - 1);
uintptr_t end = (address + byteCount - 1) & ~(K_PAGE_SIZE - 1);
for (uintptr_t page = start; page <= end; page += K_PAGE_SIZE) {
if (!MMArchHandlePageFault(page, ES_FLAGS_DEFAULT)) {
if (!MMArchHandlePageFault(page, flags)) {
return false;
}
}
@ -2335,6 +2337,14 @@ void MMInitialise() {
pmm.balanceThread->isPageGenerator = true;
scheduler.SpawnThread("MMObjTrim", (uintptr_t) MMObjectCacheTrimThread, 0, ES_FLAGS_DEFAULT);
}
{
// Create the global data shared region.
MMSharedRegion *region = MMSharedOpenRegion(EsLiteral("Desktop.Global"), sizeof(GlobalData), ES_FLAGS_DEFAULT);
globalData = (GlobalData *) MMMapShared(kernelMMSpace, region, 0, sizeof(GlobalData), MM_REGION_FIXED);
MMFaultRange((uintptr_t) globalData, sizeof(GlobalData), MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR);
}
}
#endif

View File

@ -180,7 +180,6 @@ extern "C" uint64_t ProcessorReadMXCSR();
extern "C" uint64_t KGetTimeInMs(); // Scheduler time.
void *KGetRSDP();
size_t KGetCPUCount();
CPULocalStorage *KGetCPULocal(uintptr_t index);
uint64_t KCPUCurrentID();
@ -604,6 +603,10 @@ void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type); // Send a
#include <bin/kernel_config.h>
struct KClockDevice : KDevice {
EsError (*read)(KClockDevice *device, EsDateComponents *components, uint64_t *linearMs);
};
// ---------------------------------------------------------------------------------------------------------------
// Direct memory access.
// ---------------------------------------------------------------------------------------------------------------

View File

@ -227,7 +227,7 @@ struct Scheduler {
volatile bool started, panic, shutdown;
uint64_t timeMs, lastTimeStamp;
uint64_t timeMs;
unsigned currentProcessorID;
@ -1342,14 +1342,20 @@ void Scheduler::Yield(InterruptContext *context) {
else newThread->process->cpuTimeSlices++;
// Prepare the next timer interrupt.
uint64_t time = 1;
ArchNextTimer(time);
uint64_t nextTimer = 1;
ArchNextTimer(nextTimer);
InterruptContext *newContext = newThread->interruptContext;
if (!local->processorID) {
// Update the scheduler's time.
#if 1
timeMs = ArchGetTimeMs();
globalData->schedulerTimeMs = timeMs;
#else
// This drifts by roughly a second every minute.
timeMs = ProcessorReadTimeStamp() / KGetTimeStampTicksPerMs();
#endif
// Update the time stamp counter synchronization value.
extern volatile uint64_t timeStampCounterSynchronizationValue;

View File

@ -755,7 +755,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_HANDLE_SHARE) {
SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) {
if (~currentProcess->permissions & ES_PERMISSION_GET_VOLUME_INFORMATION) {
SYSCALL_RETURN(0, false);
SYSCALL_RETURN(ES_ERROR_PERMISSION_NOT_GRANTED, false);
}
SYSCALL_HANDLE(argument0, KERNEL_OBJECT_NODE, node, KNode);
@ -1331,7 +1331,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_BATCH) {
uintptr_t _returnValue = calls[i].returnValue = DoSyscall(call.index, call.argument0, call.argument1, call.argument2, call.argument3,
DO_SYSCALL_BATCHED, &fatal, userStackPointer);
if (fatal) SYSCALL_RETURN(_returnValue, true);
if (calls->stopBatchIfError && ES_CHECK_ERROR(_returnValue)) break;
if (calls[i].stopBatchIfError && ES_CHECK_ERROR(_returnValue)) break;
if (currentThread->terminating) break;
}
@ -1863,6 +1863,19 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DEVICE_CONTROL) {
} else {
SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true);
}
} else if (device->type == ES_DEVICE_CLOCK) {
KClockDevice *clock = (KClockDevice *) device;
if (type == ES_DEVICE_CONTROL_CLOCK_READ) {
EsDateComponents components;
uint64_t linear;
EsError error = clock->read(clock, &components, &linear);
SYSCALL_WRITE(dp, &components, sizeof(EsDateComponents));
SYSCALL_WRITE(dq, &linear, sizeof(uint64_t));
SYSCALL_RETURN(error, false);
} else {
SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true);
}
} else {
SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true);
}

View File

@ -606,6 +606,31 @@ void ArchCheckAddressInRange(int type, uintptr_t address) {
}
}
uint64_t ArchGetTimeMs() {
// NOTE This will only work if called at least once every 50 ms.
// (The PIT only stores a 16-bit counter, which is depleted every 50 ms.)
static bool started = false;
static uint64_t cumulative = 0, last = 0;
if (!started) {
ProcessorOut8(0x43, 0x30);
ProcessorOut8(0x40, 0xFF);
ProcessorOut8(0x40, 0xFF);
started = true;
last = 0xFFFF;
return 0;
} else {
ProcessorOut8(0x43, 0x00);
uint16_t x = ProcessorIn8(0x40);
x |= (ProcessorIn8(0x40)) << 8;
cumulative += last - x;
if (x > last) cumulative += 0x10000;
last = x;
return cumulative * 1000 / 1193182;
}
}
void ArchDelay1Ms() {
ProcessorOut8(0x43, 0x30);
ProcessorOut8(0x40, 0xA9);
@ -810,9 +835,9 @@ size_t ProcessorSendIPI(uintptr_t interrupt, bool nmi, int processorID) {
}
void ArchNextTimer(size_t ms) {
while (!scheduler.started); // Wait until the scheduler is ready.
GetLocalStorage()->schedulerReady = true; // Make sure this CPU can be scheduled.
acpi.lapic.ArchNextTimer(ms); // Set the next timer.
while (!scheduler.started); // Wait until the scheduler is ready.
GetLocalStorage()->schedulerReady = true; // Make sure this CPU can be scheduled.
acpi.lapic.ArchNextTimer(ms); // Set the next timer.
}
NewProcessorStorage AllocateNewProcessorStorage(ACPIProcessor *archCPU) {

View File

@ -27,5 +27,7 @@ NewProcessorStorage AllocateNewProcessorStorage(struct ACPIProcessor *archCPU);
bool HasSSSE3Support();
uintptr_t GetBootloaderInformationOffset();
void ArchDelay1Ms(); // Spin for approximately 1ms. Use only during initialisation. Not thread-safe.
void *ACPIGetRSDP();
uint8_t ACPIGetCenturyRegisterIndex();
#endif

View File

@ -2,8 +2,6 @@
[section .bss]
[extern ArchNextTimer]
align 16
%define stack_size 16384
@ -250,6 +248,7 @@ StartKernel:
ProcessorReady:
; Set the timer and become this CPU's idle thread.
mov rdi,1
[extern ArchNextTimer]
call ArchNextTimer
jmp ProcessorIdle

View File

@ -1411,45 +1411,6 @@ void EsPrintHelloWorld() {
#endif
/////////////////////////////////
// Timing utility functions.
/////////////////////////////////
#ifdef SHARED_COMMON_WANT_ALL
#ifdef KERNEL
#if 0
int __tsi = 1;
#define TS(...) for (int i = 0; i < __tsi; i++) EsPrint("] "); EsPrint(__VA_ARGS__); uint64_t __ts = KGetTimeInMs(); __tsi++; \
EsDefer({__tsi--; for (int i = 0; i < __tsi; i++) EsPrint("] "); \
EsPrint("> %d ms\n", (KGetTimeInMs() - __ts)); \
for (int i = 0; i < __tsi; i++) EsPrint("] "); EsPrint("\n");})
#define TSP(...) for (int i = 0; i < __tsi; i++) EsPrint("] "); EsPrint(__VA_ARGS__, (KGetTimeInMs() - __ts));
#else
#define TS(...)
#define TSP(...)
#endif
#else
#if 0
int __tsi = 1;
#define TS(...) for (int i = 0; i < __tsi; i++) EsPrint("| "); EsPrint(__VA_ARGS__); uint64_t __ts = EsTimeStamp(); __tsi++; \
EsDefer({__tsi--; for (int i = 0; i < __tsi; i++) EsPrint("| "); \
EsPrint("> %d ms (%d mcs)\n", (EsTimeStamp() - __ts) / (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] * 1000 + 1), (EsTimeStamp() - __ts) / (api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] + 1)); \
for (int i = 0; i < __tsi; i++) EsPrint("| "); EsPrint("\n");})
#define TSP(...) for (int i = 0; i < __tsi; i++) EsPrint("| "); EsPrint(__VA_ARGS__, (EsTimeStamp() - __ts) / \
(api.systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] * 1000 + 1));
#else
#define TS(...)
#define TSP(...)
#endif
#endif
#endif
/////////////////////////////////
// Random number generator.
/////////////////////////////////
@ -2685,3 +2646,68 @@ int32_t EsBufferReadInt32Endian(EsBuffer *buffer, int32_t errorValue) {
}
#endif
/////////////////////////////////
// Time and date.
/////////////////////////////////
#if defined(SHARED_COMMON_WANT_ALL)
const uint16_t daysBeforeMonthStart[] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, // Normal year.
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, // Leap year.
};
uint64_t DateToLinear(const EsDateComponents *components) {
uint64_t dayCount = 365 * components->year + daysBeforeMonthStart[components->month - 1] + components->day - 1;
uint16_t year = components->month < 3 ? components->year - 1 : components->year;
dayCount += 1 + year / 4 - year / 100 + year / 400; // Add additional days for leap years, only including this year's if we're past February.
return components->millisecond + 1000 * (components->second + 60 * (components->minute + 60 * (components->hour + 24 * dayCount)));
}
uint8_t DateCalculateDayOfWeek(const EsDateComponents *components) {
return ((DateToLinear(components) / 86400000 + 5) % 7) + 1;
}
void DateToComponents(uint64_t x, EsDateComponents *components) {
components->millisecond = x % 1000, x /= 1000;
components->second = x % 60, x /= 60;
components->minute = x % 60, x /= 60;
components->hour = x % 24, x /= 24;
// x = days since epoch.
// 146097 days per 400 year block.
components->year = (x / 146097) * 400;
x %= 146097; // x = day within 400 year block.
bool isLeapYear = true;
// 36525 days in the first 100 year block, and 36524 per the other 100 year blocks.
if (x < 36525) {
components->year += (x / 1461) * 4;
x %= 1461; // x = day within 4 year block.
} else {
x -= 36525;
components->year += (x / 36524 + 1) * 100;
x %= 36524; // x = day within 100 year block.
// 1460 days in the first 4 year block, and 1461 per the other 4 year blocks.
if (x < 1460) components->year += x / 365, x %= 365, isLeapYear = false;
else components->year += ((x - 1460) / 1461 + 1) * 4, x = (x - 1460) % 1461;
}
if (x >= 366) components->year += (x - 1) / 365, x = (x - 1) % 365, isLeapYear = false;
// x = day within year.
for (uintptr_t i = 12; i >= 1; i--) {
uint16_t offset = daysBeforeMonthStart[i + (isLeapYear ? 11 : -1)];
if (x >= offset) {
components->month = i;
components->day = x - offset + 1;
break;
}
}
}
#endif

View File

@ -58,7 +58,7 @@ EsElementRelayout=56
EsListViewContentChanged=57
EsDrawLine=58
EsProcessCreate=59
EsTimeStamp=60
EsDateNowUTC=60
EsProcessGetExitStatus=61
EsProcessGetID=62
EsProcessGetState=63

View File

@ -275,6 +275,7 @@ Option options[] = {
{ "Driver.PCI", OPTION_TYPE_BOOL, { .b = true } },
{ "Driver.PS2", OPTION_TYPE_BOOL, { .b = true } },
{ "Driver.Root", OPTION_TYPE_BOOL, { .b = true } },
{ "Driver.RTC", OPTION_TYPE_BOOL, { .b = true } },
{ "Driver.SVGA", OPTION_TYPE_BOOL, { .b = true } },
{ "Driver.USB", OPTION_TYPE_BOOL, { .b = true } },
{ "Driver.USBBulk", OPTION_TYPE_BOOL, { .b = true } },