Merge pull request #1 from xamidev/dev

Graphics mode & linear framebuffer update
This commit was merged in pull request #1.
This commit is contained in:
xamidev
2024-08-23 15:24:09 +02:00
committed by GitHub
34 changed files with 1067 additions and 717 deletions

3
.gitignore vendored
View File

@@ -1,6 +1,7 @@
*.o *.o
build/ build/
kernel.elf kernel.elf
blankos-fat.img blankos.iso
iso/
i386-elf-7.5.0-Linux-x86_64/ i386-elf-7.5.0-Linux-x86_64/
i386-elf-7.5.0-Linux-x86_64.tar.xz i386-elf-7.5.0-Linux-x86_64.tar.xz

View File

@@ -27,7 +27,7 @@ The long-term goal of this OS is to be capable of running user programs and havi
Download the latest BlankOS disk image from the "Releases" tab, and start it using the QEMU emulator: Download the latest BlankOS disk image from the "Releases" tab, and start it using the QEMU emulator:
``` ```
qemu-system-i386 blankOS-i386-0.3.45.img qemu-system-i386 blankOS-i386-0.3.55.iso
``` ```
## Building from source ## Building from source
@@ -47,7 +47,7 @@ To run the OS on real hardware, you'll first need to have a BIOS-compatible comp
Burn your image file onto a USB stick: Burn your image file onto a USB stick:
``` ```
sudo dd bs=4M if=blankos-fat.img of=/dev/sdX status=progress oflag=sync sudo dd bs=4M if=blankos.iso of=/dev/sdX status=progress oflag=sync
``` ```
Replace `sdX` with your USB drive name (you can find it by doing `sudo fdisk -l`). Replace `sdX` with your USB drive name (you can find it by doing `sudo fdisk -l`).
@@ -56,7 +56,7 @@ Tada! You now have a working BlankOS USB stick. Go ahead and try it out!
## Debugging (QEMU w/ GDB) ## Debugging (QEMU w/ GDB)
``` ```
qemu-system-i386 -s -S -drive file=blankos-fat.img,format=raw qemu-system-i386 -s -S -drive file=blankos.iso,format=raw
``` ```
In another shell: In another shell:
@@ -68,7 +68,7 @@ gdb kernel.elf
## Documentation ## Documentation
Two other documents are available to help you understand the project better. One is the User's Manual, labelled [USERS.md](USERS.md), and the other one is the Developer's Manual, labelled [DEVELOPERS.md](DEVELOPERS.md). They are full of useful resources around Blank OS. You'll learn how to use the system and how to contribute to it. Two other documents are available to help you understand the project better. One is the User's Manual, labelled [USERS.md](docs/USERS.md), and the other one is the Developer's Manual, labelled [DEVELOPERS.md](docs/DEVELOPERS.md). They are full of useful resources around Blank OS. You'll learn how to use the system and how to contribute to it.
### Resources ### Resources
@@ -79,6 +79,7 @@ Two other documents are available to help you understand the project better. One
- the Intel [64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html) - the Intel [64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html)
- [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/index.php) - [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/index.php)
- Ralf Brown's Interrupt List - Ralf Brown's Interrupt List
- the [little book about OS development](https://littleosbook.github.io/) by Erik Helin and Adam Renberg
### ⚠️ Disclaimer ### ⚠️ Disclaimer
@@ -90,8 +91,9 @@ This is a hobbyist operating system kernel and it comes without any warranty wha
- [X] Common basic structures (IDT, GDT, ISRs, IRQs) - [X] Common basic structures (IDT, GDT, ISRs, IRQs)
- [X] Common drivers (framebuffer, keyboard, serial, timer) - [X] Common drivers (framebuffer, keyboard, serial, timer)
- [X] Kernel-space utilities (shell, simple programs) - [X] Kernel-space utilities (shell, simple programs)
- [ ] FAT32 filesystem - [ ] Filesystem (FAT32 or VFS ramdisk)
- [ ] Paging/Page Frame Allocation - [ ] Changing the default VGA font
- [X] Paging/Page Frame Allocation
- [ ] TCP/IP Network stack - [ ] TCP/IP Network stack
- [ ] Getting to Ring-3 (userspace) - [ ] Getting to Ring-3 (userspace)
- [ ] Multitasking (via round robin scheduling) - [ ] Multitasking (via round robin scheduling)

View File

@@ -1,4 +1,5 @@
menuentry "Blank OS" { menuentry "Blank OS" {
multiboot /boot/kernel.elf set gfxpayload=1024x768x32
multiboot2 /boot/kernel.elf
boot boot
} }

Binary file not shown.

17
link.ld
View File

@@ -1,30 +1,31 @@
ENTRY(loader) ENTRY(loader)
SECTIONS { SECTIONS {
/* Address to load at; 1MB */ /* Address to load at; 2MB */
. = 0x00100000; /*. = 2M;*/
.__mbHeader : { .multiboot_header ALIGN(4K) : {
*(.__mbHeader) *(.multiboot_header)
} }
/* Align relevant sections at 4KB */ /* Align relevant sections at 4KB */
.text ALIGN (0x1000) : .text ALIGN (4K) :
{ {
*(.text) *(.text)
*(.rodata) *(.rodata)
} }
.data ALIGN (0x1000) : .data ALIGN (4K) :
{ {
*(.data) *(.data)
} }
.bss ALIGN (0x1000) : .bss ALIGN (4K) :
{ {
*(COMMON) *(COMMON)
*(.bss) *(.bss)
} }
end = .; _end = .; __end = .;
} }

View File

@@ -9,6 +9,8 @@ KERNEL_DIR = $(SRC_DIR)/kernel
LIBC_DIR = $(SRC_DIR)/libc LIBC_DIR = $(SRC_DIR)/libc
PROGRAMS_DIR = $(SRC_DIR)/programs PROGRAMS_DIR = $(SRC_DIR)/programs
DRIVERS_DIR = $(SRC_DIR)/drivers DRIVERS_DIR = $(SRC_DIR)/drivers
INCLUDE_DIR = include
FONTS_DIR = $(INCLUDE_DIR)/fonts
OBJ_DIR = build OBJ_DIR = build
C_SOURCES = $(wildcard $(KERNEL_DIR)/*.c) $(wildcard $(LIBC_DIR)/*.c) $(wildcard $(PROGRAMS_DIR)/*.c) $(wildcard $(DRIVERS_DIR)/*.c) C_SOURCES = $(wildcard $(KERNEL_DIR)/*.c) $(wildcard $(LIBC_DIR)/*.c) $(wildcard $(PROGRAMS_DIR)/*.c) $(wildcard $(DRIVERS_DIR)/*.c)
@@ -19,14 +21,17 @@ OBJECTS = $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCE
TOOLCHAIN_SRC = https://newos.org/toolchains/i386-elf-7.5.0-Linux-x86_64.tar.xz TOOLCHAIN_SRC = https://newos.org/toolchains/i386-elf-7.5.0-Linux-x86_64.tar.xz
TOOLCHAIN_FILE = i386-elf-7.5.0-Linux-x86_64.tar.xz TOOLCHAIN_FILE = i386-elf-7.5.0-Linux-x86_64.tar.xz
FONT_OBJ = $(OBJ_DIR)/fonts/UniCyr_8x16.o
FONT_SRC = $(FONTS_DIR)/UniCyr_8x16.psf
all: $(OBJ_DIR) kernel.elf all: $(OBJ_DIR) kernel.elf
$(OBJ_DIR): $(OBJ_DIR):
mkdir -p $(OBJ_DIR) mkdir -p $(OBJ_DIR)
mkdir -p $(OBJ_DIR)/kernel $(OBJ_DIR)/libc $(OBJ_DIR)/programs $(OBJ_DIR)/drivers mkdir -p $(OBJ_DIR)/kernel $(OBJ_DIR)/libc $(OBJ_DIR)/programs $(OBJ_DIR)/drivers $(OBJ_DIR)/fonts
kernel.elf: $(OBJECTS) kernel.elf: $(OBJECTS) $(FONT_OBJ)
ld $(LDFLAGS) $(OBJECTS) -o kernel.elf ld $(LDFLAGS) $(OBJECTS) $(FONT_OBJ) -o kernel.elf
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $< -o $@ $(CC) $(CFLAGS) $< -o $@
@@ -34,18 +39,28 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s $(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
$(AS) $(ASFLAGS) $< -o $@ $(AS) $(ASFLAGS) $< -o $@
$(FONT_OBJ): $(FONT_SRC) | $(OBJ_DIR)/fonts
objcopy -O elf32-i386 -B i386 -I binary $(FONT_SRC) $(FONT_OBJ)
$(OBJ_DIR)/fonts:
mkdir -p $(OBJ_DIR)/fonts
toolchain: toolchain:
wget $(TOOLCHAIN_SRC) wget $(TOOLCHAIN_SRC)
tar xf $(TOOLCHAIN_FILE) tar xf $(TOOLCHAIN_FILE)
blankos-fat.img: iso: kernel.elf
sudo ./setup.sh mkdir -p iso/boot/grub
cp kernel.elf iso/boot/kernel.elf
cp grub.cfg iso/boot/grub/grub.cfg
grub-mkrescue iso -o blankos.iso
run: blankos-fat.img run: iso
qemu-system-i386 -drive file=blankos-fat.img,format=raw qemu-system-i386 -drive file=blankos.iso,format=raw
debug: debug:
qemu-system-i386 -s -S -drive file=blankos-fat.img,format=raw qemu-system-i386 -s -S -drive file=blankos.iso,format=raw
clean: clean:
rm -rf $(OBJ_DIR) kernel.elf blankos-fat.img $(TOOLCHAIN_FILE) rm -rf $(OBJ_DIR) kernel.elf blankos.iso $(TOOLCHAIN_FILE)

View File

@@ -1,75 +0,0 @@
#!/bin/bash
# A script to create a FAT32 loopback device, place a kernel onto it, and install GRUB.
# Inspired by JakeSteinburger's SpecOS setup script!
if [ "$EUID" -ne 0 ]; then
echo "Please execute this script with root privileges."
exit
fi
if [ -f "blankos-fat.img" ]; then
echo "Deleting previous disk image..."
rm blankos-fat.img
fi
if [ -d "/mnt/blankos" ]; then
echo "Deleting previous mountpoint..."
rm -rf /mnt/blankos
fi
echo "Creating new mountpoint..."
mkdir /mnt/blankos
echo "Creating an empty disk image..."
dd if=/dev/zero of=blankos-fat.img bs=512 count=131072
echo "Appending a parition to disk image..."
fdisk blankos-fat.img << EOF
n
p
1
a
w
EOF
echo "Creating loopback devices..."
losetup -fP blankos-fat.img
# Get first partition loopback
LOOP_DEVICE=$(losetup -l | grep blankos-fat.img | awk '{print $1}')
PARTITION="${LOOP_DEVICE}p1"
echo "Creating FAT32 partition..."
mkfs.vfat -F 32 $PARTITION
echo "Mounting partition..."
mount $PARTITION /mnt/blankos
echo "Installing GRUB on $LOOP_DEVICE"
grub-install --root-directory=/mnt/blankos --target=i386-pc --no-floppy --modules="normal part_msdos fat multiboot" $LOOP_DEVICE
echo "Copying kernel file and GRUB configuration file..."
cp kernel.elf /mnt/blankos/boot/
cp grub.cfg /mnt/blankos/boot/grub/
echo "Appending test files..."
mkdir /mnt/blankos/hello
echo "Hello, world from FAT32 text file." > /mnt/blankos/hello/testfile.txt
# cp program.elf /mnt/blankos/programs/
# In the future, when the OS can load programs and parse ELF
echo "Unmounting partition..."
umount /mnt/blankos
echo "Freeing loopback devices..."
losetup -d $LOOP_DEVICE
echo "Fixing disk image permissions..."
sudo chmod 666 blankos-fat.img
echo "The blankos-fat.img disk image is ready for use with QEMU or real hardware."

77
src/drivers/ata.c Normal file
View File

@@ -0,0 +1,77 @@
#include "../libc/stdint.h"
#include "../kernel/io.h"
#include "../libc/stdio.h"
#define ATA_PRIMARY_IO 0x1F0
#define ATA_PRIMARY_CTRL 0x3F6
#define ATA_CMD_READ_PIO 0x20
#define ATA_CMD_WRITE_PIO 0x30
#define ATA_IDENTIFY 0xEC
#define ATA_REG_DATA 0x00
#define ATA_REG_ERROR 0x01
#define ATA_REG_SECCOUNT0 0x02
#define ATA_REG_LBA0 0x03
#define ATA_REG_LBA1 0x04
#define ATA_REG_LBA2 0x05
#define ATA_REG_HDDEVSEL 0x06
#define ATA_REG_COMMAND 0x07
#define ATA_REG_STATUS 0x07
#define ATA_SR_BSY 0x80
#define ATA_SR_DRDY 0x40
#define ATA_SR_DRQ 0x08
#define ATA_SR_ERR 0x01
static inline uint16_t inw(uint16_t port) {
uint16_t result;
asm volatile("inw %1, %0" : "=a"(result) : "dN"(port));
return result;
}
static inline void outw(uint16_t port, uint16_t data) {
asm volatile("outw %1, %0" : : "dN"(port), "a"(data));
}
void ata_wait_bsy() {
while (inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_BSY);
}
void ata_wait_drq() {
while (!(inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_DRQ));
}
void ata_select_drive(uint8_t drive) {
outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | (drive << 4));
}
void ata_read_sector(uint32_t lba, uint8_t* buffer) {
ata_wait_bsy();
ata_select_drive(0);
outb(ATA_PRIMARY_IO + ATA_REG_SECCOUNT0, 1);
outb(ATA_PRIMARY_IO + ATA_REG_LBA0, (uint8_t)lba);
outb(ATA_PRIMARY_IO + ATA_REG_LBA1, (uint8_t)(lba >> 8));
outb(ATA_PRIMARY_IO + ATA_REG_LBA2, (uint8_t)(lba >> 16));
outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | ((lba >> 24) & 0x0F));
outb(ATA_PRIMARY_IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
ata_wait_bsy();
ata_wait_drq();
for (int i = 0; i < 256; i++) {
((uint16_t*)buffer)[i] = inw(ATA_PRIMARY_IO + ATA_REG_DATA);
}
}
// Works only w/o paging
void test_read_sector() {
uint8_t buffer[512];
ata_read_sector(0, buffer);
for (int i = 0; i < 512; i++) {
if (i%25==0) puts("\n");
printf("%02x ", buffer[i]);
}
}

7
src/drivers/ata.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef ATA_H
#define ATA_H
void ata_read_sector(uint32_t lba, uint8_t* buffer);
void test_read_sector();
#endif

94
src/drivers/framebuffer.c Normal file
View File

@@ -0,0 +1,94 @@
#include "../libc/stdint.h"
#include "framebuffer.h"
#include "serial.h"
#include "../kernel/system.h"
//extern uint32_t *g_framebuffer;
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color) // framebuffer pointer, x, y, color
{
if (bpp == 32) {
uint32_t* pixel_addr = (uint32_t*)((uint8_t*)fb + y * pitch + x *(bpp / 8));
*pixel_addr = color;
}
}
extern char* framebuffer;
extern int scanline;
extern char _binary_include_fonts_UniCyr_8x16_psf_start;
uint16_t* unicode;
#define PIXEL uint32_t
// Character, cursor X, cursor Y, foreground, background
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg)
{
PSF_font *font = (PSF_font*)&_binary_include_fonts_UniCyr_8x16_psf_start;
int bytesperline=(font->width+7)/8;
if (unicode != NULL) {
c = unicode[c];
}
unsigned char* glyph = (unsigned char*)&_binary_include_fonts_UniCyr_8x16_psf_start + font->headersize + (c>0&&c<font->numglyph?c:0)*font->bytesperglyph;
int offs =
(cy * font->height * scanline) +
(cx * (font->width) * sizeof(PIXEL));
unsigned int x, y;
int line, mask;
for (y=0; y<font->height; y++)
{
line=offs;
mask=1<<(font->width-1);
for (x=0; x<font->width; x++)
{
*((PIXEL*)(framebuffer + line)) = *((unsigned int*)glyph) & mask ? fg : bg;
mask >>= 1;
line += sizeof(PIXEL);
}
glyph += bytesperline;
offs += scanline;
}
}
void scroll()
{
serial_printf(3, "Scrolling...\r");
uint32_t bg_color = 0x00000000;
PSF_font *font = (PSF_font*)&_binary_include_fonts_UniCyr_8x16_psf_start;
int line_size = font->height * scanline;
int framebuffer_size = scanline * font->height * (1080/font->height);
// Erasing first line
for (uint32_t y=0; y<font->height; y++)
{
for (uint32_t x=0; x<scanline/sizeof(PIXEL); x++)
{
*((PIXEL*)(framebuffer + y * scanline + x * sizeof(PIXEL))) = bg_color;
}
}
// Moving all lines up by 1 line
for (int y=1; y<(framebuffer_size/line_size); y++)
{
void* src = framebuffer + y*line_size;
void* dst = framebuffer + (y-1)*line_size;
memmove(dst, src, line_size);
}
// Erasing last line
int last_line_start = (framebuffer_size/line_size-1) * line_size;
for (uint32_t y=0; y<font->height; y++)
{
for (uint32_t x=0; x<scanline/sizeof(PIXEL); x++)
{
*((PIXEL*)(framebuffer + last_line_start + y * scanline + x * sizeof(PIXEL))) = bg_color;
}
}
}

31
src/drivers/framebuffer.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#define PSF1_FONT_MAGIC 0x0436
typedef struct {
uint16_t magic; // Magic bytes for identification.
uint8_t fontMode; // PSF font mode.
uint8_t characterSize; // PSF character size.
} PSF1_Header;
#define PSF_FONT_MAGIC 0x864ab572
typedef struct {
uint32_t magic; /* magic bytes to identify PSF */
uint32_t version; /* zero */
uint32_t headersize; /* offset of bitmaps in file, 32 */
uint32_t flags; /* 0 if there's no unicode table */
uint32_t numglyph; /* number of glyphs */
uint32_t bytesperglyph; /* size of each glyph */
uint32_t height; /* height in pixels */
uint32_t width; /* width in pixels */
} PSF_font;
//extern const unsigned char font[512][64];
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color);
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg);
void scroll();
#endif

View File

@@ -130,6 +130,7 @@ void keyboard_handler()
void keyboard_install() void keyboard_install()
{ {
irq_install_handler(1, keyboard_handler); irq_install_handler(1, keyboard_handler);
printf("[keyboard] installed irq handler\n");
} }
char keyboard_getchar() char keyboard_getchar()

View File

@@ -20,6 +20,7 @@ int init_serial()
} }
outb(PORT+4, 0x0F); outb(PORT+4, 0x0F);
puts("[serial] initialized i/o on port COM1\n");
return 0; return 0;
} }

View File

@@ -6,11 +6,18 @@ volatile unsigned long global_ticks = 0;
void timer_handler() void timer_handler()
{ {
global_ticks++; global_ticks++;
if (global_ticks % 20 == 0)
{
draw_cursor(white);
} else if (global_ticks % 20 == 10) {
erase_cursor();
}
} }
void timer_install() void timer_install()
{ {
irq_install_handler(0, timer_handler); irq_install_handler(0, timer_handler);
printf("[timer] initialized, starting g_ticks...\n");
} }
void delay(int ticks) void delay(int ticks)

View File

@@ -1,4 +1,5 @@
#include "gdt.h" #include "gdt.h"
#include "../libc/stdio.h"
struct gdt_entry struct gdt_entry
{ {
@@ -41,8 +42,14 @@ void gdt_install()
gdt_set_gate(0, 0, 0, 0, 0); gdt_set_gate(0, 0, 0, 0, 0);
// Ring 0 code + data
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
// Ring 3
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
gdt_flush(); gdt_flush();
printf("[kernel] GDT gates set (ring 0 and 3), gdt=0x%x\n", &gdt);
} }

View File

@@ -1,5 +1,6 @@
#include "idt.h" #include "idt.h"
#include "system.h" #include "system.h"
#include "../libc/stdio.h"
struct idt_entry struct idt_entry
{ {
@@ -39,4 +40,5 @@ void idt_install()
memset(&idt, 0, sizeof(struct idt_entry)*256); memset(&idt, 0, sizeof(struct idt_entry)*256);
idt_load(); idt_load();
printf("[kernel] loaded IDT at idt=0x%x\n", &idt);
} }

View File

@@ -1,6 +1,7 @@
#include "system.h" #include "system.h"
#include "io.h" #include "io.h"
#include "idt.h" #include "idt.h"
#include "../libc/stdio.h"
extern void irq0(); extern void irq0();
extern void irq1(); extern void irq1();
@@ -69,6 +70,7 @@ void irq_install()
idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E); idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E);
idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E); idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E); idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
printf("[kernel] installed irq 0-15\n");
} }
void irq_handler(struct regs *r) void irq_handler(struct regs *r)

View File

@@ -70,6 +70,7 @@ void isr_install()
idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
printf("[kernel] set ISRs 0-31\n");
} }
char *exception_messages[] = char *exception_messages[] =

42
src/kernel/kheap.c Normal file
View File

@@ -0,0 +1,42 @@
#include "kheap.h"
#include "../libc/stdint.h"
extern uint32_t end;
uint32_t placement_address = (uint32_t)&end;
uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys)
{
if (align == 1 && (placement_address & 0x00000FFF))
{
placement_address &= 0xFFFFF000;
placement_address += 0x1000;
}
if (phys)
{
*phys = placement_address;
}
uint32_t tmp = placement_address;
placement_address += sz;
return tmp;
}
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);
}

11
src/kernel/kheap.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef KHEAP_H
#define KHEAP_H
#include "../libc/stdint.h"
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);
#endif

View File

@@ -3,43 +3,112 @@
#include "gdt.h" #include "gdt.h"
#include "idt.h" #include "idt.h"
#include "system.h" #include "system.h"
//#include <stdarg.h> #include "paging.h"
#include "../drivers/ata.h"
#include "../libc/stdint.h"
#include "../drivers/framebuffer.h"
char* ascii_title = typedef struct {
"\n" uint32_t type;
" oooooooooo o888 oooo ooooooo oooooooo8\n" uint32_t size;
" 888 888 888 ooooooo oo oooooo 888 ooooo o888 888o 888 \n" uint64_t framebuffer_addr;
" 888oooo88 888 ooooo888 888 888 888o888 888 888 888oooooo \n" uint32_t framebuffer_pitch;
" 888 888 888 888 888 888 888 8888 88o 888o o888 888\n" uint32_t framebuffer_width;
" o888ooo888 o888o 88ooo88 8o o888o o888o o888o o888o 88ooo88 o88oooo888\n\n" uint32_t framebuffer_height;
" --------------------------------- v0.3.55 --------------------------------\n\n"; uint8_t framebuffer_bpp;
uint8_t framebuffer_type;
uint16_t reserved;
} multiboot2_tag_framebuffer;
typedef struct {
uint32_t total_size;
uint32_t reserved;
uint8_t tags[0];
} multiboot2_info;
unsigned int g_multiboot_info_address; unsigned int g_multiboot_info_address;
void kmain(unsigned int multiboot_info_address) uint32_t* framebuffer;
int scanline;
// in characters, not pixels
uint32_t VGA_WIDTH;
uint32_t VGA_HEIGHT;
void kmain(multiboot2_info *mb_info)
{ {
g_multiboot_info_address = multiboot_info_address;
multiboot2_tag_framebuffer *fb_info = NULL;
uint8_t *tags = mb_info->tags;
while (1) {
uint32_t tag_type = *((uint32_t*) tags);
uint32_t tag_size = *((uint32_t*) (tags + 4));
if (tag_type == 0) break;
if (tag_type == 8) {
fb_info = (multiboot2_tag_framebuffer*) tags;
}
tags += ((tag_size + 7) & ~7);
}
serial_printf(3, "Framebuffer Address: 0x%x\r", fb_info->framebuffer_addr);
serial_printf(3, "Framebuffer Width: %u\r\n", fb_info->framebuffer_width);
serial_printf(3, "Framebuffer Height: %u\r\n", fb_info->framebuffer_height);
serial_printf(3, "Framebuffer Pitch: %u\r\n", fb_info->framebuffer_pitch);
serial_printf(3, "Framebuffer BPP: %u\r\n", fb_info->framebuffer_bpp);
if (fb_info) {
framebuffer = (uint32_t *)(uintptr_t) fb_info->framebuffer_addr;
uint32_t width = fb_info->framebuffer_width;
uint32_t height = fb_info->framebuffer_height;
//uint32_t pitch = fb_info->framebuffer_pitch;
uint32_t bpp = fb_info->framebuffer_bpp;
//8x16 font, not padded
VGA_WIDTH = width/8;
VGA_HEIGHT = height/16;
scanline = width * (bpp/8);
/* TEST print charset
int y_offset = 2;
for (int i=0; i<512; i++)
{
if (i%(width/9)==0) y_offset++;
draw_char(0+i, 0+i, y_offset, white, black);
}
*/
}
printf("[kernel] multiboot2 info at 0x%x, size=%u\n", mb_info, mb_info->total_size);
printf("[kernel] framebuffer discovered at 0x%x\n", fb_info->framebuffer_addr);
printf("[kernel] fb0: width=%u, height=%u, pitch=%u, bpp=%u\n", fb_info->framebuffer_width, fb_info->framebuffer_height, fb_info->framebuffer_pitch, fb_info->framebuffer_bpp);
init_serial(); init_serial();
log("serial connection established\n", 3);
gdt_install(); gdt_install();
log("initialized GDT entries\n", 2);
idt_install(); idt_install();
log("initialized IDT\n", 2);
isr_install(); isr_install();
log("initialized ISRs\n", 2);
irq_install(); irq_install();
__asm__ __volatile__("sti"); __asm__ __volatile__("sti");
log("initialized IRQs\n", 2),
clear(); //init_paging();
colorputs(ascii_title, 10);
colorputs(" by @xamidev - star the repo for a cookie!\n\n", 14); //test_read_sector();
//uint32_t *ptr = (uint32_t*)0xA0000000;
//uint32_t do_page_fault = *ptr;
timer_install(); timer_install();
serial_printf(2, "%d\tinitialized timer handler", global_ticks);
keyboard_install(); keyboard_install();
serial_printf(2, "%d\tinitialized keyboard handler", global_ticks); printf("[kernel] spawning shell...\n");
shell_install(); shell_install();
serial_printf(2, "%d\tstarted system shell", global_ticks);
} }

View File

@@ -1,19 +1,45 @@
global loader global loader
section .__mbHeader section .multiboot_header
align 0x4 align 8
section .text:
MAGIC_NUMBER equ 0x1BADB002 ; multiboot magic ; ASM macros
FLAGS equ 0x0
CHECKSUM equ -MAGIC_NUMBER
KERNEL_STACK_SIZE equ 4096
dd MAGIC_NUMBER MAGIC_NUMBER equ 0xe85250d6 ; multiboot2 magic
FLAGS equ 0x0 ; 32-bit protected mode for i386
HEADER_LEN equ 44 ; Tags=2+2+4+4+4+4+2+2+4=28
CHECKSUM equ -(MAGIC_NUMBER + FLAGS + HEADER_LEN)
; Multiboot 2 header, according to specification (16bytes)
dd MAGIC_NUMBER ; dd = 4 bytes = 32bits = u32
dd FLAGS dd FLAGS
dd HEADER_LEN
dd CHECKSUM dd CHECKSUM
; Tags? (28bytes)
; Tag 1 : set graphics mode (only recommended, can be overriden by GRUB)
dw 5 ; 2
dw 0 ; 2
dd 20 ; 4
dd 1920 ; 4
dd 1080 ; 4
dd 32 ; 4
; End of tags
dw 0 ; 2
;dw 0 ; 2
dd 8 ; 4
; End of Multiboot 2 header
section .text:
KERNEL_STACK_SIZE equ 4096
extern kmain extern kmain
loader: loader:
@@ -49,225 +75,55 @@ idt_load:
lidt [idtp] lidt [idtp]
ret ret
global isr0 %macro ISR_NOERRCODE 1
global isr1 global isr%1
global isr2 isr%1:
global isr3
global isr4
global isr5
global isr6
global isr7
global isr8
global isr9
global isr10
global isr11
global isr12
global isr13
global isr14
global isr15
global isr16
global isr17
global isr18
global isr19
global isr20
global isr21
global isr22
global isr23
global isr24
global isr25
global isr26
global isr27
global isr28
global isr29
global isr30
global isr31
; Interrupt service routine exceptions
isr0:
cli cli
push byte 0 push byte 0
push byte 0 push byte %1
jmp isr_common_stub jmp isr_common_stub
%endmacro
isr1: %macro ISR_ERRCODE 1
global isr%1
isr%1:
cli cli
push byte 0 push byte %1
push byte 1
jmp isr_common_stub jmp isr_common_stub
%endmacro
isr2: ISR_NOERRCODE 0
cli ISR_NOERRCODE 1
push byte 0 ISR_NOERRCODE 2
push byte 2 ISR_NOERRCODE 3
jmp isr_common_stub ISR_NOERRCODE 4
ISR_NOERRCODE 5
isr3: ISR_NOERRCODE 6
cli ISR_NOERRCODE 7
push byte 0 ISR_ERRCODE 8
push byte 3 ISR_NOERRCODE 9
jmp isr_common_stub ISR_ERRCODE 10
ISR_ERRCODE 11
isr4: ISR_ERRCODE 12
cli ISR_ERRCODE 13
push byte 0 ISR_ERRCODE 14
push byte 4 ISR_NOERRCODE 15
jmp isr_common_stub ISR_NOERRCODE 16
ISR_NOERRCODE 17
isr5: ISR_NOERRCODE 18
cli ISR_NOERRCODE 19
push byte 0 ISR_NOERRCODE 20
push byte 5 ISR_NOERRCODE 21
jmp isr_common_stub ISR_NOERRCODE 22
ISR_NOERRCODE 23
isr6: ISR_NOERRCODE 24
cli ISR_NOERRCODE 25
push byte 0 ISR_NOERRCODE 26
push byte 6 ISR_NOERRCODE 27
jmp isr_common_stub ISR_NOERRCODE 28
ISR_NOERRCODE 29
isr7: ISR_NOERRCODE 30
cli ISR_NOERRCODE 31
push byte 0
push byte 7
jmp isr_common_stub
isr8:
cli
push byte 8
jmp isr_common_stub
isr9:
cli
push byte 0
push byte 9
jmp isr_common_stub
isr10:
cli
push byte 10
jmp isr_common_stub
isr11:
cli
push byte 11
jmp isr_common_stub
isr12:
cli
push byte 12
jmp isr_common_stub
isr13:
cli
push byte 13
jmp isr_common_stub
isr14:
cli
push byte 14
jmp isr_common_stub
isr15:
cli
push byte 0
push byte 15
jmp isr_common_stub
isr16:
cli
push byte 0
push byte 16
jmp isr_common_stub
isr17:
cli
push byte 0
push byte 17
jmp isr_common_stub
isr18:
cli
push byte 0
push byte 18
jmp isr_common_stub
isr19:
cli
push byte 0
push byte 19
jmp isr_common_stub
isr20:
cli
push byte 0
push byte 20
jmp isr_common_stub
isr21:
cli
push byte 0
push byte 21
jmp isr_common_stub
isr22:
cli
push byte 0
push byte 22
jmp isr_common_stub
isr23:
cli
push byte 0
push byte 23
jmp isr_common_stub
isr24:
cli
push byte 0
push byte 24
jmp isr_common_stub
isr25:
cli
push byte 0
push byte 25
jmp isr_common_stub
isr26:
cli
push byte 0
push byte 26
jmp isr_common_stub
isr27:
cli
push byte 0
push byte 27
jmp isr_common_stub
isr28:
cli
push byte 0
push byte 28
jmp isr_common_stub
isr29:
cli
push byte 0
push byte 29
jmp isr_common_stub
isr30:
cli
push byte 0
push byte 30
jmp isr_common_stub
isr31:
cli
push byte 0
push byte 31
jmp isr_common_stub
extern fault_handler extern fault_handler
@@ -295,118 +151,31 @@ isr_common_stub:
add esp, 8 add esp, 8
iret iret
global irq0 %macro IRQ 2
global irq1 global irq%1
global irq2 irq%1:
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15
irq0:
cli cli
push byte 0 push byte 0
push byte 32 push byte %2
jmp irq_common_stub jmp irq_common_stub
%endmacro
irq1: IRQ 0, 32
cli IRQ 1, 33
push byte 0 IRQ 2, 34
push byte 33 IRQ 3, 35
jmp irq_common_stub IRQ 4, 36
IRQ 5, 37
irq2: IRQ 6, 38
cli IRQ 7, 39
push byte 0 IRQ 8, 40
push byte 34 IRQ 9, 41
jmp irq_common_stub IRQ 10, 42
IRQ 11, 43
irq3: IRQ 12, 44
cli IRQ 13, 45
push byte 0 IRQ 14, 46
push byte 35 IRQ 15, 47
jmp irq_common_stub
irq4:
cli
push byte 0
push byte 36
jmp irq_common_stub
irq5:
cli
push byte 0
push byte 37
jmp irq_common_stub
irq6:
cli
push byte 0
push byte 38
jmp irq_common_stub
irq7:
cli
push byte 0
push byte 39
jmp irq_common_stub
irq8:
cli
push byte 0
push byte 40
jmp irq_common_stub
irq9:
cli
push byte 0
push byte 41
jmp irq_common_stub
irq10:
cli
push byte 0
push byte 42
jmp irq_common_stub
irq11:
cli
push byte 0
push byte 43
jmp irq_common_stub
irq12:
cli
push byte 0
push byte 44
jmp irq_common_stub
irq13:
cli
push byte 0
push byte 45
jmp irq_common_stub
irq14:
cli
push byte 0
push byte 46
jmp irq_common_stub
irq15:
cli
push byte 0
push byte 47
jmp irq_common_stub
extern irq_handler extern irq_handler

150
src/kernel/paging.c Normal file
View File

@@ -0,0 +1,150 @@
#include "../libc/stdint.h"
#include "paging.h"
#include "../libc/stdio.h"
#include "system.h"
#include "kheap.h"
uint32_t *frames;
uint32_t nframes;
extern uint32_t placement_address;
#define INDEX_FROM_BIT(a) (a/(8*4))
#define OFFSET_FROM_BIT(a) (a%(8*4))
static void set_frame(uint32_t frame_addr)
{
uint32_t frame = frame_addr/0x1000;
uint32_t idx = INDEX_FROM_BIT(frame);
uint32_t off = OFFSET_FROM_BIT(frame);
frames[idx] |= (0x1 << off);
}
static void clear_frame(uint32_t frame_addr)
{
uint32_t frame = frame_addr/0x1000;
uint32_t idx = INDEX_FROM_BIT(frame);
uint32_t off = OFFSET_FROM_BIT(frame);
frames[idx] &= ~(0x1 << off);
}
/*
static uint32_t test_frame(uint32_t frame_addr)
{
uint32_t frame = frame_addr/0x1000;
uint32_t idx = INDEX_FROM_BIT(frame);
uint32_t off = OFFSET_FROM_BIT(frame);
return (frames[idx] & (0x1 << off));
}
*/
static uint32_t first_frame()
{
uint32_t i, j;
for (i=0; i<INDEX_FROM_BIT(nframes); i++)
{
if (frames[i] != 0xFFFFFFFF)
{
for (j=0; j<32; j++)
{
uint32_t toTest = 0x1 << j;
if (!(frames[i]&toTest))
{
return i*4*8+j;
}
}
}
}
return 0;
}
void alloc_frame(page_t *page, int is_kernel, int is_writeable)
{
if (page->frame != 0)
{
return;
} else {
uint32_t idx = first_frame();
if (idx == (uint32_t)-1)
{
panic();
}
set_frame(idx*0x1000);
page->present = 1;
page->rw = (is_writeable)?1:0;
page->user = (is_kernel)?0:1;
page->frame = idx;
}
}
void free_frame(page_t *page)
{
uint32_t frame;
if (!(frame=page->frame))
{
return;
} else {
clear_frame(frame);
page->frame = 0x0;
}
}
void init_paging()
{
uint32_t mem_end_page = 0x10000000;
nframes = mem_end_page / 0x1000;
frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes));
memset(frames, 0, INDEX_FROM_BIT(nframes));
page_directory_t* kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
memset(kernel_directory, 0, sizeof(page_directory_t));
//page_directory_t* current_directory = kernel_directory;
unsigned int i = 0;
while (i < placement_address)
{
alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
i += 0x1000;
}
irq_install_handler(14, page_fault);
switch_page_directory(kernel_directory);
}
void switch_page_directory(page_directory_t *dir)
{
//page_directory_t* current_directory = dir;
asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhysical));
uint32_t cr0;
asm volatile("mov %%cr0, %0": "=r"(cr0));
cr0 |= 0x80000000;
asm volatile("mov %0, %%cr0":: "r"(cr0));
}
page_t *get_page(uint32_t address, int make, page_directory_t *dir)
{
address /= 0x1000;
uint32_t table_idx = address / 1024;
if (dir->tables[table_idx])
{
return &dir->tables[table_idx]->pages[address%1024];
} else if (make)
{
uint32_t tmp;
dir->tables[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
memset(dir->tables[table_idx], 0, 0x1000);
dir->tablesPhysical[table_idx] = tmp | 0x7;
return &dir->tables[table_idx]->pages[address%1024];
} else {
return 0;
}
return 0;
}
void page_fault()
{
puts("Page fault");
panic();
}

34
src/kernel/paging.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef PAGING_H
#define PAGING_H
#include "system.h"
#include "../libc/stdint.h"
typedef struct
{
uint32_t present : 1;
uint32_t rw : 1;
uint32_t user : 1;
uint32_t accessed : 1;
uint32_t dirty : 1;
uint32_t unused : 7;
uint32_t frame : 20;
} page_t;
typedef struct
{
page_t pages[1024];
} page_table_t;
typedef struct
{
page_table_t *tables[1024];
uint32_t tablesPhysical[1024];
uint32_t physicalAsddr;
} page_directory_t;
void init_paging();
void switch_page_directory(page_directory_t *new);
page_t *get_page(uint32_t address, int make, page_directory_t *dir);
void page_fault();
#endif

View File

@@ -8,6 +8,16 @@
#define MAX_COMMANDS 16 #define MAX_COMMANDS 16
#define MAX_ARGS 64 #define MAX_ARGS 64
char* ascii_title =
"\n"
"----------------------------------------------\n"
"Blank OS version 0.3.71-dev\n"
"Author: @xamidev - star the repo for a cookie!\n"
"----------------------------------------------\n"
"\n";
typedef void (*command_func_t)(int argc, char *argv[]); typedef void (*command_func_t)(int argc, char *argv[]);
typedef struct typedef struct
@@ -54,6 +64,8 @@ int parse_input(char* input, char* argv[], int max_args)
void shell_install() void shell_install()
{ {
colorputs(ascii_title, yellow, black);
register_command("help", program_help); register_command("help", program_help);
register_command("panic", program_panic); register_command("panic", program_panic);
register_command("words", program_words); register_command("words", program_words);
@@ -73,7 +85,13 @@ void shell_install()
{ {
char input_buffer[BUFFER_SIZE]; char input_buffer[BUFFER_SIZE];
char* argv[MAX_ARGS]; char* argv[MAX_ARGS];
colorputs("blankos> ", 9);
// Prompt
colorputs("root", blue, black);
colorputs("@", white, black);
colorputs("blankos", green, black);
colorputs("~$ ", white, black);
get_input(input_buffer, BUFFER_SIZE); get_input(input_buffer, BUFFER_SIZE);
puts("\n"); puts("\n");

View File

@@ -1,4 +1,5 @@
#include "system.h" #include "system.h"
#include "../libc/stdint.h"
void *memset(void *dest, char val, size_t count) void *memset(void *dest, char val, size_t count)
{ {
@@ -6,3 +7,29 @@ void *memset(void *dest, char val, size_t count)
for(; count != 0; count--) *temp++ = val; for(; count != 0; count--) *temp++ = val;
return dest; return dest;
} }
void *memmove(void* dest, const void* src, size_t n)
{
unsigned char* d = (unsigned char*)dest;
const unsigned char* s = (const unsigned char*)src;
if (d < s)
{
for (size_t i=0; i<n; i++)
{
d[i] = s[i];
}
} else {
for (size_t i=n; i>0; i--)
{
d[i-1] = s[i-1];
}
}
return dest;
}
void panic()
{
for (;;);
}

View File

@@ -1,9 +1,12 @@
#ifndef SYSTEM_H #ifndef SYSTEM_H
#define SYSTEM_H #define SYSTEM_H
#include "../libc/stdint.h"
typedef int size_t; typedef int size_t;
void *memset(void *dest, char val, size_t count); void *memset(void *dest, char val, size_t count);
void *memmove(void* dest, const void* src, size_t n);
struct regs struct regs
{ {
@@ -13,6 +16,7 @@ struct regs
unsigned int eip, cs, eflags, useresp, ss; unsigned int eip, cs, eflags, useresp, ss;
}; };
void panic();
void isr_install(); void isr_install();
void irq_install(); void irq_install();
void irq_install_handler(int irq, void (*handler)(struct regs *r)); void irq_install_handler(int irq, void (*handler)(struct regs *r));

View File

@@ -19,4 +19,6 @@ typedef uint8_t bool;
#define NULL ((void*)0) #define NULL ((void*)0)
typedef unsigned int uintptr_t;
#endif #endif

View File

@@ -3,31 +3,46 @@
#include "string.h" #include "string.h"
#include "stdint.h" #include "stdint.h"
#include "../kernel/system.h" #include "../kernel/system.h"
#include "../drivers/framebuffer.h"
#include "../drivers/serial.h"
char* fb = (char *) 0x000B8000; extern uint32_t* framebuffer;
const unsigned VGA_WIDTH = 80; extern uint32_t VGA_WIDTH;
const unsigned VGA_HEIGHT = 25; extern uint32_t VGA_HEIGHT;
const unsigned int COLOR = 0x7;
unsigned int VGA_X = 0, VGA_Y = 0; unsigned int VGA_X = 0, VGA_Y = 0;
#define CURSOR_WIDTH 8
#define CURSOR_HEIGHT 16
extern int scanline;
void draw_cursor(uint32_t color)
{
for (int y=12; y<CURSOR_HEIGHT; y++)
{
for (int x=0; x<CURSOR_WIDTH; x++)
{
putpixel(framebuffer, scanline, 32, VGA_X * CURSOR_WIDTH + x, VGA_Y * CURSOR_HEIGHT + y, color);
}
}
}
void erase_cursor()
{
draw_cursor(black);
}
void move_cursor(int x, int y) void move_cursor(int x, int y)
{ {
unsigned short pos = y*VGA_WIDTH+x; erase_cursor();
VGA_X = x;
outb(FB_CMD_PORT, FB_HIGH_BYTE_CMD); VGA_Y = y;
outb(FB_DATA_PORT, ((pos >> 8) & 0x00FF)); draw_cursor(white);
outb(FB_CMD_PORT, FB_LOW_BYTE_CMD);
outb(FB_DATA_PORT, pos & 0x00FF);
} }
void putchar(int x, int y, char c) // stdio wrapper for draw_char in graphics mode
void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg)
{ {
fb[2*(y*VGA_WIDTH+x)] = c; draw_char(c, x, y, fg, bg);
}
void putcolor(int x, int y, unsigned int color)
{
fb[2*(y*VGA_WIDTH+x)+1] = color;
} }
void clear(void) void clear(void)
@@ -36,55 +51,15 @@ void clear(void)
{ {
for (unsigned int x=0; x<VGA_WIDTH; x++) for (unsigned int x=0; x<VGA_WIDTH; x++)
{ {
putchar(x, y, '\0'); putchar(' ', x, y, black, black);
putcolor(x, y, COLOR);
} }
} }
VGA_X = 0; move_cursor(0, 0);
VGA_Y = 0;
move_cursor(VGA_X, VGA_Y);
}
char getchar(int x, int y)
{
return fb[2*(y*VGA_WIDTH+x)];
}
unsigned int getcolor(int x, int y)
{
return fb[2*(y*VGA_WIDTH+x)+1];
}
void scroll(int lines)
{
if (lines <= 0 || (unsigned int)lines >= VGA_HEIGHT) return;
for (unsigned int y = 0; y < VGA_HEIGHT-lines; y++)
{
for (unsigned int x = 0; x < VGA_WIDTH; x++)
{
putchar(x, y, getchar(x, y+lines));
putcolor(x, y, getcolor(x, y+lines));
}
}
for (unsigned int y = VGA_HEIGHT-lines; y<VGA_HEIGHT; y++)
{
for (unsigned int x = 0; x < VGA_WIDTH; x++)
{
putchar(x, y, ' ');
putcolor(x, y, COLOR);
}
}
VGA_Y -= lines;
if ((int)VGA_Y < 0) {
VGA_Y = 0;
}
} }
void putc(char c) void putc(char c)
{ {
erase_cursor();
switch(c) switch(c)
{ {
case '\n': case '\n':
@@ -110,10 +85,10 @@ void putc(char c)
VGA_Y--; VGA_Y--;
VGA_X = VGA_WIDTH-1; VGA_X = VGA_WIDTH-1;
} }
putchar(VGA_X, VGA_Y, ' '); putchar(' ', VGA_X, VGA_Y, white, black);
break; break;
default: default:
putchar(VGA_X, VGA_Y, c); putchar(c, VGA_X, VGA_Y, white, black);
VGA_X++; VGA_X++;
break; break;
} }
@@ -123,13 +98,19 @@ void putc(char c)
VGA_Y++; VGA_Y++;
VGA_X = 0; VGA_X = 0;
} }
if (VGA_Y >= VGA_HEIGHT) scroll(1); if (VGA_Y >= VGA_HEIGHT)
{
serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT);
scroll();
VGA_Y = VGA_HEIGHT - 1;
}
move_cursor(VGA_X, VGA_Y); move_cursor(VGA_X, VGA_Y);
} }
void colorputc(char c, unsigned int color) void colorputc(char c, uint32_t fg, uint32_t bg)
{ {
erase_cursor();
switch(c) switch(c)
{ {
case '\n': case '\n':
@@ -143,8 +124,7 @@ void colorputc(char c, unsigned int color)
VGA_X += 4; VGA_X += 4;
break; break;
default: default:
putchar(VGA_X, VGA_Y, c); putchar(c, VGA_X, VGA_Y, fg, bg);
putcolor(VGA_X, VGA_Y, color);
VGA_X++; VGA_X++;
break; break;
} }
@@ -154,7 +134,14 @@ void colorputc(char c, unsigned int color)
VGA_Y++; VGA_Y++;
VGA_X = 0; VGA_X = 0;
} }
if (VGA_Y >= VGA_HEIGHT) scroll(1);
if (VGA_Y >= VGA_HEIGHT)
{
serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT);
scroll();
VGA_Y = VGA_HEIGHT - 1;
}
move_cursor(VGA_X, VGA_Y); move_cursor(VGA_X, VGA_Y);
} }
@@ -167,11 +154,11 @@ void puts(const char* str)
} }
} }
void colorputs(const char* str, unsigned int color) void colorputs(const char* str, uint32_t fg, uint32_t bg)
{ {
while (*str) while (*str)
{ {
colorputc(*str, color); colorputc(*str, fg, bg);
str++; str++;
} }
} }
@@ -221,27 +208,44 @@ void dtostrf(double val, char *buffer, int precision)
void printf(const char* fmt, ...) void printf(const char* fmt, ...)
{ {
int* argp = (int*) &fmt; int* argp = (int*)&fmt;
int state = PRINTF_STATE_START; int state = PRINTF_STATE_START;
int length = PRINTF_LENGTH_START; int length = PRINTF_LENGTH_START;
int radix = 10; int radix = 10;
bool sign = false; bool sign = false;
int width = 0;
char pad_char = ' ';
argp++; argp++;
while (*fmt) while (*fmt)
{ {
switch(state) { switch (state)
{
case PRINTF_STATE_START: case PRINTF_STATE_START:
if (*fmt == '%') if (*fmt == '%')
{ {
state = PRINTF_STATE_LENGTH; state = PRINTF_STATE_LENGTH;
width = 0;
pad_char = ' ';
} }
else { else
{
putc(*fmt); putc(*fmt);
} }
break; break;
case PRINTF_STATE_LENGTH: case PRINTF_STATE_LENGTH:
if (*fmt == 'h') if (*fmt == '0')
{
pad_char = '0';
state = PRINTF_STATE_WIDTH;
}
else if (*fmt >= '1' && *fmt <= '9')
{
width = *fmt - '0';
state = PRINTF_STATE_WIDTH;
}
else if (*fmt == 'h')
{ {
length = PRINTF_LENGTH_SHORT; length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_SHORT; state = PRINTF_STATE_SHORT;
@@ -251,40 +255,57 @@ void printf(const char* fmt, ...)
length = PRINTF_LENGTH_LONG; length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LONG; state = PRINTF_STATE_LONG;
} }
else { else
{
goto PRINTF_STATE_SPEC_; goto PRINTF_STATE_SPEC_;
} }
break; break;
case PRINTF_STATE_WIDTH:
if (*fmt >= '0' && *fmt <= '9')
{
width = width * 10 + (*fmt - '0');
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_SHORT: case PRINTF_STATE_SHORT:
if (*fmt == 'h') if (*fmt == 'h')
{ {
length = PRINTF_LENGTH_SHORT_SHORT; length = PRINTF_LENGTH_SHORT_SHORT;
state = PRINTF_STATE_SPEC; state = PRINTF_STATE_SPEC;
} }
else { else
{
goto PRINTF_STATE_SPEC_; goto PRINTF_STATE_SPEC_;
} }
break; break;
case PRINTF_STATE_LONG: case PRINTF_STATE_LONG:
if (*fmt == 'l') if (*fmt == 'l')
{ {
length = PRINTF_LENGTH_LONG_LONG; length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC; state = PRINTF_STATE_SPEC;
} }
else { else
{
goto PRINTF_STATE_SPEC_; goto PRINTF_STATE_SPEC_;
} }
break; break;
case PRINTF_STATE_SPEC: case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_: PRINTF_STATE_SPEC_:
switch(*fmt) switch (*fmt)
{ {
case 'c': case 'c':
putc((char)*argp); putc((char)*argp);
argp++; argp++;
break; break;
case 's': case 's':
puts(*(const char **)argp); puts(*(const char**)argp);
argp++; argp++;
break; break;
case '%': case '%':
@@ -294,33 +315,32 @@ void printf(const char* fmt, ...)
case 'i': case 'i':
radix = 10; radix = 10;
sign = true; sign = true;
argp = printf_number(argp, length, sign, radix); argp = printf_number(argp, length, sign, radix, width, pad_char);
break; break;
case 'u': case 'u':
radix = 10; radix = 10;
sign = false; sign = false;
argp = printf_number(argp, length, sign, radix); argp = printf_number(argp, length, sign, radix, width, pad_char);
break; break;
case 'X': case 'X':
case 'x': case 'x':
case 'p': case 'p':
radix = 16; radix = 16;
sign = false; sign = false;
argp = printf_number(argp, length, sign, radix); argp = printf_number(argp, length, sign, radix, width, pad_char);
break; break;
case 'o': case 'o':
radix = 8; radix = 8;
sign = false; sign = false;
argp = printf_number(argp, length, sign, radix); argp = printf_number(argp, length, sign, radix, width, pad_char);
break; break;
case 'f': { case 'f': {
// Handle floating-point numbers
double* dargp = (double*)argp; double* dargp = (double*)argp;
double d = *(double*)dargp; double d = *(double*)dargp;
char buffer[64]; char buffer[64];
dtostrf(d, buffer, 6); // Default precision: 6 dtostrf(d, buffer, 6);
puts(buffer); puts(buffer);
argp += 2; // Incrementing by 2 to move past the double argument argp += 2;
break; break;
} }
default: default:
@@ -330,6 +350,8 @@ void printf(const char* fmt, ...)
length = PRINTF_LENGTH_START; length = PRINTF_LENGTH_START;
radix = 10; radix = 10;
sign = false; sign = false;
width = 0;
pad_char = ' ';
break; break;
} }
fmt++; fmt++;
@@ -338,14 +360,14 @@ void printf(const char* fmt, ...)
const char charset[] = "0123456789abcdef"; const char charset[] = "0123456789abcdef";
int* printf_number(int* argp, int length, bool sign, int radix) int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char)
{ {
char buffer[32]; char buffer[32];
unsigned long long number; unsigned long long number;
int number_sign = 1; int number_sign = 1;
int pos = 0; int pos = 0;
switch(length) switch (length)
{ {
case PRINTF_LENGTH_SHORT_SHORT: case PRINTF_LENGTH_SHORT_SHORT:
case PRINTF_LENGTH_SHORT: case PRINTF_LENGTH_SHORT:
@@ -358,10 +380,11 @@ int* printf_number(int* argp, int length, bool sign, int radix)
n = -n; n = -n;
number_sign = -1; number_sign = -1;
} }
number = (unsigned long long) n; number = (unsigned long long)n;
} }
else { else
number = *(unsigned int*) argp; {
number = *(unsigned int*)argp;
} }
argp++; argp++;
break; break;
@@ -374,10 +397,11 @@ int* printf_number(int* argp, int length, bool sign, int radix)
n = -n; n = -n;
number_sign = -1; number_sign = -1;
} }
number = (unsigned long long) n; number = (unsigned long long)n;
} }
else { else
number = *(unsigned long int*) argp; {
number = *(unsigned long int*)argp;
} }
argp += 2; argp += 2;
break; break;
@@ -390,16 +414,18 @@ int* printf_number(int* argp, int length, bool sign, int radix)
n = -n; n = -n;
number_sign = -1; number_sign = -1;
} }
number = (unsigned long long) n; number = (unsigned long long)n;
} }
else { else
number = *(unsigned long long int*) argp; {
number = *(unsigned long long int*)argp;
} }
argp += 4; argp += 4;
break; break;
} }
do { do
{
uint32_t rem; uint32_t rem;
x86_div64_32(number, radix, &number, &rem); x86_div64_32(number, radix, &number, &rem);
buffer[pos++] = charset[rem]; buffer[pos++] = charset[rem];
@@ -410,6 +436,13 @@ int* printf_number(int* argp, int length, bool sign, int radix)
buffer[pos++] = '-'; buffer[pos++] = '-';
} }
int padding = width - pos;
while (padding-- > 0)
{
putc(pad_char);
}
while (--pos >= 0) while (--pos >= 0)
{ {
putc(buffer[pos]); putc(buffer[pos]);

View File

@@ -11,23 +11,27 @@
#define FB_HIGH_BYTE_CMD 14 #define FB_HIGH_BYTE_CMD 14
#define FB_LOW_BYTE_CMD 15 #define FB_LOW_BYTE_CMD 15
void draw_cursor(uint32_t color);
void erase_cursor();
void move_cursor(int x, int y); void move_cursor(int x, int y);
void putchar(int x, int y, char c); void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg);
void puts(const char* str); void puts(const char* str);
void colorputs(const char* str, unsigned int color);
void clear(void); void clear(void);
void colorputs(const char* str, uint32_t fg, uint32_t bg);
void putcolor(int x, int y, unsigned int color); void putcolor(int x, int y, unsigned int color);
char getchar(int x, int y); char getchar(int x, int y);
unsigned int getcolor(int x, int y); unsigned int getcolor(int x, int y);
void scroll(int lines);
void putc(char c); void putc(char c);
void colorputc(char c, unsigned int color); void colorputc(char c, uint32_t fg, uint32_t bg);
#define PRINTF_STATE_START 0 #define PRINTF_STATE_START 0
#define PRINTF_STATE_LENGTH 1 #define PRINTF_STATE_LENGTH 1
#define PRINTF_STATE_SHORT 2 #define PRINTF_STATE_SHORT 2
#define PRINTF_STATE_LONG 3 #define PRINTF_STATE_LONG 3
#define PRINTF_STATE_SPEC 4 #define PRINTF_STATE_SPEC 4
#define PRINTF_STATE_WIDTH 5
#define PRINTF_LENGTH_START 0 #define PRINTF_LENGTH_START 0
#define PRINTF_LENGTH_SHORT_SHORT 1 #define PRINTF_LENGTH_SHORT_SHORT 1
@@ -36,10 +40,21 @@ void colorputc(char c, unsigned int color);
#define PRINTF_LENGTH_LONG_LONG 4 #define PRINTF_LENGTH_LONG_LONG 4
void printf(const char* fmt, ...); void printf(const char* fmt, ...);
int* printf_number(int* argp, int length, bool sign, int radix); int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char);
int getch(); int getch();
void get_input(char *buffer, int size); void get_input(char *buffer, int size);
void dtostrf(double val, char *buffer, int precision); void dtostrf(double val, char *buffer, int precision);
enum Colors
{
// AARRGGBB?
white = 0xFFFFFFFF,
black = 0x00000000,
red = 0x00FF0000,
green = 0x0000FF00,
blue = 0x000000FF,
yellow = 0x00FFFF00,
};
#endif #endif

View File

@@ -15,7 +15,7 @@ void print_grid(const unsigned char grid[X][Y])
//(grid[i][j] == LIVE) ? putc(42) : putc(32); //(grid[i][j] == LIVE) ? putc(42) : putc(32);
if (grid[i][j] == LIVE) { if (grid[i][j] == LIVE) {
serial_printf(3, "alive"); serial_printf(3, "alive");
colorputc(32, 120); //colorputc(32, 120);
} else { } else {
putc(32); putc(32);
} }

View File

@@ -3,6 +3,7 @@
#include "../libc/stdio.h" #include "../libc/stdio.h"
#include "../kernel/system.h" #include "../kernel/system.h"
#include "../libc/string.h" #include "../libc/string.h"
#include "../drivers/framebuffer.h"
// Print a rainbow colorful text for testing // Print a rainbow colorful text for testing
@@ -18,7 +19,7 @@ void program_rainbow()
for (int i=0; i<COLORS; i++) for (int i=0; i<COLORS; i++)
{ {
colorputs(input_buffer, i); //colorputs(input_buffer, i);
puts("\n"); puts("\n");
} }
} }
@@ -29,7 +30,7 @@ void program_rainbow()
void program_clear() void program_clear()
{ {
for (int i=0; i<ROWS; i++) scroll(1); for (int i=0; i<ROWS; i++) scroll();
} }
// Get uptime in ticks // Get uptime in ticks