Refactoring assembly entry point
This commit is contained in:
parent
dc3803491e
commit
1b207add8c
106
.gitignore
vendored
106
.gitignore
vendored
@ -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
|
18
.travis.yml
18
.travis.yml
@ -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
|
||||
|
114
Makefile
114
Makefile
@ -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
|
||||
|
74
README.md
74
README.md
@ -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.
|
||||
|
22
bochs_cfg
22
bochs_cfg
@ -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
|
108
fs_generator.c
108
fs_generator.c
@ -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;
|
||||
}
|
14
grub.cfg
14
grub.cfg
@ -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
|
||||
}
|
||||
|
@ -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 $@
|
@ -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 $@
|
||||
|
@ -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
19
kernel/cpu/header.asm
Normal 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:
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
27
kernel/cpu/main.asm
Normal 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
|
@ -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
|
||||
|
@ -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 $@
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 $@
|
||||
|
@ -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(;;);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 $@
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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--;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 $@
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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
55
link.ld
@ -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 = .;
|
||||
}
|
Loading…
Reference in New Issue
Block a user