Refactoring assembly entry point

This commit is contained in:
Marco Cetica 2021-02-03 15:59:42 +01:00
parent dc3803491e
commit 1b207add8c
61 changed files with 4782 additions and 4779 deletions

106
.gitignore vendored
View File

@ -1,54 +1,54 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
.vscode/*
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
.vscode/*
TODO.md

View File

@ -1,9 +1,9 @@
language: C
before_install:
- sudo apt-get update
- sudo apt-get install -y nasm grub-pc-bin
- sudo ln -s /usr/bin/gcc /usr/bin/i686-elf-gcc
- sudo ln -s /usr/bin/ld /usr/bin/i686-elf-ld
script: make clean all
language: C
before_install:
- sudo apt-get update
- sudo apt-get install -y nasm grub-pc-bin
- sudo ln -s /usr/bin/gcc /usr/bin/i686-elf-gcc
- sudo ln -s /usr/bin/ld /usr/bin/i686-elf-ld
script: make clean all

1348
LICENSE

File diff suppressed because it is too large Load Diff

114
Makefile
View File

@ -1,57 +1,57 @@
LD = i686-elf-ld
LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld
all: prepare cpu kernel_code drivers libc userspace mem link iso
prepare:
mkdir -p obj/
mkdir -p isodir/boot/grub/
cp grub.cfg isodir/boot/grub/grub.cfg
cpu:
make -C kernel/cpu
cp kernel/cpu/*.o obj/
kernel_code:
make -C kernel
cp kernel/*.o obj/
drivers:
make -C kernel/drivers/
cp kernel/drivers/*.o obj/
libc:
make -C kernel/libc
cp kernel/libc/*.o obj/
userspace:
make -C kernel/userspace
cp kernel/userspace/*.o obj/
mem:
make -C kernel/mem
cp kernel/mem/*.o obj/
link:
$(LD) $(LFLAGS) -o isodir/boot/vulcanos.bin obj/*.o
iso:
grub-mkrescue isodir -o vulcanos.iso
clean:
rm -rf obj/ kernel/*.o kernel/cpu/*.o
rm -rf kernel/userspace/*.o kernel/mem/*.o
rm -rf kernel/drivers/*.o kernel/libc/*.o
rm -rf vulcanos.iso bochslog.txt commands isodir
bochs:
bochs -f bochs_cfg -q
run:
qemu-system-x86_64 -cdrom vulcanos.iso -cpu qemu32
run-debug:
qemu-system-x86_64 -cdrom vulcanos.iso -d exec,cpu
run-curses:
qemu-system-x86_64 -cdrom vulcanos.iso -curses -cpu qemu32
LD = i686-elf-ld
LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld
all: prepare cpu kernel_code drivers libc userspace mem link iso
prepare:
mkdir -p obj/
mkdir -p isodir/boot/grub/
cp grub.cfg isodir/boot/grub/grub.cfg
cpu:
make -C kernel/cpu
cp kernel/cpu/*.o obj/
kernel_code:
make -C kernel
cp kernel/*.o obj/
drivers:
make -C kernel/drivers/
cp kernel/drivers/*.o obj/
libc:
make -C kernel/libc
cp kernel/libc/*.o obj/
userspace:
make -C kernel/userspace
cp kernel/userspace/*.o obj/
mem:
make -C kernel/mem
cp kernel/mem/*.o obj/
link:
$(LD) $(LFLAGS) -o isodir/boot/vulcanos.bin obj/*.o
iso:
grub-mkrescue isodir -o vulcanos.iso
clean:
rm -rf obj/ kernel/*.o kernel/cpu/*.o
rm -rf kernel/userspace/*.o kernel/mem/*.o
rm -rf kernel/drivers/*.o kernel/libc/*.o
rm -rf vulcanos.iso bochslog.txt commands isodir
bochs:
bochs -f bochs_cfg -q
run:
qemu-system-x86_64 -cdrom vulcanos.iso -cpu qemu32
run-debug:
qemu-system-x86_64 -cdrom vulcanos.iso -d exec,cpu
run-curses:
qemu-system-x86_64 -cdrom vulcanos.iso -curses -cpu qemu32

View File

@ -1,37 +1,37 @@
# VulcanOS [![Build Status](https://travis-ci.com/ice-bit/vulcanos.svg?branch=master)](https://travis-ci.com/ice-bit/vulcanos)
**VulcanOS** is a x86 monolithic kernel written in C from scratch following the UNIX philosophy. This project is just a student learning tool to know more about operating systems, do not expect nothing more than a toy.
<div align="center">
<img src="imgs/screenshot.png" />
<h6><i>VulcanOS running under QEMU</h6></i>
</div><br /><br />
## Installation
### Requirements
Before building this project you need to setup a [cross compiler](https://wiki.osdev.org/GCC_Cross-Compiler). Also install the following packages:
- nasm
- bochs
- grub
- mtools(only for Arch Linux)
After that, you can build iceOS just by running the command listed below.
1. Type `make all` to compile the system and to create an ISO
2. Type `make run` to start it in QEMU or `make bochs` to start it with bochs(only for debug purposes).
You can also find a ISO file
[here](https://github.com/ice-bit/vulcanos/raw/master/imgs/vulcanos.iso)(md5sum: `a706cdfeea573e08550e599717d3f519`)
## Features
iceOS has the following features:
- [x] VGA driver
- [x] Interrupts
- [x] PIC & PIT driver
- [x] PS/2 driver
- [x] Heap
- [x] Paging
- [ ] VFS driver
- [ ] Usermode
## License
VulcanOS is released under GPLv3, you can obtain a copy of this license by cloning this repository or by visiting [this](https://opensource.org/licenses/GPL-3.0) page.
# VulcanOS [![Build Status](https://travis-ci.com/ice-bit/vulcanos.svg?branch=master)](https://travis-ci.com/ice-bit/vulcanos)
**VulcanOS** is a x86 monolithic kernel written in C from scratch following the UNIX philosophy. This project is just a student learning tool to know more about operating systems, do not expect nothing more than a toy.
<div align="center">
<img src="imgs/screenshot.png" />
<h6><i>VulcanOS running under QEMU</h6></i>
</div><br /><br />
## Installation
### Requirements
Before building this project you need to setup a [cross compiler](https://wiki.osdev.org/GCC_Cross-Compiler). Also install the following packages:
- nasm
- bochs
- grub
- mtools(only for Arch Linux)
After that, you can build iceOS just by running the command listed below.
1. Type `make all` to compile the system and to create an ISO
2. Type `make run` to start it in QEMU or `make bochs` to start it with bochs(only for debug purposes).
You can also find a ISO file
[here](https://github.com/ice-bit/vulcanos/raw/master/imgs/vulcanos.iso)(md5sum: `a706cdfeea573e08550e599717d3f519`)
## Features
iceOS has the following features:
- [x] VGA driver
- [x] Interrupts
- [x] PIC & PIT driver
- [x] PS/2 driver
- [x] Heap
- [x] Paging
- [ ] VFS driver
- [ ] Usermode
## License
VulcanOS is released under GPLv3, you can obtain a copy of this license by cloning this repository or by visiting [this](https://opensource.org/licenses/GPL-3.0) page.

View File

@ -1,12 +1,12 @@
# System configuration.
romimage: file=$BXSHARE/BIOS-bochs-latest
vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
cpu: model=corei7_ivy_bridge_3770k, ips=120000000
clock: sync=slowdown
megs: 256
boot: cdrom, disk
# CDROM
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
# System configuration.
romimage: file=$BXSHARE/BIOS-bochs-latest
vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
cpu: model=corei7_ivy_bridge_3770k, ips=120000000
clock: sync=slowdown
megs: 256
boot: cdrom, disk
# CDROM
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=cdrom, path="iceOS.iso", status=inserted

View File

@ -1,55 +1,55 @@
/* This program comes from James Molloy tutorial
* on how to create an UNIX clone You can find the original code at:
* http://www.jamesmolloy.co.uk/tutorial_html/8.-The%20VFS%20and%20the%20initrd.html */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct initrd_header {
unsigned char magic; // Magic number for consistency
char name[64];
unsigned int offset; // Offset of the file start
unsigned int length;
};
int main(int argc, char **argv) {
int heads = (argc - 1) / 2;
struct initrd_header headers[64];
printf("Size of header(in bytes): %ld\n", sizeof(struct initrd_header));
unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int);
for(int i = 0; i < heads; i++) {
printf("Writing file %s->%s at 0x%d\n", argv[i*2+1], argv[i*2+2], off);
strcpy(headers[i].name, argv[i*2+2]);
headers[i].offset = off;
FILE *stream = fopen(argv[i*2+1], "r");
if(stream == 0) {
puts("Error, file not found!");
return 1;
}
fseek(stream, 0, SEEK_END);
headers[i].length = ftell(stream);
off += headers[i].length;
fclose(stream);
headers[i].magic = 0xBF;
}
FILE *wstream = fopen("./initrd.img", "w");
unsigned char *data = (unsigned char*)malloc(off);
fwrite(&heads, sizeof(int), 1, wstream);
fwrite(&heads, sizeof(struct initrd_header), 64, wstream);
for(int i = 0; i < heads; i++) {
FILE *stream = fopen(argv[i*2+1], "r");
unsigned char *buf = (unsigned char*)malloc(headers[i].length);
fread(buf, 1, headers[i].length, stream);
fread(buf, 1, headers[i].length, wstream);
fclose(stream);
free(buf);
}
fclose(wstream);
free(data);
return 0;
/* This program comes from James Molloy tutorial
* on how to create an UNIX clone You can find the original code at:
* http://www.jamesmolloy.co.uk/tutorial_html/8.-The%20VFS%20and%20the%20initrd.html */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct initrd_header {
unsigned char magic; // Magic number for consistency
char name[64];
unsigned int offset; // Offset of the file start
unsigned int length;
};
int main(int argc, char **argv) {
int heads = (argc - 1) / 2;
struct initrd_header headers[64];
printf("Size of header(in bytes): %ld\n", sizeof(struct initrd_header));
unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int);
for(int i = 0; i < heads; i++) {
printf("Writing file %s->%s at 0x%d\n", argv[i*2+1], argv[i*2+2], off);
strcpy(headers[i].name, argv[i*2+2]);
headers[i].offset = off;
FILE *stream = fopen(argv[i*2+1], "r");
if(stream == 0) {
puts("Error, file not found!");
return 1;
}
fseek(stream, 0, SEEK_END);
headers[i].length = ftell(stream);
off += headers[i].length;
fclose(stream);
headers[i].magic = 0xBF;
}
FILE *wstream = fopen("./initrd.img", "w");
unsigned char *data = (unsigned char*)malloc(off);
fwrite(&heads, sizeof(int), 1, wstream);
fwrite(&heads, sizeof(struct initrd_header), 64, wstream);
for(int i = 0; i < heads; i++) {
FILE *stream = fopen(argv[i*2+1], "r");
unsigned char *buf = (unsigned char*)malloc(headers[i].length);
fread(buf, 1, headers[i].length, stream);
fread(buf, 1, headers[i].length, wstream);
fclose(stream);
free(buf);
}
fclose(wstream);
free(data);
return 0;
}

View File

@ -1,7 +1,7 @@
set timeout = 0
set default = 0
menuentry "VulcanOS" {
multiboot2 /boot/vulcanos.bin
boot
}
set timeout = 0
set default = 0
menuentry "VulcanOS" {
multiboot2 /boot/vulcanos.bin
boot
}

View File

@ -1,10 +1,10 @@
OBJS = kernel_main.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all: ${OBJS}
%.o: %.c
OBJS = kernel_main.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all: ${OBJS}
%.o: %.c
$(CC) $(CFLAGS) $< -o $@

View File

@ -1,8 +1,9 @@
OBJS = kernel_loader.asm.o ports.asm.o \
gdt.asm.o idt.asm.o interrupts.asm.o
ASM = nasm
ASMFLAGS = -f elf32
all: $(OBJS)
%.asm.o: %.asm
$(ASM) $(ASMFLAGS) $< -o $@
OBJS = main.asm.o ports.asm.o \
gdt.asm.o idt.asm.o \
interrupts.asm.o header.asm.o
ASM = nasm
ASMFLAGS = -f elf32
all: $(OBJS)
%.asm.o: %.asm
$(ASM) $(ASMFLAGS) $< -o $@

View File

@ -1,22 +1,22 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global gdt_flush ; for drivers/gdt.c
section .text
gdt_flush:
mov eax, [esp+4] ; get address of gdt_ptr_t
lgdt [eax] ; Load GDT
mov ax, 0x10 ; offset in the GDT of the data segment
mov ds, ax ; Load data segment selectors
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ; offset in the GDT of the code segment
.flush:
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/vulcanos ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global gdt_flush ; for drivers/gdt.c
section .text
gdt_flush:
mov eax, [esp+4] ; get address of gdt_ptr_t
lgdt [eax] ; Load GDT
mov ax, 0x10 ; offset in the GDT of the data segment
mov ds, ax ; Load data segment selectors
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ; offset in the GDT of the code segment
.flush:
ret

19
kernel/cpu/header.asm Normal file
View File

@ -0,0 +1,19 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/vulcanos ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .multiboot_header
header_s:
dd 0xE85250D6 ; Magic number for multiboot
dd 0 ; Protected mode flag
dd header_e - header_s ; Header length
dd 0x100000000 - (0xE85250D6 + 0 + (header_e - header_s)) ; Checksum
; Other flags
dw 0 ; Type
dw 0 ; Flags
dw 0 ; Size
header_e:

View File

@ -1,14 +1,14 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global idt_flush ; for drivers/idt.c
section .text
idt_flush:
mov eax, [esp+4] ; Retrieve idt_ptr_t*
lidt [eax]
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/vulcanos ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global idt_flush ; for drivers/idt.c
section .text
idt_flush:
mov eax, [esp+4] ; Retrieve idt_ptr_t*
lidt [eax]
ret

View File

@ -1,159 +1,159 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
extern isr_handler ; Defined in drivers/isr.h
extern irq_handler ; Defined in drivers/isr.h
; Let's implement all ISR in a very handy way
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts
push byte 0 ; Push dummy error code
push byte %1 ; Push interrupt number
jmp isr_common ; goto ISR handler
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts
push byte %1 ; Push interrupt number
jmp isr_common ; goto ISR handler
%endmacro
; Now we have to do the same thing for Interrupt Requests,
; in this case the first parameter is the IRQ number while
; the second one is the ISR number to be remapped to
%macro IRQ 2
global irq%1
irq%1:
cli ; Disable interrupts
push byte 0 ; Push dummy error code
push byte %2 ; Push interrupt number
jmp irq_common ; goto IRQ handler
%endmacro
; isr_common is a common handler for all
; Interrupt Service Routines declared in the system
; It's main scope is to save current register's states
; into the stack, call the C high level handler
; and restore the register's original values from
; the stack
isr_common:
;; Save register's content into the stack ;;
pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Get 16 bits of eax(e.g ds)
push eax
mov ax, 0x10 ; Load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;; Call C handler ;;
call isr_handler ; Call C handler
;; Restore register's content from the stack ;;
pop eax ; Restore original data segment selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax
add esp, 8 ; Cleans up pushed error code and ISR number
sti ; Re-enable interrupts
iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp
; irq_common is a common handler for all
; Interrupt Requests, it's very similar to the
; ISR one
irq_common:
;; Save register's content into the stack ;;
pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Get 16 bits of eax(e.g ds)
push eax
mov ax, 0x10 ; Load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;; Call C handler ;;
call irq_handler ; Call C handler
;; Restore register's content from the stack ;;
pop ebx ; Restore original data segment selector
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax
add esp, 8 ; Cleans up pushed error code and ISR number
sti ; Re-enable interrupts
iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp
; Standard x86 ISRs (only 8,10-14 and 17 requires to push error codes to the stack)
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_NOERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/vulcanos ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
extern isr_handler ; Defined in drivers/isr.h
extern irq_handler ; Defined in drivers/isr.h
; Let's implement all ISR in a very handy way
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts
push byte 0 ; Push dummy error code
push byte %1 ; Push interrupt number
jmp isr_common ; goto ISR handler
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts
push byte %1 ; Push interrupt number
jmp isr_common ; goto ISR handler
%endmacro
; Now we have to do the same thing for Interrupt Requests,
; in this case the first parameter is the IRQ number while
; the second one is the ISR number to be remapped to
%macro IRQ 2
global irq%1
irq%1:
cli ; Disable interrupts
push byte 0 ; Push dummy error code
push byte %2 ; Push interrupt number
jmp irq_common ; goto IRQ handler
%endmacro
; isr_common is a common handler for all
; Interrupt Service Routines declared in the system
; It's main scope is to save current register's states
; into the stack, call the C high level handler
; and restore the register's original values from
; the stack
isr_common:
;; Save register's content into the stack ;;
pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Get 16 bits of eax(e.g ds)
push eax
mov ax, 0x10 ; Load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;; Call C handler ;;
call isr_handler ; Call C handler
;; Restore register's content from the stack ;;
pop eax ; Restore original data segment selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax
add esp, 8 ; Cleans up pushed error code and ISR number
sti ; Re-enable interrupts
iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp
; irq_common is a common handler for all
; Interrupt Requests, it's very similar to the
; ISR one
irq_common:
;; Save register's content into the stack ;;
pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Get 16 bits of eax(e.g ds)
push eax
mov ax, 0x10 ; Load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;; Call C handler ;;
call irq_handler ; Call C handler
;; Restore register's content from the stack ;;
pop ebx ; Restore original data segment selector
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax
add esp, 8 ; Cleans up pushed error code and ISR number
sti ; Re-enable interrupts
iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp
; Standard x86 ISRs (only 8,10-14 and 17 requires to push error codes to the stack)
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_NOERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47

View File

@ -1,43 +0,0 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 32] ; We should be in protected mode
section .multiboot
head_s:
dd 0xE85250D6 ; Multiboot header magic number
dd 0 ; Protected mode flag
dd head_e - head_s ; Header length
dd 0x100000000 - (0xE85250D6 + 0 + (head_e - head_s)) ; Checksum of above
; Other flags
dw 0 ; type
dw 0 ; flags
dd 0 ; size
head_e:
GLOBAL kernel_loader
EXTERN kernel_main
section .text
kernel_loader:
mov esp, kernel_stack + KERNEL_STACK_SZ ; Define stack pointer
push eax ; Set multiboot header
call kernel_main ; Jump into kernel's main function
.loop:
jmp .loop ; If the kernel returns, go into an infinite loop.
; This will prevent the CPU to run non-kernel instructions
; from the memory
KERNEL_STACK_SZ equ 4096 ; Stack size(4KiB)
section .bss
align 4
kernel_stack:
resb KERNEL_STACK_SZ ; Reserve 4 KiB

27
kernel/cpu/main.asm Normal file
View File

@ -0,0 +1,27 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/vulcanos ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GLOBAL kernel_loader
EXTERN kernel_main
[BITS 32] ; Ensure we are in protected mode
section .text
kernel_loader:
mov esp, kernel_stack + KERNEL_STACK_SZ ; Define stack pointer
push eax ; Set multiboot header register
call kernel_main ; Call kernel's main function
.loop:
jmp .loop ; If the kernel returns, go into an endless loop
; This will prevent the CPU to execure any non-kernel
; instructions.
KERNEL_STACK_SZ equ 4096 ; Stack size(4KiB)
section .bss
align 4
kernel_stack:
resb KERNEL_STACK_SZ ; Reserver 4KiB for kernel's stack

View File

@ -1,21 +1,21 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global outb ; Output from port
global inb ; Input to port
outb:
mov al, [esp + 8]
mov dx, [esp + 4]
out dx, al
ret
inb:
mov dx, [esp + 4]
in al, dx
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vulcanOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019-2021 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/vulcanos ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global outb ; Output from port
global inb ; Input to port
outb:
mov al, [esp + 8]
mov dx, [esp + 4]
out dx, al
ret
inb:
mov dx, [esp + 4]
in al, dx
ret

View File

@ -1,11 +1,11 @@
OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \
fs.o cpuid.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \
fs.o cpuid.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
$(CC) $(CFLAGS) $< -o $@

View File

@ -1,195 +1,195 @@
#include "cpuid.h"
#include "../libc/string.h"
#define INTEL_MAGIC_NUMBER 0x756e6547
#define AMD_MAGIC_NUMBER 0x68747541
#define UNRECOGNIZED_CPU 0xBADFF
static cpuid_t get_cpuid(icpuid_t cpu);
static icpuid_t detect_cpu(void);
static icpuid_t intel_cpu(void);
static icpuid_t amd_cpu(void);
static icpuid_t generic_cpu(void);
icpuid_t detect_cpu(void) {
uint32_t ebx, null;
icpuid_t i_cpu;
cpuid(0, null, ebx, null, null);
// Select CPU brand
switch(ebx) {
case INTEL_MAGIC_NUMBER:
i_cpu = intel_cpu();
break;
case AMD_MAGIC_NUMBER:
i_cpu = amd_cpu();
break;
default:
i_cpu = generic_cpu();
break;
}
return i_cpu;
}
icpuid_t intel_cpu(void) {
uint32_t eax, ebx, null;
icpuid_t icpu;
// Fill the structure
cpuid(1, eax, ebx, null, null);
icpu.model = (eax >> 4) & 0xF;
icpu.family = (eax >> 8) & 0xF;
icpu.type = (eax >> 12) & 0xF;
icpu.brand = INTEL_MAGIC_NUMBER;
icpu.stepping = eax & 0xF;
icpu.reserved = eax >> 14;
return icpu;
}
icpuid_t amd_cpu(void) {
uint32_t eax, null;
icpuid_t icpu;
// Fill the structure
cpuid(1, eax, null, null, null);
icpu.model = (eax >> 4) & 0xF;
icpu.family = (eax >> 8) & 0xF;
icpu.stepping = eax & 0xF;
icpu.reserved = eax >> 12;
icpu.brand = AMD_MAGIC_NUMBER;
return icpu;
}
icpuid_t generic_cpu(void) {
icpuid_t icpu;
icpu.brand = UNRECOGNIZED_CPU; // Magic number for unknown CPUs
return icpu;
}
cpuid_t get_cpuid(icpuid_t cpu) {
cpuid_t cpuid;
uint8_t model[64];
// Recognize CPU brand
if(cpu.brand == AMD_MAGIC_NUMBER) {
switch(cpu.family) {
case 4:
strcpy(model, (uint8_t*)"486 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
case 5:
switch(cpu.model) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
strcpy(model, (uint8_t*)"K6 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
case 8:
strcpy(model, (uint8_t*)"K6-2 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
case 9:
strcpy(model, (uint8_t*)"K6-III model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
default:
strcpy(model, (uint8_t*)"K5/K6 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
}
break;
case 6:
switch(cpu.model) {
case 1:
case 2:
case 3:
cpuid.model = (uint8_t*)"Duron model 3";
break;
case 4:
strcpy(model, (uint8_t*)"Athlon model ");
strcat(model, (void*)cpu.model);
cpuid.model = model;
break;
case 6:
cpuid.model = (uint8_t*)"Athlon MP/Mobile Athlon Model 6";
break;
case 7:
cpuid.model = (uint8_t*)"Mobile Duron Model 7";
break;
default:
strcpy(model, (uint8_t*)"Duron/Athlon model ");
strcat(model, (void*)cpu.model);
cpuid.model = model;
break;
}
break;
}
} else if(cpu.brand == INTEL_MAGIC_NUMBER) {
switch(cpu.type) {
case 0:
cpuid.type =(uint8_t*)"Original OEM";
break;
case 1:
cpuid.type = (uint8_t*)"Overdrive";
break;
case 2:
cpuid.type = (uint8_t*)"Dual-capable";
break;
case 3:
cpuid.type = (uint8_t*)"Reserved";
break;
}
switch(cpu.family) {
case 3:
cpuid.family = (uint8_t*)"i386";
break;
case 4:
cpuid.family = (uint8_t*)"i486";
break;
case 5:
cpuid.family = (uint8_t*)"Pentium II Model 5/Xeon/Celeron";
break;
case 6:
cpuid.family = (uint8_t*)"Pentium Pro";
break;
case 15:
cpuid.family = (uint8_t*)"Pentium 4";
break;
}
} else if(cpu.brand == UNRECOGNIZED_CPU)
cpuid.family = (uint8_t*)"Generic (x86) CPU";
return cpuid;
}
uint8_t *get_cpu_type() {
icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86)
cpuid_t cpu_type = get_cpuid(icpu);
return (uint8_t*)cpu_type.type;
}
uint8_t *get_cpu_family() {
icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86)
cpuid_t cpu_family = get_cpuid(icpu);
return (uint8_t*)cpu_family.family;
}
#include "cpuid.h"
#include "../libc/string.h"
#define INTEL_MAGIC_NUMBER 0x756e6547
#define AMD_MAGIC_NUMBER 0x68747541
#define UNRECOGNIZED_CPU 0xBADFF
static cpuid_t get_cpuid(icpuid_t cpu);
static icpuid_t detect_cpu(void);
static icpuid_t intel_cpu(void);
static icpuid_t amd_cpu(void);
static icpuid_t generic_cpu(void);
icpuid_t detect_cpu(void) {
uint32_t ebx, null;
icpuid_t i_cpu;
cpuid(0, null, ebx, null, null);
// Select CPU brand
switch(ebx) {
case INTEL_MAGIC_NUMBER:
i_cpu = intel_cpu();
break;
case AMD_MAGIC_NUMBER:
i_cpu = amd_cpu();
break;
default:
i_cpu = generic_cpu();
break;
}
return i_cpu;
}
icpuid_t intel_cpu(void) {
uint32_t eax, ebx, null;
icpuid_t icpu;
// Fill the structure
cpuid(1, eax, ebx, null, null);
icpu.model = (eax >> 4) & 0xF;
icpu.family = (eax >> 8) & 0xF;
icpu.type = (eax >> 12) & 0xF;
icpu.brand = INTEL_MAGIC_NUMBER;
icpu.stepping = eax & 0xF;
icpu.reserved = eax >> 14;
return icpu;
}
icpuid_t amd_cpu(void) {
uint32_t eax, null;
icpuid_t icpu;
// Fill the structure
cpuid(1, eax, null, null, null);
icpu.model = (eax >> 4) & 0xF;
icpu.family = (eax >> 8) & 0xF;
icpu.stepping = eax & 0xF;
icpu.reserved = eax >> 12;
icpu.brand = AMD_MAGIC_NUMBER;
return icpu;
}
icpuid_t generic_cpu(void) {
icpuid_t icpu;
icpu.brand = UNRECOGNIZED_CPU; // Magic number for unknown CPUs
return icpu;
}
cpuid_t get_cpuid(icpuid_t cpu) {
cpuid_t cpuid;
uint8_t model[64];
// Recognize CPU brand
if(cpu.brand == AMD_MAGIC_NUMBER) {
switch(cpu.family) {
case 4:
strcpy(model, (uint8_t*)"486 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
case 5:
switch(cpu.model) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
strcpy(model, (uint8_t*)"K6 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
case 8:
strcpy(model, (uint8_t*)"K6-2 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
case 9:
strcpy(model, (uint8_t*)"K6-III model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
default:
strcpy(model, (uint8_t*)"K5/K6 model "); // Set model name
strcat(model, (void*)cpu.model); // Set model version
cpuid.model = model;
break;
}
break;
case 6:
switch(cpu.model) {
case 1:
case 2:
case 3:
cpuid.model = (uint8_t*)"Duron model 3";
break;
case 4:
strcpy(model, (uint8_t*)"Athlon model ");
strcat(model, (void*)cpu.model);
cpuid.model = model;
break;
case 6:
cpuid.model = (uint8_t*)"Athlon MP/Mobile Athlon Model 6";
break;
case 7:
cpuid.model = (uint8_t*)"Mobile Duron Model 7";
break;
default:
strcpy(model, (uint8_t*)"Duron/Athlon model ");
strcat(model, (void*)cpu.model);
cpuid.model = model;
break;
}
break;
}
} else if(cpu.brand == INTEL_MAGIC_NUMBER) {
switch(cpu.type) {
case 0:
cpuid.type =(uint8_t*)"Original OEM";
break;
case 1:
cpuid.type = (uint8_t*)"Overdrive";
break;
case 2:
cpuid.type = (uint8_t*)"Dual-capable";
break;
case 3:
cpuid.type = (uint8_t*)"Reserved";
break;
}
switch(cpu.family) {
case 3:
cpuid.family = (uint8_t*)"i386";
break;
case 4:
cpuid.family = (uint8_t*)"i486";
break;
case 5:
cpuid.family = (uint8_t*)"Pentium II Model 5/Xeon/Celeron";
break;
case 6:
cpuid.family = (uint8_t*)"Pentium Pro";
break;
case 15:
cpuid.family = (uint8_t*)"Pentium 4";
break;
}
} else if(cpu.brand == UNRECOGNIZED_CPU)
cpuid.family = (uint8_t*)"Generic (x86) CPU";
return cpuid;
}
uint8_t *get_cpu_type() {
icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86)
cpuid_t cpu_type = get_cpuid(icpu);
return (uint8_t*)cpu_type.type;
}
uint8_t *get_cpu_family() {
icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86)
cpuid_t cpu_family = get_cpuid(icpu);
return (uint8_t*)cpu_family.family;
}

View File

@ -1,36 +1,36 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef CPUID_H
#define CPUID_H
#include <stdint.h>
#define cpuid(in, a, b, c, d) __asm__("cpuid": "=a" (a), "=b"(b), "=d" (d) : "a" (in));
typedef struct {
uint32_t model;
uint32_t family;
uint32_t type;
uint32_t brand;
uint32_t stepping;
uint32_t reserved;
} icpuid_t;
typedef struct {
uint8_t *model;
uint8_t *family;
uint8_t *type;
uint8_t *brand;
uint8_t *stepping;
uint8_t *reserved;
} cpuid_t;
// return type and family processor
uint8_t *get_cpu_type();
uint8_t *get_cpu_family();
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef CPUID_H
#define CPUID_H
#include <stdint.h>
#define cpuid(in, a, b, c, d) __asm__("cpuid": "=a" (a), "=b"(b), "=d" (d) : "a" (in));
typedef struct {
uint32_t model;
uint32_t family;
uint32_t type;
uint32_t brand;
uint32_t stepping;
uint32_t reserved;
} icpuid_t;
typedef struct {
uint8_t *model;
uint8_t *family;
uint8_t *type;
uint8_t *brand;
uint8_t *stepping;
uint8_t *reserved;
} cpuid_t;
// return type and family processor
uint8_t *get_cpu_type();
uint8_t *get_cpu_family();
#endif

View File

@ -1,47 +1,47 @@
#include "fs.h"
fs_node_t *fs_root = 0; // Initialize the root of the filesystem
uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
// Check if inode got a read callback from the kernel
if(node->read != 0)
return node->read(node, offset, size, buffer);
else
return 0;
}
uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
// Check if inode got a write callback from the kernel
if(node->write != 0)
return node->write(node, offset, size, buffer);
else
return 0;
}
void open_fs(fs_node_t *node) {
// Check if inode got a open callback from the kernel
if(node->open != 0)
return node->open(node);
}
void close_fs(fs_node_t *node) {
// Check if inode got a close callback from the kernel
if(node->close != 0)
return node->close(node);
}
struct dirent *readdir_fs(fs_node_t *node, uint32_t index) {
// Read dir content(only if file descriptor is FS_DIRECTORY)
if((node->flags&0x7) == FS_DIRECTORY && node->readdir != 0)
return node->readdir(node, index);
else
return 0;
}
fs_node_t *finddir_fs(fs_node_t *node, char *name) {
// Check if an inode is a directory
if((node->flags&0x7) == FS_DIRECTORY && node->finddir != 0)
return node->finddir(node, name);
else
return 0;
#include "fs.h"
fs_node_t *fs_root = 0; // Initialize the root of the filesystem
uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
// Check if inode got a read callback from the kernel
if(node->read != 0)
return node->read(node, offset, size, buffer);
else
return 0;
}
uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
// Check if inode got a write callback from the kernel
if(node->write != 0)
return node->write(node, offset, size, buffer);
else
return 0;
}
void open_fs(fs_node_t *node) {
// Check if inode got a open callback from the kernel
if(node->open != 0)
return node->open(node);
}
void close_fs(fs_node_t *node) {
// Check if inode got a close callback from the kernel
if(node->close != 0)
return node->close(node);
}
struct dirent *readdir_fs(fs_node_t *node, uint32_t index) {
// Read dir content(only if file descriptor is FS_DIRECTORY)
if((node->flags&0x7) == FS_DIRECTORY && node->readdir != 0)
return node->readdir(node, index);
else
return 0;
}
fs_node_t *finddir_fs(fs_node_t *node, char *name) {
// Check if an inode is a directory
if((node->flags&0x7) == FS_DIRECTORY && node->finddir != 0)
return node->finddir(node, name);
else
return 0;
}

View File

@ -1,84 +1,84 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef FS_H
#define FS_H
#include <stdint.h>
/* This Virtual File System(VFS) is a simplified version of
* standard UNIX VFS where all files comes organized in a graph
* of nodes. Keeping in mind the concept of "everything is a file" we can
* store a file, a directory, a serial device or anything else just by adding
* a new node to the data structure.
* And this is a list of common operations:
* - Open: Initialize a new node as a file descriptor
* - Close: CLose a node
* - Read: return the content of a node
* - Write: set content to node
* - Readdir: Return directory content
* - Finddir: Given a specific name find the corresponding child node.*/
// Define some standard node types
#define FS_FILE 0x01
#define FS_DIRECTORY 0x02
#define FS_CHARDEVICE 0x03
#define FS_BLOCKDEVICE 0x04
#define FS_PIPE 0x05
#define FS_SYMLINK 0x06
#define FS_MOUNTPOINT 0x08
struct fs_node;
/* Define some callbacks to be called when read/write/open/close
* operations are called */
typedef uint32_t (*read_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*);
typedef uint32_t (*write_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*);
typedef void (*open_type_t)(struct fs_node*);
typedef void (*close_type_t)(struct fs_node*);
typedef struct dirent*(*readdir_type_t)(struct fs_node*, uint32_t);
typedef struct fs_node*(*finddir_type_t)(struct fs_node*, char *name);
// This define the structure of a node
typedef struct fs_node {
uint8_t name[128]; // File name
uint32_t mask; // Permission mask
uint32_t uid; // Owning user
uint32_t gid; // Owning group
uint32_t flags; // Node type
uint32_t inode; // used by file systems to identify files
uint32_t length; // Length of the file, in bytes.
uint32_t impl;
// Callback section
read_type_t read;
write_type_t write;
open_type_t open;
close_type_t close;
readdir_type_t readdir;
finddir_type_t finddir;
struct fs_node *ptr; // Used by mountpoints and symlinks
} fs_node_t;
struct dirent {
uint8_t name[120]; // File name
uint32_t ino; // POSIX standard requires inode number;
};
// Filesystem root
extern fs_node_t *fs_root;
/* Write/Read/Open/Close operations
* NOTE: those functions are NOT like the Callback
* functions; the first one deals with inodes while
* the second one deals with file descriptors. */
uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
void open_fs(fs_node_t *node);
void close_fs(fs_node_t *node);
struct dirent *readdir_fs(fs_node_t *node, uint32_t index);
fs_node_t *finddir_fs(fs_node_t *node, char *name);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef FS_H
#define FS_H
#include <stdint.h>
/* This Virtual File System(VFS) is a simplified version of
* standard UNIX VFS where all files comes organized in a graph
* of nodes. Keeping in mind the concept of "everything is a file" we can
* store a file, a directory, a serial device or anything else just by adding
* a new node to the data structure.
* And this is a list of common operations:
* - Open: Initialize a new node as a file descriptor
* - Close: CLose a node
* - Read: return the content of a node
* - Write: set content to node
* - Readdir: Return directory content
* - Finddir: Given a specific name find the corresponding child node.*/
// Define some standard node types
#define FS_FILE 0x01
#define FS_DIRECTORY 0x02
#define FS_CHARDEVICE 0x03
#define FS_BLOCKDEVICE 0x04
#define FS_PIPE 0x05
#define FS_SYMLINK 0x06
#define FS_MOUNTPOINT 0x08
struct fs_node;
/* Define some callbacks to be called when read/write/open/close
* operations are called */
typedef uint32_t (*read_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*);
typedef uint32_t (*write_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*);
typedef void (*open_type_t)(struct fs_node*);
typedef void (*close_type_t)(struct fs_node*);
typedef struct dirent*(*readdir_type_t)(struct fs_node*, uint32_t);
typedef struct fs_node*(*finddir_type_t)(struct fs_node*, char *name);
// This define the structure of a node
typedef struct fs_node {
uint8_t name[128]; // File name
uint32_t mask; // Permission mask
uint32_t uid; // Owning user
uint32_t gid; // Owning group
uint32_t flags; // Node type
uint32_t inode; // used by file systems to identify files
uint32_t length; // Length of the file, in bytes.
uint32_t impl;
// Callback section
read_type_t read;
write_type_t write;
open_type_t open;
close_type_t close;
readdir_type_t readdir;
finddir_type_t finddir;
struct fs_node *ptr; // Used by mountpoints and symlinks
} fs_node_t;
struct dirent {
uint8_t name[120]; // File name
uint32_t ino; // POSIX standard requires inode number;
};
// Filesystem root
extern fs_node_t *fs_root;
/* Write/Read/Open/Close operations
* NOTE: those functions are NOT like the Callback
* functions; the first one deals with inodes while
* the second one deals with file descriptors. */
uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
void open_fs(fs_node_t *node);
void close_fs(fs_node_t *node);
struct dirent *readdir_fs(fs_node_t *node, uint32_t index);
fs_node_t *finddir_fs(fs_node_t *node, char *name);
#endif

View File

@ -1,103 +1,103 @@
#include "gdt.h"
// Internal method
extern void gdt_flush(uint32_t); // Defined on cpu/gdt.asm
static gdt_entry_t construct_null_entry();
static gdt_entry_t construct_entry(gdt_access_t access);
static void init_gdt();
gdt_entry_t gdt_entries[5];
gdt_ptr_t gdt_ptr;
// This method will be called by the kernel
void gdt_setup() {
init_gdt();
}
static void init_gdt() {
gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1;
gdt_ptr.base = (uint32_t)&gdt_entries;
gdt_entry_t null_segment = construct_null_entry();
gdt_entry_t kernel_mode_code_segment = construct_entry(
(struct gdt_access){
.type = GDT_CODE_TYPE_EXEC_READ,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING0,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t kernel_mode_data_segment = construct_entry(
(struct gdt_access){
.type = GDT_DATA_TYPE_READ_WRITE,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING0,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t user_mode_code_segment = construct_entry(
(struct gdt_access){
.type = GDT_CODE_TYPE_EXEC_READ,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING3,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t user_mode_data_segment = construct_entry(
(struct gdt_access){
.type = GDT_DATA_TYPE_READ_WRITE,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING3,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entries[0] = null_segment;
gdt_entries[1] = kernel_mode_code_segment;
gdt_entries[2] = kernel_mode_data_segment;
gdt_entries[3] = user_mode_code_segment;
gdt_entries[4] = user_mode_data_segment;
gdt_flush((uint32_t)&gdt_ptr);
}
static gdt_entry_t construct_entry(gdt_access_t access) {
gdt_entry_t entry = (struct gdt_entry_struct) {
.base_low = GDT_BASE & 0xFFFF,
.base_middle = (GDT_BASE >> 16) & 0xFF,
.base_high = (GDT_BASE >> 24) & 0xFF,
.limit_low = (GDT_LIMIT & 0xFFFF),
.access = access,
.granularity = (struct gdt_granularity) {
.g = GDT_GRANULARITY_4K,
.d = GDT_OPERAND_SIZE_32,
.zero = 0,
.seglen = GDT_SEGMENT_LENGTH
}
};
return entry;
}
// The only difference is in the access
static gdt_entry_t construct_null_entry() {
gdt_entry_t null_entry = (struct gdt_entry_struct) {
.base_low = 0,
.base_middle = 0,
.base_high = 0,
.limit_low = 0,
.access = (struct gdt_access) {
.p = 0,
.dpl = 0,
.dt = 0,
.type = 0
},
.granularity = (struct gdt_granularity) {
.g = 0,
.d = 0,
.zero = 0,
.seglen = 0
}
};
return null_entry;
#include "gdt.h"
// Internal method
extern void gdt_flush(uint32_t); // Defined on cpu/gdt.asm
static gdt_entry_t construct_null_entry();
static gdt_entry_t construct_entry(gdt_access_t access);
static void init_gdt();
gdt_entry_t gdt_entries[5];
gdt_ptr_t gdt_ptr;
// This method will be called by the kernel
void gdt_setup() {
init_gdt();
}
static void init_gdt() {
gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1;
gdt_ptr.base = (uint32_t)&gdt_entries;
gdt_entry_t null_segment = construct_null_entry();
gdt_entry_t kernel_mode_code_segment = construct_entry(
(struct gdt_access){
.type = GDT_CODE_TYPE_EXEC_READ,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING0,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t kernel_mode_data_segment = construct_entry(
(struct gdt_access){
.type = GDT_DATA_TYPE_READ_WRITE,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING0,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t user_mode_code_segment = construct_entry(
(struct gdt_access){
.type = GDT_CODE_TYPE_EXEC_READ,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING3,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t user_mode_data_segment = construct_entry(
(struct gdt_access){
.type = GDT_DATA_TYPE_READ_WRITE,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING3,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entries[0] = null_segment;
gdt_entries[1] = kernel_mode_code_segment;
gdt_entries[2] = kernel_mode_data_segment;
gdt_entries[3] = user_mode_code_segment;
gdt_entries[4] = user_mode_data_segment;
gdt_flush((uint32_t)&gdt_ptr);
}
static gdt_entry_t construct_entry(gdt_access_t access) {
gdt_entry_t entry = (struct gdt_entry_struct) {
.base_low = GDT_BASE & 0xFFFF,
.base_middle = (GDT_BASE >> 16) & 0xFF,
.base_high = (GDT_BASE >> 24) & 0xFF,
.limit_low = (GDT_LIMIT & 0xFFFF),
.access = access,
.granularity = (struct gdt_granularity) {
.g = GDT_GRANULARITY_4K,
.d = GDT_OPERAND_SIZE_32,
.zero = 0,
.seglen = GDT_SEGMENT_LENGTH
}
};
return entry;
}
// The only difference is in the access
static gdt_entry_t construct_null_entry() {
gdt_entry_t null_entry = (struct gdt_entry_struct) {
.base_low = 0,
.base_middle = 0,
.base_high = 0,
.limit_low = 0,
.access = (struct gdt_access) {
.p = 0,
.dpl = 0,
.dt = 0,
.type = 0
},
.granularity = (struct gdt_granularity) {
.g = 0,
.d = 0,
.zero = 0,
.seglen = 0
}
};
return null_entry;
}

View File

@ -1,139 +1,139 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _GDT_H_
#define _GDT_H_
#include <stdint.h>
/*
* First a bit of theory:
* GDT(Global Descriptor Table) is a complex data structure used in x86 systems
* to define memory areas.
* Technically speaking GDT is formed by an array of 8-bytes segment descriptors,
* the first descriptor of the GDT is always a NULL one and CANNOT be used to allocate
* memory; so we need at least two descriptors(plus the null descriptor) to successfully allocate
* data on our memory.
* In x86 architecture there're two methods to provide virtual memory: Segmentation and Paging:
* With the first one every memory access is done within his own segment, so each address(of a process)
* is added to the segment's base address and checked against the segment's length.
* With paging, however, the address space is split into blocks(usually of 4KiB) called pages.
* Each page can be mapped to physical memory or it can be unmapped(to create virtual memory).
* Segmentation is a built-in functionality of x86 architecture, so to get around this we need to
* define our own GDT. A cool thing segmentation can do for us is to set Ring Level:
* a privilege level to allow our process to run in a 'unprivileged' mode(called user mode, ring 3)
* and to allow drivers(or kernel related stuff) to run in a 'supervisor-mode'(called kernel mode, ring 0).
* Usually bootloader(such as GRUB) sets up GDT for us, the problem is that we cannot known where it is or
* if it is has been overwritten during some other tasks. So it's a good idea to implement
* a new GDT ourself.
*/
/* Those values were taken from Intel's developer manual */
// GDT fields
#define GDT_BASE 0x00000000
#define GDT_LIMIT 0xFFFFFFFF
// GDT granularity
#define GDT_SEGMENT_LENGTH 0xF
#define GDT_OPERAND_SIZE_16 0
#define GDT_OPERAND_SIZE_32 1
#define GDT_GRANULARITY_1K 0
#define GDT_GRANULARITY_4K 1
// GDT access type fields
#define GDT_DATA_TYPE_READ_ONLY 0x0
#define GDT_DATA_TYPE_READ_ONLY_ACCESSED 0x1
#define GDT_DATA_TYPE_READ_WRITE 0x2
#define GDT_DATA_TYPE_READ_WRITE_ACCESSED 0x3
#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN 0x4
#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN_ACCESSED 0x5
#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN 0x6
#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN_ACCESSED 0x7
#define GDT_DATA_TYPE_EXEC_ONLY 0x8
#define GDT_CODE_TYPE_EXEC_ONLY_ACCESSED 0x9
#define GDT_CODE_TYPE_EXEC_READ 0xA
#define GDT_CODE_TYPE_EXEC_READ_ACCESSED 0xB
#define GDT_CODE_TYPE_EXEC_CONFORMING 0xC
#define GDT_CODE_TYPE_EXEC_CONFORMING_ACCESSED 0xD
#define GDT_CODE_TYPE_EXEC_READ_CONFORMING 0xE
#define GDT_CODE_TYPE_EXEC_READ_CONFORMING_ACCESSED 0xF
// Descriptor type fields
#define GDT_SYSTEM_DESCRIPTOR 0
#define GDT_CODE_AND_DATA_DESCRIPTOR 1
// GDT Ring number
#define GDT_RING0 0
#define GDT_RING1 1
#define GDT_RING2 2
#define GDT_RING3 3
// 'Present' field
#define GDT_SEGMENT_NOT_PRESENT 0
#define GDT_SEGMENT_PRESENT 1
/* Global Descriptor Table (GDT) implementation */
/* gdt_access is used to access portion of the GDT
* | 0 - 3 | 4 | 3 - 6 | 7 |
* | Type | DT | DPL | P |
* Type: Which type
* DT: descriptor type
* DPL: Kernel ring(0-3)
* P: is segment present? (bool)
*/
struct gdt_access {
uint8_t type: 4; // 4 Bits
uint8_t dt: 1; // 1 Bit
uint8_t dpl: 2; // 2 Bits
uint8_t p: 1; // 1 Bits
}__attribute__((packed));
typedef struct gdt_access gdt_access_t;
/* gdt_granularity is used to get portion of GDT entry
* | 0 - 3 | 4 | 5 | 6 | 7 |
* | seglen | 0 | D | G |
* seglen: segment length
* 0: Always zero
* D: Operand size (0 = 16 bit, 1 = 32 bit)
* G: granularity (0 = 1 Byte, 1 = 4KiB)
*/
struct gdt_granularity {
uint8_t seglen: 4;
uint8_t zero: 2;
uint8_t d: 1;
uint8_t g: 1;
}__attribute__((packed));
typedef struct gdt_granularity gdt_gran_t;
/* gdt_entry_struct contains the value of a single GDT entry
* Each slice is 64 bits.
* | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 55 | 56 - 63 |
* | lim low| base low|base mid | access | gran | base hg |
* lim low: Lower 16 bits of the limit
* base low: Lower 16 bits of the base
* base mid: Next 8 bits of the base
* access: access flag, e.g. which ring this segment can be used in.
* gran.
*/
struct gdt_entry_struct {
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
gdt_access_t access;
gdt_gran_t granularity;
uint8_t base_high;
}__attribute__((packed));
typedef struct gdt_entry_struct gdt_entry_t;
/* Also we have to define a pointer to the data structure
* This is needed to locate it later */
struct gdt_ptr {
uint16_t limit;
uint32_t base;
}__attribute__((packed));
typedef struct gdt_ptr gdt_ptr_t;
/* GDT Kernel API */
void gdt_setup();
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _GDT_H_
#define _GDT_H_
#include <stdint.h>
/*
* First a bit of theory:
* GDT(Global Descriptor Table) is a complex data structure used in x86 systems
* to define memory areas.
* Technically speaking GDT is formed by an array of 8-bytes segment descriptors,
* the first descriptor of the GDT is always a NULL one and CANNOT be used to allocate
* memory; so we need at least two descriptors(plus the null descriptor) to successfully allocate
* data on our memory.
* In x86 architecture there're two methods to provide virtual memory: Segmentation and Paging:
* With the first one every memory access is done within his own segment, so each address(of a process)
* is added to the segment's base address and checked against the segment's length.
* With paging, however, the address space is split into blocks(usually of 4KiB) called pages.
* Each page can be mapped to physical memory or it can be unmapped(to create virtual memory).
* Segmentation is a built-in functionality of x86 architecture, so to get around this we need to
* define our own GDT. A cool thing segmentation can do for us is to set Ring Level:
* a privilege level to allow our process to run in a 'unprivileged' mode(called user mode, ring 3)
* and to allow drivers(or kernel related stuff) to run in a 'supervisor-mode'(called kernel mode, ring 0).
* Usually bootloader(such as GRUB) sets up GDT for us, the problem is that we cannot known where it is or
* if it is has been overwritten during some other tasks. So it's a good idea to implement
* a new GDT ourself.
*/
/* Those values were taken from Intel's developer manual */
// GDT fields
#define GDT_BASE 0x00000000
#define GDT_LIMIT 0xFFFFFFFF
// GDT granularity
#define GDT_SEGMENT_LENGTH 0xF
#define GDT_OPERAND_SIZE_16 0
#define GDT_OPERAND_SIZE_32 1
#define GDT_GRANULARITY_1K 0
#define GDT_GRANULARITY_4K 1
// GDT access type fields
#define GDT_DATA_TYPE_READ_ONLY 0x0
#define GDT_DATA_TYPE_READ_ONLY_ACCESSED 0x1
#define GDT_DATA_TYPE_READ_WRITE 0x2
#define GDT_DATA_TYPE_READ_WRITE_ACCESSED 0x3
#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN 0x4
#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN_ACCESSED 0x5
#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN 0x6
#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN_ACCESSED 0x7
#define GDT_DATA_TYPE_EXEC_ONLY 0x8
#define GDT_CODE_TYPE_EXEC_ONLY_ACCESSED 0x9
#define GDT_CODE_TYPE_EXEC_READ 0xA
#define GDT_CODE_TYPE_EXEC_READ_ACCESSED 0xB
#define GDT_CODE_TYPE_EXEC_CONFORMING 0xC
#define GDT_CODE_TYPE_EXEC_CONFORMING_ACCESSED 0xD
#define GDT_CODE_TYPE_EXEC_READ_CONFORMING 0xE
#define GDT_CODE_TYPE_EXEC_READ_CONFORMING_ACCESSED 0xF
// Descriptor type fields
#define GDT_SYSTEM_DESCRIPTOR 0
#define GDT_CODE_AND_DATA_DESCRIPTOR 1
// GDT Ring number
#define GDT_RING0 0
#define GDT_RING1 1
#define GDT_RING2 2
#define GDT_RING3 3
// 'Present' field
#define GDT_SEGMENT_NOT_PRESENT 0
#define GDT_SEGMENT_PRESENT 1
/* Global Descriptor Table (GDT) implementation */
/* gdt_access is used to access portion of the GDT
* | 0 - 3 | 4 | 3 - 6 | 7 |
* | Type | DT | DPL | P |
* Type: Which type
* DT: descriptor type
* DPL: Kernel ring(0-3)
* P: is segment present? (bool)
*/
struct gdt_access {
uint8_t type: 4; // 4 Bits
uint8_t dt: 1; // 1 Bit
uint8_t dpl: 2; // 2 Bits
uint8_t p: 1; // 1 Bits
}__attribute__((packed));
typedef struct gdt_access gdt_access_t;
/* gdt_granularity is used to get portion of GDT entry
* | 0 - 3 | 4 | 5 | 6 | 7 |
* | seglen | 0 | D | G |
* seglen: segment length
* 0: Always zero
* D: Operand size (0 = 16 bit, 1 = 32 bit)
* G: granularity (0 = 1 Byte, 1 = 4KiB)
*/
struct gdt_granularity {
uint8_t seglen: 4;
uint8_t zero: 2;
uint8_t d: 1;
uint8_t g: 1;
}__attribute__((packed));
typedef struct gdt_granularity gdt_gran_t;
/* gdt_entry_struct contains the value of a single GDT entry
* Each slice is 64 bits.
* | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 55 | 56 - 63 |
* | lim low| base low|base mid | access | gran | base hg |
* lim low: Lower 16 bits of the limit
* base low: Lower 16 bits of the base
* base mid: Next 8 bits of the base
* access: access flag, e.g. which ring this segment can be used in.
* gran.
*/
struct gdt_entry_struct {
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
gdt_access_t access;
gdt_gran_t granularity;
uint8_t base_high;
}__attribute__((packed));
typedef struct gdt_entry_struct gdt_entry_t;
/* Also we have to define a pointer to the data structure
* This is needed to locate it later */
struct gdt_ptr {
uint16_t limit;
uint32_t base;
}__attribute__((packed));
typedef struct gdt_ptr gdt_ptr_t;
/* GDT Kernel API */
void gdt_setup();
#endif

View File

@ -1,122 +1,122 @@
#include "idt.h"
#include "../libc/string.h"
#include "ports.h"
// Internal method
extern void idt_flush(idt_ptr_t*); // defined on cpu/idt.asm
static void init_idt();
static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags);
static void pic_remap(uint8_t offset1, uint8_t offset2);
idt_entry_t idt_entries[256]; // 256 interrupts
idt_ptr_t idt_ptr;
// This method will be called by the kernel
void idt_setup() {
init_idt();
}
static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags) {
idt_entries[idx] = (struct idt_entry) {
.base_low = (uint32_t)base & 0xFFFF,
.base_high = ((uint32_t)base >> 16) & 0xFFFF,
.seg_sel = selector,
.flags = flags
};
}
static void init_idt() {
idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1;
idt_ptr.base = idt_entries;
memset(&idt_entries, 0, sizeof(idt_entry_t) * 256);
idt_flags_t flags = {
.reserved = IDT_FLAG_RESERVED, // Always 0x0E
.dpl = 0,
.p = 1
};
// Remap IDT with ISRs
idt_set_gate(0, isr0, 0x08, flags);
idt_set_gate(1, isr1, 0x08, flags);
idt_set_gate(2, isr2, 0x08, flags);
idt_set_gate(3, isr3, 0x08, flags);
idt_set_gate(4, isr4, 0x08, flags);
idt_set_gate(5, isr5, 0x08, flags);
idt_set_gate(6, isr6, 0x08, flags);
idt_set_gate(7, isr7, 0x08, flags);
idt_set_gate(8, isr8, 0x08, flags);
idt_set_gate(9, isr9, 0x08, flags);
idt_set_gate(10, isr10, 0x08, flags);
idt_set_gate(11, isr11, 0x08, flags);
idt_set_gate(12, isr12, 0x08, flags);
idt_set_gate(13, isr13, 0x08, flags);
idt_set_gate(14, isr14, 0x08, flags);
idt_set_gate(15, isr15, 0x08, flags);
idt_set_gate(16, isr16, 0x08, flags);
idt_set_gate(17, isr17, 0x08, flags);
idt_set_gate(18, isr18, 0x08, flags);
idt_set_gate(19, isr19, 0x08, flags);
idt_set_gate(20, isr20, 0x08, flags);
idt_set_gate(21, isr21, 0x08, flags);
idt_set_gate(22, isr22, 0x08, flags);
idt_set_gate(23, isr23, 0x08, flags);
idt_set_gate(24, isr24, 0x08, flags);
idt_set_gate(25, isr25, 0x08, flags);
idt_set_gate(26, isr26, 0x08, flags);
idt_set_gate(27, isr27, 0x08, flags);
idt_set_gate(28, isr28, 0x08, flags);
idt_set_gate(29, isr29, 0x08, flags);
idt_set_gate(30, isr30, 0x08, flags);
idt_set_gate(31, isr31, 0x08, flags);
// Remap PIC
pic_remap(PIC1_START_INTERRUPT, PIC2_START_INTERRUPT);
// Also remap 15 entries for IRQs
idt_set_gate(32, irq0, 0x08, flags);
idt_set_gate(33, irq1, 0x08, flags);
idt_set_gate(34, irq2, 0x08, flags);
idt_set_gate(35, irq3, 0x08, flags);
idt_set_gate(36, irq4, 0x08, flags);
idt_set_gate(37, irq5, 0x08, flags);
idt_set_gate(38, irq6, 0x08, flags);
idt_set_gate(39, irq7, 0x08, flags);
idt_set_gate(40, irq8, 0x08, flags);
idt_set_gate(41, irq9, 0x08, flags);
idt_set_gate(42, irq10, 0x08, flags);
idt_set_gate(43, irq11, 0x08, flags);
idt_set_gate(44, irq12, 0x08, flags);
idt_set_gate(45, irq13, 0x08, flags);
idt_set_gate(46, irq14, 0x08, flags);
idt_set_gate(47, irq15, 0x08, flags);
idt_flush(&idt_ptr);
// Finally enable hardware interrupts with an assembly instruction
__asm__ __volatile__ ("sti");
}
// Taken from: http://wiki.osdev.org/8259_PIC
static void pic_remap(uint8_t offset1, uint8_t offset2) {
uint8_t a1, a2;
a1 = inb(PIC1_DATA); // Save masks
a2 = inb(PIC2_DATA);
outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); // Start init sequence
outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
outb(PIC1_DATA, offset1);
outb(PIC2_DATA, offset2);
outb(PIC1_DATA, 4); // Tell master PIC that there is a slave PIC at IRQ2
outb(PIC1_DATA, 2); // Tell salve PIC it's cascade identity
outb(PIC1_DATA, ICW4_8086);
outb(PIC2_DATA, ICW4_8086);
// Restore saved masks
outb(PIC1_DATA, a1);
outb(PIC2_DATA, a2);
#include "idt.h"
#include "../libc/string.h"
#include "ports.h"
// Internal method
extern void idt_flush(idt_ptr_t*); // defined on cpu/idt.asm
static void init_idt();
static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags);
static void pic_remap(uint8_t offset1, uint8_t offset2);
idt_entry_t idt_entries[256]; // 256 interrupts
idt_ptr_t idt_ptr;
// This method will be called by the kernel
void idt_setup() {
init_idt();
}
static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags) {
idt_entries[idx] = (struct idt_entry) {
.base_low = (uint32_t)base & 0xFFFF,
.base_high = ((uint32_t)base >> 16) & 0xFFFF,
.seg_sel = selector,
.flags = flags
};
}
static void init_idt() {
idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1;
idt_ptr.base = idt_entries;
memset(&idt_entries, 0, sizeof(idt_entry_t) * 256);
idt_flags_t flags = {
.reserved = IDT_FLAG_RESERVED, // Always 0x0E
.dpl = 0,
.p = 1
};
// Remap IDT with ISRs
idt_set_gate(0, isr0, 0x08, flags);
idt_set_gate(1, isr1, 0x08, flags);
idt_set_gate(2, isr2, 0x08, flags);
idt_set_gate(3, isr3, 0x08, flags);
idt_set_gate(4, isr4, 0x08, flags);
idt_set_gate(5, isr5, 0x08, flags);
idt_set_gate(6, isr6, 0x08, flags);
idt_set_gate(7, isr7, 0x08, flags);
idt_set_gate(8, isr8, 0x08, flags);
idt_set_gate(9, isr9, 0x08, flags);
idt_set_gate(10, isr10, 0x08, flags);
idt_set_gate(11, isr11, 0x08, flags);
idt_set_gate(12, isr12, 0x08, flags);
idt_set_gate(13, isr13, 0x08, flags);
idt_set_gate(14, isr14, 0x08, flags);
idt_set_gate(15, isr15, 0x08, flags);
idt_set_gate(16, isr16, 0x08, flags);
idt_set_gate(17, isr17, 0x08, flags);
idt_set_gate(18, isr18, 0x08, flags);
idt_set_gate(19, isr19, 0x08, flags);
idt_set_gate(20, isr20, 0x08, flags);
idt_set_gate(21, isr21, 0x08, flags);
idt_set_gate(22, isr22, 0x08, flags);
idt_set_gate(23, isr23, 0x08, flags);
idt_set_gate(24, isr24, 0x08, flags);
idt_set_gate(25, isr25, 0x08, flags);
idt_set_gate(26, isr26, 0x08, flags);
idt_set_gate(27, isr27, 0x08, flags);
idt_set_gate(28, isr28, 0x08, flags);
idt_set_gate(29, isr29, 0x08, flags);
idt_set_gate(30, isr30, 0x08, flags);
idt_set_gate(31, isr31, 0x08, flags);
// Remap PIC
pic_remap(PIC1_START_INTERRUPT, PIC2_START_INTERRUPT);
// Also remap 15 entries for IRQs
idt_set_gate(32, irq0, 0x08, flags);
idt_set_gate(33, irq1, 0x08, flags);
idt_set_gate(34, irq2, 0x08, flags);
idt_set_gate(35, irq3, 0x08, flags);
idt_set_gate(36, irq4, 0x08, flags);
idt_set_gate(37, irq5, 0x08, flags);
idt_set_gate(38, irq6, 0x08, flags);
idt_set_gate(39, irq7, 0x08, flags);
idt_set_gate(40, irq8, 0x08, flags);
idt_set_gate(41, irq9, 0x08, flags);
idt_set_gate(42, irq10, 0x08, flags);
idt_set_gate(43, irq11, 0x08, flags);
idt_set_gate(44, irq12, 0x08, flags);
idt_set_gate(45, irq13, 0x08, flags);
idt_set_gate(46, irq14, 0x08, flags);
idt_set_gate(47, irq15, 0x08, flags);
idt_flush(&idt_ptr);
// Finally enable hardware interrupts with an assembly instruction
__asm__ __volatile__ ("sti");
}
// Taken from: http://wiki.osdev.org/8259_PIC
static void pic_remap(uint8_t offset1, uint8_t offset2) {
uint8_t a1, a2;
a1 = inb(PIC1_DATA); // Save masks
a2 = inb(PIC2_DATA);
outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); // Start init sequence
outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
outb(PIC1_DATA, offset1);
outb(PIC2_DATA, offset2);
outb(PIC1_DATA, 4); // Tell master PIC that there is a slave PIC at IRQ2
outb(PIC1_DATA, 2); // Tell salve PIC it's cascade identity
outb(PIC1_DATA, ICW4_8086);
outb(PIC2_DATA, ICW4_8086);
// Restore saved masks
outb(PIC1_DATA, a1);
outb(PIC2_DATA, a2);
}

View File

@ -1,144 +1,144 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _IDT_H_
#define _IDT_H_
#include <stdint.h>
/*
* First a bit of theory:
* Sometimes you want to interrupt the processor from what it is currently doing
* and force it to do something more "critical", such as a timer update or a keyboard interrupt
* request(IRQ) fires. The processor, then, will handle those IRQs activating an
* interrupt handler(ISR, Interrupt Service Routines). In order to know where to find those
* ISRs, the CPU will use the IDT. So we can say that the Interrupt Description Table
* is another data structure(organized the same way as the GDT) that will provide a list
* of interrupts handlers(ISRs) to the CPU.
*/
// Reserved bits in IDT entries
#define IDT_FLAG_RESERVED 0x0E
// PIC
#define PIC1 0x20 // I/O address for master PIC
#define PIC2 0xA0 // I/O address for slave PIC
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define PIC1_START_INTERRUPT 0x20 // Master PIC after remapping
#define PIC2_START_INTERRUPT 0x28 // Slave PIC after remapping
#define PIC_EOI 0x20 // End of interrupt
#define ICW1_ICW4 0x01
#define ICW1_SINGLE 0x02
#define ICW1_INTERVAL4 0x04
#define ICW1_LEVEL 0x08
#define ICW1_INIT 0x10
#define ICW4_8086 0x01 // 8086/88 (MCS-80/85) mode
#define ICW4_AUTO 0x02
#define ICW4_BUF_SLAVE 0x08
#define ICW4_BUF_MASTER 0x0C
#define ICW4_SFNM 0x10
/* Interrupt Descriptor Table */
/* idt_flags contains access flag of a single IDT entry
* | 0 - 4 | 5 - 6 | 7 |
* | res | dpl | p |
* res: always 0x0E
* dpl: ring num (0 - 3)
* p: segment present (bool)
*/
struct idt_flags {
uint8_t reserved: 5;
uint8_t dpl: 2;
uint8_t p: 1;
}__attribute__((packed));
typedef struct idt_flags idt_flags_t;
/* idt_entry contains the value of an IDT entry
* Each entry is 64 bits(like GDT entry)
* | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 63 |
* | b low | seg sel | res | flags | b high |
* b low: Lower 16 bits of the base
* seg sel: Segment selector for code segment
* res: always 0
* flags: idt_flags struct
* b high: Higher 16 bits of the base
*/
struct idt_entry {
uint16_t base_low;
uint16_t seg_sel;
uint8_t reserved;
idt_flags_t flags;
uint16_t base_high;
}__attribute__((packed));
typedef struct idt_entry idt_entry_t;
/* Also we have to define a pointer to the data structure
* This is needed to locate it later */
struct idt_ptr {
uint16_t limit;
idt_entry_t *base;
}__attribute__((packed));
typedef struct idt_ptr idt_ptr_t;
/* IDT Kernel API */
void idt_setup();
// ISRs method declaration
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _IDT_H_
#define _IDT_H_
#include <stdint.h>
/*
* First a bit of theory:
* Sometimes you want to interrupt the processor from what it is currently doing
* and force it to do something more "critical", such as a timer update or a keyboard interrupt
* request(IRQ) fires. The processor, then, will handle those IRQs activating an
* interrupt handler(ISR, Interrupt Service Routines). In order to know where to find those
* ISRs, the CPU will use the IDT. So we can say that the Interrupt Description Table
* is another data structure(organized the same way as the GDT) that will provide a list
* of interrupts handlers(ISRs) to the CPU.
*/
// Reserved bits in IDT entries
#define IDT_FLAG_RESERVED 0x0E
// PIC
#define PIC1 0x20 // I/O address for master PIC
#define PIC2 0xA0 // I/O address for slave PIC
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define PIC1_START_INTERRUPT 0x20 // Master PIC after remapping
#define PIC2_START_INTERRUPT 0x28 // Slave PIC after remapping
#define PIC_EOI 0x20 // End of interrupt
#define ICW1_ICW4 0x01
#define ICW1_SINGLE 0x02
#define ICW1_INTERVAL4 0x04
#define ICW1_LEVEL 0x08
#define ICW1_INIT 0x10
#define ICW4_8086 0x01 // 8086/88 (MCS-80/85) mode
#define ICW4_AUTO 0x02
#define ICW4_BUF_SLAVE 0x08
#define ICW4_BUF_MASTER 0x0C
#define ICW4_SFNM 0x10
/* Interrupt Descriptor Table */
/* idt_flags contains access flag of a single IDT entry
* | 0 - 4 | 5 - 6 | 7 |
* | res | dpl | p |
* res: always 0x0E
* dpl: ring num (0 - 3)
* p: segment present (bool)
*/
struct idt_flags {
uint8_t reserved: 5;
uint8_t dpl: 2;
uint8_t p: 1;
}__attribute__((packed));
typedef struct idt_flags idt_flags_t;
/* idt_entry contains the value of an IDT entry
* Each entry is 64 bits(like GDT entry)
* | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 63 |
* | b low | seg sel | res | flags | b high |
* b low: Lower 16 bits of the base
* seg sel: Segment selector for code segment
* res: always 0
* flags: idt_flags struct
* b high: Higher 16 bits of the base
*/
struct idt_entry {
uint16_t base_low;
uint16_t seg_sel;
uint8_t reserved;
idt_flags_t flags;
uint16_t base_high;
}__attribute__((packed));
typedef struct idt_entry idt_entry_t;
/* Also we have to define a pointer to the data structure
* This is needed to locate it later */
struct idt_ptr {
uint16_t limit;
idt_entry_t *base;
}__attribute__((packed));
typedef struct idt_ptr idt_ptr_t;
/* IDT Kernel API */
void idt_setup();
// ISRs method declaration
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();
#endif

View File

@ -1,56 +1,56 @@
#include "initrd.h"
// Declare various things
initrd_header_t *initrd_header; // Header
initrd_file_header_t *file_header; // List of headers
fs_node_t *initrd_root; // Directory root node
fs_node_t *initrd_dev; // Directory dev node(/dev)
fs_node_t *root_nodes; // List of file nodes
uint32_t nroot_nodes;
struct dirent dirent;
fs_node_t *init_ramdisk(uint32_t multiboot_location) {
// Initialize main and file headers
initrd_header = (initrd_header_t*)multiboot_location;
file_header = (initrd_file_header_t*)(multiboot_location+sizeof(initrd_header_t));
// Initialize root directory
initrd_root = (fs_node_t*)
}
static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
initrd_file_header_t header = file_header[node->inode];
if(offset > header.length)
return 0;
if(offset+size > header.length)
size = header.length-offset;
memcpy(buffer, (uint8_t*) (header.offset+offset), size);
return size;
}
static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index) {
if(node == initrd_root && index == 0) {
strcpy(dirent.name, "dev");
dirent.name[3] = 0; // Add null terminator to the string
dirent.ino = 0;
return &dirent;
}
if(index-1 >= &root_nodes)
return 0;
strcpy(dirent.name, root_nodes[index-1].name);
dirent.name[strlen(root_nodes[index-1].name)] = 0; // Add null terminator
dirent.ino = root_nodes[index-1].inode;
return &dirent;
}
static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name) {
if(node == initrd_root && !strcmp(name, "dev"))
return initrd_dev;
for(uint32_t i = 0; i < nroot_nodes; i++)
if(!strcmp(name, root_nodes[i].name))
return &root_nodes[i];
return 0;
#include "initrd.h"
// Declare various things
initrd_header_t *initrd_header; // Header
initrd_file_header_t *file_header; // List of headers
fs_node_t *initrd_root; // Directory root node
fs_node_t *initrd_dev; // Directory dev node(/dev)
fs_node_t *root_nodes; // List of file nodes
uint32_t nroot_nodes;
struct dirent dirent;
fs_node_t *init_ramdisk(uint32_t multiboot_location) {
// Initialize main and file headers
initrd_header = (initrd_header_t*)multiboot_location;
file_header = (initrd_file_header_t*)(multiboot_location+sizeof(initrd_header_t));
// Initialize root directory
initrd_root = (fs_node_t*)
}
static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
initrd_file_header_t header = file_header[node->inode];
if(offset > header.length)
return 0;
if(offset+size > header.length)
size = header.length-offset;
memcpy(buffer, (uint8_t*) (header.offset+offset), size);
return size;
}
static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index) {
if(node == initrd_root && index == 0) {
strcpy(dirent.name, "dev");
dirent.name[3] = 0; // Add null terminator to the string
dirent.ino = 0;
return &dirent;
}
if(index-1 >= &root_nodes)
return 0;
strcpy(dirent.name, root_nodes[index-1].name);
dirent.name[strlen(root_nodes[index-1].name)] = 0; // Add null terminator
dirent.ino = root_nodes[index-1].inode;
return &dirent;
}
static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name) {
if(node == initrd_root && !strcmp(name, "dev"))
return initrd_dev;
for(uint32_t i = 0; i < nroot_nodes; i++)
if(!strcmp(name, root_nodes[i].name))
return &root_nodes[i];
return 0;
}

View File

@ -1,36 +1,36 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef INITRD_H
#define INITRD_H
/* Ramdisk is a file system that is loaded along with the kernel
* and it usually contains configuration files or file system drivers.
* It is used BEFORE partitions are being mounted*/
#include <stdint.h>
#include "../libc/string.h"
#include "fs.h"
typedef struct {
uint32_t nfiles; // Number of files in the ramdisk
} initrd_header_t;
typedef struct {
uint8_t magic; // Magic number for error checking
int8_t name[64]; // Filename
uint32_t offset;
uint32_t length; // Length of the file
} initrd_file_header_t;
// Function to initialize initrd, we'll pass the multiboot
// module as parameter
fs_node_t *init_ramdisk(uint32_t multiboot_location);
static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index);
static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef INITRD_H
#define INITRD_H
/* Ramdisk is a file system that is loaded along with the kernel
* and it usually contains configuration files or file system drivers.
* It is used BEFORE partitions are being mounted*/
#include <stdint.h>
#include "../libc/string.h"
#include "fs.h"
typedef struct {
uint32_t nfiles; // Number of files in the ramdisk
} initrd_header_t;
typedef struct {
uint8_t magic; // Magic number for error checking
int8_t name[64]; // Filename
uint32_t offset;
uint32_t length; // Length of the file
} initrd_file_header_t;
// Function to initialize initrd, we'll pass the multiboot
// module as parameter
fs_node_t *init_ramdisk(uint32_t multiboot_location);
static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer);
static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index);
static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name);
#endif

View File

@ -1,87 +1,87 @@
#include <stdint.h>
#include "isr.h"
#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
#define PIC1 0x20 // I/O address for master PIC
#define PIC2 0xA0 // I/O address for slave PIC
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define PIC_EOI 0x20 // End Of Interrupt command
// List of messages for known interrupts
uint8_t *interrupts_messages[] = {
(uint8_t*)"Division by Zero", // 0
(uint8_t*)"Debug",
(uint8_t*)"Non-maskable interrupt",
(uint8_t*)"Breakpoint",
(uint8_t*)"Detected overflow",
(uint8_t*)"Out-of-bounds", // 5
(uint8_t*)"Invalid opcode",
(uint8_t*)"No coprocessor",
(uint8_t*)"Double fault",
(uint8_t*)"Coprocessor segment overrun",
(uint8_t*)"Bad TSS", // 10
(uint8_t*)"Segment not present",
(uint8_t*)"Stack fault",
(uint8_t*)"General protection fault",
(uint8_t*)"Page fault",
(uint8_t*)"Unknown interrupt", // 15
(uint8_t*)"Coprocessor fault",
(uint8_t*)"Alignment check",
(uint8_t*)"Machine check",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved"
};
isr_t interrupt_handler[256];
void isr_handler(registers_t regs) {
if(interrupt_handler[regs.int_num] != 0) {
isr_t handler = interrupt_handler[regs.int_num];
handler(regs);
} else {
uint8_t *buf = (uint8_t*)"\nReceived interrupt: ";
kprint_c((uint8_t*)buf,strlen(buf), LIGHT_BROWN, BLACK);
kprint_c(interrupts_messages[(uint8_t)regs.int_num],
strlen(interrupts_messages[(uint8_t)regs.int_num]),
WHITE,
BLACK
);
}
}
void ack_irq(uint32_t int_num) {
// Send and End Of Interrupt(EOF) at the PICs.
if(int_num >= 40)
outb(PIC2_COMMAND, PIC_EOI); // Send reset signal to slave
outb(PIC1_COMMAND, PIC_EOI); // In any case, reset the master
}
void irq_handler(registers_t regs) {
ack_irq(regs.int_num);
if(interrupt_handler[regs.int_num] != 0) {
isr_t handler = interrupt_handler[regs.int_num];
handler(regs);
}
}
void register_interrupt_handler(uint8_t n, isr_t handler) {
interrupt_handler[n] = handler;
#include <stdint.h>
#include "isr.h"
#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
#define PIC1 0x20 // I/O address for master PIC
#define PIC2 0xA0 // I/O address for slave PIC
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define PIC_EOI 0x20 // End Of Interrupt command
// List of messages for known interrupts
uint8_t *interrupts_messages[] = {
(uint8_t*)"Division by Zero", // 0
(uint8_t*)"Debug",
(uint8_t*)"Non-maskable interrupt",
(uint8_t*)"Breakpoint",
(uint8_t*)"Detected overflow",
(uint8_t*)"Out-of-bounds", // 5
(uint8_t*)"Invalid opcode",
(uint8_t*)"No coprocessor",
(uint8_t*)"Double fault",
(uint8_t*)"Coprocessor segment overrun",
(uint8_t*)"Bad TSS", // 10
(uint8_t*)"Segment not present",
(uint8_t*)"Stack fault",
(uint8_t*)"General protection fault",
(uint8_t*)"Page fault",
(uint8_t*)"Unknown interrupt", // 15
(uint8_t*)"Coprocessor fault",
(uint8_t*)"Alignment check",
(uint8_t*)"Machine check",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved"
};
isr_t interrupt_handler[256];
void isr_handler(registers_t regs) {
if(interrupt_handler[regs.int_num] != 0) {
isr_t handler = interrupt_handler[regs.int_num];
handler(regs);
} else {
uint8_t *buf = (uint8_t*)"\nReceived interrupt: ";
kprint_c((uint8_t*)buf,strlen(buf), LIGHT_BROWN, BLACK);
kprint_c(interrupts_messages[(uint8_t)regs.int_num],
strlen(interrupts_messages[(uint8_t)regs.int_num]),
WHITE,
BLACK
);
}
}
void ack_irq(uint32_t int_num) {
// Send and End Of Interrupt(EOF) at the PICs.
if(int_num >= 40)
outb(PIC2_COMMAND, PIC_EOI); // Send reset signal to slave
outb(PIC1_COMMAND, PIC_EOI); // In any case, reset the master
}
void irq_handler(registers_t regs) {
ack_irq(regs.int_num);
if(interrupt_handler[regs.int_num] != 0) {
isr_t handler = interrupt_handler[regs.int_num];
handler(regs);
}
}
void register_interrupt_handler(uint8_t n, isr_t handler) {
interrupt_handler[n] = handler;
}

View File

@ -1,72 +1,72 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _ISR_H_
#define _ISR_H_
#include <stdint.h>
/*
* When we implement ISRs we have to keep in mind that the first 32 interrupts(and so the
* first 32 ISRs) are reserved by the CPU to signal the kernel about critical actions,
* such as divide-by-zero or a stack overflow/buffer overflow.
*
* Below ther's a list of the first, reserved, interrupts...and yeah, we have to implement
* all of them by ourself(btw in Assembly) :D
*
* 0 - Division by zero exception
* 1 - Debug exception
* 2 - Non maskable interrupt
* 3 - Breakpoint exception
* 4 - Into detected overflow
* 5 - Out of bounds exception
* 6 - Invalid opcode exception
* 7 - No coprocessor exception
* 8 - Double fault (pushes an error code)
* 9 - Coprocessor segment overrun
* 10 - Bad TSS (pushes an error code)
* 11 - Segment not present (pushes an error code)
* 12 - Stack fault (pushes an error code)
* 13 - General protection fault (pushes an error code)
* 14 - Page fault (pushes an error code)
* 15 - Unknown interrupt exception
* 16 - Coprocessor fault
* 17 - Alignment check exception
* 18 - Machine check exception
* 19-31 - Reserved */
#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
typedef struct registers {
uint32_t ds; // Data segment
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed with pusha
uint32_t int_num, err_code; // Interrupt number and error code
uint32_t eip, cs, eflags, usereap, ss; // Pushed by CPU
} registers_t;
typedef void (*isr_t)(registers_t);
void ack_irq(uint32_t int_num);
void register_interrupt_handler(uint8_t n, isr_t handler);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _ISR_H_
#define _ISR_H_
#include <stdint.h>
/*
* When we implement ISRs we have to keep in mind that the first 32 interrupts(and so the
* first 32 ISRs) are reserved by the CPU to signal the kernel about critical actions,
* such as divide-by-zero or a stack overflow/buffer overflow.
*
* Below ther's a list of the first, reserved, interrupts...and yeah, we have to implement
* all of them by ourself(btw in Assembly) :D
*
* 0 - Division by zero exception
* 1 - Debug exception
* 2 - Non maskable interrupt
* 3 - Breakpoint exception
* 4 - Into detected overflow
* 5 - Out of bounds exception
* 6 - Invalid opcode exception
* 7 - No coprocessor exception
* 8 - Double fault (pushes an error code)
* 9 - Coprocessor segment overrun
* 10 - Bad TSS (pushes an error code)
* 11 - Segment not present (pushes an error code)
* 12 - Stack fault (pushes an error code)
* 13 - General protection fault (pushes an error code)
* 14 - Page fault (pushes an error code)
* 15 - Unknown interrupt exception
* 16 - Coprocessor fault
* 17 - Alignment check exception
* 18 - Machine check exception
* 19-31 - Reserved */
#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
typedef struct registers {
uint32_t ds; // Data segment
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed with pusha
uint32_t int_num, err_code; // Interrupt number and error code
uint32_t eip, cs, eflags, usereap, ss; // Pushed by CPU
} registers_t;
typedef void (*isr_t)(registers_t);
void ack_irq(uint32_t int_num);
void register_interrupt_handler(uint8_t n, isr_t handler);
#endif

View File

@ -1,118 +1,118 @@
/* The keyboard driver works with a device called PS/2: to talk with this
* controller we can use serial communication(e.g. ports.h). The actual flow of
* data is made with "commands", each command is one byte and the keyboard's
* controller can send two type of response:
* ACK(Acknowledge): to acknowledge the previous command
* Resend: to resend the previous command due to an error.
* We have also to wait between the command, the data and the response of
* the PS/2 controller.
* This device should not exists anymore in any modern computer
* motherboard; however the CPU(or the motherboard?) should be able to
* simulate it even if we're using some USB keyboard.
* Apart of that the keyboard will be listen on IRQ1(33),
* so we have to register an ISR for that.
*/
#include "keyboard.h"
#include "isr.h"
#include "ports.h"
#include "tty.h"
#include "../userspace/shell.h"
#include "../libc/stdio.h"
static void keyboard_callback();
/* Keyboard scan codes map , layout is: standard US keyboard */
uint8_t keyboard_scan_codes[] = {
0, (uint8_t)27, (uint8_t)'1', (uint8_t)'2', (uint8_t)'3', (uint8_t)'4', (uint8_t)'5', (uint8_t)'6', (uint8_t)'7', (uint8_t)'8',
(uint8_t)'0', (uint8_t)'0', (uint8_t)'-', (uint8_t)'=', (uint8_t)'\b',
(uint8_t)'\t',
(uint8_t)'q', (uint8_t)'w', (uint8_t)'e', (uint8_t)'r',
(uint8_t)'t', (uint8_t)'y', (uint8_t)'u', (uint8_t)'i', (uint8_t)'o', (uint8_t)'p', (uint8_t)'[', (uint8_t)']', (uint8_t)'\n',
0,
(uint8_t)'a', (uint8_t)'s', (uint8_t)'d', (uint8_t)'f', (uint8_t)'g', (uint8_t)'h', (uint8_t)'j', (uint8_t)'k', (uint8_t)'l', (uint8_t)';',
(uint8_t)'\'', (uint8_t)'`', 0,
(uint8_t)'\\', (uint8_t)'z', (uint8_t)'x', (uint8_t)'c', (uint8_t)'v', (uint8_t)'b', (uint8_t)'n',
(uint8_t)'m', (uint8_t)',', (uint8_t)'.', (uint8_t)'/', 0,
(uint8_t)'*',
0, // Alt
(uint8_t)' ', // Spacebar
0, // Caps lock
0, // 59 - F1 key
0, // 59 - F1 key
0, 0, 0, 0, 0, 0, 0, 0,
0, // F10
0, // 69 - Num lock
0, // Scroll lock
0, // Home key
0, // Up arrow
0, // Page up
(uint8_t)'-',
0, // Left arrow
0,
0, // Right arrow
(uint8_t)'+',
0, // 79 End key
0, // Down arrow
0, // Page down
0, // Insert key
0, // Delete key
0, 0, 0,
0, // F11 key
0, // F12 key
0 // Others key are undefined
};
uint8_t command[512]; // Max length of a single command
uint8_t temp[512];
uint32_t cmd_index = 0;
uint32_t shiftdown = 0;
void clear() {
for(uint16_t i = 0; i < 512; i++)
command[i] = 0;
}
void clear_tmp(void) {
for(uint16_t i = 0; i < 512; i++)
command[i] = 0;
}
static void keyboard_callback() {
uint8_t scan_code = inb(KB_DATA_PORT); // Read from keyboard
uint8_t keycode = keyboard_scan_codes[scan_code]; // Get ASCII value
if(scan_code & 0x80) {
if(scan_code == 0xAA || scan_code == 0x86)
shiftdown = 0;
} else {
// Handle backspace
if(keycode == 0x08) {
if(cmd_index <= 0) // If at start of the prompt
return; // Do not delete it.
cmd_index--; // Otherwise go back
for(uint32_t i = 0; i < cmd_index; ++i)
temp[i] = command[i];
clear();
for(uint32_t i = 0; i < cmd_index; ++i)
command[i] = temp[i];
clear_tmp();
backspace();
} else if(keycode == 0x0A) { // Handle Enter
processCommand(command);
cmd_index = 0;
clear();
init_prompt();
} else {
printf("%c", keycode);
command[cmd_index] = keycode;
cmd_index++;
}
}
}
void init_keyboard() {
register_interrupt_handler(IRQ1, &keyboard_callback);
}
/* The keyboard driver works with a device called PS/2: to talk with this
* controller we can use serial communication(e.g. ports.h). The actual flow of
* data is made with "commands", each command is one byte and the keyboard's
* controller can send two type of response:
* ACK(Acknowledge): to acknowledge the previous command
* Resend: to resend the previous command due to an error.
* We have also to wait between the command, the data and the response of
* the PS/2 controller.
* This device should not exists anymore in any modern computer
* motherboard; however the CPU(or the motherboard?) should be able to
* simulate it even if we're using some USB keyboard.
* Apart of that the keyboard will be listen on IRQ1(33),
* so we have to register an ISR for that.
*/
#include "keyboard.h"
#include "isr.h"
#include "ports.h"
#include "tty.h"
#include "../userspace/shell.h"
#include "../libc/stdio.h"
static void keyboard_callback();
/* Keyboard scan codes map , layout is: standard US keyboard */
uint8_t keyboard_scan_codes[] = {
0, (uint8_t)27, (uint8_t)'1', (uint8_t)'2', (uint8_t)'3', (uint8_t)'4', (uint8_t)'5', (uint8_t)'6', (uint8_t)'7', (uint8_t)'8',
(uint8_t)'0', (uint8_t)'0', (uint8_t)'-', (uint8_t)'=', (uint8_t)'\b',
(uint8_t)'\t',
(uint8_t)'q', (uint8_t)'w', (uint8_t)'e', (uint8_t)'r',
(uint8_t)'t', (uint8_t)'y', (uint8_t)'u', (uint8_t)'i', (uint8_t)'o', (uint8_t)'p', (uint8_t)'[', (uint8_t)']', (uint8_t)'\n',
0,
(uint8_t)'a', (uint8_t)'s', (uint8_t)'d', (uint8_t)'f', (uint8_t)'g', (uint8_t)'h', (uint8_t)'j', (uint8_t)'k', (uint8_t)'l', (uint8_t)';',
(uint8_t)'\'', (uint8_t)'`', 0,
(uint8_t)'\\', (uint8_t)'z', (uint8_t)'x', (uint8_t)'c', (uint8_t)'v', (uint8_t)'b', (uint8_t)'n',
(uint8_t)'m', (uint8_t)',', (uint8_t)'.', (uint8_t)'/', 0,
(uint8_t)'*',
0, // Alt
(uint8_t)' ', // Spacebar
0, // Caps lock
0, // 59 - F1 key
0, // 59 - F1 key
0, 0, 0, 0, 0, 0, 0, 0,
0, // F10
0, // 69 - Num lock
0, // Scroll lock
0, // Home key
0, // Up arrow
0, // Page up
(uint8_t)'-',
0, // Left arrow
0,
0, // Right arrow
(uint8_t)'+',
0, // 79 End key
0, // Down arrow
0, // Page down
0, // Insert key
0, // Delete key
0, 0, 0,
0, // F11 key
0, // F12 key
0 // Others key are undefined
};
uint8_t command[512]; // Max length of a single command
uint8_t temp[512];
uint32_t cmd_index = 0;
uint32_t shiftdown = 0;
void clear() {
for(uint16_t i = 0; i < 512; i++)
command[i] = 0;
}
void clear_tmp(void) {
for(uint16_t i = 0; i < 512; i++)
command[i] = 0;
}
static void keyboard_callback() {
uint8_t scan_code = inb(KB_DATA_PORT); // Read from keyboard
uint8_t keycode = keyboard_scan_codes[scan_code]; // Get ASCII value
if(scan_code & 0x80) {
if(scan_code == 0xAA || scan_code == 0x86)
shiftdown = 0;
} else {
// Handle backspace
if(keycode == 0x08) {
if(cmd_index <= 0) // If at start of the prompt
return; // Do not delete it.
cmd_index--; // Otherwise go back
for(uint32_t i = 0; i < cmd_index; ++i)
temp[i] = command[i];
clear();
for(uint32_t i = 0; i < cmd_index; ++i)
command[i] = temp[i];
clear_tmp();
backspace();
} else if(keycode == 0x0A) { // Handle Enter
processCommand(command);
cmd_index = 0;
clear();
init_prompt();
} else {
printf("%c", keycode);
command[cmd_index] = keycode;
cmd_index++;
}
}
}
void init_keyboard() {
register_interrupt_handler(IRQ1, &keyboard_callback);
}

View File

@ -1,17 +1,17 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _KEYBOARD_H_
#define _KEYBOARD_H_
#include <stdint.h>
#define KB_DATA_PORT 0x60 // Keyboard serial port
void init_keyboard();
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _KEYBOARD_H_
#define _KEYBOARD_H_
#include <stdint.h>
#define KB_DATA_PORT 0x60 // Keyboard serial port
void init_keyboard();
#endif

View File

@ -1,27 +1,27 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _PORTS_H
#define _PORTS_H
#include <stdint.h>
/* outb:
* Redirect data to port(high level interface for ports.asm)
* @param port: Output port to send data to.
* @param data: The actual data to send to port
*/
void outb(uint16_t port, uint16_t data);
/* inb:
* Fetch data from a port, return a char
* @param port: Input port to read data from.
*/
uint8_t inb(uint16_t port);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _PORTS_H
#define _PORTS_H
#include <stdint.h>
/* outb:
* Redirect data to port(high level interface for ports.asm)
* @param port: Output port to send data to.
* @param data: The actual data to send to port
*/
void outb(uint16_t port, uint16_t data);
/* inb:
* Fetch data from a port, return a char
* @param port: Input port to read data from.
*/
uint8_t inb(uint16_t port);
#endif

View File

@ -1,39 +1,39 @@
#include "timer.h"
#include "isr.h"
#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
// Start tick at zero
uint32_t tick = 0;
static void timer_callback(registers_t regs) {
tick++;
/* uint8_t buf[8];
itoa(tick, buf, 10);
kprint((uint8_t*)"Time: ");
uitoa(tick, buf, 10);
kprint((uint8_t*)buf);
kprint((uint8_t*)"\n");*/
// Cast to void unused parameter
UNUSED_PAR(regs);
}
void init_timer(uint32_t frequency) {
// Register a new ISR for IRQ0
register_interrupt_handler(IRQ0, &timer_callback);
/* As mentioned before, we'll send to PIT a value to divide for
* his system clock(1.1931 MHz). We have to keep in mind that
* this value must fit into a 16 bits variable */
uint32_t divisor = 1193180 / frequency;
// Send command to the right port
outb(0x43, 0x36);
// The two divisor has to be sent byte-wise, to do this we split them in two parts
uint8_t low = (uint8_t)(divisor & 0xFF);
uint8_t high = (uint8_t)((divisor >> 8) & 0xFF);
// Send the frequency divisor
outb(0x40, low);
outb(0x40, high);
}
#include "timer.h"
#include "isr.h"
#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
// Start tick at zero
uint32_t tick = 0;
static void timer_callback(registers_t regs) {
tick++;
/* uint8_t buf[8];
itoa(tick, buf, 10);
kprint((uint8_t*)"Time: ");
uitoa(tick, buf, 10);
kprint((uint8_t*)buf);
kprint((uint8_t*)"\n");*/
// Cast to void unused parameter
UNUSED_PAR(regs);
}
void init_timer(uint32_t frequency) {
// Register a new ISR for IRQ0
register_interrupt_handler(IRQ0, &timer_callback);
/* As mentioned before, we'll send to PIT a value to divide for
* his system clock(1.1931 MHz). We have to keep in mind that
* this value must fit into a 16 bits variable */
uint32_t divisor = 1193180 / frequency;
// Send command to the right port
outb(0x43, 0x36);
// The two divisor has to be sent byte-wise, to do this we split them in two parts
uint8_t low = (uint8_t)(divisor & 0xFF);
uint8_t high = (uint8_t)((divisor >> 8) & 0xFF);
// Send the frequency divisor
outb(0x40, low);
outb(0x40, high);
}

View File

@ -1,41 +1,41 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _TIMER_H_
#define _TIMER_H_
#include <stdint.h>
/*
* The PIT(Programmable Interval Timer) is a chip that consist of an oscillator
* It's connected to IRQ0 and it can be configure at a user-defined rate
* between 10.Hz to 1.1931 MHz. The PIT is the primary method used to implement
* a system clock and for implement multitasking.
* The PIT's internal clock(~1.1931 MHz) is fed through a frequency divider that
* modulate the final signal. This chip has 3 channel, each with his own
* frequency divider:
* Channel 0: The most useful, it's output is connected to IRQ0
* Channel 1: It were used to control refresh rates on DRAM(RAMs with capacitors)
* Channel 2: Controls the PC speakers.
*
* In our case, we will use only channel 0.
* So we have to set up PIT at a frequency 'f', so it interrupts us at regular
* intervals. We'll set the frequency to 100Hz(once every 10 ms); to do this
* we'll send the PIT a divisor that will be divided for it's input frequency.
* E.g. -> divisor = 1193180 Hz(1.1931MHz) / 100 Hz
*
* Apart of that, the PIT has 4 registers: 0x40-0x42(data ports) and 0x43(command port)
*/
void init_timer(uint32_t frequency);
extern uint32_t tick;
/* Since regs parameter(from timer_callback) will be unused
* GCC(with -Werror flag) will throw an error, so we can avoid this
* using the following macro
*/
#define UNUSED_PAR(x) (void)(x)
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _TIMER_H_
#define _TIMER_H_
#include <stdint.h>
/*
* The PIT(Programmable Interval Timer) is a chip that consist of an oscillator
* It's connected to IRQ0 and it can be configure at a user-defined rate
* between 10.Hz to 1.1931 MHz. The PIT is the primary method used to implement
* a system clock and for implement multitasking.
* The PIT's internal clock(~1.1931 MHz) is fed through a frequency divider that
* modulate the final signal. This chip has 3 channel, each with his own
* frequency divider:
* Channel 0: The most useful, it's output is connected to IRQ0
* Channel 1: It were used to control refresh rates on DRAM(RAMs with capacitors)
* Channel 2: Controls the PC speakers.
*
* In our case, we will use only channel 0.
* So we have to set up PIT at a frequency 'f', so it interrupts us at regular
* intervals. We'll set the frequency to 100Hz(once every 10 ms); to do this
* we'll send the PIT a divisor that will be divided for it's input frequency.
* E.g. -> divisor = 1193180 Hz(1.1931MHz) / 100 Hz
*
* Apart of that, the PIT has 4 registers: 0x40-0x42(data ports) and 0x43(command port)
*/
void init_timer(uint32_t frequency);
extern uint32_t tick;
/* Since regs parameter(from timer_callback) will be unused
* GCC(with -Werror flag) will throw an error, so we can avoid this
* using the following macro
*/
#define UNUSED_PAR(x) (void)(x)
#endif

View File

@ -1,153 +1,153 @@
#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
#define VGA_PTR ((uint8_t*) VIDEO_MEM_ADDR) // Pointer to frame buffer
// Also define a 2 byte pointer because cells are 16 bits wide
#define UVGA_PTR ((uint16_t *)VIDEO_MEM_ADDR)
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
static uint32_t fb_col = 1; // X
static uint32_t fb_row = 0; // Y
void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg) {
uint8_t *fb = VGA_PTR;
fb[i*2] = c;
fb[i*2 + 1] = ((bg & 0x0F) << 4) | (fg & 0x0F);
}
void move_cursor(uint16_t pos) {
outb(VGA_CMD_PORT, VGA_HIGH_BYTE);
outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF));
outb(VGA_CMD_PORT, VGA_LOW_BYTE);
outb(VGA_DATA_PORT, pos & 0x00FF);
}
void cursor_adv() { // TODO: specify number of adv. with a parameter
if(fb_col < VGA_WIDTH - 1)
fb_col++;
else
newline();
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void cursor_prev() {
if(fb_col == 0) {
if(fb_row == 0)
return; // If first row do not do anything
fb_col = VGA_WIDTH - 1;
fb_row--;
} else
fb_col--;
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void backspace() {
uint16_t pos;
uint8_t c = ' ';
fb_col--;
pos = fb_col + (fb_row * VGA_WIDTH);
write_cell(pos, c, WHITE, BLACK);
}
void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg) {
uint16_t pos;
for(uint32_t i = 0; i < len; i++) {
uint8_t c = buf[i];
if(c == '\n' || c == '\r')
newline();
else if(c == '\t')
tab();
else {
pos = fb_col + (fb_row * VGA_WIDTH);
write_cell(pos, (uint8_t)c, fg, bg);
cursor_adv();
}
}
}
void kprint(uint8_t *buf) {
kprint_c(buf, strlen(buf), WHITE, BLACK);
}
void kprint_dec(uint32_t num) {
if(num == 0) {
uint8_t *buf = (uint8_t*)'0';
kprint_c(buf, strlen(buf), WHITE, BLACK);;
return;
}
int32_t acc = num;
uint8_t c[32];
int32_t i = 0;
while(acc > 0) {
c[i] = '0' + acc%10;
acc /= 10;
i++;
}
c[i] = 0;
uint8_t c2[32];
c2[i--] = 0;
uint32_t j = 0;
while(i >= 0)
c2[i--] = c[j++];
kprint(c2);
}
void init_prompt() {
uint8_t user[64], hostname[64];
#ifdef DEFAULT_USER
strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER));
#else
#error "-DDEFAULT_USER flag not set"
#endif
#ifdef DEFAULT_HOSTNAME
strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME));
#else
#error "-DDEFAULT_HOSTNAME flag not set"
#endif
newline();
kprint_c(user, strlen(user), LIGHT_CYAN, BLACK);
kprint_c((uint8_t*)"@", 1, LIGHT_RED, BLACK);
kprint_c(hostname, strlen(hostname), LIGHT_MAGENTA, BLACK);
kprint_c((uint8_t*)" #> ", 4, LIGHT_BLUE, BLACK);
}
void clear_prompt() {
fb_col = 1;
fb_row = 0;
for(uint32_t i = 0; i < (VGA_WIDTH * VGA_HEIGHT); i++)
write_cell(i, ' ', WHITE, BLACK);
move_cursor(0);
}
void clear_row(uint8_t row) {
for(size_t i = 0; i < VGA_WIDTH; i++)
write_cell((row*VGA_WIDTH)+i, ' ', WHITE, BLACK);
}
void scroll() {
uint16_t *fb = UVGA_PTR;
memmove(fb, fb+VGA_WIDTH, VGA_WIDTH*2*(VGA_HEIGHT*2-1));
clear_row(VGA_HEIGHT - 1);
}
void newline() {
if(fb_row < VGA_HEIGHT - 1) // If there's at least one cell add it
fb_row++;
else // Otherwise scroll framebuffer
scroll();
fb_col = 1;
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void tab() {
for(uint8_t i = 0; i < 4; i++)
cursor_adv(); // Increment cursor 4 times
}
#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
#define VGA_PTR ((uint8_t*) VIDEO_MEM_ADDR) // Pointer to frame buffer
// Also define a 2 byte pointer because cells are 16 bits wide
#define UVGA_PTR ((uint16_t *)VIDEO_MEM_ADDR)
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
static uint32_t fb_col = 1; // X
static uint32_t fb_row = 0; // Y
void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg) {
uint8_t *fb = VGA_PTR;
fb[i*2] = c;
fb[i*2 + 1] = ((bg & 0x0F) << 4) | (fg & 0x0F);
}
void move_cursor(uint16_t pos) {
outb(VGA_CMD_PORT, VGA_HIGH_BYTE);
outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF));
outb(VGA_CMD_PORT, VGA_LOW_BYTE);
outb(VGA_DATA_PORT, pos & 0x00FF);
}
void cursor_adv() { // TODO: specify number of adv. with a parameter
if(fb_col < VGA_WIDTH - 1)
fb_col++;
else
newline();
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void cursor_prev() {
if(fb_col == 0) {
if(fb_row == 0)
return; // If first row do not do anything
fb_col = VGA_WIDTH - 1;
fb_row--;
} else
fb_col--;
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void backspace() {
uint16_t pos;
uint8_t c = ' ';
fb_col--;
pos = fb_col + (fb_row * VGA_WIDTH);
write_cell(pos, c, WHITE, BLACK);
}
void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg) {
uint16_t pos;
for(uint32_t i = 0; i < len; i++) {
uint8_t c = buf[i];
if(c == '\n' || c == '\r')
newline();
else if(c == '\t')
tab();
else {
pos = fb_col + (fb_row * VGA_WIDTH);
write_cell(pos, (uint8_t)c, fg, bg);
cursor_adv();
}
}
}
void kprint(uint8_t *buf) {
kprint_c(buf, strlen(buf), WHITE, BLACK);
}
void kprint_dec(uint32_t num) {
if(num == 0) {
uint8_t *buf = (uint8_t*)'0';
kprint_c(buf, strlen(buf), WHITE, BLACK);;
return;
}
int32_t acc = num;
uint8_t c[32];
int32_t i = 0;
while(acc > 0) {
c[i] = '0' + acc%10;
acc /= 10;
i++;
}
c[i] = 0;
uint8_t c2[32];
c2[i--] = 0;
uint32_t j = 0;
while(i >= 0)
c2[i--] = c[j++];
kprint(c2);
}
void init_prompt() {
uint8_t user[64], hostname[64];
#ifdef DEFAULT_USER
strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER));
#else
#error "-DDEFAULT_USER flag not set"
#endif
#ifdef DEFAULT_HOSTNAME
strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME));
#else
#error "-DDEFAULT_HOSTNAME flag not set"
#endif
newline();
kprint_c(user, strlen(user), LIGHT_CYAN, BLACK);
kprint_c((uint8_t*)"@", 1, LIGHT_RED, BLACK);
kprint_c(hostname, strlen(hostname), LIGHT_MAGENTA, BLACK);
kprint_c((uint8_t*)" #> ", 4, LIGHT_BLUE, BLACK);
}
void clear_prompt() {
fb_col = 1;
fb_row = 0;
for(uint32_t i = 0; i < (VGA_WIDTH * VGA_HEIGHT); i++)
write_cell(i, ' ', WHITE, BLACK);
move_cursor(0);
}
void clear_row(uint8_t row) {
for(size_t i = 0; i < VGA_WIDTH; i++)
write_cell((row*VGA_WIDTH)+i, ' ', WHITE, BLACK);
}
void scroll() {
uint16_t *fb = UVGA_PTR;
memmove(fb, fb+VGA_WIDTH, VGA_WIDTH*2*(VGA_HEIGHT*2-1));
clear_row(VGA_HEIGHT - 1);
}
void newline() {
if(fb_row < VGA_HEIGHT - 1) // If there's at least one cell add it
fb_row++;
else // Otherwise scroll framebuffer
scroll();
fb_col = 1;
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void tab() {
for(uint8_t i = 0; i < 4; i++)
cursor_adv(); // Increment cursor 4 times
}

View File

@ -1,63 +1,63 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _TTY_H_
#define _TTY_H_
#include <stdint.h>
// TODO: write something about Frame Buffer
// VGA colors
enum TTY_COLORS {
BLACK, // 0
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHT_GREY,
DARK_GREY,
LIGHT_BLUE,
LIGHT_GREEN,
LIGHT_CYAN,
LIGHT_RED,
LIGHT_MAGENTA,
LIGHT_BROWN,
WHITE // 15
};
/* Framebuffer properties */
#define VIDEO_MEM_ADDR 0x000B8000 // frame buffer address
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
/* VGA I/O ports */
#define VGA_CMD_PORT 0x3D4
#define VGA_DATA_PORT 0x3D5
/* VGA I/O ports commands */
#define VGA_HIGH_BYTE 14
#define VGA_LOW_BYTE 15
/* Kernel's VGA API */
void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg);
void move_cursor(uint16_t pos);
void cursor_adv();
void backspace();
void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg);
void kprint(uint8_t *buf);
void kprint_dec(uint32_t num);
void init_prompt();
void clear_prompt();
void clear_row(uint8_t row);
void scroll(); // Scroll one row
void newline();
void tab();
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _TTY_H_
#define _TTY_H_
#include <stdint.h>
// TODO: write something about Frame Buffer
// VGA colors
enum TTY_COLORS {
BLACK, // 0
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHT_GREY,
DARK_GREY,
LIGHT_BLUE,
LIGHT_GREEN,
LIGHT_CYAN,
LIGHT_RED,
LIGHT_MAGENTA,
LIGHT_BROWN,
WHITE // 15
};
/* Framebuffer properties */
#define VIDEO_MEM_ADDR 0x000B8000 // frame buffer address
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
/* VGA I/O ports */
#define VGA_CMD_PORT 0x3D4
#define VGA_DATA_PORT 0x3D5
/* VGA I/O ports commands */
#define VGA_HIGH_BYTE 14
#define VGA_LOW_BYTE 15
/* Kernel's VGA API */
void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg);
void move_cursor(uint16_t pos);
void cursor_adv();
void backspace();
void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg);
void kprint(uint8_t *buf);
void kprint_dec(uint32_t num);
void init_prompt();
void clear_prompt();
void clear_row(uint8_t row);
void scroll(); // Scroll one row
void newline();
void tab();
#endif

View File

@ -1,79 +1,79 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#include "drivers/tty.h"
#include "drivers/gdt.h"
#include "drivers/idt.h"
#include "drivers/timer.h"
#include "drivers/keyboard.h"
#include "mem/paging.h"
#include "mem/kheap.h"
#include "mem/multiboot.h"
#include "userspace/shell.h"
#include "libc/stdio.h"
#include "libc/panic.h"
#include <stdint.h>
#define PRTOK printf("\n["); printf_color(" OK ", LIGHT_GREEN, BLACK); printf("]"); // Ugly hack to print "[ OK ]"
#define PRTAT printf("\n["); printf_color(" ** ", LIGHT_BROWN, BLACK); printf("]"); // Ugly hack to print "[ * ]"
#define PRTER printf("\n["); printf_color(" ERR ", LIGHT_RED, BLACK); printf("]"); // Ugly hack to print "[ ER ]"
void kernel_main(unsigned long magic, uint32_t addr) {
// First of all, check if we're booted by a Multiboot-compliant boot loader
if(magic != MULTIBOOT2_BOOTLOADER_MAGIC) {
PRTER
printf(" - Invalid magic number: %x\n", (unsigned)magic);
PANIC("Invalid multiboot magic number");
}
if(addr & 7) {
PRTER
printf(" - Unaligned mbi: %x\n", addr);
PANIC("Unaligned multiboot MBI");
}
printf("Loading kernel, wait please...");
gdt_setup(); // Setup Global Descriptor Table
PRTOK
printf(" - Loaded GDT");
idt_setup(); // Setup Interrupt Descriptor Table
PRTOK
printf(" - Loaded IDT");
init_timer(1); // Initialize PIT driver
PRTOK
printf(" - Loaded PIT");
init_keyboard(); // Initialize keyboard driver
PRTOK
printf(" - Loaded PS/2 driver");
init_paging(); // Initialize paging
PRTOK
printf(" - Loaded Paging");
PRTAT
printf(" - Testing heap...\t");
uint32_t x = kmalloc(32), y = kmalloc(32);
printf("x: %x, y: %x", x, y);
kfree((void*)y);
uint32_t z = kmalloc(8);
printf(", z: %x", z); // If z is equal to y, heap's anti-fragmentation algorithm works
ASSERT(z == y);
kfree((void*)z), kfree((void*)x);
PRTOK
printf(" - Heap works!");
init_prompt(); // Initialize frame buffer
}
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#include "drivers/tty.h"
#include "drivers/gdt.h"
#include "drivers/idt.h"
#include "drivers/timer.h"
#include "drivers/keyboard.h"
#include "mem/paging.h"
#include "mem/kheap.h"
#include "mem/multiboot.h"
#include "userspace/shell.h"
#include "libc/stdio.h"
#include "libc/panic.h"
#include <stdint.h>
#define PRTOK printf("\n["); printf_color(" OK ", LIGHT_GREEN, BLACK); printf("]"); // Ugly hack to print "[ OK ]"
#define PRTAT printf("\n["); printf_color(" ** ", LIGHT_BROWN, BLACK); printf("]"); // Ugly hack to print "[ * ]"
#define PRTER printf("\n["); printf_color(" ERR ", LIGHT_RED, BLACK); printf("]"); // Ugly hack to print "[ ER ]"
void kernel_main(unsigned long magic, uint32_t addr) {
// First of all, check if we're booted by a Multiboot-compliant boot loader
if(magic != MULTIBOOT2_BOOTLOADER_MAGIC) {
PRTER
printf(" - Invalid magic number: %x\n", (unsigned)magic);
PANIC("Invalid multiboot magic number");
}
if(addr & 7) {
PRTER
printf(" - Unaligned mbi: %x\n", addr);
PANIC("Unaligned multiboot MBI");
}
printf("Loading kernel, wait please...");
gdt_setup(); // Setup Global Descriptor Table
PRTOK
printf(" - Loaded GDT");
idt_setup(); // Setup Interrupt Descriptor Table
PRTOK
printf(" - Loaded IDT");
init_timer(1); // Initialize PIT driver
PRTOK
printf(" - Loaded PIT");
init_keyboard(); // Initialize keyboard driver
PRTOK
printf(" - Loaded PS/2 driver");
init_paging(); // Initialize paging
PRTOK
printf(" - Loaded Paging");
PRTAT
printf(" - Testing heap...\t");
uint32_t x = kmalloc(32), y = kmalloc(32);
printf("x: %x, y: %x", x, y);
kfree((void*)y);
uint32_t z = kmalloc(8);
printf(", z: %x", z); // If z is equal to y, heap's anti-fragmentation algorithm works
ASSERT(z == y);
kfree((void*)z), kfree((void*)x);
PRTOK
printf(" - Heap works!");
init_prompt(); // Initialize frame buffer
}

View File

@ -1,11 +1,11 @@
OBJS = stdio.o string.o panic.o time.o
VER := $(shell git rev-parse --short HEAD)
CC = i686-elf-gcc # cross-compiler
CFLAGS = -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
OBJS = stdio.o string.o panic.o time.o
VER := $(shell git rev-parse --short HEAD)
CC = i686-elf-gcc # cross-compiler
CFLAGS = -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
$(CC) $(CFLAGS) $< -o $@

View File

@ -1,51 +1,51 @@
#include "panic.h"
#include "../drivers/cpuid.h"
#include "../libc/stdio.h"
#include "../libc/string.h"
#define KINFO printf("["); printf_color(" I ", LIGHT_RED, BLACK); printf("]: ");
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
// We panic when we find a critical error, this function is called by assert macro
extern void panic(const char *message, const char *file, uint32_t line) {
uint8_t version[64];
#ifdef VULCAN_VERSION
strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION));
#else
#error "-DVULCAN_VERSION flag not set"
#endif
printf_color("=============================================\n", LIGHT_MAGENTA, BLACK);
printf_color(" .:: KERNEL PANIC ::. \n", LIGHT_RED, BLACK);
printf_color("Reason: ", LIGHT_BROWN, BLACK);
printf("'%s' at '%s':%d\n", message, file, line);
KINFO
printf_color("Disabling interrupts\n", LIGHT_GREEN, BLACK);
asm volatile("cli"); // Disable interrupts
KINFO
printf_color("Dropping you into an endless loop\n", LIGHT_GREEN, BLACK);
KINFO
printf_color("Your are on your own now...good luck.\n", LIGHT_GREEN, BLACK);
KINFO
printf_color("VulcanOS version: ", LIGHT_GREEN, BLACK);
printf_color((char*)version, LIGHT_CYAN, BLACK);
printf_color("\n\t\t (c) 2019-2021 Marco Cetica", LIGHT_BROWN, BLACK);
printf_color("\n=============================================\n", LIGHT_MAGENTA, BLACK);
for(;;);
}
// Check for assertion failed, this function is called by assert macro
extern void panic_assert(const char *file, uint32_t line, const char *desc) {
asm volatile("cli"); // Disable interrupts
kprint((uint8_t*)"ASSERTION-FAILED(");
kprint((uint8_t*)desc);
kprint((uint8_t*)") at ");
kprint((uint8_t*)file);
kprint((uint8_t*)":");
kprint_dec(line);
kprint((uint8_t*)"\n");
// Now hang on forever
for(;;);
}
#include "panic.h"
#include "../drivers/cpuid.h"
#include "../libc/stdio.h"
#include "../libc/string.h"
#define KINFO printf("["); printf_color(" I ", LIGHT_RED, BLACK); printf("]: ");
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
// We panic when we find a critical error, this function is called by assert macro
extern void panic(const char *message, const char *file, uint32_t line) {
uint8_t version[64];
#ifdef VULCAN_VERSION
strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION));
#else
#error "-DVULCAN_VERSION flag not set"
#endif
printf_color("=============================================\n", LIGHT_MAGENTA, BLACK);
printf_color(" .:: KERNEL PANIC ::. \n", LIGHT_RED, BLACK);
printf_color("Reason: ", LIGHT_BROWN, BLACK);
printf("'%s' at '%s':%d\n", message, file, line);
KINFO
printf_color("Disabling interrupts\n", LIGHT_GREEN, BLACK);
asm volatile("cli"); // Disable interrupts
KINFO
printf_color("Dropping you into an endless loop\n", LIGHT_GREEN, BLACK);
KINFO
printf_color("Your are on your own now...good luck.\n", LIGHT_GREEN, BLACK);
KINFO
printf_color("VulcanOS version: ", LIGHT_GREEN, BLACK);
printf_color((char*)version, LIGHT_CYAN, BLACK);
printf_color("\n\t\t (c) 2019-2021 Marco Cetica", LIGHT_BROWN, BLACK);
printf_color("\n=============================================\n", LIGHT_MAGENTA, BLACK);
for(;;);
}
// Check for assertion failed, this function is called by assert macro
extern void panic_assert(const char *file, uint32_t line, const char *desc) {
asm volatile("cli"); // Disable interrupts
kprint((uint8_t*)"ASSERTION-FAILED(");
kprint((uint8_t*)desc);
kprint((uint8_t*)") at ");
kprint((uint8_t*)file);
kprint((uint8_t*)":");
kprint_dec(line);
kprint((uint8_t*)"\n");
// Now hang on forever
for(;;);
}

View File

@ -1,20 +1,20 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef PANIC_H
#define PANIC_H
#include <stdint.h>
#include "../drivers/tty.h"
#define PANIC(msg) panic(msg, __FILE__, __LINE__);
#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b))
extern void panic(const char *message, const char *file, uint32_t line);
extern void panic_assert(const char *file, uint32_t line, const char *desc);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef PANIC_H
#define PANIC_H
#include <stdint.h>
#include "../drivers/tty.h"
#define PANIC(msg) panic(msg, __FILE__, __LINE__);
#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b))
extern void panic(const char *message, const char *file, uint32_t line);
extern void panic_assert(const char *file, uint32_t line, const char *desc);
#endif

View File

@ -1,59 +1,59 @@
#include "stdio.h"
#include "string.h"
#include "../drivers/tty.h"
int printf(const char *format, ...) {
uint8_t buf[20],c,*s;
int val;
int32_t uval;
va_list ap;
va_start(ap, format);
for(size_t i = 0; i < strlen((uint8_t*)format); i++) {
if(format[i] == '%') {
i++;
while(format[i] == ' ')
i++;
switch(format[i]) {
case 'i':
val = va_arg(ap, int);
itoa(val, buf, 10);
kprint(buf);
break;
case 'x':
uval = va_arg(ap, uint32_t);
uitoa(uval, buf, 16);
kprint(buf);
break;
case 'd':
uval = va_arg(ap, uint32_t);
uitoa(uval, buf, 10);
kprint(buf);
break;
case 'c':
c = (uint8_t)va_arg(ap, uint32_t);
kprint_c(&c, 1, WHITE, BLACK);
break;
case 's':
s = va_arg(ap, uint8_t*);
kprint(s);
break;
default:
kprint_c((uint8_t*)format+i, 1, WHITE, BLACK);
}
} else
kprint_c((uint8_t*)format+i, 1, WHITE, BLACK);
}
va_end(ap);
return 0;
}
int printf_color(const char *format, uint8_t fg, uint8_t bg) {
kprint_c((uint8_t*)format, strlen((uint8_t*)format), fg, bg);
return 0;
}
void puts(const char *buf) {
printf("%s\n", buf);
}
#include "stdio.h"
#include "string.h"
#include "../drivers/tty.h"
int printf(const char *format, ...) {
uint8_t buf[20],c,*s;
int val;
int32_t uval;
va_list ap;
va_start(ap, format);
for(size_t i = 0; i < strlen((uint8_t*)format); i++) {
if(format[i] == '%') {
i++;
while(format[i] == ' ')
i++;
switch(format[i]) {
case 'i':
val = va_arg(ap, int);
itoa(val, buf, 10);
kprint(buf);
break;
case 'x':
uval = va_arg(ap, uint32_t);
uitoa(uval, buf, 16);
kprint(buf);
break;
case 'd':
uval = va_arg(ap, uint32_t);
uitoa(uval, buf, 10);
kprint(buf);
break;
case 'c':
c = (uint8_t)va_arg(ap, uint32_t);
kprint_c(&c, 1, WHITE, BLACK);
break;
case 's':
s = va_arg(ap, uint8_t*);
kprint(s);
break;
default:
kprint_c((uint8_t*)format+i, 1, WHITE, BLACK);
}
} else
kprint_c((uint8_t*)format+i, 1, WHITE, BLACK);
}
va_end(ap);
return 0;
}
int printf_color(const char *format, uint8_t fg, uint8_t bg) {
kprint_c((uint8_t*)format, strlen((uint8_t*)format), fg, bg);
return 0;
}
void puts(const char *buf) {
printf("%s\n", buf);
}

View File

@ -1,19 +1,19 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _STDIO_H_
#define _STDIO_H_
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
int printf(const char *format, ...);
int printf_color(const char *format, uint8_t fg, uint8_t bg); // Only for string for now
void puts(const char *buf);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _STDIO_H_
#define _STDIO_H_
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
int printf(const char *format, ...);
int printf_color(const char *format, uint8_t fg, uint8_t bg); // Only for string for now
void puts(const char *buf);
#endif

View File

@ -1,150 +1,150 @@
#include "string.h"
// C library implementation
int32_t strcmp(const uint8_t *s1, const uint8_t *s2) {
while ((*s1) && (*s1 == *s2)) {
s1++;
s2++;
}
return (*(uint8_t*)s1 - *(uint8_t*)s2);
}
uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix) {
uint32_t i = 0;
uint32_t start = i;
if(val < 0 && radix == 10) {
buf[i++] = '-';
start = i;
}
if(radix == 10) {
buf[i++] = '0';
buf[i++] = 'x';
start = i;
}
int x = val;
do {
int a = x % radix;
if(a < 10)
buf[i++] = a + '0';
else
buf[i++]= a + 'a' - 10;
} while(x /= radix);
uint8_t *s = buf+start;
uint8_t *e = buf+(i-1);
while(s < e) {
uint8_t t = *s;
*s = *e;
*e = t;
i++;
e--;
}
buf[i] = 0;
return buf;
}
uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix) {
uint32_t i = 0;
uint32_t start = i;
uint32_t x = val;
if(radix == 16) {
buf[i++] = '0';
buf[i++] = 'x';
start = i;
}
do {
uint32_t a = x % radix;
if(a < 10)
buf[i++] = a + '0';
else
buf[i++] = a + 'a' - 10;
} while(x /= radix);
uint8_t *s = buf+start;
uint8_t *e = buf+(i-1);
while(s < e) {
uint8_t t = *s;
*s = *e;
*e = t;
s++;
e--;
}
buf[i] = 0;
return buf;
}
size_t strlen(const uint8_t *buf) {
uint32_t i = 0;
while(buf[i] != 0)
i++;
return i;
}
uint8_t *strcpy(uint8_t *dst, const uint8_t *src) {
uint8_t *dst_p = dst;
while((*dst++ = *src++));
return dst_p;
}
void strcat(void *dest, const void *src) {
uint8_t *end = (uint8_t*)dest + strlen(dest);
memcpy((uint8_t*)end, (uint8_t*)src, strlen((uint8_t*)src));
end += strlen((uint8_t*)src);
*end = '\0';
}
/* Worst memset implementation
* i could find on the net.
* however it works so... */
void *memset(void *s, uint32_t c, size_t n) {
char *mem = (char*)s;
for(size_t i = 0; i < n; i++)
mem[i] = (uint8_t)c;
return s;
}
void *memcpy(void *dst, void const *src, uint32_t n) {
uint8_t *ret = dst;
uint8_t *p = dst;
const uint8_t *q = src;
while(n--)
*p++ = *q++;
return ret;
}
void *memmove(void *dst, const void *src, size_t len) {
char *dstmem = (char*)dst;
char *srcmem = (char*)src;
for(size_t i = 0; i < len; i++)
dstmem[i] = srcmem[i];
return dstmem;
}
void strupper(uint8_t *str) {
for(unsigned int i = 0; i < strlen(str); i++) {
if(str[i] == 'a' && str[i] < 'z')
str[i] &= 0x4F;
}
}
void strlower(uint8_t *str) {
for(unsigned int i = 0; i < strlen(str); i++) {
if(str[i] == 'A' && str[i] < 'Z')
str[i] |= 0x60;
}
}
#include "string.h"
// C library implementation
int32_t strcmp(const uint8_t *s1, const uint8_t *s2) {
while ((*s1) && (*s1 == *s2)) {
s1++;
s2++;
}
return (*(uint8_t*)s1 - *(uint8_t*)s2);
}
uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix) {
uint32_t i = 0;
uint32_t start = i;
if(val < 0 && radix == 10) {
buf[i++] = '-';
start = i;
}
if(radix == 10) {
buf[i++] = '0';
buf[i++] = 'x';
start = i;
}
int x = val;
do {
int a = x % radix;
if(a < 10)
buf[i++] = a + '0';
else
buf[i++]= a + 'a' - 10;
} while(x /= radix);
uint8_t *s = buf+start;
uint8_t *e = buf+(i-1);
while(s < e) {
uint8_t t = *s;
*s = *e;
*e = t;
i++;
e--;
}
buf[i] = 0;
return buf;
}
uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix) {
uint32_t i = 0;
uint32_t start = i;
uint32_t x = val;
if(radix == 16) {
buf[i++] = '0';
buf[i++] = 'x';
start = i;
}
do {
uint32_t a = x % radix;
if(a < 10)
buf[i++] = a + '0';
else
buf[i++] = a + 'a' - 10;
} while(x /= radix);
uint8_t *s = buf+start;
uint8_t *e = buf+(i-1);
while(s < e) {
uint8_t t = *s;
*s = *e;
*e = t;
s++;
e--;
}
buf[i] = 0;
return buf;
}
size_t strlen(const uint8_t *buf) {
uint32_t i = 0;
while(buf[i] != 0)
i++;
return i;
}
uint8_t *strcpy(uint8_t *dst, const uint8_t *src) {
uint8_t *dst_p = dst;
while((*dst++ = *src++));
return dst_p;
}
void strcat(void *dest, const void *src) {
uint8_t *end = (uint8_t*)dest + strlen(dest);
memcpy((uint8_t*)end, (uint8_t*)src, strlen((uint8_t*)src));
end += strlen((uint8_t*)src);
*end = '\0';
}
/* Worst memset implementation
* i could find on the net.
* however it works so... */
void *memset(void *s, uint32_t c, size_t n) {
char *mem = (char*)s;
for(size_t i = 0; i < n; i++)
mem[i] = (uint8_t)c;
return s;
}
void *memcpy(void *dst, void const *src, uint32_t n) {
uint8_t *ret = dst;
uint8_t *p = dst;
const uint8_t *q = src;
while(n--)
*p++ = *q++;
return ret;
}
void *memmove(void *dst, const void *src, size_t len) {
char *dstmem = (char*)dst;
char *srcmem = (char*)src;
for(size_t i = 0; i < len; i++)
dstmem[i] = srcmem[i];
return dstmem;
}
void strupper(uint8_t *str) {
for(unsigned int i = 0; i < strlen(str); i++) {
if(str[i] == 'a' && str[i] < 'z')
str[i] &= 0x4F;
}
}
void strlower(uint8_t *str) {
for(unsigned int i = 0; i < strlen(str); i++) {
if(str[i] == 'A' && str[i] < 'Z')
str[i] |= 0x60;
}
}

View File

@ -1,26 +1,26 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _STRING_H_
#define _STRING_H_
#include <stdint.h> // For uinx_t
#include <stddef.h> // For size_t
int32_t strcmp(const uint8_t *s1, const uint8_t *s2);
uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix);
uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix);
size_t strlen(const uint8_t *buf);
uint8_t *strcpy(uint8_t *dst, const uint8_t *src);
void strcat(void *dest, const void *src);
void *memset(void *s, uint32_t c, size_t n);
void *memmove(void *dst, const void *src, size_t len);
void *memcpy(void *dst, void const *src, uint32_t n);
void strupper(uint8_t *str);
void strlower(uint8_t *str);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef _STRING_H_
#define _STRING_H_
#include <stdint.h> // For uinx_t
#include <stddef.h> // For size_t
int32_t strcmp(const uint8_t *s1, const uint8_t *s2);
uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix);
uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix);
size_t strlen(const uint8_t *buf);
uint8_t *strcpy(uint8_t *dst, const uint8_t *src);
void strcat(void *dest, const void *src);
void *memset(void *s, uint32_t c, size_t n);
void *memmove(void *dst, const void *src, size_t len);
void *memcpy(void *dst, void const *src, uint32_t n);
void strupper(uint8_t *str);
void strlower(uint8_t *str);
#endif

View File

@ -1,38 +1,38 @@
#include "time.h"
#include "../drivers/ports.h"
// Check whether CMOS is updated or not
static uint8_t is_cmos_updated() {
outb(CMOS_ADDRESS, 0x0A);
return (inb(CMOS_DATA) & 0x80);
}
// Get CMOS register's status
static uint8_t reg_status(int32_t reg) {
outb(CMOS_ADDRESS, reg);
return inb(CMOS_DATA);
}
time_t cmos_reader() {
while(is_cmos_updated()); // Wait until the CMOS is being updated
time_t tm;
tm.second = BCD_CONVERTER(reg_status(TIME_R_SECOND));
tm.minute = BCD_CONVERTER(reg_status(TIME_R_MINUTE));
tm.hour = BCD_CONVERTER(reg_status(TIME_R_HOUR));
tm.day = BCD_CONVERTER(reg_status(TIME_R_DAY));
tm.month = BCD_CONVERTER(reg_status(TIME_R_MONTH));
tm.year = BCD_CONVERTER(reg_status(TIME_R_YEAR));
return tm;
}
uint32_t get_time(uint32_t field) {
while(is_cmos_updated()); // Wait the CMOS is being updated
return BCD_CONVERTER(reg_status(field));
}
#include "time.h"
#include "../drivers/ports.h"
// Check whether CMOS is updated or not
static uint8_t is_cmos_updated() {
outb(CMOS_ADDRESS, 0x0A);
return (inb(CMOS_DATA) & 0x80);
}
// Get CMOS register's status
static uint8_t reg_status(int32_t reg) {
outb(CMOS_ADDRESS, reg);
return inb(CMOS_DATA);
}
time_t cmos_reader() {
while(is_cmos_updated()); // Wait until the CMOS is being updated
time_t tm;
tm.second = BCD_CONVERTER(reg_status(TIME_R_SECOND));
tm.minute = BCD_CONVERTER(reg_status(TIME_R_MINUTE));
tm.hour = BCD_CONVERTER(reg_status(TIME_R_HOUR));
tm.day = BCD_CONVERTER(reg_status(TIME_R_DAY));
tm.month = BCD_CONVERTER(reg_status(TIME_R_MONTH));
tm.year = BCD_CONVERTER(reg_status(TIME_R_YEAR));
return tm;
}
uint32_t get_time(uint32_t field) {
while(is_cmos_updated()); // Wait the CMOS is being updated
return BCD_CONVERTER(reg_status(field));
}

View File

@ -1,42 +1,42 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
/* Get time reading the RTC(real time clock) CMOS on the motherboard */
#ifndef TIME_H
#define TIME_H
#include <stdint.h>
// Define RTC field registers
#define TIME_R_YEAR 0x09
#define TIME_R_MONTH 0x08
#define TIME_R_DAY 0x07
#define TIME_R_HOUR 0x06
#define TIME_R_MINUTE 0x05
#define TIME_R_SECOND 0x04
//#define TIME_R_CENTURY 0x32
// Define RTC address
#define CMOS_ADDRESS 0x70
#define CMOS_DATA 0x71
// Convert BCD encoed values to binary
#define BCD_CONVERTER(n) ((n / 16) * 10 + (n & 0xF))
typedef struct {
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t day;
uint8_t month;
uint8_t year;
} time_t;
time_t cmos_reader();
uint32_t get_time(uint32_t field);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
/* Get time reading the RTC(real time clock) CMOS on the motherboard */
#ifndef TIME_H
#define TIME_H
#include <stdint.h>
// Define RTC field registers
#define TIME_R_YEAR 0x09
#define TIME_R_MONTH 0x08
#define TIME_R_DAY 0x07
#define TIME_R_HOUR 0x06
#define TIME_R_MINUTE 0x05
#define TIME_R_SECOND 0x04
//#define TIME_R_CENTURY 0x32
// Define RTC address
#define CMOS_ADDRESS 0x70
#define CMOS_DATA 0x71
// Convert BCD encoed values to binary
#define BCD_CONVERTER(n) ((n / 16) * 10 + (n & 0xF))
typedef struct {
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t day;
uint8_t month;
uint8_t year;
} time_t;
time_t cmos_reader();
uint32_t get_time(uint32_t field);
#endif

View File

@ -1,9 +1,9 @@
OBJS = paging.o kheap.o ordered_array.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
OBJS = paging.o kheap.o ordered_array.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
${CC} ${CFLAGS} $< -o $@

View File

@ -1,329 +1,329 @@
#include "kheap.h"
#include "paging.h"
#include "../libc/panic.h"
extern uint32_t end;
uint32_t placement_addr = (uint32_t)&end;
extern page_directory_t *kernel_directory;
heap_t *kheap = 0;
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys) {
if(kheap != 0) {
void *addr = alloc(sz, (uint8_t)align, kheap);
if(phys != 0) {
page_t *page = get_page((uint32_t)addr, 0, kernel_directory);
*phys = page->fr*0x1000 + ((uint32_t)addr&0xFFF);
}
return (uint32_t)addr;
} else {
if(align == 1 && (placement_addr & 0xFFFFF000)) {
placement_addr &= 0xFFFFF000;
placement_addr += 0x1000;
}
if(phys)
*phys = placement_addr;
uint32_t tmp = placement_addr;
placement_addr += sz;
return tmp;
}
}
void kfree(void *p) {
free(p, kheap);
}
uint32_t kmalloc_a(uint32_t sz) {
return kmalloc_int(sz, 1, 0);
}
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 0, phys);
}
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 1, phys);
}
uint32_t kmalloc(uint32_t sz) {
return kmalloc_int(sz, 0, 0);
}
static void expand(uint32_t new_size, heap_t *heap) {
// First check if new size is greater than older one
ASSERT(new_size > heap->end_address - heap->start_address);
// Get nearest page boundary
if((new_size&0xFFFFF000) != 0) {
new_size &= 0xFFFFF000;
new_size += 0x1000;
}
// Check if new size is not greater than maximum size
ASSERT(heap->start_address+new_size <= heap->max_address);
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size;
while(it < new_size) {
alloc_frame(get_page(heap->start_address+it, 1, kernel_directory),
(heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1);
it += 0x1000; // Page size
}
heap->end_address = heap->start_address+new_size;
}
static uint32_t contract(uint32_t new_size, heap_t *heap) {
ASSERT(new_size < heap->end_address-heap->start_address);
if(new_size&0x1000) {
new_size &= 0x1000;
new_size += 0x1000;
}
if(new_size < HEAP_MIN_SIZE)
new_size = HEAP_MIN_SIZE;
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size - 0x1000;
while(new_size < it) {
free_frame(get_page(heap->start_address+it, 0, kernel_directory));
it -= 0x1000;
}
heap->end_address = heap->start_address + new_size;
return new_size;
}
static uint32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t it = 0;
// Find smallest hole that fit our request
while(it < heap->index.size) {
header_t *head = (header_t*)lookup_ordered_array(it, &heap->index);
if(page_align > 0) {
// page must be aligned?
uint32_t location = (uint32_t)head;
uint32_t offset = 0;
if(((location+sizeof(header_t)) & 0xFFFFF000) != 0)
offset = 0x1000 - (location+sizeof(header_t))%0x1000;
uint32_t hole_size = (uint32_t)head->size - offset;
// Check if we can fit this page in that hole
if(hole_size >= (uint32_t)size)
break;
} else if(head->size >= size)
break;
it++;
}
// If we didn't find anything
if(it == heap->index.size)
return -1;
else
return it;
}
static uint8_t header_t_less_than(void *a, void *b) {
return (((header_t*)a)->size < ((header_t*)b)->size)?1:0;
}
heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly) {
heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t));
ASSERT(start%0x1000 == 0);
ASSERT(end_addr%0x1000 == 0);
// Initialize the index
heap->index = place_ordered_array((void*)start, HEAP_INDEX_SIZE, &header_t_less_than);
// Shift start address to the right
start += sizeof(type_t) * HEAP_INDEX_SIZE;
// Check if start address is page-aligned
if ((start & 0xFFFFF000) != 0) {
start &= 0xFFFFF000;
start += 0x1000;
}
// Store vars into heap
heap->start_address = start;
heap->end_address = end_addr;
heap->max_address = max;
heap->supervisor = supervisor;
heap->readonly = readonly;
header_t *hole = (header_t*)start;
hole->size = end_addr - start;
hole->magic = HEAP_MAGIC;
hole->is_hole = 1;
insert_ordered_array((void*)hole, &heap->index);
return heap;
}
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t);
// Find smallest hole suitable
uint32_t it = find_smallest_hole(new_size, page_align, heap);
if((int32_t)it == -1) {
uint32_t old_len = heap->end_address - heap->start_address;
uint32_t old_end_addr = heap->end_address;
// Allocate more space
expand(old_len+new_size, heap);
uint32_t new_len = heap->end_address - heap->start_address;
it = 0;
uint32_t idx = -1; uint32_t value = 0x0;
while(it < heap->index.size) {
uint32_t tmp = (uint32_t)lookup_ordered_array(it, &heap->index);
if(tmp > value) {
value = tmp;
idx = it;
}
it++;
}
// If no headers has been found, add a new one
if((int32_t)idx == -1) {
header_t *head = (header_t*)old_end_addr;
head->magic = HEAP_MAGIC;
head->size = new_len - old_len;
head->is_hole = 1;
footer_t *foot = (footer_t*)(old_end_addr + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
insert_ordered_array((void*)head, &heap->index);
} else {
header_t *head = lookup_ordered_array(idx, &heap->index);
head->size += new_len - old_len;
// Update the footer
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->header = head;
foot->magic = HEAP_MAGIC;
}
// Now we have enough space, so recall this function again
return alloc(size, page_align, heap);
}
header_t *origin_hole_head = (header_t*)lookup_ordered_array(it, &heap->index);
uint32_t origin_hole_p = (uint32_t)origin_hole_head;
uint32_t origin_hole_s = origin_hole_head->size;
// Check if we should split the hole into two parts
if(origin_hole_s-new_size < sizeof(header_t)+sizeof(footer_t)) {
// Increase the requested size to the size of the hole we found
size += origin_hole_s-new_size;
new_size = origin_hole_s;
}
// Check if we need to page-align data
if(page_align && origin_hole_p&0xFFFFF000) {
uint32_t new_loc = origin_hole_p + 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
header_t *hole_header = (header_t*)origin_hole_p;
hole_header->size = 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = 1;
footer_t *hole_footer = (footer_t*)((uint32_t)new_loc - sizeof(header_t));
hole_footer->magic = HEAP_MAGIC;
hole_footer->header = hole_header;
origin_hole_p = new_loc;
origin_hole_s = origin_hole_s - hole_header->size;
} else
remove_ordered_array(it, &heap->index); // Remove hole, since we don't need it anymore
// Rewrite original header
header_t *block_head = (header_t*)origin_hole_p;
block_head->magic = HEAP_MAGIC;
block_head->is_hole = 0;
block_head->size = new_size;
// and the footer
footer_t *block_foot = (footer_t*)(origin_hole_p + sizeof(header_t) + size);
block_foot->magic = HEAP_MAGIC;
block_foot->header = block_head;
// Check if we need to write a new hole after the allocated block
if(origin_hole_s - new_size > 0) {
header_t *hole_head = (header_t*)(origin_hole_p + sizeof(header_t) + size + sizeof(footer_t));
hole_head->magic = HEAP_MAGIC;
hole_head->is_hole = 1;
hole_head->size = origin_hole_s - new_size;
footer_t *hole_foot = (footer_t*)((uint32_t)hole_head + origin_hole_s - new_size - sizeof(footer_t));
if((uint32_t)hole_foot < heap->end_address) {
hole_foot->magic = HEAP_MAGIC;
hole_foot->header = hole_head;
}
// Add new hole to the data structure
insert_ordered_array((void*)hole_head, &heap->index);
}
// Return the block header
return (void*)((uint32_t)block_head+sizeof(header_t));
}
void free(void *p, heap_t *heap) {
// Check null pointers
if(p == 0)
return;
// Retrieve data
header_t *head = (header_t*)((uint32_t)p - sizeof(header_t));
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
ASSERT(head->magic == HEAP_MAGIC);
ASSERT(foot->magic == HEAP_MAGIC);
head->is_hole = 1; // Make this a hole
int8_t add_to_free_hole = 1; // Add this header to free holes
// Left unify
footer_t *test_foot = (footer_t*)((uint32_t)head - sizeof(footer_t));
if(test_foot->magic == HEAP_MAGIC && test_foot->header->is_hole == 1 ) {
uint32_t cache_s = head->size; // Store current size
head = test_foot->header; // Rewrite header into new one
foot->header = head; // Point footer to the new header
head->size += cache_s; // Increase size
add_to_free_hole = 0; // Header already in the structure.
}
// Right unify
header_t *test_head = (header_t*)((uint32_t)foot + sizeof(footer_t));
if(test_head->magic == HEAP_MAGIC && test_head->is_hole) {
head->size += test_head->size; // Increase size
test_foot = (footer_t*)((uint32_t)test_foot + test_head->size - sizeof(footer_t));
foot = test_foot;
// Find and remove this header from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// Check if we actually found something
ASSERT(it < heap->index.size);
// Remove that item
remove_ordered_array(it, &heap->index);
}
// If footer is located at the end, we can contract the heap
if((uint32_t)foot+sizeof(footer_t) == heap->end_address) {
uint32_t old_len = heap->end_address-heap->start_address;
uint32_t new_len = contract((uint32_t)head - heap->start_address, heap);
// Check dimensions after resizing
if(head->size - (old_len-new_len) > 0) {
// Dimensions is still a positive value, so we can resize
head->size -= old_len-new_len;
foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
} else {
// Remove block from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// If we didn't find that block we haven't nothing to remove
if(it < heap->index.size)
remove_ordered_array(it, &heap->index);
}
}
// If required by the user, add that block to the structure
if(add_to_free_hole == 1)
insert_ordered_array((void*)head, &heap->index);
}
#include "kheap.h"
#include "paging.h"
#include "../libc/panic.h"
extern uint32_t end;
uint32_t placement_addr = (uint32_t)&end;
extern page_directory_t *kernel_directory;
heap_t *kheap = 0;
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys) {
if(kheap != 0) {
void *addr = alloc(sz, (uint8_t)align, kheap);
if(phys != 0) {
page_t *page = get_page((uint32_t)addr, 0, kernel_directory);
*phys = page->fr*0x1000 + ((uint32_t)addr&0xFFF);
}
return (uint32_t)addr;
} else {
if(align == 1 && (placement_addr & 0xFFFFF000)) {
placement_addr &= 0xFFFFF000;
placement_addr += 0x1000;
}
if(phys)
*phys = placement_addr;
uint32_t tmp = placement_addr;
placement_addr += sz;
return tmp;
}
}
void kfree(void *p) {
free(p, kheap);
}
uint32_t kmalloc_a(uint32_t sz) {
return kmalloc_int(sz, 1, 0);
}
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 0, phys);
}
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) {
return kmalloc_int(sz, 1, phys);
}
uint32_t kmalloc(uint32_t sz) {
return kmalloc_int(sz, 0, 0);
}
static void expand(uint32_t new_size, heap_t *heap) {
// First check if new size is greater than older one
ASSERT(new_size > heap->end_address - heap->start_address);
// Get nearest page boundary
if((new_size&0xFFFFF000) != 0) {
new_size &= 0xFFFFF000;
new_size += 0x1000;
}
// Check if new size is not greater than maximum size
ASSERT(heap->start_address+new_size <= heap->max_address);
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size;
while(it < new_size) {
alloc_frame(get_page(heap->start_address+it, 1, kernel_directory),
(heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1);
it += 0x1000; // Page size
}
heap->end_address = heap->start_address+new_size;
}
static uint32_t contract(uint32_t new_size, heap_t *heap) {
ASSERT(new_size < heap->end_address-heap->start_address);
if(new_size&0x1000) {
new_size &= 0x1000;
new_size += 0x1000;
}
if(new_size < HEAP_MIN_SIZE)
new_size = HEAP_MIN_SIZE;
uint32_t old_size = heap->end_address - heap->start_address;
uint32_t it = old_size - 0x1000;
while(new_size < it) {
free_frame(get_page(heap->start_address+it, 0, kernel_directory));
it -= 0x1000;
}
heap->end_address = heap->start_address + new_size;
return new_size;
}
static uint32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t it = 0;
// Find smallest hole that fit our request
while(it < heap->index.size) {
header_t *head = (header_t*)lookup_ordered_array(it, &heap->index);
if(page_align > 0) {
// page must be aligned?
uint32_t location = (uint32_t)head;
uint32_t offset = 0;
if(((location+sizeof(header_t)) & 0xFFFFF000) != 0)
offset = 0x1000 - (location+sizeof(header_t))%0x1000;
uint32_t hole_size = (uint32_t)head->size - offset;
// Check if we can fit this page in that hole
if(hole_size >= (uint32_t)size)
break;
} else if(head->size >= size)
break;
it++;
}
// If we didn't find anything
if(it == heap->index.size)
return -1;
else
return it;
}
static uint8_t header_t_less_than(void *a, void *b) {
return (((header_t*)a)->size < ((header_t*)b)->size)?1:0;
}
heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly) {
heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t));
ASSERT(start%0x1000 == 0);
ASSERT(end_addr%0x1000 == 0);
// Initialize the index
heap->index = place_ordered_array((void*)start, HEAP_INDEX_SIZE, &header_t_less_than);
// Shift start address to the right
start += sizeof(type_t) * HEAP_INDEX_SIZE;
// Check if start address is page-aligned
if ((start & 0xFFFFF000) != 0) {
start &= 0xFFFFF000;
start += 0x1000;
}
// Store vars into heap
heap->start_address = start;
heap->end_address = end_addr;
heap->max_address = max;
heap->supervisor = supervisor;
heap->readonly = readonly;
header_t *hole = (header_t*)start;
hole->size = end_addr - start;
hole->magic = HEAP_MAGIC;
hole->is_hole = 1;
insert_ordered_array((void*)hole, &heap->index);
return heap;
}
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) {
uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t);
// Find smallest hole suitable
uint32_t it = find_smallest_hole(new_size, page_align, heap);
if((int32_t)it == -1) {
uint32_t old_len = heap->end_address - heap->start_address;
uint32_t old_end_addr = heap->end_address;
// Allocate more space
expand(old_len+new_size, heap);
uint32_t new_len = heap->end_address - heap->start_address;
it = 0;
uint32_t idx = -1; uint32_t value = 0x0;
while(it < heap->index.size) {
uint32_t tmp = (uint32_t)lookup_ordered_array(it, &heap->index);
if(tmp > value) {
value = tmp;
idx = it;
}
it++;
}
// If no headers has been found, add a new one
if((int32_t)idx == -1) {
header_t *head = (header_t*)old_end_addr;
head->magic = HEAP_MAGIC;
head->size = new_len - old_len;
head->is_hole = 1;
footer_t *foot = (footer_t*)(old_end_addr + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
insert_ordered_array((void*)head, &heap->index);
} else {
header_t *head = lookup_ordered_array(idx, &heap->index);
head->size += new_len - old_len;
// Update the footer
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->header = head;
foot->magic = HEAP_MAGIC;
}
// Now we have enough space, so recall this function again
return alloc(size, page_align, heap);
}
header_t *origin_hole_head = (header_t*)lookup_ordered_array(it, &heap->index);
uint32_t origin_hole_p = (uint32_t)origin_hole_head;
uint32_t origin_hole_s = origin_hole_head->size;
// Check if we should split the hole into two parts
if(origin_hole_s-new_size < sizeof(header_t)+sizeof(footer_t)) {
// Increase the requested size to the size of the hole we found
size += origin_hole_s-new_size;
new_size = origin_hole_s;
}
// Check if we need to page-align data
if(page_align && origin_hole_p&0xFFFFF000) {
uint32_t new_loc = origin_hole_p + 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
header_t *hole_header = (header_t*)origin_hole_p;
hole_header->size = 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t);
hole_header->magic = HEAP_MAGIC;
hole_header->is_hole = 1;
footer_t *hole_footer = (footer_t*)((uint32_t)new_loc - sizeof(header_t));
hole_footer->magic = HEAP_MAGIC;
hole_footer->header = hole_header;
origin_hole_p = new_loc;
origin_hole_s = origin_hole_s - hole_header->size;
} else
remove_ordered_array(it, &heap->index); // Remove hole, since we don't need it anymore
// Rewrite original header
header_t *block_head = (header_t*)origin_hole_p;
block_head->magic = HEAP_MAGIC;
block_head->is_hole = 0;
block_head->size = new_size;
// and the footer
footer_t *block_foot = (footer_t*)(origin_hole_p + sizeof(header_t) + size);
block_foot->magic = HEAP_MAGIC;
block_foot->header = block_head;
// Check if we need to write a new hole after the allocated block
if(origin_hole_s - new_size > 0) {
header_t *hole_head = (header_t*)(origin_hole_p + sizeof(header_t) + size + sizeof(footer_t));
hole_head->magic = HEAP_MAGIC;
hole_head->is_hole = 1;
hole_head->size = origin_hole_s - new_size;
footer_t *hole_foot = (footer_t*)((uint32_t)hole_head + origin_hole_s - new_size - sizeof(footer_t));
if((uint32_t)hole_foot < heap->end_address) {
hole_foot->magic = HEAP_MAGIC;
hole_foot->header = hole_head;
}
// Add new hole to the data structure
insert_ordered_array((void*)hole_head, &heap->index);
}
// Return the block header
return (void*)((uint32_t)block_head+sizeof(header_t));
}
void free(void *p, heap_t *heap) {
// Check null pointers
if(p == 0)
return;
// Retrieve data
header_t *head = (header_t*)((uint32_t)p - sizeof(header_t));
footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
ASSERT(head->magic == HEAP_MAGIC);
ASSERT(foot->magic == HEAP_MAGIC);
head->is_hole = 1; // Make this a hole
int8_t add_to_free_hole = 1; // Add this header to free holes
// Left unify
footer_t *test_foot = (footer_t*)((uint32_t)head - sizeof(footer_t));
if(test_foot->magic == HEAP_MAGIC && test_foot->header->is_hole == 1 ) {
uint32_t cache_s = head->size; // Store current size
head = test_foot->header; // Rewrite header into new one
foot->header = head; // Point footer to the new header
head->size += cache_s; // Increase size
add_to_free_hole = 0; // Header already in the structure.
}
// Right unify
header_t *test_head = (header_t*)((uint32_t)foot + sizeof(footer_t));
if(test_head->magic == HEAP_MAGIC && test_head->is_hole) {
head->size += test_head->size; // Increase size
test_foot = (footer_t*)((uint32_t)test_foot + test_head->size - sizeof(footer_t));
foot = test_foot;
// Find and remove this header from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// Check if we actually found something
ASSERT(it < heap->index.size);
// Remove that item
remove_ordered_array(it, &heap->index);
}
// If footer is located at the end, we can contract the heap
if((uint32_t)foot+sizeof(footer_t) == heap->end_address) {
uint32_t old_len = heap->end_address-heap->start_address;
uint32_t new_len = contract((uint32_t)head - heap->start_address, heap);
// Check dimensions after resizing
if(head->size - (old_len-new_len) > 0) {
// Dimensions is still a positive value, so we can resize
head->size -= old_len-new_len;
foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t));
foot->magic = HEAP_MAGIC;
foot->header = head;
} else {
// Remove block from the structure
uint32_t it = 0;
while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head))
it++;
// If we didn't find that block we haven't nothing to remove
if(it < heap->index.size)
remove_ordered_array(it, &heap->index);
}
}
// If required by the user, add that block to the structure
if(add_to_free_hole == 1)
insert_ordered_array((void*)head, &heap->index);
}

View File

@ -1,70 +1,70 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
/*** Heap implementation from James Molloy's tutorial:
http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/
/* This heap algorithm uses two different data structures: blocks and holes.
* Blocks: Contiguous areas of memory containing user data
* Holes: Special kind of blocks that are not in use, this is the result
* of free() operation. Those spaces lend to a common problem called "Fragmentation";
* where malloc() cannot use those spaces anymore because they are too small for any
* kind of program. Any modern OS must have a solution to avoid this problem, but to keep
* things simple as possible i wont implement anything like that.
* Blocks/holes contains informations like the magic number(error checking), the type of
* chunk(hole or block) and the size, while the footer contains only a pointer to the header
* (and obviously an error checking flag).
*/
#ifndef KHEAP_H
#define KHEAP_H
#define KHEAP_START 0xC0000000
#define KHEAP_INITIAL_SIZE 0x100000
#define HEAP_INDEX_SIZE 0x20000
#define HEAP_MAGIC 0x123890AB
#define HEAP_MIN_SIZE 0x70000
#include <stdint.h>
#include "ordered_array.h"
// Data structure for single hole/block
typedef struct {
uint32_t magic; // Magic number for error checking
uint8_t is_hole; // 1 if it's an hole, 0 for a block
uint32_t size; // Size of block
} header_t;
typedef struct {
uint32_t magic; // Same as above
header_t *header; // Pointer to the header block
} footer_t;
typedef struct {
ordered_array_t index;
uint32_t start_address; // Begin of allocated space
uint32_t end_address; // End of allocated space
uint32_t max_address; // Maximum size heap can be expanded to
uint8_t supervisor;
uint8_t readonly;
} heap_t;
// Create a new heap
heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly);
// Allocates a contigious region of memory in size
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap);
// Free a block allocated with alloc
void free(void *p, heap_t *heap);
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys);
uint32_t kmalloc_a(uint32_t sz);
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
uint32_t kmalloc(uint32_t sz);
void kfree(void *p);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
/*** Heap implementation from James Molloy's tutorial:
http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/
/* This heap algorithm uses two different data structures: blocks and holes.
* Blocks: Contiguous areas of memory containing user data
* Holes: Special kind of blocks that are not in use, this is the result
* of free() operation. Those spaces lend to a common problem called "Fragmentation";
* where malloc() cannot use those spaces anymore because they are too small for any
* kind of program. Any modern OS must have a solution to avoid this problem, but to keep
* things simple as possible i wont implement anything like that.
* Blocks/holes contains informations like the magic number(error checking), the type of
* chunk(hole or block) and the size, while the footer contains only a pointer to the header
* (and obviously an error checking flag).
*/
#ifndef KHEAP_H
#define KHEAP_H
#define KHEAP_START 0xC0000000
#define KHEAP_INITIAL_SIZE 0x100000
#define HEAP_INDEX_SIZE 0x20000
#define HEAP_MAGIC 0x123890AB
#define HEAP_MIN_SIZE 0x70000
#include <stdint.h>
#include "ordered_array.h"
// Data structure for single hole/block
typedef struct {
uint32_t magic; // Magic number for error checking
uint8_t is_hole; // 1 if it's an hole, 0 for a block
uint32_t size; // Size of block
} header_t;
typedef struct {
uint32_t magic; // Same as above
header_t *header; // Pointer to the header block
} footer_t;
typedef struct {
ordered_array_t index;
uint32_t start_address; // Begin of allocated space
uint32_t end_address; // End of allocated space
uint32_t max_address; // Maximum size heap can be expanded to
uint8_t supervisor;
uint8_t readonly;
} heap_t;
// Create a new heap
heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly);
// Allocates a contigious region of memory in size
void *alloc(uint32_t size, uint8_t page_align, heap_t *heap);
// Free a block allocated with alloc
void free(void *p, heap_t *heap);
uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys);
uint32_t kmalloc_a(uint32_t sz);
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
uint32_t kmalloc(uint32_t sz);
void kfree(void *p);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +1,66 @@
#include "ordered_array.h"
#include "kheap.h"
#include "../libc/panic.h"
#include "../libc/string.h"
uint8_t standard_lessthan_predicate(type_t a, type_t b) {
if (a < b)
return 1;
else
return 0;
}
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (void*)kmalloc(max_size*sizeof(type_t));
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (type_t*)addr;
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
void destroy_ordered_array(ordered_array_t *array) {
kfree(array->array);
}
void insert_ordered_array(type_t item, ordered_array_t *array) {
uint32_t it = 0;
while(it < array->size && array->less_than(array->array[it], item))
it++;
if(it == array->size)
array->array[array->size++] = item;
else {
type_t tmp = array->array[it];
array->array[it] = item;
while(it < array->size) {
it++;
type_t tmp2 = array->array[it];
array->array[it] = tmp;
tmp = tmp2;
}
array->size++;
}
}
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) {
return array->array[i];
}
void remove_ordered_array(uint32_t i, ordered_array_t *array) {
while(i < array->size) {
array->array[i] = array->array[i+1];
i++;
}
array->size--;
}
#include "ordered_array.h"
#include "kheap.h"
#include "../libc/panic.h"
#include "../libc/string.h"
uint8_t standard_lessthan_predicate(type_t a, type_t b) {
if (a < b)
return 1;
else
return 0;
}
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (void*)kmalloc(max_size*sizeof(type_t));
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than) {
ordered_array_t to_ret;
to_ret.array = (type_t*)addr;
memset(to_ret.array, 0, max_size*sizeof(type_t));
to_ret.size = 0;
to_ret.max_size = max_size;
to_ret.less_than = less_than;
return to_ret;
}
void destroy_ordered_array(ordered_array_t *array) {
kfree(array->array);
}
void insert_ordered_array(type_t item, ordered_array_t *array) {
uint32_t it = 0;
while(it < array->size && array->less_than(array->array[it], item))
it++;
if(it == array->size)
array->array[array->size++] = item;
else {
type_t tmp = array->array[it];
array->array[it] = item;
while(it < array->size) {
it++;
type_t tmp2 = array->array[it];
array->array[it] = tmp;
tmp = tmp2;
}
array->size++;
}
}
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) {
return array->array[i];
}
void remove_ordered_array(uint32_t i, ordered_array_t *array) {
while(i < array->size) {
array->array[i] = array->array[i+1];
i++;
}
array->size--;
}

View File

@ -1,39 +1,39 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef ORDERED_ARRAY_H
#define ORDERED_ARRAY_H
#include <stdint.h>
/* Our list is always in a 'sorted state',
* it can store anything that can be casted
* to void* */
typedef void* type_t;
/* The following predicate should return non-zero
* if the first argument is less than the second */
typedef uint8_t (*lessthan_predicate_t)(type_t,type_t);
typedef struct {
type_t *array;
uint32_t size;
uint32_t max_size;
lessthan_predicate_t less_than;
} ordered_array_t;
uint8_t standard_lessthan_predicate(type_t a, type_t b);
// Create a new ordered array
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than);
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than);
// Destroy an ordered array
void destroy_ordered_array(ordered_array_t *array);
// Add an item into the array
void insert_ordered_array(type_t item, ordered_array_t *array);
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array);
void remove_ordered_array(uint32_t i, ordered_array_t *array);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef ORDERED_ARRAY_H
#define ORDERED_ARRAY_H
#include <stdint.h>
/* Our list is always in a 'sorted state',
* it can store anything that can be casted
* to void* */
typedef void* type_t;
/* The following predicate should return non-zero
* if the first argument is less than the second */
typedef uint8_t (*lessthan_predicate_t)(type_t,type_t);
typedef struct {
type_t *array;
uint32_t size;
uint32_t max_size;
lessthan_predicate_t less_than;
} ordered_array_t;
uint8_t standard_lessthan_predicate(type_t a, type_t b);
// Create a new ordered array
ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than);
ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than);
// Destroy an ordered array
void destroy_ordered_array(ordered_array_t *array);
// Add an item into the array
void insert_ordered_array(type_t item, ordered_array_t *array);
type_t lookup_ordered_array(uint32_t i, ordered_array_t *array);
void remove_ordered_array(uint32_t i, ordered_array_t *array);
#endif

View File

@ -1,141 +1,141 @@
#include "paging.h"
#include "../libc/string.h"
#include "../libc/panic.h"
#include "../libc/stdio.h"
#include "../drivers/tty.h"
// External definitions from kheap.c
extern uint32_t placement_addr;
extern heap_t *kheap;
// Bitset of frames, used or free
uint32_t *frame_allocations;
uint32_t nframes; // Number of physical frames
page_directory_t *kernel_directory = 0;
page_directory_t *current_directory = 0;
static void set_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] |= (1 << frame_alloc_o);
}
static void clear_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] &= ~(1 << frame_alloc_o);
}
static uint32_t first_frame() {
uint32_t nsections = nframes / FRAME_ALLOCATIONS_SECTION_SIZE;
for(uint32_t sec = 0; sec < nsections; sec++)
if(frame_allocations[sec] != USED_FRAME_SECTION)
for(uint32_t idx = 0; idx < FRAME_ALLOCATIONS_SECTION_SIZE; idx++)
if(!(frame_allocations[sec] & (0x1 << idx)))
return (sec*FRAME_ALLOCATIONS_SECTION_SIZE) + idx;
return nsections * FRAME_ALLOCATIONS_SECTION_SIZE;
}
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) {
if(page->fr != 0)
return;
else {
uint32_t fframe = first_frame();
if(fframe == (uint32_t)-1) {
PANIC("No free frames availables!");
} else {
// Set free frames to the page
page->pr = PAGE_PRESENT;
page->rw = (is_write) ? PAGE_READ_WRITE : PAGE_READ_ONLY;
page->us = (is_super) ? PAGE_SUPERVISOR : PAGE_USER;
page->fr = fframe;
// Set new frames as used
uint32_t physical_addr = fframe * FRAME_SIZE;
set_frame(physical_addr);
}
}
}
void free_frame(page_t *page) {
uint32_t frame;
if(!(frame=page->fr))
return; // page doesn't have a frame in first place
else {
clear_frame(frame);
page->fr = 0x0;
}
}
void init_paging() {
// Setup frame allocation
nframes = PHYSICAL_MEM_SIZE / FRAME_SIZE;
frame_allocations = (uint32_t*)kmalloc(nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
memset(frame_allocations, 0, nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
// Setup page directory
kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
memset(kernel_directory, 0, sizeof(page_directory_t));
current_directory = kernel_directory;
// Map heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
get_page(i, 1, kernel_directory);
// Setup identity map
for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Allocate heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Register a new ISR to listen to IRQ 14
register_interrupt_handler(14, page_fault);
enable_paging(kernel_directory);
kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
}
void enable_paging(page_directory_t *dir) {
current_directory = dir;
asm volatile("mov %0, %%cr3" :: "r"(&dir->page_tables_physical));
uint32_t cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 0x80000000; // Correct code to enable paging
asm volatile("mov %0, %%cr0" :: "r"(cr0));
}
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) {
address /= 0x1000; // turn address into an index
uint32_t table_idx = address / 1024; // Find page that contains the address
if(dir->page_tables_virtual[table_idx])
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
else if(make) {
uint32_t tmp;
dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
memset(dir->page_tables_virtual[table_idx], 0, 0x1000);
dir->page_tables_physical[table_idx] = tmp | 0x7;
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
} else
return 0;
}
void page_fault(registers_t regs) {
// Handle a page fault
uint32_t faulting_addr;
asm volatile("mov %%cr2, %0" : "=r" (faulting_addr));
// Gracefully print the error
kprint((uint8_t*)"\nPage fault! ( ");
if(!(regs.err_code & 0x1))
kprint((uint8_t*)"Present ");
if(regs.err_code & 0x2)
kprint((uint8_t*)"Read-Only ");
if(regs.err_code & 0x4)
kprint((uint8_t*)"User-Mode ");
if(regs.err_code & 0x8)
kprint((uint8_t*)"Reserved");
printf(") at %x\n", faulting_addr);
PANIC("Page fault");
}
#include "paging.h"
#include "../libc/string.h"
#include "../libc/panic.h"
#include "../libc/stdio.h"
#include "../drivers/tty.h"
// External definitions from kheap.c
extern uint32_t placement_addr;
extern heap_t *kheap;
// Bitset of frames, used or free
uint32_t *frame_allocations;
uint32_t nframes; // Number of physical frames
page_directory_t *kernel_directory = 0;
page_directory_t *current_directory = 0;
static void set_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] |= (1 << frame_alloc_o);
}
static void clear_frame(uint32_t addr) {
uint32_t frame = FRAME(addr);
uint32_t frame_alloc_s = FRAME_SECTION(frame);
uint32_t frame_alloc_o = FRAME_OFFSET(frame);
frame_allocations[frame_alloc_s] &= ~(1 << frame_alloc_o);
}
static uint32_t first_frame() {
uint32_t nsections = nframes / FRAME_ALLOCATIONS_SECTION_SIZE;
for(uint32_t sec = 0; sec < nsections; sec++)
if(frame_allocations[sec] != USED_FRAME_SECTION)
for(uint32_t idx = 0; idx < FRAME_ALLOCATIONS_SECTION_SIZE; idx++)
if(!(frame_allocations[sec] & (0x1 << idx)))
return (sec*FRAME_ALLOCATIONS_SECTION_SIZE) + idx;
return nsections * FRAME_ALLOCATIONS_SECTION_SIZE;
}
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) {
if(page->fr != 0)
return;
else {
uint32_t fframe = first_frame();
if(fframe == (uint32_t)-1) {
PANIC("No free frames availables!");
} else {
// Set free frames to the page
page->pr = PAGE_PRESENT;
page->rw = (is_write) ? PAGE_READ_WRITE : PAGE_READ_ONLY;
page->us = (is_super) ? PAGE_SUPERVISOR : PAGE_USER;
page->fr = fframe;
// Set new frames as used
uint32_t physical_addr = fframe * FRAME_SIZE;
set_frame(physical_addr);
}
}
}
void free_frame(page_t *page) {
uint32_t frame;
if(!(frame=page->fr))
return; // page doesn't have a frame in first place
else {
clear_frame(frame);
page->fr = 0x0;
}
}
void init_paging() {
// Setup frame allocation
nframes = PHYSICAL_MEM_SIZE / FRAME_SIZE;
frame_allocations = (uint32_t*)kmalloc(nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
memset(frame_allocations, 0, nframes/FRAME_ALLOCATIONS_SECTION_SIZE);
// Setup page directory
kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
memset(kernel_directory, 0, sizeof(page_directory_t));
current_directory = kernel_directory;
// Map heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
get_page(i, 1, kernel_directory);
// Setup identity map
for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Allocate heap pages
for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE)
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
// Register a new ISR to listen to IRQ 14
register_interrupt_handler(14, page_fault);
enable_paging(kernel_directory);
kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
}
void enable_paging(page_directory_t *dir) {
current_directory = dir;
asm volatile("mov %0, %%cr3" :: "r"(&dir->page_tables_physical));
uint32_t cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 0x80000000; // Correct code to enable paging
asm volatile("mov %0, %%cr0" :: "r"(cr0));
}
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) {
address /= 0x1000; // turn address into an index
uint32_t table_idx = address / 1024; // Find page that contains the address
if(dir->page_tables_virtual[table_idx])
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
else if(make) {
uint32_t tmp;
dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
memset(dir->page_tables_virtual[table_idx], 0, 0x1000);
dir->page_tables_physical[table_idx] = tmp | 0x7;
return &dir->page_tables_virtual[table_idx]->pages[address%1024];
} else
return 0;
}
void page_fault(registers_t regs) {
// Handle a page fault
uint32_t faulting_addr;
asm volatile("mov %%cr2, %0" : "=r" (faulting_addr));
// Gracefully print the error
kprint((uint8_t*)"\nPage fault! ( ");
if(!(regs.err_code & 0x1))
kprint((uint8_t*)"Present ");
if(regs.err_code & 0x2)
kprint((uint8_t*)"Read-Only ");
if(regs.err_code & 0x4)
kprint((uint8_t*)"User-Mode ");
if(regs.err_code & 0x8)
kprint((uint8_t*)"Reserved");
printf(") at %x\n", faulting_addr);
PANIC("Page fault");
}

View File

@ -1,81 +1,81 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef PAGING_H
#define PAGING_H
#include <stdint.h>
#include "../drivers/isr.h"
#include "kheap.h"
#define FRAME_SIZE 4096
#define PAGE_TABLE_SIZE 1024
#define PAGE_DIRECTORY_SIZE 1024
#define PAGE_NOT_PRESENT 0
#define PAGE_PRESENT 1
#define PAGE_READ_ONLY 0
#define PAGE_READ_WRITE 1
#define PAGE_USER 0
#define PAGE_SUPERVISOR 0
#define PAGE_SIZE_4KB 0
#define PAGE_SIZE_4MB 1
// Frames macros
#define FRAME_ALLOCATIONS_SECTION_SIZE 32
#define USED_FRAME_SECTION 0xFFFFFFFF
#define FREE_FRAME_SECTION 0x00000000
#define FRAME(addr) (addr/FRAME_SIZE)
#define FRAME_SECTION(frame) (frame/FRAME_ALLOCATIONS_SECTION_SIZE)
#define FRAME_OFFSET(frame) (frame%FRAME_ALLOCATIONS_SECTION_SIZE)
// Set physical memory to 15 MiB
#define PHYSICAL_MEM_SIZE 0x10000000
struct page { // Single page structure, from intel's developer manual
uint8_t pr : 1; // Present: 1 to map 4KB page
uint8_t rw : 1; // Read/Write mode
uint8_t us : 1; // if 0, user mode access aren't allowed to the page
uint8_t pw : 1; // Page-level write through
uint8_t pc : 1; // Page-level cache disable
uint8_t ac : 1; // 1 if we have accessed 4kb page
uint8_t di : 1; // 1 if page has been written(dirty)
uint8_t pa : 1; // Unused bit
uint8_t gl : 1; // 1 if page is global
uint8_t ig : 3; // Unused bit
uint32_t fr: 20; // Physical address of frame
} __attribute__((packed));
typedef struct page page_t;
typedef struct page_table {
page_t pages[PAGE_TABLE_SIZE];
} page_table_t;
/* Holds 2 arrays for each page directory
* one holds the physical address, while
* the other one holds the virtual address
* (to write/read to it) */
typedef struct page_directory {
page_table_t *page_tables_virtual[PAGE_DIRECTORY_SIZE];
uint32_t page_tables_physical[PAGE_DIRECTORY_SIZE];
} page_directory_t;
// Setup environment, page directories and enable paging
void init_paging();
// Perform the "enable-paging" operation to the right register
void enable_paging(page_directory_t *dir);
// Retrieve a pointer from the given page
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir);
// Identity map(phys = virtual addr) to access it as if paging wasn't enabled
void identity_map();
// Delete a frame
void free_frame(page_t *page);
// Allocate a new frame
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write);
// Page faults handler(ISR recorder)
void page_fault(registers_t regs);
#endif
/*****************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/vulcanos *
*****************************************/
#ifndef PAGING_H
#define PAGING_H
#include <stdint.h>
#include "../drivers/isr.h"
#include "kheap.h"
#define FRAME_SIZE 4096
#define PAGE_TABLE_SIZE 1024
#define PAGE_DIRECTORY_SIZE 1024
#define PAGE_NOT_PRESENT 0
#define PAGE_PRESENT 1
#define PAGE_READ_ONLY 0
#define PAGE_READ_WRITE 1
#define PAGE_USER 0
#define PAGE_SUPERVISOR 0
#define PAGE_SIZE_4KB 0
#define PAGE_SIZE_4MB 1
// Frames macros
#define FRAME_ALLOCATIONS_SECTION_SIZE 32
#define USED_FRAME_SECTION 0xFFFFFFFF
#define FREE_FRAME_SECTION 0x00000000
#define FRAME(addr) (addr/FRAME_SIZE)
#define FRAME_SECTION(frame) (frame/FRAME_ALLOCATIONS_SECTION_SIZE)
#define FRAME_OFFSET(frame) (frame%FRAME_ALLOCATIONS_SECTION_SIZE)
// Set physical memory to 15 MiB
#define PHYSICAL_MEM_SIZE 0x10000000
struct page { // Single page structure, from intel's developer manual
uint8_t pr : 1; // Present: 1 to map 4KB page
uint8_t rw : 1; // Read/Write mode
uint8_t us : 1; // if 0, user mode access aren't allowed to the page
uint8_t pw : 1; // Page-level write through
uint8_t pc : 1; // Page-level cache disable
uint8_t ac : 1; // 1 if we have accessed 4kb page
uint8_t di : 1; // 1 if page has been written(dirty)
uint8_t pa : 1; // Unused bit
uint8_t gl : 1; // 1 if page is global
uint8_t ig : 3; // Unused bit
uint32_t fr: 20; // Physical address of frame
} __attribute__((packed));
typedef struct page page_t;
typedef struct page_table {
page_t pages[PAGE_TABLE_SIZE];
} page_table_t;
/* Holds 2 arrays for each page directory
* one holds the physical address, while
* the other one holds the virtual address
* (to write/read to it) */
typedef struct page_directory {
page_table_t *page_tables_virtual[PAGE_DIRECTORY_SIZE];
uint32_t page_tables_physical[PAGE_DIRECTORY_SIZE];
} page_directory_t;
// Setup environment, page directories and enable paging
void init_paging();
// Perform the "enable-paging" operation to the right register
void enable_paging(page_directory_t *dir);
// Retrieve a pointer from the given page
page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir);
// Identity map(phys = virtual addr) to access it as if paging wasn't enabled
void identity_map();
// Delete a frame
void free_frame(page_t *page);
// Allocate a new frame
void alloc_frame(page_t *page, int32_t is_super, int32_t is_write);
// Page faults handler(ISR recorder)
void page_fault(registers_t regs);
#endif

View File

@ -1,10 +1,10 @@
OBJS = shell.o fetch.o
VER := $(shell git rev-parse --short HEAD)
CC = i686-elf-gcc # cross-compiler
CFLAGS = -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
OBJS = shell.o fetch.o
VER := $(shell git rev-parse --short HEAD)
CC = i686-elf-gcc # cross-compiler
CFLAGS = -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c
all:${OBJS}
%.o: %.c
$(CC) $(CFLAGS) $< -o $@

View File

@ -1,75 +1,75 @@
#include "fetch.h"
#include "../libc/stdio.h"
#include "../libc/string.h"
#include "../libc/time.h"
#include "../drivers/tty.h"
#include "../drivers/cpuid.h"
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
static void get_date();
static void get_cpuid();
static void get_version();
void system_fetcher() {
uint8_t user[64], hostname[64];
#ifdef DEFAULT_USER
strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER));
#else
#error "-DDEFAULT_USER flag not set"
#endif
#ifdef DEFAULT_HOSTNAME
strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME));
#else
#error "-DDEFAULT_HOSTNAME flag not set"
#endif
// print first line
printf_color("\n __ __ ___ ___ ", LIGHT_RED, BLACK);
printf_color((char*)user, LIGHT_CYAN, BLACK);
printf_color("@", LIGHT_RED, BLACK);
printf_color((char*)hostname, LIGHT_CYAN, BLACK);
// print second line
printf_color("\n \\ \\ / / / _ \\/ __| ", LIGHT_RED, BLACK);
printf_color("-----------", LIGHT_RED, BLACK);
// print third line
printf_color("\n \\ V / | (_) \\__ \\ ", LIGHT_RED, BLACK);
printf_color("Date: ", LIGHT_CYAN, BLACK);
get_date();
// print fourth line
printf_color("\n \\_/ \\___/|___/ ", LIGHT_RED, BLACK);
get_cpuid();
// print VulcanOS version
get_version();
}
// Date format is D/M/YY
void get_date() {
printf("%d", get_time(TIME_R_DAY)); // Day
printf_color("/", LIGHT_BLUE, BLACK);
printf("%d", get_time(TIME_R_MONTH)); // Month
printf_color("/", LIGHT_BLUE, BLACK);
printf("%d", get_time(TIME_R_YEAR)); // Year
}
void get_cpuid() {
printf_color("CPU type: ", LIGHT_CYAN, BLACK);
printf("%s", (char*)get_cpu_type()); // Print CPU type
printf("%s%s%c", " (", (char*)get_cpu_family(), ')');
}
void get_version() {
uint8_t version[64];
#ifdef VULCAN_VERSION
strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION));
#else
#error "-DVULCAN_VERSION flag not set"
#endif
printf_color("\n\t\t\t\t\t Version: ", LIGHT_CYAN, BLACK);
printf_color((char*)version, LIGHT_GREEN, BLACK);
}
#include "fetch.h"
#include "../libc/stdio.h"
#include "../libc/string.h"
#include "../libc/time.h"
#include "../drivers/tty.h"
#include "../drivers/cpuid.h"
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
static void get_date();
static void get_cpuid();
static void get_version();
void system_fetcher() {
uint8_t user[64], hostname[64];
#ifdef DEFAULT_USER
strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER));
#else
#error "-DDEFAULT_USER flag not set"
#endif
#ifdef DEFAULT_HOSTNAME
strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME));
#else
#error "-DDEFAULT_HOSTNAME flag not set"
#endif
// print first line
printf_color("\n __ __ ___ ___ ", LIGHT_RED, BLACK);
printf_color((char*)user, LIGHT_CYAN, BLACK);
printf_color("@", LIGHT_RED, BLACK);
printf_color((char*)hostname, LIGHT_CYAN, BLACK);
// print second line
printf_color("\n \\ \\ / / / _ \\/ __| ", LIGHT_RED, BLACK);
printf_color("-----------", LIGHT_RED, BLACK);
// print third line
printf_color("\n \\ V / | (_) \\__ \\ ", LIGHT_RED, BLACK);
printf_color("Date: ", LIGHT_CYAN, BLACK);
get_date();
// print fourth line
printf_color("\n \\_/ \\___/|___/ ", LIGHT_RED, BLACK);
get_cpuid();
// print VulcanOS version
get_version();
}
// Date format is D/M/YY
void get_date() {
printf("%d", get_time(TIME_R_DAY)); // Day
printf_color("/", LIGHT_BLUE, BLACK);
printf("%d", get_time(TIME_R_MONTH)); // Month
printf_color("/", LIGHT_BLUE, BLACK);
printf("%d", get_time(TIME_R_YEAR)); // Year
}
void get_cpuid() {
printf_color("CPU type: ", LIGHT_CYAN, BLACK);
printf("%s", (char*)get_cpu_type()); // Print CPU type
printf("%s%s%c", " (", (char*)get_cpu_family(), ')');
}
void get_version() {
uint8_t version[64];
#ifdef VULCAN_VERSION
strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION));
#else
#error "-DVULCAN_VERSION flag not set"
#endif
printf_color("\n\t\t\t\t\t Version: ", LIGHT_CYAN, BLACK);
printf_color((char*)version, LIGHT_GREEN, BLACK);
}

View File

@ -1,15 +1,15 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef FETCH_H
#define FETCH_H
#include <stdint.h>
void system_fetcher();
#endif
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef FETCH_H
#define FETCH_H
#include <stdint.h>
void system_fetcher();
#endif

View File

@ -1,122 +1,122 @@
#include "shell.h"
#include "fetch.h"
#include "../libc/string.h"
#include "../libc/stdio.h"
#include "../drivers/tty.h"
#include "../drivers/ports.h"
#include "../drivers/timer.h"
void helper() {
puts("\nList of available commands:\n"
"\nhelp - Print this helper"
"\nint - Test some interrupts"
"\nbanner - Show banner"
"\nclear, cls - Clear the screen"
"\nregs - Prints register dump"
"\ntimer - Prints timer tick"
"\nabout - About this kernel"
"\nreboot - Reboot the system"
);
}
void test_interrupts() {
// Testing some interrupts
asm("int $0"); // Division by zero
asm("int $4"); // Stack overflow
asm("int $1"); // Page fault
}
void about() {
printf_color("\n====== IceOS v0.0.1 (c) 2019 Marco 'icebit' Cetica ======\n\n",
LIGHT_CYAN, BLACK);
printf_color(
"iceOS is a x86 monolithic kernel written in C from scratch.\n"
"This project doesn't aim to be a fully functional operating system\n"
"with tons of drivers and graphical applications,\nit's just a learning tool "
"to teach myself concepts like\nOperating Systems, Computer Architecture and Digital Electronics.\n"
"\n\n"
"iceOS comes with the following features:\n"
"- Bare metal booting;\n"
"- VGA driver;\n"
"- Interrupts implementation;\n"
"- PIC & PIT implementation;\n"
"- PS2 driver;\n"
"- Support for x86 architecture;\n"
"- GRUB as bootloader;\n",
LIGHT_GREEN, BLACK);
}
void register_dump() {
register uint32_t eax_v asm("eax");
register uint32_t ebx_v asm("ebx");
register uint32_t ecx_v asm("ecx");
register uint32_t edx_v asm("edx");
register uint32_t esx_v asm("esi");
register uint32_t edi_v asm("edi");
register uint32_t ebp_v asm("ebp");
register uint32_t esp_v asm("esp");
printf_color("\n===================================\n"
" BEGIN 32 BITS CPU REGISTER DUMP \n"
"===================================\n",
LIGHT_BROWN, BLACK);
printf(" EAX: %x\n"
" EBX: %x\n"
" ECX: %x\n"
" EDX: %x\n"
" ESX: %x\n"
" EDI: %x\n"
" EBP: %x\n"
" ESP: %x\n",
eax_v, ebx_v, ecx_v, edx_v, esx_v, edi_v, ebp_v, esp_v);
printf_color("\n==================================\n"
" END 32 BITS CPU REGISTER DUMP \n"
"==================================\n",
LIGHT_BROWN, BLACK);
}
void timer_dump() {
uint8_t buf[8];
uitoa(tick, buf, 10);
printf_color("\nTicks since boot: ",
LIGHT_GREEN, BLACK);
printf_color((const char*)buf,
LIGHT_CYAN, BLACK);
}
void reboot() {
uint8_t tmp;
asm("cli"); // First disable all interrupts
// Clear keyboard buffers
do {
tmp = inb(0x64); // Keyboard interface
if(check_flag(tmp, 0) != 0)
inb(0x60); // Clear keyboard data
} while(check_flag(tmp, 1) != 0);
outb(0x64, 0xFE); // Reset the CPU
}
void processCommand(uint8_t *cmd) {
if(strcmp(cmd, (uint8_t*)"help") == 0)
helper();
else if(strcmp(cmd, (uint8_t*)"int") == 0)
test_interrupts();
else if(strcmp(cmd, (uint8_t*)"clear") == 0 || strcmp(cmd, (uint8_t*)"cls") == 0)
clear_prompt();
else if(strcmp(cmd, (uint8_t*)"about") == 0)
about();
else if(strcmp(cmd, (uint8_t*)"regs") == 0)
register_dump();
else if(strcmp(cmd, (uint8_t*)"timer") == 0)
timer_dump();
else if(strcmp(cmd, (uint8_t*)"fetch") == 0)
system_fetcher();
else if(strcmp(cmd, (uint8_t*)"reboot") == 0)
reboot();
else if(strcmp(cmd, (uint8_t*)"") == 0)
puts("");
else
puts("\nCommand not found!");
}
#include "shell.h"
#include "fetch.h"
#include "../libc/string.h"
#include "../libc/stdio.h"
#include "../drivers/tty.h"
#include "../drivers/ports.h"
#include "../drivers/timer.h"
void helper() {
puts("\nList of available commands:\n"
"\nhelp - Print this helper"
"\nint - Test some interrupts"
"\nbanner - Show banner"
"\nclear, cls - Clear the screen"
"\nregs - Prints register dump"
"\ntimer - Prints timer tick"
"\nabout - About this kernel"
"\nreboot - Reboot the system"
);
}
void test_interrupts() {
// Testing some interrupts
asm("int $0"); // Division by zero
asm("int $4"); // Stack overflow
asm("int $1"); // Page fault
}
void about() {
printf_color("\n====== IceOS v0.0.1 (c) 2019 Marco 'icebit' Cetica ======\n\n",
LIGHT_CYAN, BLACK);
printf_color(
"iceOS is a x86 monolithic kernel written in C from scratch.\n"
"This project doesn't aim to be a fully functional operating system\n"
"with tons of drivers and graphical applications,\nit's just a learning tool "
"to teach myself concepts like\nOperating Systems, Computer Architecture and Digital Electronics.\n"
"\n\n"
"iceOS comes with the following features:\n"
"- Bare metal booting;\n"
"- VGA driver;\n"
"- Interrupts implementation;\n"
"- PIC & PIT implementation;\n"
"- PS2 driver;\n"
"- Support for x86 architecture;\n"
"- GRUB as bootloader;\n",
LIGHT_GREEN, BLACK);
}
void register_dump() {
register uint32_t eax_v asm("eax");
register uint32_t ebx_v asm("ebx");
register uint32_t ecx_v asm("ecx");
register uint32_t edx_v asm("edx");
register uint32_t esx_v asm("esi");
register uint32_t edi_v asm("edi");
register uint32_t ebp_v asm("ebp");
register uint32_t esp_v asm("esp");
printf_color("\n===================================\n"
" BEGIN 32 BITS CPU REGISTER DUMP \n"
"===================================\n",
LIGHT_BROWN, BLACK);
printf(" EAX: %x\n"
" EBX: %x\n"
" ECX: %x\n"
" EDX: %x\n"
" ESX: %x\n"
" EDI: %x\n"
" EBP: %x\n"
" ESP: %x\n",
eax_v, ebx_v, ecx_v, edx_v, esx_v, edi_v, ebp_v, esp_v);
printf_color("\n==================================\n"
" END 32 BITS CPU REGISTER DUMP \n"
"==================================\n",
LIGHT_BROWN, BLACK);
}
void timer_dump() {
uint8_t buf[8];
uitoa(tick, buf, 10);
printf_color("\nTicks since boot: ",
LIGHT_GREEN, BLACK);
printf_color((const char*)buf,
LIGHT_CYAN, BLACK);
}
void reboot() {
uint8_t tmp;
asm("cli"); // First disable all interrupts
// Clear keyboard buffers
do {
tmp = inb(0x64); // Keyboard interface
if(check_flag(tmp, 0) != 0)
inb(0x60); // Clear keyboard data
} while(check_flag(tmp, 1) != 0);
outb(0x64, 0xFE); // Reset the CPU
}
void processCommand(uint8_t *cmd) {
if(strcmp(cmd, (uint8_t*)"help") == 0)
helper();
else if(strcmp(cmd, (uint8_t*)"int") == 0)
test_interrupts();
else if(strcmp(cmd, (uint8_t*)"clear") == 0 || strcmp(cmd, (uint8_t*)"cls") == 0)
clear_prompt();
else if(strcmp(cmd, (uint8_t*)"about") == 0)
about();
else if(strcmp(cmd, (uint8_t*)"regs") == 0)
register_dump();
else if(strcmp(cmd, (uint8_t*)"timer") == 0)
timer_dump();
else if(strcmp(cmd, (uint8_t*)"fetch") == 0)
system_fetcher();
else if(strcmp(cmd, (uint8_t*)"reboot") == 0)
reboot();
else if(strcmp(cmd, (uint8_t*)"") == 0)
puts("");
else
puts("\nCommand not found!");
}

View File

@ -1,19 +1,19 @@
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _SHELL_H_
#define _SHELL_H_
#include <stdint.h>
#define bit(n) (1 << (n))
#define check_flag(flags, n) ((flags) & bit(n))
void helper();
void processCommand(uint8_t *cmd);
#endif
/**************************************
* VulcanOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019-2021 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _SHELL_H_
#define _SHELL_H_
#include <stdint.h>
#define bit(n) (1 << (n))
#define check_flag(flags, n) ((flags) & bit(n))
void helper();
void processCommand(uint8_t *cmd);
#endif

55
link.ld
View File

@ -1,28 +1,27 @@
ENTRY(kernel_loader)
SECTIONS
{
.text 0x100000 :
{
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
ENTRY(kernel_loader)
SECTIONS
{
. = 1M;
.boot :
{
KEEP(*(.multiboot_header))
. = ALIGN(4096);
}
.text :
{
*(.data)
*(.rodata)
. = ALIGN(4096);
}
.bss :
{
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}