Graphics mode & linear framebuffer update #1
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
*.o
|
||||
build/
|
||||
kernel.elf
|
||||
blankos-fat.img
|
||||
blankos.iso
|
||||
iso/
|
||||
i386-elf-7.5.0-Linux-x86_64/
|
||||
i386-elf-7.5.0-Linux-x86_64.tar.xz
|
||||
|
||||
14
README.md
14
README.md
@@ -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:
|
||||
|
||||
```
|
||||
qemu-system-i386 blankOS-i386-0.3.45.img
|
||||
qemu-system-i386 blankOS-i386-0.3.55.iso
|
||||
```
|
||||
|
||||
## 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:
|
||||
```
|
||||
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`).
|
||||
@@ -56,7 +56,7 @@ Tada! You now have a working BlankOS USB stick. Go ahead and try it out!
|
||||
## 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:
|
||||
@@ -68,7 +68,7 @@ gdb kernel.elf
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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)
|
||||
- [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/index.php)
|
||||
- Ralf Brown's Interrupt List
|
||||
- the [little book about OS development](https://littleosbook.github.io/) by Erik Helin and Adam Renberg
|
||||
|
||||
### ⚠️ 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 drivers (framebuffer, keyboard, serial, timer)
|
||||
- [X] Kernel-space utilities (shell, simple programs)
|
||||
- [ ] FAT32 filesystem
|
||||
- [ ] Paging/Page Frame Allocation
|
||||
- [ ] Filesystem (FAT32 or VFS ramdisk)
|
||||
- [ ] Changing the default VGA font
|
||||
- [X] Paging/Page Frame Allocation
|
||||
- [ ] TCP/IP Network stack
|
||||
- [ ] Getting to Ring-3 (userspace)
|
||||
- [ ] Multitasking (via round robin scheduling)
|
||||
|
||||
3
grub.cfg
3
grub.cfg
@@ -1,4 +1,5 @@
|
||||
menuentry "Blank OS" {
|
||||
multiboot /boot/kernel.elf
|
||||
set gfxpayload=1024x768x32
|
||||
multiboot2 /boot/kernel.elf
|
||||
boot
|
||||
}
|
||||
|
||||
BIN
include/fonts/UniCyr_8x16.psf
Normal file
BIN
include/fonts/UniCyr_8x16.psf
Normal file
Binary file not shown.
17
link.ld
17
link.ld
@@ -1,30 +1,31 @@
|
||||
ENTRY(loader)
|
||||
|
||||
SECTIONS {
|
||||
/* Address to load at; 1MB */
|
||||
/* Address to load at; 2MB */
|
||||
|
||||
. = 0x00100000;
|
||||
/*. = 2M;*/
|
||||
|
||||
.__mbHeader : {
|
||||
*(.__mbHeader)
|
||||
.multiboot_header ALIGN(4K) : {
|
||||
*(.multiboot_header)
|
||||
}
|
||||
|
||||
/* Align relevant sections at 4KB */
|
||||
|
||||
.text ALIGN (0x1000) :
|
||||
.text ALIGN (4K) :
|
||||
{
|
||||
*(.text)
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.data ALIGN (0x1000) :
|
||||
.data ALIGN (4K) :
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss ALIGN (0x1000) :
|
||||
.bss ALIGN (4K) :
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
end = .; _end = .; __end = .;
|
||||
}
|
||||
|
||||
33
makefile
33
makefile
@@ -9,6 +9,8 @@ KERNEL_DIR = $(SRC_DIR)/kernel
|
||||
LIBC_DIR = $(SRC_DIR)/libc
|
||||
PROGRAMS_DIR = $(SRC_DIR)/programs
|
||||
DRIVERS_DIR = $(SRC_DIR)/drivers
|
||||
INCLUDE_DIR = include
|
||||
FONTS_DIR = $(INCLUDE_DIR)/fonts
|
||||
OBJ_DIR = build
|
||||
|
||||
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_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
|
||||
|
||||
$(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)
|
||||
ld $(LDFLAGS) $(OBJECTS) -o kernel.elf
|
||||
kernel.elf: $(OBJECTS) $(FONT_OBJ)
|
||||
ld $(LDFLAGS) $(OBJECTS) $(FONT_OBJ) -o kernel.elf
|
||||
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
@@ -34,18 +39,28 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
|
||||
$(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:
|
||||
wget $(TOOLCHAIN_SRC)
|
||||
tar xf $(TOOLCHAIN_FILE)
|
||||
|
||||
blankos-fat.img:
|
||||
sudo ./setup.sh
|
||||
iso: kernel.elf
|
||||
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
|
||||
qemu-system-i386 -drive file=blankos-fat.img,format=raw
|
||||
run: iso
|
||||
qemu-system-i386 -drive file=blankos.iso,format=raw
|
||||
|
||||
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:
|
||||
rm -rf $(OBJ_DIR) kernel.elf blankos-fat.img $(TOOLCHAIN_FILE)
|
||||
rm -rf $(OBJ_DIR) kernel.elf blankos.iso $(TOOLCHAIN_FILE)
|
||||
|
||||
|
||||
75
setup.sh
75
setup.sh
@@ -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
77
src/drivers/ata.c
Normal 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
7
src/drivers/ata.h
Normal 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
94
src/drivers/framebuffer.c
Normal 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
31
src/drivers/framebuffer.h
Normal 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
|
||||
@@ -130,6 +130,7 @@ void keyboard_handler()
|
||||
void keyboard_install()
|
||||
{
|
||||
irq_install_handler(1, keyboard_handler);
|
||||
printf("[keyboard] installed irq handler\n");
|
||||
}
|
||||
|
||||
char keyboard_getchar()
|
||||
|
||||
@@ -20,6 +20,7 @@ int init_serial()
|
||||
}
|
||||
|
||||
outb(PORT+4, 0x0F);
|
||||
puts("[serial] initialized i/o on port COM1\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,18 @@ volatile unsigned long global_ticks = 0;
|
||||
void timer_handler()
|
||||
{
|
||||
global_ticks++;
|
||||
if (global_ticks % 20 == 0)
|
||||
{
|
||||
draw_cursor(white);
|
||||
} else if (global_ticks % 20 == 10) {
|
||||
erase_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
void timer_install()
|
||||
{
|
||||
irq_install_handler(0, timer_handler);
|
||||
printf("[timer] initialized, starting g_ticks...\n");
|
||||
}
|
||||
|
||||
void delay(int ticks)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "gdt.h"
|
||||
#include "../libc/stdio.h"
|
||||
|
||||
struct gdt_entry
|
||||
{
|
||||
@@ -41,8 +42,14 @@ void gdt_install()
|
||||
|
||||
gdt_set_gate(0, 0, 0, 0, 0);
|
||||
|
||||
// Ring 0 code + data
|
||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 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();
|
||||
printf("[kernel] GDT gates set (ring 0 and 3), gdt=0x%x\n", &gdt);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "idt.h"
|
||||
#include "system.h"
|
||||
#include "../libc/stdio.h"
|
||||
|
||||
struct idt_entry
|
||||
{
|
||||
@@ -39,4 +40,5 @@ void idt_install()
|
||||
memset(&idt, 0, sizeof(struct idt_entry)*256);
|
||||
|
||||
idt_load();
|
||||
printf("[kernel] loaded IDT at idt=0x%x\n", &idt);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "system.h"
|
||||
#include "io.h"
|
||||
#include "idt.h"
|
||||
#include "../libc/stdio.h"
|
||||
|
||||
extern void irq0();
|
||||
extern void irq1();
|
||||
@@ -69,6 +70,7 @@ void irq_install()
|
||||
idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E);
|
||||
idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
|
||||
idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
|
||||
printf("[kernel] installed irq 0-15\n");
|
||||
}
|
||||
|
||||
void irq_handler(struct regs *r)
|
||||
|
||||
@@ -70,6 +70,7 @@ void isr_install()
|
||||
idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
|
||||
idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
|
||||
idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
|
||||
printf("[kernel] set ISRs 0-31\n");
|
||||
}
|
||||
|
||||
char *exception_messages[] =
|
||||
|
||||
42
src/kernel/kheap.c
Normal file
42
src/kernel/kheap.c
Normal 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
11
src/kernel/kheap.h
Normal 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
|
||||
@@ -3,43 +3,112 @@
|
||||
#include "gdt.h"
|
||||
#include "idt.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 =
|
||||
"\n"
|
||||
" oooooooooo o888 oooo ooooooo oooooooo8\n"
|
||||
" 888 888 888 ooooooo oo oooooo 888 ooooo o888 888o 888 \n"
|
||||
" 888oooo88 888 ooooo888 888 888 888o888 888 888 888oooooo \n"
|
||||
" 888 888 888 888 888 888 888 8888 88o 888o o888 888\n"
|
||||
" o888ooo888 o888o 88ooo88 8o o888o o888o o888o o888o 88ooo88 o88oooo888\n\n"
|
||||
" --------------------------------- v0.3.55 --------------------------------\n\n";
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
uint64_t framebuffer_addr;
|
||||
uint32_t framebuffer_pitch;
|
||||
uint32_t framebuffer_width;
|
||||
uint32_t framebuffer_height;
|
||||
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;
|
||||
|
||||
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();
|
||||
log("serial connection established\n", 3);
|
||||
gdt_install();
|
||||
log("initialized GDT entries\n", 2);
|
||||
idt_install();
|
||||
log("initialized IDT\n", 2);
|
||||
isr_install();
|
||||
log("initialized ISRs\n", 2);
|
||||
irq_install();
|
||||
__asm__ __volatile__("sti");
|
||||
log("initialized IRQs\n", 2),
|
||||
|
||||
clear();
|
||||
colorputs(ascii_title, 10);
|
||||
colorputs(" by @xamidev - star the repo for a cookie!\n\n", 14);
|
||||
//init_paging();
|
||||
|
||||
//test_read_sector();
|
||||
|
||||
//uint32_t *ptr = (uint32_t*)0xA0000000;
|
||||
//uint32_t do_page_fault = *ptr;
|
||||
|
||||
timer_install();
|
||||
serial_printf(2, "%d\tinitialized timer handler", global_ticks);
|
||||
keyboard_install();
|
||||
serial_printf(2, "%d\tinitialized keyboard handler", global_ticks);
|
||||
printf("[kernel] spawning shell...\n");
|
||||
shell_install();
|
||||
serial_printf(2, "%d\tstarted system shell", global_ticks);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,45 @@
|
||||
global loader
|
||||
|
||||
section .__mbHeader
|
||||
section .multiboot_header
|
||||
|
||||
align 0x4
|
||||
section .text:
|
||||
align 8
|
||||
|
||||
MAGIC_NUMBER equ 0x1BADB002 ; multiboot magic
|
||||
FLAGS equ 0x0
|
||||
CHECKSUM equ -MAGIC_NUMBER
|
||||
KERNEL_STACK_SIZE equ 4096
|
||||
; ASM macros
|
||||
|
||||
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 HEADER_LEN
|
||||
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
|
||||
|
||||
loader:
|
||||
@@ -49,225 +75,55 @@ idt_load:
|
||||
lidt [idtp]
|
||||
ret
|
||||
|
||||
global isr0
|
||||
global isr1
|
||||
global isr2
|
||||
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:
|
||||
%macro ISR_NOERRCODE 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 0
|
||||
push byte %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
isr1:
|
||||
%macro ISR_ERRCODE 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 1
|
||||
push byte %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
isr2:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 2
|
||||
jmp isr_common_stub
|
||||
|
||||
isr3:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 3
|
||||
jmp isr_common_stub
|
||||
|
||||
isr4:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 4
|
||||
jmp isr_common_stub
|
||||
|
||||
isr5:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 5
|
||||
jmp isr_common_stub
|
||||
|
||||
isr6:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 6
|
||||
jmp isr_common_stub
|
||||
|
||||
isr7:
|
||||
cli
|
||||
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
|
||||
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
|
||||
|
||||
extern fault_handler
|
||||
|
||||
@@ -295,118 +151,31 @@ isr_common_stub:
|
||||
add esp, 8
|
||||
iret
|
||||
|
||||
global irq0
|
||||
global irq1
|
||||
global irq2
|
||||
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:
|
||||
%macro IRQ 2
|
||||
global irq%1
|
||||
irq%1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 32
|
||||
push byte %2
|
||||
jmp irq_common_stub
|
||||
%endmacro
|
||||
|
||||
irq1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 33
|
||||
jmp irq_common_stub
|
||||
|
||||
irq2:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 34
|
||||
jmp irq_common_stub
|
||||
|
||||
irq3:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 35
|
||||
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
|
||||
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
|
||||
|
||||
extern irq_handler
|
||||
|
||||
|
||||
150
src/kernel/paging.c
Normal file
150
src/kernel/paging.c
Normal 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
34
src/kernel/paging.h
Normal 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
|
||||
@@ -8,6 +8,16 @@
|
||||
#define MAX_COMMANDS 16
|
||||
#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 struct
|
||||
@@ -54,6 +64,8 @@ int parse_input(char* input, char* argv[], int max_args)
|
||||
|
||||
void shell_install()
|
||||
{
|
||||
colorputs(ascii_title, yellow, black);
|
||||
|
||||
register_command("help", program_help);
|
||||
register_command("panic", program_panic);
|
||||
register_command("words", program_words);
|
||||
@@ -73,7 +85,13 @@ void shell_install()
|
||||
{
|
||||
char input_buffer[BUFFER_SIZE];
|
||||
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);
|
||||
puts("\n");
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "system.h"
|
||||
#include "../libc/stdint.h"
|
||||
|
||||
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;
|
||||
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 (;;);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
#include "../libc/stdint.h"
|
||||
|
||||
typedef int size_t;
|
||||
|
||||
void *memset(void *dest, char val, size_t count);
|
||||
void *memmove(void* dest, const void* src, size_t n);
|
||||
|
||||
struct regs
|
||||
{
|
||||
@@ -13,6 +16,7 @@ struct regs
|
||||
unsigned int eip, cs, eflags, useresp, ss;
|
||||
};
|
||||
|
||||
void panic();
|
||||
void isr_install();
|
||||
void irq_install();
|
||||
void irq_install_handler(int irq, void (*handler)(struct regs *r));
|
||||
|
||||
@@ -19,4 +19,6 @@ typedef uint8_t bool;
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
typedef unsigned int uintptr_t;
|
||||
|
||||
#endif
|
||||
|
||||
227
src/libc/stdio.c
227
src/libc/stdio.c
@@ -3,31 +3,46 @@
|
||||
#include "string.h"
|
||||
#include "stdint.h"
|
||||
#include "../kernel/system.h"
|
||||
#include "../drivers/framebuffer.h"
|
||||
#include "../drivers/serial.h"
|
||||
|
||||
char* fb = (char *) 0x000B8000;
|
||||
const unsigned VGA_WIDTH = 80;
|
||||
const unsigned VGA_HEIGHT = 25;
|
||||
const unsigned int COLOR = 0x7;
|
||||
extern uint32_t* framebuffer;
|
||||
extern uint32_t VGA_WIDTH;
|
||||
extern uint32_t VGA_HEIGHT;
|
||||
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)
|
||||
{
|
||||
unsigned short pos = y*VGA_WIDTH+x;
|
||||
|
||||
outb(FB_CMD_PORT, FB_HIGH_BYTE_CMD);
|
||||
outb(FB_DATA_PORT, ((pos >> 8) & 0x00FF));
|
||||
outb(FB_CMD_PORT, FB_LOW_BYTE_CMD);
|
||||
outb(FB_DATA_PORT, pos & 0x00FF);
|
||||
erase_cursor();
|
||||
VGA_X = x;
|
||||
VGA_Y = y;
|
||||
draw_cursor(white);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void putcolor(int x, int y, unsigned int color)
|
||||
{
|
||||
fb[2*(y*VGA_WIDTH+x)+1] = color;
|
||||
draw_char(c, x, y, fg, bg);
|
||||
}
|
||||
|
||||
void clear(void)
|
||||
@@ -36,55 +51,15 @@ void clear(void)
|
||||
{
|
||||
for (unsigned int x=0; x<VGA_WIDTH; x++)
|
||||
{
|
||||
putchar(x, y, '\0');
|
||||
putcolor(x, y, COLOR);
|
||||
putchar(' ', x, y, black, black);
|
||||
}
|
||||
}
|
||||
VGA_X = 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;
|
||||
}
|
||||
move_cursor(0, 0);
|
||||
}
|
||||
|
||||
void putc(char c)
|
||||
{
|
||||
erase_cursor();
|
||||
switch(c)
|
||||
{
|
||||
case '\n':
|
||||
@@ -110,10 +85,10 @@ void putc(char c)
|
||||
VGA_Y--;
|
||||
VGA_X = VGA_WIDTH-1;
|
||||
}
|
||||
putchar(VGA_X, VGA_Y, ' ');
|
||||
putchar(' ', VGA_X, VGA_Y, white, black);
|
||||
break;
|
||||
default:
|
||||
putchar(VGA_X, VGA_Y, c);
|
||||
putchar(c, VGA_X, VGA_Y, white, black);
|
||||
VGA_X++;
|
||||
break;
|
||||
}
|
||||
@@ -123,13 +98,19 @@ void putc(char c)
|
||||
VGA_Y++;
|
||||
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);
|
||||
}
|
||||
|
||||
void colorputc(char c, unsigned int color)
|
||||
void colorputc(char c, uint32_t fg, uint32_t bg)
|
||||
{
|
||||
erase_cursor();
|
||||
switch(c)
|
||||
{
|
||||
case '\n':
|
||||
@@ -143,8 +124,7 @@ void colorputc(char c, unsigned int color)
|
||||
VGA_X += 4;
|
||||
break;
|
||||
default:
|
||||
putchar(VGA_X, VGA_Y, c);
|
||||
putcolor(VGA_X, VGA_Y, color);
|
||||
putchar(c, VGA_X, VGA_Y, fg, bg);
|
||||
VGA_X++;
|
||||
break;
|
||||
}
|
||||
@@ -154,7 +134,14 @@ void colorputc(char c, unsigned int color)
|
||||
VGA_Y++;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
colorputc(*str, color);
|
||||
colorputc(*str, fg, bg);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
@@ -221,27 +208,44 @@ void dtostrf(double val, char *buffer, int precision)
|
||||
|
||||
void printf(const char* fmt, ...)
|
||||
{
|
||||
int* argp = (int*) &fmt;
|
||||
int* argp = (int*)&fmt;
|
||||
int state = PRINTF_STATE_START;
|
||||
int length = PRINTF_LENGTH_START;
|
||||
int radix = 10;
|
||||
bool sign = false;
|
||||
int width = 0;
|
||||
char pad_char = ' ';
|
||||
|
||||
argp++;
|
||||
while (*fmt)
|
||||
{
|
||||
switch(state) {
|
||||
switch (state)
|
||||
{
|
||||
case PRINTF_STATE_START:
|
||||
if (*fmt == '%')
|
||||
{
|
||||
state = PRINTF_STATE_LENGTH;
|
||||
width = 0;
|
||||
pad_char = ' ';
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
putc(*fmt);
|
||||
}
|
||||
break;
|
||||
|
||||
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;
|
||||
state = PRINTF_STATE_SHORT;
|
||||
@@ -251,40 +255,57 @@ void printf(const char* fmt, ...)
|
||||
length = PRINTF_LENGTH_LONG;
|
||||
state = PRINTF_STATE_LONG;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
goto PRINTF_STATE_SPEC_;
|
||||
}
|
||||
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:
|
||||
if (*fmt == 'h')
|
||||
{
|
||||
length = PRINTF_LENGTH_SHORT_SHORT;
|
||||
state = PRINTF_STATE_SPEC;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
goto PRINTF_STATE_SPEC_;
|
||||
}
|
||||
break;
|
||||
|
||||
case PRINTF_STATE_LONG:
|
||||
if (*fmt == 'l')
|
||||
{
|
||||
length = PRINTF_LENGTH_LONG_LONG;
|
||||
state = PRINTF_STATE_SPEC;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
goto PRINTF_STATE_SPEC_;
|
||||
}
|
||||
break;
|
||||
|
||||
case PRINTF_STATE_SPEC:
|
||||
PRINTF_STATE_SPEC_:
|
||||
switch(*fmt)
|
||||
switch (*fmt)
|
||||
{
|
||||
case 'c':
|
||||
putc((char)*argp);
|
||||
argp++;
|
||||
break;
|
||||
case 's':
|
||||
puts(*(const char **)argp);
|
||||
puts(*(const char**)argp);
|
||||
argp++;
|
||||
break;
|
||||
case '%':
|
||||
@@ -294,33 +315,32 @@ void printf(const char* fmt, ...)
|
||||
case 'i':
|
||||
radix = 10;
|
||||
sign = true;
|
||||
argp = printf_number(argp, length, sign, radix);
|
||||
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||
break;
|
||||
case 'u':
|
||||
radix = 10;
|
||||
sign = false;
|
||||
argp = printf_number(argp, length, sign, radix);
|
||||
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||
break;
|
||||
case 'X':
|
||||
case 'x':
|
||||
case 'p':
|
||||
radix = 16;
|
||||
sign = false;
|
||||
argp = printf_number(argp, length, sign, radix);
|
||||
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||
break;
|
||||
case 'o':
|
||||
radix = 8;
|
||||
sign = false;
|
||||
argp = printf_number(argp, length, sign, radix);
|
||||
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||
break;
|
||||
case 'f': {
|
||||
// Handle floating-point numbers
|
||||
double* dargp = (double*)argp;
|
||||
double d = *(double*)dargp;
|
||||
char buffer[64];
|
||||
dtostrf(d, buffer, 6); // Default precision: 6
|
||||
dtostrf(d, buffer, 6);
|
||||
puts(buffer);
|
||||
argp += 2; // Incrementing by 2 to move past the double argument
|
||||
argp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -330,6 +350,8 @@ void printf(const char* fmt, ...)
|
||||
length = PRINTF_LENGTH_START;
|
||||
radix = 10;
|
||||
sign = false;
|
||||
width = 0;
|
||||
pad_char = ' ';
|
||||
break;
|
||||
}
|
||||
fmt++;
|
||||
@@ -338,14 +360,14 @@ void printf(const char* fmt, ...)
|
||||
|
||||
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];
|
||||
unsigned long long number;
|
||||
int number_sign = 1;
|
||||
int pos = 0;
|
||||
|
||||
switch(length)
|
||||
switch (length)
|
||||
{
|
||||
case PRINTF_LENGTH_SHORT_SHORT:
|
||||
case PRINTF_LENGTH_SHORT:
|
||||
@@ -358,10 +380,11 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
||||
n = -n;
|
||||
number_sign = -1;
|
||||
}
|
||||
number = (unsigned long long) n;
|
||||
number = (unsigned long long)n;
|
||||
}
|
||||
else {
|
||||
number = *(unsigned int*) argp;
|
||||
else
|
||||
{
|
||||
number = *(unsigned int*)argp;
|
||||
}
|
||||
argp++;
|
||||
break;
|
||||
@@ -374,10 +397,11 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
||||
n = -n;
|
||||
number_sign = -1;
|
||||
}
|
||||
number = (unsigned long long) n;
|
||||
number = (unsigned long long)n;
|
||||
}
|
||||
else {
|
||||
number = *(unsigned long int*) argp;
|
||||
else
|
||||
{
|
||||
number = *(unsigned long int*)argp;
|
||||
}
|
||||
argp += 2;
|
||||
break;
|
||||
@@ -390,16 +414,18 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
||||
n = -n;
|
||||
number_sign = -1;
|
||||
}
|
||||
number = (unsigned long long) n;
|
||||
number = (unsigned long long)n;
|
||||
}
|
||||
else {
|
||||
number = *(unsigned long long int*) argp;
|
||||
else
|
||||
{
|
||||
number = *(unsigned long long int*)argp;
|
||||
}
|
||||
argp += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
uint32_t rem;
|
||||
x86_div64_32(number, radix, &number, &rem);
|
||||
buffer[pos++] = charset[rem];
|
||||
@@ -410,6 +436,13 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
||||
buffer[pos++] = '-';
|
||||
}
|
||||
|
||||
int padding = width - pos;
|
||||
|
||||
while (padding-- > 0)
|
||||
{
|
||||
putc(pad_char);
|
||||
}
|
||||
|
||||
while (--pos >= 0)
|
||||
{
|
||||
putc(buffer[pos]);
|
||||
|
||||
@@ -11,23 +11,27 @@
|
||||
#define FB_HIGH_BYTE_CMD 14
|
||||
#define FB_LOW_BYTE_CMD 15
|
||||
|
||||
|
||||
void draw_cursor(uint32_t color);
|
||||
void erase_cursor();
|
||||
|
||||
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 colorputs(const char* str, unsigned int color);
|
||||
void clear(void);
|
||||
void colorputs(const char* str, uint32_t fg, uint32_t bg);
|
||||
void putcolor(int x, int y, unsigned int color);
|
||||
char getchar(int x, int y);
|
||||
unsigned int getcolor(int x, int y);
|
||||
void scroll(int lines);
|
||||
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_LENGTH 1
|
||||
#define PRINTF_STATE_SHORT 2
|
||||
#define PRINTF_STATE_LONG 3
|
||||
#define PRINTF_STATE_SPEC 4
|
||||
#define PRINTF_STATE_WIDTH 5
|
||||
|
||||
#define PRINTF_LENGTH_START 0
|
||||
#define PRINTF_LENGTH_SHORT_SHORT 1
|
||||
@@ -36,10 +40,21 @@ void colorputc(char c, unsigned int color);
|
||||
#define PRINTF_LENGTH_LONG_LONG 4
|
||||
|
||||
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();
|
||||
void get_input(char *buffer, int size);
|
||||
|
||||
void dtostrf(double val, char *buffer, int precision);
|
||||
|
||||
enum Colors
|
||||
{
|
||||
// AARRGGBB?
|
||||
white = 0xFFFFFFFF,
|
||||
black = 0x00000000,
|
||||
red = 0x00FF0000,
|
||||
green = 0x0000FF00,
|
||||
blue = 0x000000FF,
|
||||
yellow = 0x00FFFF00,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ void print_grid(const unsigned char grid[X][Y])
|
||||
//(grid[i][j] == LIVE) ? putc(42) : putc(32);
|
||||
if (grid[i][j] == LIVE) {
|
||||
serial_printf(3, "alive");
|
||||
colorputc(32, 120);
|
||||
//colorputc(32, 120);
|
||||
} else {
|
||||
putc(32);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../libc/stdio.h"
|
||||
#include "../kernel/system.h"
|
||||
#include "../libc/string.h"
|
||||
#include "../drivers/framebuffer.h"
|
||||
|
||||
// Print a rainbow colorful text for testing
|
||||
|
||||
@@ -18,7 +19,7 @@ void program_rainbow()
|
||||
|
||||
for (int i=0; i<COLORS; i++)
|
||||
{
|
||||
colorputs(input_buffer, i);
|
||||
//colorputs(input_buffer, i);
|
||||
puts("\n");
|
||||
}
|
||||
}
|
||||
@@ -29,7 +30,7 @@ void program_rainbow()
|
||||
|
||||
void program_clear()
|
||||
{
|
||||
for (int i=0; i<ROWS; i++) scroll(1);
|
||||
for (int i=0; i<ROWS; i++) scroll();
|
||||
}
|
||||
|
||||
// Get uptime in ticks
|
||||
|
||||
Reference in New Issue
Block a user