diff options
40 files changed, 862 insertions, 189 deletions
@@ -1,6 +1,7 @@ -*.out +*.bin *.o *.img *.map bx_enh_dbg.ini stage3/isr.asm +fs.tar @@ -24,22 +24,29 @@ STAGE3 = \ stage3/paging.o \ stage3/heap.o \ stage3/font.o \ - stage3/letters.o \ - stage3/anna.o + stage3/font_classic.o \ + stage3/ata.o \ + stage3/string.o \ + stage3/pci.o \ + stage3/fs.o -cuddles.img: stage1.out stage2.out stage3.out - cat stage{1,2,3}.out > cuddles.img +PAD_BOUNDARY = pad() { truncate -s $$(echo "($$(du -b $$1 | cut -f1)+$$2-1)/$$2*$$2" | bc) $$1; }; pad -stage1.out: stage1/main.asm stage1/print.asm stage2.out stage3.out - nasm -f bin stage1/main.asm -o stage1.out \ - -dKSIZE=$$(du -cb stage{2,3}.out | tail -n1 | cut -f1) +cuddles.img: stage1.bin stage2.bin stage3.bin fs.tar + cat stage{1,2,3}.bin fs.tar > cuddles.img + $(PAD_BOUNDARY) cuddles.img 1048576 -stage2.out: stage2/main.asm stage2/mmap.asm stage2/paging.asm stage2/vesa.asm stage1/print.asm - nasm -f bin stage2/main.asm -o stage2.out - dd if=/dev/zero bs=1 count=$$(echo 4608-$$(du -b stage2.out | cut -f1) | bc) >> stage2.out +stage1.bin: stage1/main.asm stage1/print.asm stage2.bin stage3.bin + nasm -f bin stage1/main.asm -o stage1.bin \ + -dKSIZE=$$(du -cb stage{2,3}.bin | tail -n1 | cut -f1) -stage3.out: $(STAGE3) stage3.ld +stage2.bin: stage2/main.asm stage2/mmap.asm stage2/paging.asm stage2/vesa.asm stage1/print.asm + nasm -f bin stage2/main.asm -o stage2.bin + truncate -s 4608 stage2.bin + +stage3.bin: $(STAGE3) stage3.ld ld $(STAGE3) -T stage3.ld -Map=stage3.map + $(PAD_BOUNDARY) stage3.bin 512 stage3/%.o: stage3/%.asm nasm -f elf64 $< -o $@ @@ -50,19 +57,28 @@ stage3/%.o: stage3/%.c stage3/isr.asm: stage3/isr.lua lua stage3/isr.lua > stage3/isr.asm -.PHONY: run clean flash disas map +fs.tar: $(shell find fs | sed 's/ /\\ /g') + cd fs && tar --format=ustar -cf ../fs.tar * + +.PHONY: run clean flash disas map qemu bochs -run: cuddles.img +bochs: cuddles.img + rm -f cuddles.img.lock echo c | bochs -q +qemu: cuddles.img + qemu-system-x86_64 -drive format=raw,file=cuddles.img + +run: qemu + clean: - rm -rf stage3/*.o *.out *.img *.map stage3/isr.asm + rm -rf stage3/*.o *.bin *.img *.map stage3/isr.asm fs.tar flash: cuddles.img dd if=cuddles.img of=$(DEV) -disas: stage3.out - objdump -b binary -D -M intel -m i386:x86-64 stage3.out --adjust-vma 0x9000 --disassembler-color=on +disas: stage3.bin + objdump -b binary -D -M intel -m i386:x86-64 stage3.bin --adjust-vma 0x9000 --disassembler-color=on -map: stage3.out +map: stage3.bin cat stage3.map @@ -1,5 +1,6 @@ -floppya: 1_44=cuddles.img, status=inserted -boot: a +#floppya: 1_44=cuddles.img, status=inserted +ata0-master: type=disk, path="cuddles.img", mode=flat +boot: c #display_library: x, options="gui_debug" megs: 32 #debug: PIC=report diff --git a/fs/blahaj.cuddleimg b/fs/blahaj.cuddleimg Binary files differnew file mode 100644 index 0000000..f616983 --- /dev/null +++ b/fs/blahaj.cuddleimg diff --git a/fs/blahaj.png b/fs/blahaj.png Binary files differnew file mode 100644 index 0000000..d7d5b26 --- /dev/null +++ b/fs/blahaj.png diff --git a/fs/fonts/Bm437_IBM_VGA_8x16.cuddlefont b/fs/fonts/Bm437_IBM_VGA_8x16.cuddlefont Binary files differnew file mode 100644 index 0000000..8809f2d --- /dev/null +++ b/fs/fonts/Bm437_IBM_VGA_8x16.cuddlefont diff --git a/fs/fonts/otb/Bm437_IBM_VGA_8x16.otb b/fs/fonts/otb/Bm437_IBM_VGA_8x16.otb Binary files differnew file mode 100644 index 0000000..2dc41c3 --- /dev/null +++ b/fs/fonts/otb/Bm437_IBM_VGA_8x16.otb diff --git a/fs/fonts/otb/ter-u16b.otb b/fs/fonts/otb/ter-u16b.otb Binary files differnew file mode 100644 index 0000000..8c8070a --- /dev/null +++ b/fs/fonts/otb/ter-u16b.otb diff --git a/fs/fonts/otb/ter-u16n.otb b/fs/fonts/otb/ter-u16n.otb Binary files differnew file mode 100644 index 0000000..28a468d --- /dev/null +++ b/fs/fonts/otb/ter-u16n.otb diff --git a/fs/fonts/ter-u16n.cuddlefont b/fs/fonts/ter-u16n.cuddlefont Binary files differnew file mode 100644 index 0000000..9bc55e7 --- /dev/null +++ b/fs/fonts/ter-u16n.cuddlefont @@ -0,0 +1,10 @@ +font fonts/Bm437_IBM_VGA_8x16.cuddlefont +echo hello world +cat uwu.txt +charset_demo +lspci +echo meow meow meow +img blahaj.cuddleimg +font fonts/ter-u16n.cuddlefont +echo This is the terminus font! +charset_demo diff --git a/fs/uwu.txt b/fs/uwu.txt new file mode 100644 index 0000000..9c758be --- /dev/null +++ b/fs/uwu.txt @@ -0,0 +1,15 @@ + -------- -------- + --/ \ / \-- + / \/ \ +/ \ +| | +| anna | +\ / + \ / + \ / + \ / + \ / + \ / + \ / + \ / + \/ diff --git a/stage1/main.asm b/stage1/main.asm index c51fc59..33264b0 100644 --- a/stage1/main.asm +++ b/stage1/main.asm @@ -19,6 +19,9 @@ boot: mov ebx, .msg call print_str + ; save offset of the file system + mov dword[0x1000-10-8], KSIZE+512 + ; print boot drive pusha movzx eax, dl @@ -145,5 +148,8 @@ load_stages: %include "stage1/print.asm" +times 440-($-$$) db 0 +db "hugs" + times 510-($-$$) db 0 dw 0xAA55 @@ -1,4 +1,4 @@ -OUTPUT(stage3.out) +OUTPUT(stage3.bin) OUTPUT_FORMAT(binary) SECTIONS diff --git a/stage3/anna.c b/stage3/anna.c deleted file mode 100644 index d590ee7..0000000 --- a/stage3/anna.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "font.h" - -void uwu() -{ - print( - " -------- -------- " "\n" - " --/ \\ / \\--" "\n" - " / \\/ \\" "\n" - "/ \\" "\n" - "| |" "\n" - "| anna |" "\n" - "\\ /" "\n" - " \\ /" "\n" - " \\ /" "\n" - " \\ /" "\n" - " \\ /" "\n" - " \\ /" "\n" - " \\ /" "\n" - " \\ /" "\n" - " \\/" "\n"); -} diff --git a/stage3/anna.h b/stage3/anna.h deleted file mode 100644 index 42bb664..0000000 --- a/stage3/anna.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef ANNA_H -#define ANNA_H - -void uwu(); - -#endif diff --git a/stage3/ata.c b/stage3/ata.c new file mode 100644 index 0000000..ccfd695 --- /dev/null +++ b/stage3/ata.c @@ -0,0 +1,158 @@ +#include "ata.h" +#include "halt.h" +#include "heap.h" +#include "io.h" +#include "font.h" + +#define ATA_IO_DATA 0 +#define ATA_IO_ERR 1 +#define ATA_IO_FEATURES 1 +#define ATA_IO_SECTORS 2 +#define ATA_IO_LBA_LOW 3 +#define ATA_IO_LBA_MID 4 +#define ATA_IO_LBA_HIGH 5 +#define ATA_IO_HEAD 6 +#define ATA_IO_STATUS 7 +#define ATA_IO_COMMAND 7 + +#define IO_ATA0_DATA 0x1F0 +#define IO_ATA0_CTRL 0x3F6 + +#define ATA_CMD_IDENTIFY 0xEC +#define ATA_CMD_READ_SECTORS_EXT 0x24 + +typedef struct __attribute__((packed)) { + bool err : 1; + bool idx : 1; + bool corr : 1; // corrected data + bool drq : 1; // has data or ready to accept data + bool srv : 1; // overlapped + bool df : 1; // drive fault + bool rdy : 1; // clear if spun down or error + bool bsy : 1; // preparing/busy +} ata_status; + +typedef struct { + unsigned int bits : 4; + bool doll : 1; + bool one0 : 1; + bool lba : 1; + bool one1 : 1; +} __attribute__((packed)) ata_head; + +void ata_recv(u16 *buffer) +{ + for (;;) { + ata_status status = BITCAST(inb(IO_ATA0_DATA + ATA_IO_STATUS), u8, ata_status); + + if (status.err) { + u8 err = inb(IO_ATA0_DATA + ATA_IO_ERR); + + const char *errors[] = { + "address mark not found\n", + "track zero not found\n", + "aborted command\n", + "media change request\n", + "id not found\n", + "media changed\n", + "uncorrectable data error\n", + "bad block detected\n", + }; + + for (int i = 0; i < 8; i++) + if (err & (1 << i)) + print(errors[i]); + + panic("ata0-witch error\n"); + } else if (status.drq) + break; + } + + for (int i = 0; i < 256; i++) + buffer[i] = inw(IO_ATA0_DATA + ATA_IO_DATA); +} + +void ata_delay() +{ + for (int i = 0; i < 15; i++) + inb(IO_ATA0_DATA + ATA_IO_STATUS); +} + +void ata_init() +{ + u8 floating = inb(IO_ATA0_DATA + ATA_IO_STATUS); + if (floating == 0xFF) + panic("ata0 floating\n"); + + outb(IO_ATA0_DATA + ATA_IO_HEAD, BITCAST(((ata_head) { + .bits = 0, + .doll = false, + .one0 = true, + .lba = false, + .one1 = true, + }), ata_head, u8)); + ata_delay(); + outb(IO_ATA0_DATA + ATA_IO_LBA_LOW, 0); + outb(IO_ATA0_DATA + ATA_IO_LBA_MID, 0); + outb(IO_ATA0_DATA + ATA_IO_LBA_HIGH, 0); + outb(IO_ATA0_DATA + ATA_IO_COMMAND, ATA_CMD_IDENTIFY); + + u8 status_byte = inb(IO_ATA0_DATA + ATA_IO_STATUS); + if (status_byte == 0) + panic("no ata0-witch drive\n"); + + while (BITCAST(status_byte, u8, ata_status).bsy) + status_byte = inb(IO_ATA0_DATA + ATA_IO_STATUS); + + if (inb(IO_ATA0_DATA + ATA_IO_LBA_MID) != 0 || inb(IO_ATA0_DATA + ATA_IO_LBA_HIGH) != 0) + panic("ata0-witch is not ATA\n"); + + u16 *idvec = malloc(256 * sizeof *idvec); + ata_recv(idvec); + + if (!(idvec[83] & (1 << 10))) + panic("ata0-witch does not support LBA48 mode\n"); + + // u64 lba48_sectors = *(u64 *) &idvec[100]; + // print_num(lba48_sectors, 10, 0); print("\n"); + + free(idvec); +} + +void ata_read(u64 lba, u16 sectors, void *buffer) +{ + outb(IO_ATA0_DATA + ATA_IO_HEAD, BITCAST(((ata_head) { + .bits = 0, + .doll = false, + .one0 = true, + .lba = true, + .one1 = true, + }), ata_head, u8)); + ata_delay(); + outb(IO_ATA0_DATA + ATA_IO_SECTORS, sectors >> 8); + outb(IO_ATA0_DATA + ATA_IO_LBA_LOW, (lba >> 24) & 0xff); + outb(IO_ATA0_DATA + ATA_IO_LBA_MID, (lba >> 32) & 0xff); + outb(IO_ATA0_DATA + ATA_IO_LBA_HIGH, (lba >> 40) & 0xff); + outb(IO_ATA0_DATA + ATA_IO_SECTORS, sectors & 0xff); + outb(IO_ATA0_DATA + ATA_IO_LBA_LOW, lba & 0xff); + outb(IO_ATA0_DATA + ATA_IO_LBA_MID, (lba >> 8) & 0xff); + outb(IO_ATA0_DATA + ATA_IO_LBA_HIGH, (lba >> 16) & 0xff); + outb(IO_ATA0_DATA + ATA_IO_COMMAND, ATA_CMD_READ_SECTORS_EXT); + + for (u16 i = 0; i < sectors; i++) + ata_recv(buffer + i*512); +} + +void *ata_read_full(u64 lba, u64 sectors) +{ + void *buffer = malloc(512 * sectors); + + for (u64 off = 0; off < sectors; off += 0x10000) { + u64 sects = sectors - off; + if (sects >= 0x10000) + sects = 0; + ata_read(lba + off, (u16) sects, buffer + off * 512); + } + + return buffer; +} diff --git a/stage3/ata.h b/stage3/ata.h new file mode 100644 index 0000000..56743e8 --- /dev/null +++ b/stage3/ata.h @@ -0,0 +1,12 @@ +#ifndef ATA_H +#define ATA_H + +#include "def.h" + +void ata_recv(u16 *buffer); +void ata_delay(); +void ata_init(); +void ata_read(u64 lba, u16 sectors, void *buffer); +void *ata_read_full(u64 lba, u64 sectors); + +#endif diff --git a/stage3/font.c b/stage3/font.c index 291cdb1..9e315e6 100644 --- a/stage3/font.c +++ b/stage3/font.c @@ -1,10 +1,17 @@ #include "font.h" -#include "letters.h" +#include "font_classic.h" #include "gfx.h" +#include "heap.h" +#include "memory.h" // important: must be a multiple of 2, else code won't work #define TAB_SIZE 4 +#define CHAR_WIDTH 8 +#define CHAR_HEIGHT 16 + +static u8 *font; // u8[256][16] + static u16 font_size; static u16 outer_width, outer_height; @@ -12,17 +19,55 @@ static u16 cursor_x, cursor_y; static u16 screen_width, screen_height; -void set_font_size(u16 size) +void font_init() +{ + font = malloc(256 * 16); +} + +void font_set_size(u16 size) { font_size = size; - outer_width = (LETTER_WIDTH + 2) * font_size; - outer_height = (LETTER_HEIGHT + 2) * font_size; + outer_width = CHAR_WIDTH * font_size; + outer_height = CHAR_HEIGHT * font_size; screen_width = gfx_info->width / outer_width; screen_height = gfx_info->height / outer_height; } +void font_load_blob(const void *blob) +{ + memcpy(font, blob, 256*16); +} + +void font_load_classic() +{ + memset(font, 0, 256 * 16); + + classic_char *cfont = font_classic(); + + int scale = 2; + int xpad = (CHAR_WIDTH - CLASSIC_CHAR_WIDTH * scale) / 2; + int ypad = (CHAR_HEIGHT - CLASSIC_CHAR_HEIGHT * scale) / 2; + + for (int i = 0; i < 255; i++) + for (int xc = 0; xc < CLASSIC_CHAR_WIDTH; xc++) + for (int yc = 0; yc < CLASSIC_CHAR_HEIGHT; yc++) { + if (!cfont[i].data[yc * CLASSIC_CHAR_WIDTH + xc]) + continue; + + for (int xf = 0; xf < scale; xf++) + for (int yf = 0; yf < scale; yf++) { + int x = xc * scale + xpad + xf; + int y = yc * scale + ypad + yf; + + font[i * CHAR_HEIGHT + y] |= (1 << x); + } + } + + free(cfont); +} + static void render_char(u8 c) { u16 base_x = cursor_x * outer_width; @@ -30,14 +75,14 @@ static void render_char(u8 c) gfx_set_area(base_x, base_y, outer_width, outer_height, 0xFF000000); - for (u16 x = 0; x < LETTER_WIDTH; x++) - for (u16 y = 0; y < LETTER_HEIGHT; y++) { - if (!letters[c].data[y * LETTER_WIDTH + x]) + for (u16 x = 0; x < CHAR_WIDTH; x++) + for (u16 y = 0; y < CHAR_HEIGHT; y++) { + if (!(font[c * CHAR_HEIGHT + y] & (1 << x))) continue; gfx_set_area( - base_x + (x + 1) * font_size, - base_y + (y + 1) * font_size, + base_x + x * font_size, + base_y + y * font_size, font_size, font_size, 0xFFFFFFFF); } } @@ -103,8 +148,13 @@ void print(const char *line) print_char(*line++); } +void printn(const char *line, usize len) +{ + for (usize i = 0; i < len; i++) + print_char(*line++); +} -void print_num(u64 x, u8 base, u8 pad) +void print_padded(u64 x, u8 base, u8 pad_len, char pad_char) { char digit[65]; char *ptr = &digit[64]; @@ -116,8 +166,13 @@ void print_num(u64 x, u8 base, u8 pad) x /= base; } while (x != 0); - while (ptr > digit + 64 - pad) - *--ptr = ' '; + while (ptr > digit + 64 - pad_len) + *--ptr = pad_char; print(ptr); } + +void print_num(u64 x, u8 base, u8 pad) +{ + print_padded(x, base, pad, ' '); +} diff --git a/stage3/font.h b/stage3/font.h index 009d1de..ec99118 100644 --- a/stage3/font.h +++ b/stage3/font.h @@ -3,9 +3,15 @@ #include "def.h" +void font_init(); +void font_set_size(u16 size); +void font_load_blob(const void *blob); +void font_load_classic(); + void print(const char *line); -void set_font_size(u16 size); +void printn(const char *line, usize len); void print_char(char c); -void print_num(u64 x, u8 base, u8 pad); +void print_num(u64 x, u8 base, u8 pad_len); +void print_padded(u64 x, u8 base, u8 pad_len, char pad_char); #endif diff --git a/stage3/letters.c b/stage3/font_classic.c index 43f78fb..4346f16 100644 --- a/stage3/letters.c +++ b/stage3/font_classic.c @@ -1,490 +1,495 @@ -#include "letters.h" +#include "font_classic.h" +#include "heap.h" +#include "memory.h" -Letter letters[256]; - -void letters_init() +classic_char *font_classic() { - letters[' '] = (Letter) {{ + classic_char *font = malloc(256 * sizeof *font); + memset(font, 0, 256 * sizeof *font); + + font[' '] = (classic_char) {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; - letters['!'] = (Letter) {{ + font['!'] = (classic_char) {{ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }}; - letters['\"'] = (Letter) {{ + font['\"'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; - letters['#'] = (Letter) {{ + font['#'] = (classic_char) {{ 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1 }}; - letters['$'] = (Letter) {{ + font['$'] = (classic_char) {{ 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0 }}; - letters['%'] = (Letter) {{ + font['%'] = (classic_char) {{ 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 }}; - letters['&'] = (Letter) {{ + font['&'] = (classic_char) {{ 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }}; - letters['\''] = (Letter) {{ + font['\''] = (classic_char) {{ 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; - letters['('] = (Letter) {{ + font['('] = (classic_char) {{ 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0 }}; - letters[')'] = (Letter) {{ + font[')'] = (classic_char) {{ 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0 }}; - letters['*'] = (Letter) {{ + font['*'] = (classic_char) {{ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 }}; - letters['+'] = (Letter) {{ + font['+'] = (classic_char) {{ 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0 }}; - letters[','] = (Letter) {{ + font[','] = (classic_char) {{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0 }}; - letters['-'] = (Letter) {{ + font['-'] = (classic_char) {{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0 }}; - letters['.'] = (Letter) {{ + font['.'] = (classic_char) {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }}; - letters['/'] = (Letter) {{ + font['/'] = (classic_char) {{ 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0 }}; - letters['0'] = (Letter) {{ + font['0'] = (classic_char) {{ 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0 }}; - letters['1'] = (Letter) {{ + font['1'] = (classic_char) {{ 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1 }}; - letters['2'] = (Letter) {{ + font['2'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1 }}; - letters['3'] = (Letter) {{ + font['3'] = (classic_char) {{ 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1 }}; - letters['4'] = (Letter) {{ + font['4'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1 }}; - letters['5'] = (Letter) {{ + font['5'] = (classic_char) {{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0 }}; - letters['6'] = (Letter) {{ + font['6'] = (classic_char) {{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }}; - letters['7'] = (Letter) {{ + font['7'] = (classic_char) {{ 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0 }}; - letters['8'] = (Letter) {{ + font['8'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }}; - letters['9'] = (Letter) {{ + font['9'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 }}; - letters[':'] = (Letter) {{ + font[':'] = (classic_char) {{ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }}; - letters[';'] = (Letter) {{ + font[';'] = (classic_char) {{ 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0 }}; - letters['<'] = (Letter) {{ + font['<'] = (classic_char) {{ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }}; - letters['='] = (Letter) {{ + font['='] = (classic_char) {{ 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0 }}; - letters['>'] = (Letter) {{ + font['>'] = (classic_char) {{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0 }}; - letters['?'] = (Letter) {{ + font['?'] = (classic_char) {{ 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0 }}; - letters['@'] = (Letter) {{ + font['@'] = (classic_char) {{ 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }}; - letters['['] = (Letter) {{ + font['['] = (classic_char) {{ 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0 }}; - letters[']'] = (Letter) {{ + font[']'] = (classic_char) {{ 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1 }}; - letters['\\'] = (Letter) {{ + font['\\'] = (classic_char) {{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1 }}; - letters['^'] = (Letter) {{ + font['^'] = (classic_char) {{ 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; - letters['_'] = (Letter) {{ + font['_'] = (classic_char) {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 }}; - letters['`'] = (Letter) {{ + font['`'] = (classic_char) {{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; - letters['~'] = (Letter) {{ + font['~'] = (classic_char) {{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }}; - letters['{'] = (Letter) {{ + font['{'] = (classic_char) {{ 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1 }}; - letters['}'] = (Letter) {{ + font['}'] = (classic_char) {{ 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0 }}; - letters['|'] = (Letter) {{ + font['|'] = (classic_char) {{ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 }}; - letters['A'] = letters['a'] = (Letter) {{ + font['A'] = font['a'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1 }}; - letters['B'] = letters['b'] = (Letter) {{ + font['B'] = font['b'] = (classic_char) {{ 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 }}; - letters['C'] = letters['c'] = (Letter) {{ + font['C'] = font['c'] = (classic_char) {{ 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1 }}; - letters['D'] = letters['d'] = (Letter) {{ + font['D'] = font['d'] = (classic_char) {{ 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0 }}; - letters['E'] = letters['e'] = (Letter) {{ + font['E'] = font['e'] = (classic_char) {{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1 }}; - letters['F'] = letters['f'] = (Letter) {{ + font['F'] = font['f'] = (classic_char) {{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0 }}; - letters['G'] = letters['g'] = (Letter) {{ + font['G'] = font['g'] = (classic_char) {{ 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1 }}; - letters['H'] = letters['h'] = (Letter) {{ + font['H'] = font['h'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1 }}; - letters['I'] = letters['i'] = (Letter) {{ + font['I'] = font['i'] = (classic_char) {{ 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1 }}; - letters['J'] = letters['j'] = (Letter) {{ + font['J'] = font['j'] = (classic_char) {{ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1 }}; - letters['K'] = letters['k'] = (Letter) {{ + font['K'] = font['k'] = (classic_char) {{ 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, }}; - letters['L'] = letters['l'] = (Letter) {{ + font['L'] = font['l'] = (classic_char) {{ 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1 }}; - letters['M'] = letters['m'] = (Letter) {{ + font['M'] = font['m'] = (classic_char) {{ 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 }}; - letters['N'] = letters['n'] = (Letter) {{ + font['N'] = font['n'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 }}; - letters['O'] = letters['o'] = (Letter) {{ + font['O'] = font['o'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1 }}; - letters['P'] = letters['p'] = (Letter) {{ + font['P'] = font['p'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0 }}; - letters['Q'] = letters['q'] = (Letter) {{ + font['Q'] = font['q'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1 }}; - letters['R'] = letters['r'] = (Letter) {{ + font['R'] = font['r'] = (classic_char) {{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1 }}; - letters['S'] = letters['s'] = (Letter) {{ + font['S'] = font['s'] = (classic_char) {{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1 }}; - letters['T'] = letters['t'] = (Letter) {{ + font['T'] = font['t'] = (classic_char) {{ 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 }}; - letters['U'] = letters['u'] = (Letter) {{ + font['U'] = font['u'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1 }}; - letters['V'] = letters['v'] = (Letter) {{ + font['V'] = font['v'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0 }}; - letters['W'] = letters['w'] = (Letter) {{ + font['W'] = font['w'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1 }}; - letters['X'] = letters['x'] = (Letter) {{ + font['X'] = font['x'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1 }}; - letters['Y'] = letters['y'] = (Letter) {{ + font['Y'] = font['y'] = (classic_char) {{ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0 }}; - letters['Z'] = letters['z'] = (Letter) {{ + font['Z'] = font['z'] = (classic_char) {{ 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1 }}; + + return font; } diff --git a/stage3/font_classic.h b/stage3/font_classic.h new file mode 100644 index 0000000..cc80873 --- /dev/null +++ b/stage3/font_classic.h @@ -0,0 +1,15 @@ +#ifndef FONT_CLASSIC_H +#define FONT_CLASSIC_H + +#include "def.h" + +#define CLASSIC_CHAR_WIDTH 3 +#define CLASSIC_CHAR_HEIGHT 5 + +typedef struct __attribute__((packed)) { + u8 data[CLASSIC_CHAR_WIDTH * CLASSIC_CHAR_HEIGHT]; +} classic_char; + +classic_char *font_classic(); + +#endif diff --git a/stage3/fs.c b/stage3/fs.c new file mode 100644 index 0000000..9f7ea51 --- /dev/null +++ b/stage3/fs.c @@ -0,0 +1,31 @@ +#include "fs.h" +#include "ata.h" +#include "string.h" +#include "memory.h" +#include "heap.h" + +file fs_read(const char *filename) +{ + u64 start = (*(u32 *) (0x1000-10-8))/512; + + for (;;) { + u8 *info = ata_read_full(start, 1); + + if (memcmp(info+257, "ustar", 5) != 0) { + free(info); + return (file) { .len = 0, .data = nil }; + } + + u8 *infop = info+124; + usize fsize = parse_num(&infop, 8, 11); + usize fsect = (fsize+511)/512; + + if (memcmp(info, filename, strlen(filename) + 1) == 0) { + free(info); + return (file) { .len = fsize, .data = ata_read_full(start+1, fsect) }; + } else { + free(info); + start += 1 + fsect; + } + } +} diff --git a/stage3/fs.h b/stage3/fs.h new file mode 100644 index 0000000..b585577 --- /dev/null +++ b/stage3/fs.h @@ -0,0 +1,13 @@ +#ifndef FS_H +#define FS_H + +#include "def.h" + +typedef struct { + usize len; + void *data; +} file; + +file fs_read(const char *filename); + +#endif diff --git a/stage3/gfx.c b/stage3/gfx.c index 2afc766..79c76a3 100644 --- a/stage3/gfx.c +++ b/stage3/gfx.c @@ -1,4 +1,5 @@ #include "gfx.h" +#include "memory.h" struct GfxInfo *gfx_info = (void *) (0x1000-10); @@ -6,10 +7,10 @@ struct GfxInfo *gfx_info = (void *) (0x1000-10); u32 make_color(color col) { return ((u32) 0) - & ((u32) col.r << 0) - & ((u32) col.g << 8) - & ((u32) col.b << 16) - & ((u32) col.a << 24); + | ((u32) col.b << 0) + | ((u32) col.g << 8) + | ((u32) col.r << 16) + | ((u32) col.a << 24); } void gfx_set_pixel(u16 x, u16 y, u32 col) @@ -30,3 +31,10 @@ void gfx_set_area(u16 x, u16 y, u16 w, u16 h, u32 col) *((u32 *) rbeg) = col; } } + +void gfx_draw_img(u16 x, u16 y, u16 w, u16 h, color *img) +{ + void *cbeg = (void *) (u64) (gfx_info->framebuffer + y * gfx_info->pitch + x * sizeof(color)); + for (u16 yi = 0; yi < h; cbeg += gfx_info->pitch, yi++) + memcpy(cbeg, img + yi * w, w * sizeof(color)); +} diff --git a/stage3/gfx.h b/stage3/gfx.h index 47e98db..6eee074 100644 --- a/stage3/gfx.h +++ b/stage3/gfx.h @@ -10,12 +10,13 @@ extern struct __attribute__((packed)) GfxInfo { u32 framebuffer; } *gfx_info; -typedef struct { +typedef struct __attribute__((packed)) { u8 r, g, b, a; } color; u32 make_color(color col); void gfx_set_pixel(u16 x, u16 y, u32 col); void gfx_set_area(u16 x, u16 y, u16 w, u16 h, u32 col); +void gfx_draw_img(u16 x, u16 y, u16 w, u16 h, color *img); #endif diff --git a/stage3/heap.c b/stage3/heap.c index 2909ba7..dd1b23a 100644 --- a/stage3/heap.c +++ b/stage3/heap.c @@ -46,7 +46,7 @@ void *try_malloc(usize size) prev->next = h->next; } else { // split - h->size -= size; + h->size -= size + sizeof(Header); h = ((void *) h) + sizeof(Header) + h->size; h->size = size; } diff --git a/stage3/interrupts.c b/stage3/interrupts.c index e7b819e..71f953f 100644 --- a/stage3/interrupts.c +++ b/stage3/interrupts.c @@ -102,6 +102,13 @@ void interrupt_handler(interrupt_frame *frame) } } +typedef struct { + u16 size; + u64 addr; +} __attribute__((packed)) idt_descriptor; + +idt_descriptor idtr; + void init_interrupts() { typedef struct { @@ -139,12 +146,7 @@ void init_interrupts() }; } - typedef struct { - u16 size; - u64 addr; - } __attribute__((packed)) idt_descriptor; - - idt_descriptor idtr = { + idtr = (idt_descriptor) { .size = 256 * sizeof *idt - 1, .addr = (u64) &idt[0], }; diff --git a/stage3/letters.h b/stage3/letters.h deleted file mode 100644 index ffaa6d5..0000000 --- a/stage3/letters.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef LETTERS_H -#define LETTERS_H - -#include "def.h" - -#define LETTER_WIDTH 3 -#define LETTER_HEIGHT 5 - -typedef struct __attribute__((packed)) { - u8 data[LETTER_HEIGHT * LETTER_WIDTH]; -} Letter; - -extern Letter letters[]; - -void letters_init(); - -#endif diff --git a/stage3/main.c b/stage3/main.c index d3ebe9d..5362984 100644 --- a/stage3/main.c +++ b/stage3/main.c @@ -1,20 +1,34 @@ +void kmain(); + +void init() +{ + kmain(); +} + #include "def.h" #include "paging.h" #include "gfx.h" #include "halt.h" #include "heap.h" #include "font.h" -#include "letters.h" #include "interrupts.h" #include "pic.h" -#include "anna.h" - -void init() +#include "io.h" +#include "memory.h" +#include "ata.h" +#include "fs.h" +#include "string.h" +#include "pci.h" + +void eat_whitespace(char **str) { - letters_init(); + while (**str == ' ' || **str == '\t') + (*str)++; +} +void kmain() +{ heap_init(); - set_font_size(2); #define MMAP for (MemRegion *mreg = (void *) 0x500; mreg->start != nil; mreg++) @@ -42,20 +56,9 @@ void init() // gfx init gfx_set_area(0, 0, gfx_info->width, gfx_info->height, 0xFF000000); - // charset demo - { - const u8 max = '~' - '!' + 1; - - char str[max + 1]; - str[max] = '\0'; - - for (u8 i = 0; i < max; i++) - str[i] = i + '!'; - - print("charset demo:\n"); - print(str); - print("\n"); - } + font_init(); + font_set_size(1); + font_load_classic(); // memory map print("memory map:\n"); @@ -70,11 +73,130 @@ void init() init_interrupts(); pic_init(); + ata_init(); + + file f = fs_read("init"); + if (f.data == nil) + panic("no init script"); + + // this is horrible horrible horrible + // if you read this i am genuinely sorry + + char *init = malloc(f.len+1); + char *init_orig = init; + init[f.len] = '\0'; + memcpy(init, f.data, f.len); + free(f.data); + + for (;;) { + eat_whitespace(&init); + + if (*init == '\0') + break; + else if (*init == '\n') { + init++; + continue; + } + + if (strncmp(init, "echo ", strlen("echo ")) == 0) { + init += strlen("echo "); + usize idx = find_char(init, '\n'); + printn(init, idx); + print("\n"); + init += idx; + } else if (strncmp(init, "cat ", strlen("cat ")) == 0) { + init += strlen("cat "); + usize idx = find_char(init, '\n'); + + char filename[idx+1]; + filename[idx] = '\0'; + memcpy(filename, init, idx); + + file f = fs_read(filename); + if (f.data == nil) { + print("cat: file not found: "); + print(filename); + print("\n"); + } else { + printn(f.data, f.len); + free(f.data); + } + + init += idx; + } else if (strncmp(init, "font ", strlen("font ")) == 0) { + init += strlen("font "); + usize idx = find_char(init, '\n'); + + char filename[idx+1]; + filename[idx] = '\0'; + memcpy(filename, init, idx); + + file f = fs_read(filename); + if (f.data == nil) { + print("font: file not found: "); + print(filename); + print("\n"); + } else { + if (f.len == 16*256) + font_load_blob(f.data); + else + print("font: file has wrong size\n"); + free(f.data); + } + + init += idx; + } else if (strncmp(init, "img ", strlen("img ")) == 0) { + init += strlen("img "); + usize idx = find_char(init, '\n'); + + char filename[idx+1]; + filename[idx] = '\0'; + memcpy(filename, init, idx); + + file f = fs_read(filename); + if (f.data == nil) { + print("img: file not found: "); + print(filename); + print("\n"); + } else { + if (f.len < 2 * sizeof(u32)) + print("img: missing header\n"); + else { + u32 width = ((u32 *) f.data)[0]; + u32 height = ((u32 *) f.data)[1]; + if (f.len != 2 * sizeof(u32) + width * height * sizeof(color)) + panic("img: invalid file size\n"); + gfx_draw_img(gfx_info->width-width, 0, width, height, f.data + 2 * sizeof(u32)); + } + free(f.data); + } + + init += idx; + } else if (strncmp(init, "lspci", strlen("lspci")) == 0) { + pci_enumerate(); + init += find_char(init, '\n'); + } else if (strncmp(init, "charset_demo", strlen("charset_demo")) == 0) { + const u8 max = '~' - '!' + 1; + + char str[max + 1]; + str[max] = '\0'; + + for (u8 i = 0; i < max; i++) + str[i] = i + '!'; + + print("charset demo:\n"); + print(str); + print("\n"); + init += find_char(init, '\n'); + } else { + print("unknown command: "); + usize idx = find_char(init, '\n'); + printn(init, idx); + print("\n"); + init += idx; + } + } - uwu(); - - // unmask_irq(IRQ_PIT); - enable_irqs(); - + free(init_orig); halt(); } diff --git a/stage3/pci.c b/stage3/pci.c new file mode 100644 index 0000000..164071d --- /dev/null +++ b/stage3/pci.c @@ -0,0 +1,40 @@ +#include "pci.h" +#include "def.h" +#include "io.h" +#include "font.h" + +#define PCI_CONFIG_ADDRESS 0xCF8 +#define PCI_CONFIG_DATA 0xCFC + +void pci_enumerate() +{ + typedef struct __attribute__((packed)) { + u8 offset; + unsigned int func : 3; + unsigned int dev : 5; + u8 bus; + unsigned int reserved : 7; + bool enable : 1; + } pci_config_addr; + + for (int bus = 0; bus < 256; bus++) + for (int dev = 0; dev < 32; dev++) { + pci_config_addr addr = { + .offset = 0, + .func = 0, + .dev = dev, + .bus = bus, + .enable = true, + }; + + outl(PCI_CONFIG_ADDRESS, BITCAST(addr, pci_config_addr, u32)); + u32 x = inl(PCI_CONFIG_DATA); + if (x != 0xFFFFFFFF) { + print("bus: "); print_num(bus, 16, 2); + print(" dev: "); print_num(dev, 16, 1); + print(" vendor: "); print_num(x & 0xFFFF, 16, 4); + print(" id: "); print_num((x >> 16) & 0xFFFF, 16, 4); + print("\n"); + } + } +} diff --git a/stage3/pci.h b/stage3/pci.h new file mode 100644 index 0000000..ac893ee --- /dev/null +++ b/stage3/pci.h @@ -0,0 +1,6 @@ +#ifndef PCI_H +#define PCI_H + +void pci_enumerate(); + +#endif diff --git a/stage3/string.c b/stage3/string.c new file mode 100644 index 0000000..ff4bfc3 --- /dev/null +++ b/stage3/string.c @@ -0,0 +1,56 @@ +#include "string.h" + +usize find_char(const char *str, char chr) +{ + usize ret = 0; + while (*str != chr && *str != '\0') + str++, ret++; + return ret; +} + +u64 parse_num(u8 **str, u8 base, isize size) +{ + u64 x = 0; + + while (size-- != 0) { + u8 c = **str; + + u64 d; + if (c >= '0' && c <= '9') + d = c - '0'; + else if (c >= 'a' && c <= 'z') + d = c - 'a'; + else if (c >= 'A' && c <= 'z') + d = c - 'A'; + else + return x; + + if (d >= base) + return x; + + (*str)++; + x = x * base + d; + } + + return x; +} + +usize strlen(const char *str) +{ + return find_char(str, '\0'); +} + +int strcmp(const char *p1, const char *p2) +{ + while (*p1 == *p2 && *p1 != '\0') + p1++, p2++; + return *p1 - *p2; +} + +int strncmp(const char *p1, const char *p2, usize size) +{ + for (usize i = 0; i < size; i++) + if (p1[i] != p2[i]) + return p1[i]-p2[i]; + return 0; +} diff --git a/stage3/string.h b/stage3/string.h new file mode 100644 index 0000000..2738f60 --- /dev/null +++ b/stage3/string.h @@ -0,0 +1,12 @@ +#ifndef STRING_H +#define STRING_H + +#include "def.h" + +u64 parse_num(u8 **str, u8 base, isize size); +usize find_char(const char *str, char chr); +usize strlen(const char *str); +int strcmp(const char *p1, const char *p2); +int strncmp(const char *p1, const char *p2, usize size); + +#endif diff --git a/util/png2cuddleimg/.gitignore b/util/png2cuddleimg/.gitignore new file mode 100644 index 0000000..daad221 --- /dev/null +++ b/util/png2cuddleimg/.gitignore @@ -0,0 +1 @@ +png2cuddleimg diff --git a/util/png2cuddleimg/Makefile b/util/png2cuddleimg/Makefile new file mode 100644 index 0000000..3a18ee6 --- /dev/null +++ b/util/png2cuddleimg/Makefile @@ -0,0 +1,2 @@ +png2cuddleimg: main.c + gcc $$(pkg-config --cflags --libs libpng) -Wall -Wextra main.c -o png2cuddleimg diff --git a/util/png2cuddleimg/main.c b/util/png2cuddleimg/main.c new file mode 100644 index 0000000..8dbfb14 --- /dev/null +++ b/util/png2cuddleimg/main.c @@ -0,0 +1,68 @@ +#include <png.h> +#include <stdlib.h> +#include <stdio.h> +#include <endian.h> + +int main(int argc, char *argv[]) +{ +#define TRY(expr, ...) if (!(expr)) { \ + fprintf(stderr, "%s: ", argv[0]); \ + fprintf(stderr, __VA_ARGS__); \ + if (file != NULL) fclose(file); \ + png_destroy_read_struct(&png, &info, NULL); \ + return EXIT_FAILURE; } + + FILE *file = NULL; + png_structp png = NULL; + png_infop info = NULL; + + TRY(argc == 2, "usage: %s infile.png > outfile.cuddleimg\n", argv[0]); + TRY((file = fopen(argv[1], "r")) != NULL, "failed to open %s\n", argv[1]); + + TRY(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL), + "png_create_read_struct failed\n"); + + TRY(info = png_create_info_struct(png), "png_create_info_struct failed\n"); + + png_init_io(png, file); + png_read_info(png, info); + + png_uint_32 width = png_get_image_width(png, info); + png_uint_32 height = png_get_image_height(png, info); + png_byte color_type = png_get_color_type(png, info); + png_byte bit_depth = png_get_bit_depth(png, info); + + if (bit_depth == 16) + png_set_strip_16(png); + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png); + if(png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png); + if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_PALETTE) + png_set_filler(png, 0xFF, PNG_FILLER_AFTER); + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + + png_read_update_info(png, info); + + fwrite(&width, 1, sizeof width, stdout); + fwrite(&height, 1, sizeof height, stdout); + + png_uint_32 pitch = png_get_rowbytes(png, info); + png_byte row[pitch]; + for (png_uint_32 y = 0; y < height; y++) { + png_read_row(png, row, NULL); + + for (png_uint_32 x = 0; x < width; x++) { + png_byte tmp = row[4*x]; + row[4*x] = row[4*x+2]; + row[4*x+2] = tmp; + } + + fwrite(row, 1, pitch, stdout); + } + + fclose(file); + png_destroy_read_struct(&png, &info, NULL); + return EXIT_SUCCESS; +} diff --git a/util/ttf2cuddlefont/.gitignore b/util/ttf2cuddlefont/.gitignore new file mode 100644 index 0000000..1423b0e --- /dev/null +++ b/util/ttf2cuddlefont/.gitignore @@ -0,0 +1 @@ +ttf2cuddlefont diff --git a/util/ttf2cuddlefont/Makefile b/util/ttf2cuddlefont/Makefile new file mode 100644 index 0000000..82b54cf --- /dev/null +++ b/util/ttf2cuddlefont/Makefile @@ -0,0 +1,2 @@ +ttf2cuddlefont: main.c + gcc $$(pkg-config --cflags --libs freetype2) -Wall -Wextra main.c -o ttf2cuddlefont diff --git a/util/ttf2cuddlefont/main.c b/util/ttf2cuddlefont/main.c new file mode 100644 index 0000000..764dec9 --- /dev/null +++ b/util/ttf2cuddlefont/main.c @@ -0,0 +1,52 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <ft2build.h> +#include FT_FREETYPE_H + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +static inline unsigned char bitreverse(unsigned char b) { + b = (b & 0b11110000) >> 4 | (b & 0b00001111) << 4; + b = (b & 0b11001100) >> 2 | (b & 0b00110011) << 2; + b = (b & 0b10101010) >> 1 | (b & 0b01010101) << 1; + return b; +} + +int main(int argc, char *argv[]) +{ +#define TRY(expr, ...) if (!(expr)) \ + { fprintf(stderr, "%s: ", argv[0]); fprintf(stderr, __VA_ARGS__); return EXIT_FAILURE; } + + TRY(argc == 2, "usage: %s infile.ttf > outfile.cuddlefont\n", argv[0]); + + FT_Library lib; + TRY(FT_Init_FreeType(&lib) == 0, "failed to initialize freetype\n"); + + FT_Face face; + TRY(FT_New_Face(lib, argv[1], 0, &face) == 0, "failed to load %s\n", argv[1]); + // TRY(FT_Set_Pixel_Sizes(face, 0, 16) == 0, "failed to select pixel size of 8x16\n"); + + for (int i = 0;; i++) { + TRY(i != face->num_fixed_sizes, "no 8x16 size available\n"); + + if (face->available_sizes[i].height == 16 && + face->available_sizes[i].width == 8) { + TRY(FT_Select_Size(face, i) == 0, "failed to select font size"); + break; + } + } + + assert(bitreverse(0b10000000) == 0b00000001); + + for (int i = 0; i < 256; i++) { + TRY(FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT) == 0, + "failed to load glyph %d\n", i); + + TRY(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO) == 0, + "failed to render glyph %d\n", i); + + for (unsigned int y = 0; y < 16; y++) + putchar(bitreverse(face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch])); + } +} |