From ea416765bfc46b58cc0542891849fcf66f477009 Mon Sep 17 00:00:00 2001 From: Teodor Date: Tue, 14 Apr 2026 16:04:17 +0000 Subject: [PATCH] Assignment 3 (only src and notes) --- notes/work-summary-2026-04-11-to-14.md | 0 src/OSDev_18/CMakeLists.txt | 4 + src/OSDev_18/include/kernel/gdt.h | 18 ++-- src/OSDev_18/include/kernel/idt.h | 24 +++++ src/OSDev_18/include/kernel/interrupt.h | 54 ++++++++++ src/OSDev_18/include/kernel/io.h | 20 ++++ src/OSDev_18/include/kernel/keyboard.h | 11 ++ src/OSDev_18/include/kernel/terminal.h | 18 ++-- src/OSDev_18/src/arch/i386/gdt_flush.asm | 4 +- src/OSDev_18/src/gdt.c | 18 ++-- src/OSDev_18/src/idt.c | 39 +++++++ src/OSDev_18/src/interrupt.asm | 130 +++++++++++++++++++++++ src/OSDev_18/src/interrupt.c | 114 ++++++++++++++++++++ src/OSDev_18/src/kernel.c | 14 ++- src/OSDev_18/src/keyboard.c | 43 ++++++++ src/OSDev_18/src/terminal.c | 67 +++++++++--- 16 files changed, 531 insertions(+), 47 deletions(-) create mode 100644 notes/work-summary-2026-04-11-to-14.md create mode 100644 src/OSDev_18/include/kernel/idt.h create mode 100644 src/OSDev_18/include/kernel/interrupt.h create mode 100644 src/OSDev_18/include/kernel/io.h create mode 100644 src/OSDev_18/include/kernel/keyboard.h create mode 100644 src/OSDev_18/src/idt.c create mode 100644 src/OSDev_18/src/interrupt.asm create mode 100644 src/OSDev_18/src/interrupt.c create mode 100644 src/OSDev_18/src/keyboard.c diff --git a/notes/work-summary-2026-04-11-to-14.md b/notes/work-summary-2026-04-11-to-14.md new file mode 100644 index 0000000..e69de29 diff --git a/src/OSDev_18/CMakeLists.txt b/src/OSDev_18/CMakeLists.txt index e41252c..4bbbe1c 100644 --- a/src/OSDev_18/CMakeLists.txt +++ b/src/OSDev_18/CMakeLists.txt @@ -63,6 +63,10 @@ add_executable(uiaos-kernel src/kernel.c src/gdt.c src/terminal.c + src/idt.c + src/interrupt.c + src/interrupt.asm + src/keyboard.c ) diff --git a/src/OSDev_18/include/kernel/gdt.h b/src/OSDev_18/include/kernel/gdt.h index 31d9d9e..37a10d8 100644 --- a/src/OSDev_18/include/kernel/gdt.h +++ b/src/OSDev_18/include/kernel/gdt.h @@ -8,19 +8,19 @@ #define GDT_DATA_SELECTOR 0x10 struct GdtEntry { - uint16_t limit_low; - uint16_t base_low; - uint8_t base_middle; - uint8_t access; - uint8_t granularity; - uint8_t base_high; + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; } __attribute__((packed)); struct GdtDescriptor { - uint16_t size; - uint32_t offset; + uint16_t size; + uint32_t offset; } __attribute__((packed)); -void gdtInitialize(void); +void GdtInitialize(void); #endif \ No newline at end of file diff --git a/src/OSDev_18/include/kernel/idt.h b/src/OSDev_18/include/kernel/idt.h new file mode 100644 index 0000000..d90ca18 --- /dev/null +++ b/src/OSDev_18/include/kernel/idt.h @@ -0,0 +1,24 @@ +#ifndef KERNEL_IDT_H +#define KERNEL_IDT_H + +#include + +#define IDT_ENTRIES 256 + +struct IdtEntry{ + uint16_t interrupt_low; + uint16_t kernel_cs; + uint8_t reserved; + uint8_t attributes; + uint16_t interrupt_high; +} __attribute__((packed)); + +struct Idtr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +void IdtInitialize(void); +void IdtSetDescriptor(uint8_t vector, uint32_t interrupt, uint8_t flags); + +#endif \ No newline at end of file diff --git a/src/OSDev_18/include/kernel/interrupt.h b/src/OSDev_18/include/kernel/interrupt.h new file mode 100644 index 0000000..c6633f0 --- /dev/null +++ b/src/OSDev_18/include/kernel/interrupt.h @@ -0,0 +1,54 @@ +#ifndef KERNEL_INTERRUPT_H +#define KERNEL_INTERRUPT_H + +#include + +#define IRQ0 32 +#define IRQ1 33 +#define IRQ2 34 +#define IRQ3 35 +#define IRQ4 36 +#define IRQ5 37 +#define IRQ6 38 +#define IRQ7 39 +#define IRQ8 40 +#define IRQ9 41 +#define IRQ10 42 +#define IRQ11 43 +#define IRQ12 44 +#define IRQ13 45 +#define IRQ14 46 +#define IRQ15 47 + +struct Registers { + uint32_t ds; + + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + + uint32_t int_no; + uint32_t err_code; + + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t useresp; + uint32_t ss; +}; + +void PicSendEoi(uint8_t irqNum); +void PicRemap(void); + +void IsrHandler(struct Registers* registers); +void IrqHandler(struct Registers* registers); + +typedef void (*InterruptHandler)(struct Registers* registers); +void RegisterInterruptHandler(uint8_t iNum, InterruptHandler handler); + +#endif \ No newline at end of file diff --git a/src/OSDev_18/include/kernel/io.h b/src/OSDev_18/include/kernel/io.h new file mode 100644 index 0000000..74101ee --- /dev/null +++ b/src/OSDev_18/include/kernel/io.h @@ -0,0 +1,20 @@ +#ifndef KERNEL_IO_H +#define KERNEL_IO_H + +#include + +static inline void OutPortByte(uint16_t port, uint8_t val) { + __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); +} + +static inline uint8_t InPortByte(uint16_t port) { + uint8_t ret; + __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline void IoWait(void) { + __asm__ volatile ("outb %%al, $0x80" : : "a"(0)); +} + +#endif \ No newline at end of file diff --git a/src/OSDev_18/include/kernel/keyboard.h b/src/OSDev_18/include/kernel/keyboard.h new file mode 100644 index 0000000..876f15a --- /dev/null +++ b/src/OSDev_18/include/kernel/keyboard.h @@ -0,0 +1,11 @@ +#ifndef KERNEL_KEYBOARD_H +#define KERNEL_KEYBOARD_H + +#include + +#define KEYBOARD_DATA_PORT 0x60 +#define KEYBOARD_BUFFER_SIZE 256 + +void KeyboardHandler(struct Registers* registers); + +#endif \ No newline at end of file diff --git a/src/OSDev_18/include/kernel/terminal.h b/src/OSDev_18/include/kernel/terminal.h index 7bd7a57..382433d 100644 --- a/src/OSDev_18/include/kernel/terminal.h +++ b/src/OSDev_18/include/kernel/terminal.h @@ -23,14 +23,16 @@ enum vga_colour{ VGA_COLOR_WHITE = 15, }; -uint8_t vgaEntryColour(enum vga_colour fg, enum vga_colour bg); -uint16_t vgaEntry(unsigned char uc, uint8_t color); +uint8_t VgaEntryColour(enum vga_colour fg, enum vga_colour bg); +uint16_t VgaEntry(unsigned char uc, uint8_t color); -void terminalEntryAt(char c, uint8_t colour, size_t x, size_t y); -void terminalInitialize(void); -void terminalSetColour(uint8_t colour); -void terminalPutChar(char c); -void terminalWrite(const char* data, size_t size); -void terminalWriteString(const char* data); +void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y); +void TerminalInitialize(void); +void TerminalSetColour(uint8_t colour); +void TerminalUpdateCursor(void); +void TerminalPutChar(char c); +void TerminalWrite(const char* data, size_t size); +void TerminalWriteString(const char* data); +void TerminalWriteUInt(uint32_t num); #endif \ No newline at end of file diff --git a/src/OSDev_18/src/arch/i386/gdt_flush.asm b/src/OSDev_18/src/arch/i386/gdt_flush.asm index f13701e..5178985 100644 --- a/src/OSDev_18/src/arch/i386/gdt_flush.asm +++ b/src/OSDev_18/src/arch/i386/gdt_flush.asm @@ -1,12 +1,12 @@ %define GDT_CODE_SELECTOR 0x08 %define GDT_DATA_SELECTOR 0x10 -global gdtFlush +global GdtFlush section .text bits 32 -gdtFlush: +GdtFlush: mov eax, [esp + 4] lgdt [eax] diff --git a/src/OSDev_18/src/gdt.c b/src/OSDev_18/src/gdt.c index 58743c6..dce88d3 100644 --- a/src/OSDev_18/src/gdt.c +++ b/src/OSDev_18/src/gdt.c @@ -3,14 +3,14 @@ static struct GdtEntry gdtEntries[3]; static struct GdtDescriptor gdtDescriptor; -extern void gdtFlush(uint32_t gdtDescriptorAddress); +extern void GdtFlush(uint32_t gdtDescriptorAddress); -static void gdtSetEntry( +static void GdtSetEntry( uint32_t index, uint32_t base, uint32_t limit, - uint8_t access, - uint8_t granularity + uint8_t access, + uint8_t granularity ) { gdtEntries[index].base_low = (uint16_t)(base & 0xFFFF); gdtEntries[index].base_middle = (uint8_t)((base >> 16) & 0xFF); @@ -22,17 +22,17 @@ static void gdtSetEntry( gdtEntries[index].access = access; } -void gdtInitialize(void) { +void GdtInitialize(void) { gdtDescriptor.size = sizeof(gdtEntries) - 1; gdtDescriptor.offset = (uint32_t)&gdtEntries; - gdtSetEntry(0, 0, 0, 0, 0); + GdtSetEntry(0, 0, 0, 0, 0); // Kernel code segment: base 0, 4 GiB span, ring 0, executable, readable - gdtSetEntry(1, 0, 0x000FFFFF, 0x9A, 0xCF); + GdtSetEntry(1, 0, 0x000FFFFF, 0x9A, 0xCF); // Kernel data segment: base 0, 4 GiB span, ring 0, writable - gdtSetEntry(2, 0, 0x000FFFFF, 0x92, 0xCF); + GdtSetEntry(2, 0, 0x000FFFFF, 0x92, 0xCF); - gdtFlush((uint32_t)&gdtDescriptor); + GdtFlush((uint32_t)&gdtDescriptor); } \ No newline at end of file diff --git a/src/OSDev_18/src/idt.c b/src/OSDev_18/src/idt.c new file mode 100644 index 0000000..3d53175 --- /dev/null +++ b/src/OSDev_18/src/idt.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +static struct IdtEntry idt[IDT_ENTRIES]; +static struct Idtr idtr; + +void IdtSetDescriptor(uint8_t vector, uint32_t interrupt, uint8_t flags) { + struct IdtEntry* descriptor = &idt[vector]; + + descriptor->interrupt_low = (uint32_t)interrupt & 0xFFFF; + descriptor->kernel_cs = GDT_CODE_SELECTOR; + descriptor->attributes = flags; + descriptor->interrupt_high = (uint32_t)interrupt >> 16; + descriptor->reserved = 0; +} + +extern void* isr_stub_table[]; +extern void* irq_stub_table[]; + +void IdtInitialize(void) { + idtr.base = (uint32_t)&idt[0]; + idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_ENTRIES - 1; + + for (uint8_t iNum = 0; iNum < 32; iNum++) { + IdtSetDescriptor(iNum, (uint32_t)isr_stub_table[iNum], 0x8E); + } + + for (uint8_t iNum = 32; iNum < 48; iNum++) { + IdtSetDescriptor(iNum, (uint32_t)irq_stub_table[iNum - 32], 0x8E); + } + + PicRemap(); + + __asm__ volatile ("lidt %0" : : "m"(idtr)); + __asm__ volatile ("sti"); +} + diff --git a/src/OSDev_18/src/interrupt.asm b/src/OSDev_18/src/interrupt.asm new file mode 100644 index 0000000..55e1338 --- /dev/null +++ b/src/OSDev_18/src/interrupt.asm @@ -0,0 +1,130 @@ +extern IsrHandler +extern IrqHandler + +isr_common_stub: + pusha + mov ax, ds + push eax + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + push esp + call IsrHandler + add esp, 4 + pop eax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + popa + add esp, 8 + iret + +irq_common_stub: + pusha + mov ax, ds + push eax + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + push esp + call IrqHandler + add esp, 4 + pop eax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + popa + add esp, 8 + iret + +%macro isr_no_err_stub 1 +isr_stub_%+%1: + push dword 0 + push dword %1 + jmp isr_common_stub +%endmacro + +%macro isr_err_stub 1 +isr_stub_%+%1: + push dword %1 + jmp isr_common_stub +%endmacro + +%macro irq_stub 1 +irq_stub_%+%1: + push dword 0 + push dword (32 + %1) + jmp irq_common_stub +%endmacro + +isr_no_err_stub 0 +isr_no_err_stub 1 +isr_no_err_stub 2 +isr_no_err_stub 3 +isr_no_err_stub 4 +isr_no_err_stub 5 +isr_no_err_stub 6 +isr_no_err_stub 7 +isr_err_stub 8 +isr_no_err_stub 9 +isr_err_stub 10 +isr_err_stub 11 +isr_err_stub 12 +isr_err_stub 13 +isr_err_stub 14 +isr_no_err_stub 15 +isr_no_err_stub 16 +isr_err_stub 17 +isr_no_err_stub 18 +isr_no_err_stub 19 +isr_no_err_stub 20 +isr_no_err_stub 21 +isr_no_err_stub 22 +isr_no_err_stub 23 +isr_no_err_stub 24 +isr_no_err_stub 25 +isr_no_err_stub 26 +isr_no_err_stub 27 +isr_no_err_stub 28 +isr_no_err_stub 29 +isr_err_stub 30 +isr_no_err_stub 31 + +irq_stub 0 +irq_stub 1 +irq_stub 2 +irq_stub 3 +irq_stub 4 +irq_stub 5 +irq_stub 6 +irq_stub 7 +irq_stub 8 +irq_stub 9 +irq_stub 10 +irq_stub 11 +irq_stub 12 +irq_stub 13 +irq_stub 14 +irq_stub 15 + +global isr_stub_table +isr_stub_table: +%assign i 0 +%rep 32 + dd isr_stub_%+i +%assign i i+1 +%endrep + +global irq_stub_table +irq_stub_table: +%assign i 0 +%rep 16 + dd irq_stub_%+i +%assign i i+1 +%endrep \ No newline at end of file diff --git a/src/OSDev_18/src/interrupt.c b/src/OSDev_18/src/interrupt.c new file mode 100644 index 0000000..33602aa --- /dev/null +++ b/src/OSDev_18/src/interrupt.c @@ -0,0 +1,114 @@ +#include +#include +#include + +#define PIC1_COMMAND 0x20 +#define PIC1_DATA 0x21 +#define PIC2_COMMAND 0xA0 +#define PIC2_DATA 0xA1 +#define PIC_EOI 0x20 + +static InterruptHandler interruptHandlers[256]; + +const char* isrMessages[] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Overflow", + "Bound Range Exceeded", + "Invalid Opcode", + "Device Not Available", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack-Segment Fault", + "General Protection Fault", + "Page Fault", + "Reserved", + "x87 Floating-Point Exception", + "Alignment Check", + "Machine Check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +void PicSendEoi(uint8_t irqNum) { + if (irqNum >= 8) { + OutPortByte(PIC2_COMMAND, PIC_EOI); + } + OutPortByte(PIC1_COMMAND, PIC_EOI); +} + +void PicRemap(void) { + OutPortByte(PIC1_COMMAND, 0x11); + OutPortByte(PIC2_COMMAND, 0x11); + + OutPortByte(PIC1_DATA, 0x20); + OutPortByte(PIC2_DATA, 0x28); + + OutPortByte(PIC1_DATA, 0x04); + OutPortByte(PIC2_DATA, 0x02); + + OutPortByte(PIC1_DATA, 0x01); + OutPortByte(PIC2_DATA, 0x01); + + OutPortByte(PIC1_DATA, 0x00); + OutPortByte(PIC2_DATA, 0x00); +} + +void IsrHandler(struct Registers* registers) { + TerminalWriteString("\n=== INTERRUPT RECEIVED ===\n"); + + TerminalWriteString("Interrupt Number: "); + TerminalWriteUInt(registers->int_no); + TerminalWriteString("\n"); + + TerminalWriteString("Message: "); + if (registers->int_no < 32) { + TerminalWriteString(isrMessages[registers->int_no]); + } else { + TerminalWriteString("Unknown Interrupt"); + } + TerminalWriteString("\n"); + + TerminalWriteString("Error Code: "); + TerminalWriteUInt(registers->err_code); + TerminalWriteString("\n"); + + TerminalWriteString("==========================\n"); + + for (;;) { + __asm__ volatile("cli; hlt"); + } +} + +void RegisterInterruptHandler(uint8_t iNum, InterruptHandler handler) { + interruptHandlers[iNum] = handler; +} + +void IrqHandler(struct Registers* registers) { + uint8_t irqNum = (uint8_t)(registers->int_no - 32); + + if (interruptHandlers[registers->int_no] != 0) { + interruptHandlers[registers->int_no](registers); + } else if (irqNum != 0) { + TerminalWriteString("IRQ triggered: "); + TerminalWriteUInt(irqNum); + TerminalWriteString("\n"); + } + + PicSendEoi(irqNum); +} diff --git a/src/OSDev_18/src/kernel.c b/src/OSDev_18/src/kernel.c index 4fcfd48..b354461 100644 --- a/src/OSDev_18/src/kernel.c +++ b/src/OSDev_18/src/kernel.c @@ -1,14 +1,18 @@ #include #include #include +#include +#include +#include void main(void) { - gdtInitialize(); + TerminalInitialize(); + GdtInitialize(); + IdtInitialize(); + + RegisterInterruptHandler(IRQ1, KeyboardHandler); - terminalInitialize(); - terminalWriteString("Hello, World!\n"); - for (;;) { - __asm__ volatile ("hlt"); + __asm__ volatile("hlt"); } } \ No newline at end of file diff --git a/src/OSDev_18/src/keyboard.c b/src/OSDev_18/src/keyboard.c new file mode 100644 index 0000000..a62f24f --- /dev/null +++ b/src/OSDev_18/src/keyboard.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +static uint32_t index = 0; +static uint8_t keyboardBuffer[KEYBOARD_BUFFER_SIZE]; + +static const char scancodeToAscii[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', + 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', + 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, + '*', 0, ' ', 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', + '1', '2', '3', '0', '.', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void KeyboardHandler(struct Registers* registers) { + (void) registers; + + uint8_t scancode = InPortByte(KEYBOARD_DATA_PORT); + + if (index < KEYBOARD_BUFFER_SIZE) { + keyboardBuffer[index] = scancode; + index++; + } + + if (scancode & 0x80) { + return; + } + + if (scancode < 128) { + char ascii = scancodeToAscii[scancode]; + + if (ascii != 0) { + TerminalPutChar(ascii); + } + } +} \ No newline at end of file diff --git a/src/OSDev_18/src/terminal.c b/src/OSDev_18/src/terminal.c index 22a407d..316de0f 100644 --- a/src/OSDev_18/src/terminal.c +++ b/src/OSDev_18/src/terminal.c @@ -1,5 +1,6 @@ #include #include +#include const size_t VGA_HEIGHT = 25; const size_t VGA_WIDTH = 80; @@ -11,44 +12,55 @@ static uint8_t terminal_colour; static uint16_t* terminal_buffer = (uint16_t*) 0xB8000; // Builds the colour byte -uint8_t vgaEntryColour(enum vga_colour fg, enum vga_colour bg) { +uint8_t VgaEntryColour(enum vga_colour fg, enum vga_colour bg) { return fg | bg << 4; } // Builds the full cell -uint16_t vgaEntry(unsigned char uc, uint8_t color) { +uint16_t VgaEntry(unsigned char uc, uint8_t color) { return (uint16_t) uc | (uint16_t) color << 8; } -void terminalEntryAt(char c, uint8_t colour, size_t x, size_t y){ +void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y){ size_t index = y * VGA_WIDTH + x; - terminal_buffer[index] = vgaEntry(c, colour); + terminal_buffer[index] = VgaEntry(c, colour); } -void terminalInitialize(void) { +void TerminalInitialize(void) { terminal_row = 0; terminal_column = 0; - terminal_colour = vgaEntryColour(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + terminal_colour = VgaEntryColour(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); terminal_buffer = (uint16_t*) 0xB8000; for (size_t y = 0; y < VGA_HEIGHT; y++) { for (size_t x = 0; x < VGA_WIDTH; x++) { - terminalEntryAt(' ', terminal_colour, x, y); + TerminalEntryAt(' ', terminal_colour, x, y); } } } -void terminalSetColour(uint8_t colour) { +void TerminalSetColour(uint8_t colour) { terminal_colour = colour; } -void terminalPutChar(char c) { +void TerminalUpdateCursor(void) { + uint16_t pos = (uint16_t)(terminal_row * VGA_WIDTH + terminal_column); + + OutPortByte(0x3D4, 0x0F); + OutPortByte(0x3D5, (uint8_t)(pos & 0xFF)); + + OutPortByte(0x3D4, 0x0E); + OutPortByte(0x3D5, (uint8_t)((pos >> 8) & 0xFF)); +} + +void TerminalPutChar(char c) { if (c == '\n') { terminal_column = 0; terminal_row++; + TerminalUpdateCursor(); return; } - terminalEntryAt(c, terminal_colour,terminal_column, terminal_row); + TerminalEntryAt(c, terminal_colour,terminal_column, terminal_row); terminal_column++; if (terminal_column == VGA_WIDTH) { @@ -59,21 +71,48 @@ void terminalPutChar(char c) { if (terminal_row == VGA_HEIGHT) { terminal_row = 0; } + + TerminalUpdateCursor(); } -void terminalWrite(const char* data, size_t size) { +void TerminalWrite(const char* data, size_t size) { for (size_t i = 0; i < size; i++) { - terminalPutChar(data[i]); + TerminalPutChar(data[i]); } } -void terminalWriteString(const char* data) { +void TerminalWriteString(const char* data) { size_t len = 0; while (data[len] != '\0') { len++; } - terminalWrite(data, len); + TerminalWrite(data, len); +} + +void TerminalWriteUInt(uint32_t num) { + if (num == 0) { + TerminalPutChar('0'); + return; + } + + char buffer[10]; + size_t i = 0; + + while (num > 0) { + buffer[i++] = '0' + (num % 10); + num /= 10; + } + + for (size_t j = 0; j < i / 2; j++) { + char temp = buffer[j]; + buffer[j] = buffer[i - j - 1]; + buffer[i - j - 1] = temp; + } + + for (size_t j = 0; j < i; j++) { + TerminalPutChar(buffer[j]); + } }