Compare commits
7 Commits
56025d55f9
...
01f16ce210
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01f16ce210 | ||
|
|
bffea5b0c1 | ||
|
|
bbd4b62697 | ||
|
|
01e6022fa7 | ||
|
|
57ef424e00 | ||
|
|
1402a227f1 | ||
|
|
ff664b0687 |
@@ -5,8 +5,8 @@
|
|||||||
- `make`
|
- `make`
|
||||||
- `grub`
|
- `grub`
|
||||||
- `mtools`
|
- `mtools`
|
||||||
- `gcc`
|
- `x86_64-elf-gcc`
|
||||||
- `ld`
|
- `x86_64-elf-ld`
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
|||||||
32
makefile
32
makefile
@@ -1,8 +1,15 @@
|
|||||||
CC = gcc
|
CC = x86_64-elf-gcc
|
||||||
LD = ld
|
LD = x86_64-elf-ld
|
||||||
|
|
||||||
CFLAGS = -m32 -ffreestanding -fno-pie -fno-stack-protector -fno-builtin -Wall -Wextra -Werror -Wshadow -std=c23
|
CFLAGS = -m64 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23
|
||||||
LDFLAGS = -m elf_i386 -Ttext 0x100000 -nostdlib
|
LDFLAGS =
|
||||||
|
|
||||||
|
SRC_C := src/kernel.c src/vga.c src/idt.c src/string.c
|
||||||
|
SRC_ASM := src/boot.asm src/idt_stub.asm
|
||||||
|
|
||||||
|
OBJ_C := $(SRC_C:src/%.c=.build/%.o)
|
||||||
|
OBJ_ASM := $(SRC_ASM:src/%.asm=.build/%.o)
|
||||||
|
OBJS := $(OBJ_C) $(OBJ_ASM)
|
||||||
|
|
||||||
all: .build/nub-os.iso
|
all: .build/nub-os.iso
|
||||||
|
|
||||||
@@ -12,20 +19,17 @@ clean:
|
|||||||
build-dir:
|
build-dir:
|
||||||
mkdir .build 2>/dev/null || true
|
mkdir .build 2>/dev/null || true
|
||||||
|
|
||||||
.build/nub-os.iso: build-dir .build/kernel
|
.build/nub-os.iso: .build/kernel
|
||||||
mkdir -p .build/iso/boot/grub
|
mkdir -p .build/iso/boot/grub
|
||||||
cp grub.cfg .build/iso/boot/grub
|
cp grub.cfg .build/iso/boot/grub
|
||||||
cp .build/kernel .build/iso/boot/
|
cp .build/kernel .build/iso/boot/
|
||||||
grub-mkrescue -o .build/nub-os.iso .build/iso/
|
grub-mkrescue -o .build/nub-os.iso .build/iso/
|
||||||
|
|
||||||
.build/kernel: build-dir .build/boot.o .build/kernel.o .build/vga.o
|
.build/kernel: $(OBJS)
|
||||||
$(LD) $(LDFLAGS) -Ttext 0x100000 -o .build/kernel .build/boot.o .build/kernel.o .build/vga.o
|
$(LD) $(LDFLAGS) -T src/boot.ld -o $@ $^
|
||||||
|
|
||||||
.build/kernel.o: build-dir src/kernel.c
|
.build/%.o: src/%.c | build-dir
|
||||||
$(CC) $(CFLAGS) -c -o .build/kernel.o src/kernel.c
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
.build/vga.o: build-dir src/vga.c
|
.build/%.o: src/%.asm | build-dir
|
||||||
$(CC) $(CFLAGS) -c -o .build/vga.o src/vga.c
|
nasm -f elf64 -o $@ $<
|
||||||
|
|
||||||
.build/boot.o: build-dir src/boot.asm
|
|
||||||
nasm -f elf32 -o .build/boot.o src/boot.asm
|
|
||||||
183
src/boot.asm
183
src/boot.asm
@@ -3,6 +3,7 @@
|
|||||||
%define LEN header_end - header_start
|
%define LEN header_end - header_start
|
||||||
%define CHECKSUM -(MAGIC + ARCH + LEN)
|
%define CHECKSUM -(MAGIC + ARCH + LEN)
|
||||||
|
|
||||||
|
section .multiboot2
|
||||||
header_start:
|
header_start:
|
||||||
align 4
|
align 4
|
||||||
dd MAGIC
|
dd MAGIC
|
||||||
@@ -18,14 +19,186 @@ align 16
|
|||||||
resb 16384
|
resb 16384
|
||||||
stack_top:
|
stack_top:
|
||||||
|
|
||||||
extern kernel_main
|
align 4096
|
||||||
|
pml4_table:
|
||||||
|
resb 4096
|
||||||
|
pdp_table:
|
||||||
|
resb 4096
|
||||||
|
pd_table:
|
||||||
|
resb 4096
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
|
bits 32
|
||||||
global _start
|
global _start
|
||||||
_start:
|
_start:
|
||||||
mov esp, stack_top
|
|
||||||
call kernel_main
|
|
||||||
hang:
|
|
||||||
cli
|
cli
|
||||||
|
mov esp, stack_top
|
||||||
|
|
||||||
|
; Check if CPU supports 64-bit mode
|
||||||
|
call check_multiboot
|
||||||
|
call check_cpuid
|
||||||
|
call check_long_mode
|
||||||
|
|
||||||
|
; Set up paging for 64-bit mode
|
||||||
|
call set_up_page_tables
|
||||||
|
call enable_paging
|
||||||
|
|
||||||
|
; Load GDT and jump to 64-bit mode
|
||||||
|
lgdt [gdt64.pointer]
|
||||||
|
jmp gdt64.code:long_mode_start
|
||||||
|
|
||||||
|
check_multiboot:
|
||||||
|
cmp eax, 0x36d76289
|
||||||
|
jne .no_multiboot
|
||||||
|
ret
|
||||||
|
|
||||||
|
.no_multiboot:
|
||||||
|
mov al, 'M'
|
||||||
|
jmp error
|
||||||
|
|
||||||
|
check_cpuid:
|
||||||
|
; Copy flags to eax through the stack
|
||||||
|
pushfd
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
; Copy flags to ecx for a later comparison
|
||||||
|
mov ecx, eax
|
||||||
|
|
||||||
|
; Flit the cpuid bit
|
||||||
|
xor eax, 1 << 21
|
||||||
|
|
||||||
|
; Copy eax (with the flipped cpuid bit) back to flags
|
||||||
|
push eax
|
||||||
|
popfd
|
||||||
|
|
||||||
|
; Copy flags back to eax. The cpiuid bit will be flipped if cpuid is supported
|
||||||
|
pushfd
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
; Restore flags from the original flags stored in ecx
|
||||||
|
push ecx
|
||||||
|
popfd
|
||||||
|
|
||||||
|
; Compare eax and ecx. If thry are equal, cpuid is not supported
|
||||||
|
cmp eax, ecx
|
||||||
|
je .no_cpuid
|
||||||
|
ret
|
||||||
|
|
||||||
|
.no_cpuid:
|
||||||
|
mov al, 'I'
|
||||||
|
jmp error
|
||||||
|
|
||||||
|
check_long_mode:
|
||||||
|
; Test if extended processor info is available
|
||||||
|
mov eax, 0x80000000
|
||||||
|
cpuid
|
||||||
|
cmp eax, 0x80000001
|
||||||
|
jb .no_long_mode
|
||||||
|
|
||||||
|
; Test if long mode is available
|
||||||
|
mov eax, 0x80000001
|
||||||
|
cpuid
|
||||||
|
test edx, 1 << 29
|
||||||
|
jz .no_long_mode
|
||||||
|
ret
|
||||||
|
|
||||||
|
.no_long_mode:
|
||||||
|
mov al, 'L'
|
||||||
|
jmp error
|
||||||
|
|
||||||
|
; todo(nub): This is copy pasted. I will research hat it does later
|
||||||
|
set_up_page_tables:
|
||||||
|
; Map first PML4 entry to PDP table
|
||||||
|
mov eax, pdp_table
|
||||||
|
or eax, 0b11 ; present + writable
|
||||||
|
mov [pml4_table], eax
|
||||||
|
|
||||||
|
; Map first PDP entry to PD table
|
||||||
|
mov eax, pd_table
|
||||||
|
or eax, 0b11 ; present + writable
|
||||||
|
mov [pdp_table], eax
|
||||||
|
|
||||||
|
; Map each PD entry to a huge 2MiB page
|
||||||
|
mov ecx, 0 ; counter variable
|
||||||
|
.map_pd_table:
|
||||||
|
; Map ecx-th PD entry to a huge page that starts at address (2MiB * ecx)
|
||||||
|
mov eax, 0x200000 ; 2MiB
|
||||||
|
mul ecx ; Start address of ecx-th page
|
||||||
|
or eax, 0b10000011 ; present + writable + huge
|
||||||
|
mov [pd_table + ecx * 8], eax ; Map ecx-th entry
|
||||||
|
|
||||||
|
inc ecx ; Increase counter
|
||||||
|
cmp ecx, 512 ; If counter == 512, the whole PD table is mapped
|
||||||
|
jne .map_pd_table ; Else map the next entry
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
; todo(nub): This is copy pasted. I will research hat it does later
|
||||||
|
enable_paging:
|
||||||
|
; Load PML4 to cr3 register (cpu uses this to access the PML4 table)
|
||||||
|
mov eax, pml4_table
|
||||||
|
mov cr3, eax
|
||||||
|
|
||||||
|
; Enable PAE-flag in cr4 (Physical Address Extension)
|
||||||
|
mov eax, cr4
|
||||||
|
or eax, 1 << 5
|
||||||
|
mov cr4, eax
|
||||||
|
|
||||||
|
; Set the long mode bit in the EFER MSR (model specific register)
|
||||||
|
mov ecx, 0xC0000080
|
||||||
|
rdmsr
|
||||||
|
or eax, 1 << 8
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
; Enable paging in the cr0 register
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 1 << 31
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
error:
|
||||||
|
mov byte [0xb8000], '['
|
||||||
|
mov byte [0xb8002], ' '
|
||||||
|
mov byte [0xb8004], 'E'
|
||||||
|
mov byte [0xb8005], 4
|
||||||
|
mov byte [0xb8006], 'R'
|
||||||
|
mov byte [0xb8007], 4
|
||||||
|
mov byte [0xb8008], 'R'
|
||||||
|
mov byte [0xb8009], 4
|
||||||
|
mov byte [0xb800a], ' '
|
||||||
|
mov byte [0xb800c], ']'
|
||||||
|
mov byte [0xb800e], ':'
|
||||||
|
mov byte [0xb8010], ' '
|
||||||
|
mov byte [0xb8012], al
|
||||||
|
cli
|
||||||
|
.hang:
|
||||||
hlt
|
hlt
|
||||||
jmp hang
|
jmp .hang
|
||||||
|
|
||||||
|
section .rodata
|
||||||
|
gdt64:
|
||||||
|
dq 0
|
||||||
|
.code: equ $ - gdt64
|
||||||
|
dq (1<<43) | (1<<44) | (1<<47) | (1<<53)
|
||||||
|
.pointer:
|
||||||
|
dw $ - gdt64 - 1
|
||||||
|
dq gdt64
|
||||||
|
|
||||||
|
section .text
|
||||||
|
bits 64
|
||||||
|
long_mode_start:
|
||||||
|
mov ax, 0
|
||||||
|
mov ss, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
|
||||||
|
extern kernel_main
|
||||||
|
call kernel_main
|
||||||
|
|
||||||
|
cli
|
||||||
|
.hang:
|
||||||
|
hlt
|
||||||
|
jmp .hang
|
||||||
28
src/boot.ld
Normal file
28
src/boot.ld
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 2M;
|
||||||
|
|
||||||
|
.text BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.multiboot2)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/idt.c
Normal file
74
src/idt.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "idt.h"
|
||||||
|
#include "vga.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t address_low;
|
||||||
|
uint16_t selector;
|
||||||
|
uint8_t ist;
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t address_mid;
|
||||||
|
uint32_t address_high;
|
||||||
|
uint32_t reserved;
|
||||||
|
} __attribute__((packed)) interrupt_descriptor;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t limit;
|
||||||
|
uint64_t base;
|
||||||
|
} __attribute__((packed)) idtr_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||||
|
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||||
|
uint64_t int_no;
|
||||||
|
uint64_t err_code;
|
||||||
|
uint64_t rip, cs, rflags, rsp, ss;
|
||||||
|
} __attribute__((packed)) isr_frame_t;
|
||||||
|
|
||||||
|
#define IDT_SIZE 256
|
||||||
|
|
||||||
|
extern void* isr_stub_table[];
|
||||||
|
|
||||||
|
static interrupt_descriptor idt[IDT_SIZE];
|
||||||
|
|
||||||
|
void idt_set_descriptor(uint8_t vector, void* handler, uint8_t dpl)
|
||||||
|
{
|
||||||
|
interrupt_descriptor* entry = &idt[vector];
|
||||||
|
|
||||||
|
entry->address_low = (uint64_t)handler & 0xFFFF;
|
||||||
|
entry->address_mid = ((uint64_t)handler >> 16) & 0xFFFF;
|
||||||
|
entry->address_high = (uint64_t)handler >> 32;
|
||||||
|
entry->selector = 0x08;
|
||||||
|
entry->flags = 0b1110 | ((dpl & 0b11) << 5) | (1 << 7);
|
||||||
|
entry->ist = 0;
|
||||||
|
entry->reserved = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exception_handler(isr_frame_t* frame)
|
||||||
|
{
|
||||||
|
vga_print("Interrupt\n");
|
||||||
|
vga_print(" int_no: ");
|
||||||
|
vga_print_uint(frame->int_no);
|
||||||
|
vga_print("\n");
|
||||||
|
vga_print(" err_code: ");
|
||||||
|
vga_print_uint(frame->err_code);
|
||||||
|
vga_print("\n");
|
||||||
|
__asm__ volatile("cli; hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
void idt_init(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
idt_set_descriptor(i, isr_stub_table[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
idtr_t idtr = { .base = (uintptr_t)&idt[0], .limit = (uint16_t)sizeof(interrupt_descriptor) * IDT_SIZE - 1 };
|
||||||
|
|
||||||
|
__asm__ volatile("lidt %0" : : "m"(idtr));
|
||||||
|
}
|
||||||
6
src/idt.h
Normal file
6
src/idt.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void idt_init(void);
|
||||||
|
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags);
|
||||||
121
src/idt_stub.asm
Normal file
121
src/idt_stub.asm
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
extern exception_handler
|
||||||
|
|
||||||
|
%macro ISR_NOERR 1
|
||||||
|
isr_stub_%1:
|
||||||
|
push qword 0
|
||||||
|
push qword %1
|
||||||
|
jmp isr_common
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro ISR_ERR 1
|
||||||
|
isr_stub_%1:
|
||||||
|
push qword %1
|
||||||
|
jmp isr_common
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
isr_common:
|
||||||
|
push rax
|
||||||
|
push rbx
|
||||||
|
push rcx
|
||||||
|
push rdx
|
||||||
|
push rsi
|
||||||
|
push rdi
|
||||||
|
push rbp
|
||||||
|
push r8
|
||||||
|
push r9
|
||||||
|
push r10
|
||||||
|
push r11
|
||||||
|
push r12
|
||||||
|
push r13
|
||||||
|
push r14
|
||||||
|
push r15
|
||||||
|
|
||||||
|
mov rdi, rsp
|
||||||
|
call exception_handler
|
||||||
|
|
||||||
|
pop r15
|
||||||
|
pop r14
|
||||||
|
pop r13
|
||||||
|
pop r12
|
||||||
|
pop r11
|
||||||
|
pop r10
|
||||||
|
pop r9
|
||||||
|
pop r8
|
||||||
|
pop rbp
|
||||||
|
pop rdi
|
||||||
|
pop rsi
|
||||||
|
pop rdx
|
||||||
|
pop rcx
|
||||||
|
pop rbx
|
||||||
|
pop rax
|
||||||
|
|
||||||
|
add rsp, 16
|
||||||
|
iretq
|
||||||
|
|
||||||
|
ISR_NOERR 0
|
||||||
|
ISR_NOERR 1
|
||||||
|
ISR_NOERR 2
|
||||||
|
ISR_NOERR 3
|
||||||
|
ISR_NOERR 4
|
||||||
|
ISR_NOERR 5
|
||||||
|
ISR_NOERR 6
|
||||||
|
ISR_NOERR 7
|
||||||
|
ISR_ERR 8
|
||||||
|
ISR_NOERR 9
|
||||||
|
ISR_ERR 10
|
||||||
|
ISR_ERR 11
|
||||||
|
ISR_ERR 12
|
||||||
|
ISR_ERR 13
|
||||||
|
ISR_ERR 14
|
||||||
|
ISR_NOERR 15
|
||||||
|
ISR_NOERR 16
|
||||||
|
ISR_ERR 17
|
||||||
|
ISR_NOERR 18
|
||||||
|
ISR_NOERR 19
|
||||||
|
ISR_NOERR 20
|
||||||
|
ISR_NOERR 21
|
||||||
|
ISR_NOERR 22
|
||||||
|
ISR_NOERR 23
|
||||||
|
ISR_NOERR 24
|
||||||
|
ISR_NOERR 25
|
||||||
|
ISR_NOERR 26
|
||||||
|
ISR_NOERR 27
|
||||||
|
ISR_NOERR 28
|
||||||
|
ISR_NOERR 29
|
||||||
|
ISR_ERR 30
|
||||||
|
ISR_NOERR 31
|
||||||
|
|
||||||
|
global isr_stub_table
|
||||||
|
isr_stub_table:
|
||||||
|
dq isr_stub_0
|
||||||
|
dq isr_stub_1
|
||||||
|
dq isr_stub_2
|
||||||
|
dq isr_stub_3
|
||||||
|
dq isr_stub_4
|
||||||
|
dq isr_stub_5
|
||||||
|
dq isr_stub_6
|
||||||
|
dq isr_stub_7
|
||||||
|
dq isr_stub_8
|
||||||
|
dq isr_stub_9
|
||||||
|
dq isr_stub_10
|
||||||
|
dq isr_stub_11
|
||||||
|
dq isr_stub_12
|
||||||
|
dq isr_stub_13
|
||||||
|
dq isr_stub_14
|
||||||
|
dq isr_stub_15
|
||||||
|
dq isr_stub_16
|
||||||
|
dq isr_stub_17
|
||||||
|
dq isr_stub_18
|
||||||
|
dq isr_stub_19
|
||||||
|
dq isr_stub_20
|
||||||
|
dq isr_stub_21
|
||||||
|
dq isr_stub_22
|
||||||
|
dq isr_stub_23
|
||||||
|
dq isr_stub_24
|
||||||
|
dq isr_stub_25
|
||||||
|
dq isr_stub_26
|
||||||
|
dq isr_stub_27
|
||||||
|
dq isr_stub_28
|
||||||
|
dq isr_stub_29
|
||||||
|
dq isr_stub_30
|
||||||
|
dq isr_stub_31
|
||||||
13
src/kernel.c
13
src/kernel.c
@@ -1,7 +1,18 @@
|
|||||||
|
#include "idt.h"
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
|
|
||||||
void kernel_main(void)
|
void kernel_main(void)
|
||||||
{
|
{
|
||||||
vga_clear();
|
vga_clear();
|
||||||
vga_print("Welcome to nub OS\n");
|
vga_print_success();
|
||||||
|
vga_print(" VGA intialzied\n");
|
||||||
|
|
||||||
|
idt_init();
|
||||||
|
vga_print_success();
|
||||||
|
vga_print(" IDT intialzied\n");
|
||||||
|
|
||||||
|
vga_print("\nWelcome to nub OS\n");
|
||||||
|
vga_print(">");
|
||||||
|
|
||||||
|
int x = 1 / 0;
|
||||||
}
|
}
|
||||||
77
src/string.c
77
src/string.c
@@ -1,4 +1,5 @@
|
|||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
int strcmp(const char* a, const char* b)
|
int strcmp(const char* a, const char* b)
|
||||||
{
|
{
|
||||||
@@ -10,3 +11,79 @@ int strcmp(const char* a, const char* b)
|
|||||||
|
|
||||||
return (*a == *b) ? 0 : (*a > *b) ? 1 : -1;
|
return (*a == *b) ? 0 : (*a > *b) ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reverse(char* str, size_t length)
|
||||||
|
{
|
||||||
|
int start = 0;
|
||||||
|
int end = length - 1;
|
||||||
|
while (start < end)
|
||||||
|
{
|
||||||
|
char temp = str[start];
|
||||||
|
str[start] = str[end];
|
||||||
|
str[end] = temp;
|
||||||
|
start++;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uitoa(uint64_t value, char* buffer)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
buffer[i++] = '0';
|
||||||
|
buffer[i] = '\0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (value > 0)
|
||||||
|
{
|
||||||
|
buffer[i++] = (value % 10) + '0';
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = '\0';
|
||||||
|
reverse(buffer, i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itoa(int64_t value, char* buffer)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
buffer[i++] = '0';
|
||||||
|
buffer[i] = '\0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool negative = false;
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
negative = true;
|
||||||
|
v = (uint64_t)(-value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v = (uint64_t)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (v > 0)
|
||||||
|
{
|
||||||
|
buffer[i++] = (v % 10) + '0';
|
||||||
|
v /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negative)
|
||||||
|
{
|
||||||
|
buffer[i++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = '\0';
|
||||||
|
reverse(buffer, i);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
int strcmp(const char* a, const char* b);
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int strcmp(const char* a, const char* b);
|
||||||
|
void reverse(char* str, size_t length);
|
||||||
|
int uitoa(uint64_t value, char* buffer);
|
||||||
|
int itoa(int64_t value, char* buffer);
|
||||||
32
src/vga.c
32
src/vga.c
@@ -1,4 +1,8 @@
|
|||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define ROWS 25
|
#define ROWS 25
|
||||||
#define COLUMNS 80
|
#define COLUMNS 80
|
||||||
@@ -108,4 +112,32 @@ void vga_print_colored(const char* string, vga_color_t color)
|
|||||||
void vga_print(const char* string)
|
void vga_print(const char* string)
|
||||||
{
|
{
|
||||||
vga_print_colored(string, vga_default_color());
|
vga_print_colored(string, vga_default_color());
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_print_success(void)
|
||||||
|
{
|
||||||
|
vga_print("[ ");
|
||||||
|
vga_print_colored("success", VGA_GREEN);
|
||||||
|
vga_print(" ]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_print_error(void)
|
||||||
|
{
|
||||||
|
vga_print("[ ");
|
||||||
|
vga_print_colored("error", VGA_RED);
|
||||||
|
vga_print(" ]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_print_uint(uint64_t value)
|
||||||
|
{
|
||||||
|
char buffer[11];
|
||||||
|
uitoa(value, buffer);
|
||||||
|
vga_print(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_print_int(int64_t value)
|
||||||
|
{
|
||||||
|
char buffer[12];
|
||||||
|
itoa(value, buffer);
|
||||||
|
vga_print(buffer);
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,12 @@ void vga_set_cursor_position(uint8_t row, uint8_t col);
|
|||||||
void vga_print_colored(const char* string, vga_color_t color);
|
void vga_print_colored(const char* string, vga_color_t color);
|
||||||
void vga_print(const char* string);
|
void vga_print(const char* string);
|
||||||
|
|
||||||
|
void vga_print_success(void);
|
||||||
|
void vga_print_error(void);
|
||||||
|
|
||||||
|
void vga_print_uint(uint64_t value);
|
||||||
|
void vga_print_int(int64_t value);
|
||||||
|
|
||||||
static inline vga_color_t vga_color(vga_color_t fg_color, vga_color_t bg_color)
|
static inline vga_color_t vga_color(vga_color_t fg_color, vga_color_t bg_color)
|
||||||
{
|
{
|
||||||
return fg_color | bg_color << 4;
|
return fg_color | bg_color << 4;
|
||||||
|
|||||||
Reference in New Issue
Block a user