Renamings some header files.
A linked list implementation stolen from Linux.
#include <arch/x86/boot/multiboot.h>
#include <arch/x86/idt.h>
#include <lunaix/mm/page.h>
-#include <lunaix/constants.h>
+#include <lunaix/common.h>
#define PT_ADDR(ptd, pt_index) ((ptd_t*)ptd + (pt_index + 1) * 1024)
#define SET_PDE(ptd, pde_index, pde) *((ptd_t*)ptd + pde_index) = pde;
#include "parser/madt_parser.h"
-acpi_context* toc = NULL;
+static acpi_context* toc = NULL;
LOG_MODULE("ACPI")
kprintf(KINFO "OEM: %s\n", toc->oem_id);
kprintf(KINFO "IOAPIC address: %p\n", toc->madt.ioapic->ioapic_addr);
kprintf(KINFO "APIC address: %p\n", toc->madt.apic_addr);
-
+
for (size_t i = 0; i < 24; i++) {
acpi_intso_t* intso = toc->madt.irq_exception[i];
if (!intso)
apic_setup_lvts();
void
-init_apic()
+apic_init()
{
// ensure that external interrupt is disabled
cpu_disable_interrupt();
// install our handler for spurious interrupt.
spiv = (spiv & ~0xff) | APIC_SPIV_APIC_ENABLE | APIC_SPIV_IV;
apic_write_reg(APIC_SPIVR, spiv);
-
- // setup timer and performing calibrations
- apic_setup_timer();
}
#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector)
// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14)
#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE)
#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector)
-#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector)
void
apic_setup_lvts()
apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1);
apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV));
}
-
-void
-temp_intr_routine_rtc_tick(const isr_param* param);
-
-void
-temp_intr_routine_apic_timer(const isr_param* param);
-
-void
-test_timer(const isr_param* param);
-
-uint32_t apic_timer_base_freq = 0;
-
-// Don't optimize them! Took me an half hour to figure that out...
-
-volatile uint32_t rtc_counter = 0;
-volatile uint8_t apic_timer_done = 0;
-
-#define APIC_CALIBRATION_CONST 0x100000
-
-void
-apic_setup_timer()
-{
- cpu_disable_interrupt();
-
- // Setup APIC timer
-
- // Setup a one-shot timer, we will use this to measure the bus speed. So we can
- // then calibrate apic timer to work at *nearly* accurate hz
- apic_write_reg(APIC_TIMER_LVT, LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_ONESHOT));
-
- // Set divider to 64
- apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64);
-
- /*
- Timer calibration process - measure the APIC timer base frequency
-
- step 1: setup a temporary isr for RTC timer which trigger at each tick (1024Hz)
- step 2: setup a temporary isr for #APIC_TIMER_IV
- step 3: setup the divider, APIC_TIMER_DCR
- step 4: Startup RTC timer
- step 5: Write a large value, v, to APIC_TIMER_ICR to start APIC timer
- (this must be followed immediately after step 4)
- step 6: issue a write to EOI and clean up.
-
- When the APIC ICR counting down to 0 #APIC_TIMER_IV triggered, save the rtc timer's
- counter, k, and disable RTC timer immediately (although the RTC interrupts should be
- blocked by local APIC as we are currently busy on handling #APIC_TIMER_IV)
-
- So the apic timer frequency F_apic in Hz can be calculate as
- v / F_apic = k / 1024
- => F_apic = v / k * 1024
-
- */
-
- apic_timer_base_freq = 0;
- rtc_counter = 0;
- apic_timer_done = 0;
-
- intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
- intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
-
-
- rtc_enable_timer(); // start RTC timer
- apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); // start APIC timer
-
- // enable interrupt, just for our RTC start ticking!
- cpu_enable_interrupt();
-
- wait_until(apic_timer_done);
-
- // cpu_disable_interrupt();
-
- assert_msg(apic_timer_base_freq, "Fail to initialize timer");
-
- kprintf(KINFO "Timer base frequency: %u Hz\n", apic_timer_base_freq);
-
- // cleanup
- intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
- intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
-
- // TODO: now setup timer with our custom frequency which we can derived from the base frequency
- // we measured
-
- apic_write_reg(APIC_TIMER_LVT, LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC));
- intr_subscribe(APIC_TIMER_IV, test_timer);
-
- apic_write_reg(APIC_TIMER_ICR, apic_timer_base_freq);
-}
-
-volatile rtc_datetime datetime;
-
-void
-test_timer(const isr_param* param) {
-
- rtc_get_datetime(&datetime);
-
- kprintf(KWARN "%u/%02u/%02u %02u:%02u:%02u\r",
- datetime.year,
- datetime.month,
- datetime.day,
- datetime.hour,
- datetime.minute,
- datetime.second);
-}
-
-void
-temp_intr_routine_rtc_tick(const isr_param* param) {
- rtc_counter++;
-
- // dummy read on register C so RTC can send anther interrupt
- // This strange behaviour observed in virtual box & bochs
- (void) rtc_read_reg(RTC_REG_C);
-}
-
-void
-temp_intr_routine_apic_timer(const isr_param* param) {
- apic_timer_base_freq = APIC_CALIBRATION_CONST / rtc_counter * RTC_TIMER_BASE_FREQUENCY;
- apic_timer_done = 1;
-
- rtc_disable_timer();
-}
\ No newline at end of file
*
*/
#include <hal/rtc.h>
+#include <lunaix/time.h>
#include <klibc/string.h>
void
}
int
-rtc_date_same(rtc_datetime* a, rtc_datetime* b) {
+rtc_date_same(datetime_t* a, datetime_t* b) {
return a->year == b->year &&
a->month == b->month &&
a->day == b->day &&
}
void
-rtc_get_datetime(rtc_datetime* datetime)
+time_getdatetime(datetime_t* datetime)
{
- rtc_datetime current;
+ datetime_t current;
do
{
while (rtc_read_reg(RTC_REG_A) & 0x80);
- memcpy(¤t, datetime, sizeof(rtc_datetime));
+ memcpy(¤t, datetime, sizeof(datetime_t));
datetime->year = rtc_read_reg(RTC_REG_YRS);
datetime->month = rtc_read_reg(RTC_REG_MTH);
#define apic_write_reg(reg, val) (*(uint32_t*)(APIC_BASE_VADDR + (reg)) = (val))
void
-init_apic();
+apic_init();
/**
* @brief Tell the APIC that the handler for current interrupt is finished.
#define RTC_FREQUENCY_1024HZ 0b110
#define RTC_DIVIDER_33KHZ (0b010 << 4)
-typedef struct
-{
- uint32_t year; // use int32 as we need to store the 4-digit year
- uint8_t month;
- uint8_t day;
- uint8_t weekday;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
-} rtc_datetime;
-
void
rtc_init();
void
rtc_write_reg(uint8_t reg_selector, uint8_t val);
-void
-rtc_get_datetime(rtc_datetime* datetime);
-
void
rtc_enable_timer();
--- /dev/null
+#ifndef __LUNAIX_CONSTANTS_H
+#define __LUNAIX_CONSTANTS_H
+
+#include <stddef.h>
+
+#define K_STACK_SIZE (64 << 10)
+#define K_STACK_START ((0xFFBFFFFFU - K_STACK_SIZE) + 1)
+#define HIGHER_HLF_BASE 0xC0000000UL
+#define MEM_1MB 0x100000UL
+
+#define VGA_BUFFER_VADDR 0xB0000000UL
+#define VGA_BUFFER_PADDR 0xB8000UL
+#define VGA_BUFFER_SIZE 4096
+
+#define SYS_TIMER_FREQUENCY_HZ 2048
+
+
+// From Linux kernel v2.6.0 <kernel.h:194>
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#endif /* __LUNAIX_CONSTANTS_H */
+++ /dev/null
-#ifndef __LUNAIX_CONSTANTS_H
-#define __LUNAIX_CONSTANTS_H
-
-#define K_STACK_SIZE (64 << 10)
-#define K_STACK_START ((0xFFBFFFFFU - K_STACK_SIZE) + 1)
-#define HIGHER_HLF_BASE 0xC0000000UL
-#define MEM_1MB 0x100000UL
-
-#define VGA_BUFFER_VADDR 0xB0000000UL
-#define VGA_BUFFER_PADDR 0xB8000UL
-#define VGA_BUFFER_SIZE 4096
-
-#endif /* __LUNAIX_CONSTANTS_H */
--- /dev/null
+/**
+ * @file llist.h
+ * @author Lunaixsky
+ * @brief This doubly linked cyclic list is adopted from Linux kernel <linux/list.h>
+ * @version 0.1
+ * @date 2022-03-12
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#ifndef __LUNAIX_LLIST_H
+#define __LUNAIX_LLIST_H
+
+#include <lunaix/common.h>
+
+struct llist_header
+{
+ struct llist_header* prev;
+ struct llist_header* next;
+};
+
+static inline void
+__llist_add(struct llist_header* elem,
+ struct llist_header* prev,
+ struct llist_header* next)
+{
+ next->prev = elem;
+ elem->next = next;
+ elem->prev = prev;
+ prev->next = elem;
+}
+
+static inline void
+llist_init_head(struct llist_header* head) {
+ head->next = head;
+ head->prev = head;
+}
+
+static inline void
+llist_append(struct llist_header* head, struct llist_header* elem)
+{
+ __llist_add(elem, head, head->next);
+}
+
+static inline void
+llist_prepend(struct llist_header* head, struct llist_header* elem)
+{
+ __llist_add(elem, head->prev, head);
+}
+
+static inline void
+llist_delete(struct llist_header* elem) {
+ elem->prev->next = elem->next;
+ elem->next->prev = elem->next;
+
+ // make elem orphaned
+ elem->prev = elem;
+ elem->next = elem;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define llist_for_each(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#endif /* __LUNAIX_LLIST_H */
#ifndef __LUNAIX_PAGE_H
#define __LUNAIX_PAGE_H
#include <stdint.h>
-#include <lunaix/constants.h>
+#include <lunaix/common.h>
#define PG_SIZE_BITS 12
#define PG_SIZE (1 << PG_SIZE_BITS)
--- /dev/null
+#ifndef __LUNAIX_TIME_H
+#define __LUNAIX_TIME_H
+
+#include <stdint.h>
+
+typedef struct
+{
+ uint32_t year; // use int32 as we need to store the 4-digit year
+ uint8_t month;
+ uint8_t day;
+ uint8_t weekday;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+} datetime_t;
+
+void
+time_getdatetime(datetime_t* datetime);
+
+#endif /* __LUNAIX_TIME_H */
--- /dev/null
+#ifndef __LUNAIX_TIMER_H
+#define __LUNAIX_TIMER_H
+
+#include <lunaix/ds/llist.h>
+#include <stdint.h>
+
+#define SYS_TIMER_FREQUENCY_HZ 2048UL
+
+#define TIMER_MODE_PERIODIC 0x1
+
+struct lx_timer_context {
+ struct lx_timer *active_timers;
+ uint32_t base_frequency;
+ uint32_t running_frequency;
+ uint32_t tick_interval;
+};
+
+struct lx_timer {
+ struct llist_header link;
+ uint32_t deadline;
+ uint32_t counter;
+ void* payload;
+ void (*callback)(void*);
+ uint8_t flags;
+};
+
+
+/**
+ * @brief Initialize the system timer that runs at specified frequency
+ *
+ * @param frequency The frequency that timer should run in Hz.
+ */
+void
+timer_init(uint32_t frequency);
+
+int
+timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags);
+
+int
+timer_run(uint32_t ticks, void (*callback)(void*), void* payload, uint8_t flags);
+
+#endif /* __LUNAIX_TIMER_H */
#include <lunaix/syslog.h>
#include <lunaix/tty/tty.h>
-int_subscriber subscribers[256];
+static int_subscriber subscribers[256];
static int_subscriber fallback = (int_subscriber) 0;
-#include <lunaix/constants.h>
+#include <lunaix/common.h>
#include <lunaix/tty/tty.h>
#include <lunaix/mm/page.h>
#include <lunaix/mm/kalloc.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
+#include <lunaix/timer.h>
#include <hal/rtc.h>
#include <hal/apic.h>
extern uint8_t __kernel_end;
extern uint8_t __init_hhk_end;
+
+// Set remotely by kernel/asm/x86/prologue.S
multiboot_info_t* _k_init_mb_info;
LOG_MODULE("INIT");
vmm_set_mapping(IOAPIC_BASE_VADDR, ioapic_addr, PG_PREM_RW);
ioapic_init();
- init_apic();
+ apic_init();
+ timer_init(SYS_TIMER_FREQUENCY_HZ);
for (size_t i = 256; i < hhk_init_pg_count; i++) {
vmm_unmap_page((void*)(i << PG_SIZE_BITS));
#include <hal/cpu.h>
-#include <hal/rtc.h>
#include <lunaix/syslog.h>
#include <lunaix/mm/kalloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/spike.h>
+#include <lunaix/time.h>
+#include <lunaix/timer.h>
#include <stdint.h>
extern uint8_t __kernel_start;
LOG_MODULE("LX")
+void
+test_timer(void* payload);
+
void
_kernel_main()
{
lxfree(arr);
lxfree(big_);
+ timer_run_second(1, test_timer, NULL, TIMER_MODE_PERIODIC);
+
spin();
+}
+
+static datetime_t datetime;
+
+void test_timer(void* payload) {
+ time_getdatetime(&datetime);
+
+ kprintf(KWARN "%u/%02u/%02u %02u:%02u:%02u\r",
+ datetime.year,
+ datetime.month,
+ datetime.day,
+ datetime.hour,
+ datetime.minute,
+ datetime.second);
}
\ No newline at end of file
#define MAX_KPRINTF_BUF_SIZE 1024
#define MAX_XFMT_SIZE 1024
-char buf[MAX_KPRINTF_BUF_SIZE];
+static char buf[MAX_KPRINTF_BUF_SIZE];
void
__kprintf(const char* component, const char* fmt, va_list args) {
#include <lunaix/mm/kalloc.h>
#include <lunaix/mm/dmm.h>
-#include <lunaix/constants.h>
+#include <lunaix/common.h>
#include <lunaix/spike.h>
#include <klibc/string.h>
extern uint8_t __kernel_heap_start;
-heap_context_t __kalloc_kheap;
+static heap_context_t __kalloc_kheap;
void*
lx_malloc_internal(heap_context_t* heap, size_t size);
uint32_t leading_shifts = \
(page_count + offset) < 8 ? page_count : 8 - offset;
-uint8_t pm_bitmap[PM_BMP_MAX_SIZE];
+static uint8_t pm_bitmap[PM_BMP_MAX_SIZE];
-uintptr_t max_pg;
+static uintptr_t max_pg;
// ... |xxxx xxxx |
// ... |-->|
--- /dev/null
+/**
+ * @file timer.c
+ * @author Lunaixsky
+ * @brief A simple timer implementation based on APIC with adjustable frequency and subscribable "timerlets"
+ * @version 0.1
+ * @date 2022-03-12
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#include <arch/x86/interrupts.h>
+#include <hal/apic.h>
+#include <hal/rtc.h>
+
+#include <lunaix/mm/kalloc.h>
+#include <lunaix/spike.h>
+#include <lunaix/syslog.h>
+#include <lunaix/time.h>
+#include <lunaix/timer.h>
+
+#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector)
+
+
+LOG_MODULE("TIMER");
+
+static void
+temp_intr_routine_rtc_tick(const isr_param* param);
+
+static void
+temp_intr_routine_apic_timer(const isr_param* param);
+
+static void
+timer_update(const isr_param* param);
+
+static volatile struct lx_timer_context* timer_ctx;
+
+// Don't optimize them! Took me an half hour to figure that out...
+
+static volatile uint32_t rtc_counter = 0;
+static volatile uint8_t apic_timer_done = 0;
+
+#define APIC_CALIBRATION_CONST 0x100000
+
+void
+timer_init_context()
+{
+ timer_ctx =
+ (struct lx_timer_context*)lxmalloc(sizeof(struct lx_timer_context));
+
+ assert_msg(timer_ctx, "Fail to initialize timer contex");
+
+ timer_ctx->active_timers =
+ (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
+ llist_init_head(timer_ctx->active_timers);
+}
+
+void
+timer_init(uint32_t frequency)
+{
+ timer_init_context();
+
+ cpu_disable_interrupt();
+
+ // Setup APIC timer
+
+ // Setup a one-shot timer, we will use this to measure the bus speed. So we
+ // can
+ // then calibrate apic timer to work at *nearly* accurate hz
+ apic_write_reg(APIC_TIMER_LVT,
+ LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_ONESHOT));
+
+ // Set divider to 64
+ apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64);
+
+ /*
+ Timer calibration process - measure the APIC timer base frequency
+
+ step 1: setup a temporary isr for RTC timer which trigger at each tick
+ (1024Hz) step 2: setup a temporary isr for #APIC_TIMER_IV step 3: setup
+ the divider, APIC_TIMER_DCR step 4: Startup RTC timer step 5: Write a
+ large value, v, to APIC_TIMER_ICR to start APIC timer (this must be
+ followed immediately after step 4) step 6: issue a write to EOI and clean
+ up.
+
+ When the APIC ICR counting down to 0 #APIC_TIMER_IV triggered, save the
+ rtc timer's counter, k, and disable RTC timer immediately (although the
+ RTC interrupts should be blocked by local APIC as we are currently busy
+ on handling #APIC_TIMER_IV)
+
+ So the apic timer frequency F_apic in Hz can be calculate as
+ v / F_apic = k / 1024
+ => F_apic = v / k * 1024
+
+ */
+
+ timer_ctx->base_frequency = 0;
+ rtc_counter = 0;
+ apic_timer_done = 0;
+
+ intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
+ intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
+
+ rtc_enable_timer(); // start RTC timer
+ apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); // start APIC timer
+
+ // enable interrupt, just for our RTC start ticking!
+ cpu_enable_interrupt();
+
+ wait_until(apic_timer_done);
+
+ // cpu_disable_interrupt();
+
+ assert_msg(timer_ctx->base_frequency, "Fail to initialize timer (NOFREQ)");
+
+ kprintf(KINFO "Base frequency: %u Hz\n", timer_ctx->base_frequency);
+
+ timer_ctx->running_frequency = frequency;
+ timer_ctx->tick_interval = timer_ctx->base_frequency / frequency;
+
+ // cleanup
+ intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
+ intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
+
+ apic_write_reg(APIC_TIMER_LVT,
+ LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC));
+ intr_subscribe(APIC_TIMER_IV, timer_update);
+
+ apic_write_reg(APIC_TIMER_ICR, timer_ctx->tick_interval);
+}
+
+int
+timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags)
+{
+ return timer_run(second * timer_ctx->running_frequency, callback, payload, flags);
+}
+
+int
+timer_run(uint32_t ticks, void (*callback)(void*), void* payload, uint8_t flags)
+{
+ struct lx_timer* timer = (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
+
+ if (!timer) return 0;
+
+ timer->callback = callback;
+ timer->counter = ticks;
+ timer->deadline = ticks;
+ timer->payload = payload;
+ timer->flags = flags;
+
+ llist_append(timer_ctx->active_timers, timer);
+
+ return 1;
+}
+
+static void
+timer_update(const isr_param* param)
+{
+ struct lx_timer *pos, *n;
+ struct lx_timer* timer_list_head = timer_ctx->active_timers;
+
+ llist_for_each(pos, n, &timer_list_head->link, link)
+ {
+ if (--pos->counter) {
+ continue;
+ }
+
+ pos->callback ? pos->callback(pos->payload) : 1;
+
+ if (pos->flags & TIMER_MODE_PERIODIC) {
+ pos->counter = pos->deadline;
+ } else {
+ llist_delete(pos);
+ lxfree(pos);
+ }
+ }
+}
+
+static void
+temp_intr_routine_rtc_tick(const isr_param* param)
+{
+ rtc_counter++;
+
+ // dummy read on register C so RTC can send anther interrupt
+ // This strange behaviour observed in virtual box & bochs
+ (void)rtc_read_reg(RTC_REG_C);
+}
+
+static void
+temp_intr_routine_apic_timer(const isr_param* param)
+{
+ timer_ctx->base_frequency =
+ APIC_CALIBRATION_CONST / rtc_counter * RTC_TIMER_BASE_FREQUENCY;
+ apic_timer_done = 1;
+
+ rtc_disable_timer();
+}
\ No newline at end of file
#include <klibc/string.h>
#include <lunaix/tty/tty.h>
-#include <lunaix/constants.h>
+#include <lunaix/common.h>
#include <stdint.h>
#define TTY_WIDTH 80
#define TTY_HEIGHT 25
-vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR;
+static vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR;
-vga_attribute tty_theme_color = VGA_COLOR_BLACK;
+static vga_attribute tty_theme_color = VGA_COLOR_BLACK;
-uint32_t tty_x = 0;
-uint16_t tty_y = 0;
+static uint32_t tty_x = 0;
+static uint16_t tty_y = 0;
void tty_init(void* vga_buf) {
tty_vga_buffer = (vga_attribute*)vga_buf;