|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* timer.c
|
|
|
*
|
|
|
- * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
|
|
|
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
|
|
|
*
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
@@ -22,7 +22,9 @@
|
|
|
|
|
|
volatile qword_t total_ticks = 0;
|
|
|
|
|
|
-void timer_irq(registers_t *regs, byte_t irq_num)
|
|
|
+static dword_t timer_reload_value;
|
|
|
+
|
|
|
+static void timer_irq(registers_t *regs, byte_t irq_num)
|
|
|
{
|
|
|
total_ticks++;
|
|
|
|
|
@@ -33,12 +35,12 @@ void timer_irq(registers_t *regs, byte_t irq_num)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-sysret_t syscall_get_milliseconds(void)
|
|
|
+qword_t timer_get_milliseconds(void)
|
|
|
{
|
|
|
return total_ticks;
|
|
|
}
|
|
|
|
|
|
-sysret_t syscall_get_nanoseconds(void)
|
|
|
+qword_t timer_get_nanoseconds(void)
|
|
|
{
|
|
|
critical_t critical;
|
|
|
enter_critical(&critical);
|
|
@@ -48,25 +50,65 @@ sysret_t syscall_get_nanoseconds(void)
|
|
|
cpu_write_port_byte(TIMER_CMD_PORT, 0x00);
|
|
|
word_t count = cpu_read_port_byte(TIMER_CHANNEL_PORT(0));
|
|
|
count |= cpu_read_port_byte(TIMER_CHANNEL_PORT(0)) << 8;
|
|
|
- count = -count;
|
|
|
|
|
|
- result += (count * 1000ULL) / (qword_t)TIMER_BASE_FREQUENCY;
|
|
|
+ ASSERT(count <= timer_reload_value);
|
|
|
+ count = timer_reload_value - count;
|
|
|
+
|
|
|
+ result += (count * 1000000000ULL) / (qword_t)TIMER_BASE_FREQUENCY;
|
|
|
|
|
|
leave_critical(&critical);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+sysret_t syscall_query_timer(long reserved, timer_info_type_t info_type, void *buffer, size_t size)
|
|
|
+{
|
|
|
+ if (get_previous_mode() == USER_MODE && !check_usermode(buffer, size)) return ERR_BADPTR;
|
|
|
+ if (size < sizeof(qword_t)) return ERR_SMALLBUF;
|
|
|
+ qword_t value;
|
|
|
+
|
|
|
+ switch (info_type)
|
|
|
+ {
|
|
|
+ case TIMER_MILLISECONDS:
|
|
|
+ value = timer_get_milliseconds();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TIMER_NANOSECONDS:
|
|
|
+ value = timer_get_nanoseconds();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TIMER_PRECISION:
|
|
|
+ value = TIMER_BASE_FREQUENCY;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return ERR_INVALID;
|
|
|
+ }
|
|
|
+
|
|
|
+ EH_TRY
|
|
|
+ {
|
|
|
+ *(qword_t*)buffer = value;
|
|
|
+ }
|
|
|
+ EH_CATCH
|
|
|
+ {
|
|
|
+ EH_ESCAPE(return ERR_BADPTR);
|
|
|
+ }
|
|
|
+ EH_DONE;
|
|
|
+
|
|
|
+ return ERR_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
void timer_init(void)
|
|
|
{
|
|
|
- dword_t value = TIMER_BASE_FREQUENCY / TIMER_FREQUENCY;
|
|
|
- dword_t remainder = TIMER_BASE_FREQUENCY - value * TIMER_FREQUENCY;
|
|
|
+ timer_reload_value = TIMER_BASE_FREQUENCY / TIMER_FREQUENCY;
|
|
|
+
|
|
|
+ dword_t remainder = TIMER_BASE_FREQUENCY - timer_reload_value * TIMER_FREQUENCY;
|
|
|
+ if ((remainder * 2) > TIMER_FREQUENCY) timer_reload_value++;
|
|
|
|
|
|
- if ((remainder * 2) > TIMER_FREQUENCY) value++;
|
|
|
- if (value == 0) value = 1;
|
|
|
- if (value >= 65536) value = 0;
|
|
|
+ if (timer_reload_value == 0) timer_reload_value = 1;
|
|
|
+ if (timer_reload_value >= 65536) timer_reload_value = 0;
|
|
|
|
|
|
cpu_write_port_byte(TIMER_CMD_PORT, TIMER_RATE_GENERATOR(0));
|
|
|
- cpu_write_port_byte(TIMER_CHANNEL_PORT(0), value & 0xFF);
|
|
|
- cpu_write_port_byte(TIMER_CHANNEL_PORT(0), (value >> 8) & 0xFF);
|
|
|
+ cpu_write_port_byte(TIMER_CHANNEL_PORT(0), timer_reload_value & 0xFF);
|
|
|
+ cpu_write_port_byte(TIMER_CHANNEL_PORT(0), (timer_reload_value >> 8) & 0xFF);
|
|
|
register_irq_handler(TIMER_IRQ, &timer_irq, FALSE);
|
|
|
}
|