79 lines
2.3 KiB
C
79 lines
2.3 KiB
C
// HAL serial output endpoint. This file owns polling COM1 writes and subscribes serial to HAL text streams.
|
|
|
|
#include <stdint.h>
|
|
#include <intrin.h>
|
|
#include <ntlite/ddi/hal_api.h>
|
|
#include <kernel/hal/hal_output.h>
|
|
|
|
#define HAL_COM1_DATA_PORT 0x03F8u
|
|
#define HAL_COM1_STATUS_PORT 0x03FDu
|
|
#define HAL_COM1_TX_READY 0x20u
|
|
|
|
static volatile long gSerialWriteLock;
|
|
|
|
// Waits until COM1 can accept one byte.
|
|
static void HalSerialWaitForTransmit(void) {
|
|
while ((__inbyte(HAL_COM1_STATUS_PORT) & HAL_COM1_TX_READY) == 0)
|
|
_mm_pause();
|
|
}
|
|
|
|
// Writes one byte to COM1.
|
|
static void HalSerialWriteByte(uint8_t value) {
|
|
HalSerialWaitForTransmit();
|
|
__outbyte(HAL_COM1_DATA_PORT, value);
|
|
}
|
|
|
|
// Acquires the normal serial writer lock.
|
|
static void HalSerialAcquireWriteLock(void) {
|
|
while (_InterlockedCompareExchange(&gSerialWriteLock, 1, 0) != 0)
|
|
_mm_pause();
|
|
}
|
|
|
|
// Releases the normal serial writer lock.
|
|
static void HalSerialReleaseWriteLock(void) {
|
|
_InterlockedExchange(&gSerialWriteLock, 0);
|
|
}
|
|
|
|
// Writes one output record through polling COM1.
|
|
static void HalSerialWriteRecord(void* context, const HAL_OUTPUT_RECORD* record) {
|
|
(void)context;
|
|
if (!record || !record->Buffer)
|
|
return;
|
|
|
|
bool emergency = (record->Flags & HAL_OUTPUT_WRITE_EMERGENCY) != 0;
|
|
uintptr_t interruptFlags = 0;
|
|
if (!emergency) {
|
|
interruptFlags = HalDisableInterrupts();
|
|
HalSerialAcquireWriteLock();
|
|
}
|
|
|
|
for (size_t i = 0; i < record->Length; i++) {
|
|
char c = record->Buffer[i];
|
|
if (c == '\n')
|
|
HalSerialWriteByte('\r');
|
|
HalSerialWriteByte((uint8_t)c);
|
|
}
|
|
|
|
if (!emergency) {
|
|
HalSerialReleaseWriteLock();
|
|
HalRestoreInterrupts(interruptFlags);
|
|
}
|
|
}
|
|
|
|
// Registers the polling serial endpoint.
|
|
void HalSerialInitialize(HAL_OUTPUT_ROUTER* output) {
|
|
if (!output || !output->RegisterEndpoint)
|
|
return;
|
|
|
|
HAL_OUTPUT_ENDPOINT endpoint;
|
|
endpoint.Name = "serial0";
|
|
endpoint.StreamMask = HAL_OUTPUT_STREAM_ALL;
|
|
endpoint.Capabilities = HAL_OUTPUT_ENDPOINT_PANIC_SAFE;
|
|
endpoint.Write = HalSerialWriteRecord;
|
|
endpoint.Context = 0;
|
|
|
|
uint32_t endpointId = HAL_OUTPUT_ENDPOINT_INVALID;
|
|
if (KSUCCESS(output->RegisterEndpoint(&endpoint, &endpointId)))
|
|
output->SerialEndpointId = endpointId;
|
|
}
|