mirror of https://gitlab.com/nakst/essence
use PIT for scheduler time; RTC driver; date conversion functions; add EsDateNowUTC
This commit is contained in:
parent
969ca8e4c4
commit
293f19de42
|
@ -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();
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ _EsCRTlongjmp:
|
|||
.return:
|
||||
ret
|
||||
|
||||
[global EsTimeStamp]
|
||||
EsTimeStamp:
|
||||
[global ProcessorReadTimeStamp]
|
||||
ProcessorReadTimeStamp:
|
||||
rdtsc
|
||||
shl rdx,32
|
||||
or rax,rdx
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -58,7 +58,7 @@ EsElementRelayout=56
|
|||
EsListViewContentChanged=57
|
||||
EsDrawLine=58
|
||||
EsProcessCreate=59
|
||||
EsTimeStamp=60
|
||||
EsDateNowUTC=60
|
||||
EsProcessGetExitStatus=61
|
||||
EsProcessGetID=62
|
||||
EsProcessGetState=63
|
||||
|
|
|
@ -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 } },
|
||||
|
|
Loading…
Reference in New Issue