diff --git a/Makefile b/Makefile index 7bc8fbb..f723508 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ boot.elf: $(OBJS) src/nbp.ld $(LD) $(LDFLAGS) -T src/nbp.ld -o $@ $(OBJS) %.o: %.S - $(CC) $(CFLAGS) -c -o $@ $(@:.o=.S) + $(CC) $(CFLAGS) -c -o $@ $(@:.o=.S) $(CPPFLAGS) %.o: %.c - $(CC) $(CFLAGS) -O0 -c -o $@ $(@:.o=.c) + $(CC) $(CFLAGS) -O0 -c -o $@ $(@:.o=.c) $(CPPFLAGS) diff --git a/config.mk b/config.mk index 3b2d1a4..54f94cb 100644 --- a/config.mk +++ b/config.mk @@ -3,5 +3,6 @@ CC = gcc LD = ld -CFLAGS = -no-pie -fno-pic -fno-stack-protector -nostdinc -m32 +CFLAGS = -no-pie -fno-pic -fno-stack-protector -nostdinc -ffreestanding -m32 +CPPFLAGS = -I3rdparty/include LDFLAGS = -m elf_i386 diff --git a/src/bios.S b/src/bios.S index fb0b97c..9601080 100644 --- a/src/bios.S +++ b/src/bios.S @@ -9,27 +9,22 @@ bios_write: push %ebp push %ebx mov 8+0(%ebp), %edx - mov 8+4(%ebp), %ecx PROT16 REAL -.bwloop: test %ecx, %ecx +.bwloop: cmpb $0, (%edx) jz .bwreturn xor %bx, %bx mov $0x0E, %ah mov (%edx), %al - push %ecx push %edx int $0x10 pop %edx - pop %ecx add $1, %edx - sub $1, %ecx - jmp .bwloop .bwreturn: PROT @@ -77,3 +72,57 @@ _gmdone: add $24, %di pop %ebp ret + .global bios_func +bios_func: push %ebp + mov %esp, %ebp + push %ebx + push %ebp + push %edi + push %esi + + mov 8+0(%ebp), %eax + mov 8+4(%ebp), %edi + + // The interrupt number is given as an immediate value to INT. + // To support any interrupt number, we use self-modifying code. + mov %al, _bf_int+1 + + mov 0(%edi), %eax + mov 4(%edi), %ecx + mov 8(%edi), %edx + mov 12(%edi), %ebx + mov 16(%edi), %ebp + mov 20(%edi), %esi + mov 24(%edi), %edi + + PROT16 + REAL + + // This instruction will get written at runtime +_bf_int: .byte 0xCD, 0 // INT imm8 + push $0 + pushf + + PROT + PROT32 + + push %edi + mov 8+4(%ebp), %edi + mov %eax, 0(%edi) + mov %ecx, 4(%edi) + mov %edx, 8(%edi) + mov %ebx, 12(%edi) + mov %ebp, 16(%edi) + mov %esi, 20(%edi) + pop %eax + mov %eax, 24(%edi) + + pop %eax + + pop %esi + pop %edi + pop %ebp + pop %ebx + mov %ebp, %esp + pop %ebp + ret diff --git a/src/main.c b/src/main.c index 495daa7..ef5d87a 100644 --- a/src/main.c +++ b/src/main.c @@ -1,8 +1,6 @@ -//#include +#include "std.h" -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; +#include #define COM1_BASE_PORT 0x3F8 @@ -20,44 +18,98 @@ outb(uint16_t port, uint8_t data) __asm__ ("outb %%al, %%dx" :: "a"(data), "d"(port)); } -void serial_write_char(char c) -{ - while (1) { - int line_status = inb(COM1_BASE_PORT + 5); - if (line_status & 0x20) { - break; - } - } - outb(COM1_BASE_PORT, c); -} - -void serial_write(const char *msg) -{ - for (const char *c = msg; *c; c++) { - outb(0xE9, *c); - //serial_write_char(*c); - } -} - -extern void bios_write(const char *msg, unsigned length); +extern void bios_write(const char *msg); extern void *bios_getmap(void *buffer); -unsigned char memmap[24 * 128]; +extern BOOTBOOT bootboot; + +#define E820_TYPE_FREE 0x1 +#define E820_TYPE_RESERVED 0x2 +#define E820_TYPE_RECLAIMABLE 0x3 +#define E820_TYPE_NONVOLATILE 0x4 +#define E820_TYPE_BADMEM 0x5 + +struct e820_entry { + uint64_t base; + uint64_t length; + uint32_t type; + uint32_t xattr; +}; + +struct e820_entry memmap[128]; + +struct vesa_info { + char signature[4]; + uint16_t version; + uint16_t oem_name[2]; + uint8_t capab[4]; + uint16_t video_mode_offset; + uint16_t video_mode_segment; + uint16_t num_64k_blocks; + uint8_t reserved[492]; +}; + +extern uint16_t bios_func(uint8_t inum, uint32_t reg[]); void main() { - bios_write("init\r\n", 6); - void *end = bios_getmap(memmap); - bios_write("karlos\r\n", 8); + bios_write("Netboot via fernlader v2 ...\r\n"); + + memcpy(bootboot.magic, BOOTBOOT_MAGIC, sizeof bootboot.magic); + bootboot.size = 128; + bootboot.protocol = PROTOCOL_MINIMAL | LOADER_BIOS; + bootboot.numcores = 1; + + bios_write("init\r\n"); + struct e820_entry *end = bios_getmap(memmap); + bios_write("karlos\r\n"); for (int i = 0; ; i++) { - unsigned char *entry = memmap + 24 * i; - if ((void *)entry >= end) break; - unsigned char type = *(entry + 16); - char c = type < 10 ? type + '0' : '?'; - bios_write(&c, 1); + if (&memmap[i] >= end) break; + char buf[2]; + buf[0] = memmap[i].type < 10 ? memmap[i].type + '0' : '?'; + buf[1] = 0; + bios_write(buf); } + +#if 0 + char foo[24]; + + bios_write("bios_func():\r\n"); + uint32_t reg[6]; + reg[0] = 0xE820; + reg[1] = 24; + reg[2] = 0x534D4150; + reg[3] = 0; + reg[4] = (uint32_t)&foo; + reg[5] = 0; + uint16_t flags = bios_func(0x15, reg); + + const char *hex_digits = "0123456789ABCDEF"; + char buf[100]; + buf[0] = hex_digits[(flags >> 12) & 0xF]; + buf[1] = hex_digits[(flags >> 8) & 0xF]; + buf[2] = hex_digits[(flags >> 4) & 0xF]; + buf[3] = hex_digits[(flags >> 0) & 0xF]; + buf[4] = ' '; + buf[5] = hex_digits[(foo[16] >> 0) & 0xF]; + buf[6] = ' '; + buf[7] = 0; + + bios_write(buf); +#endif + + uint32_t reg[7]; + reg[0] = (0x0E << 8) + 'J'; + reg[1] = 0; + reg[2] = 0; + reg[3] = 0; + reg[4] = 0; + reg[5] = 0; + reg[6] = 0; + bios_func(0x10, reg); + for (;;) { - __asm__ ("hlt" :); + __asm__ ("hlt"); } } diff --git a/src/nbp.S b/src/nbp.S index 4c724a7..fc81945 100644 --- a/src/nbp.S +++ b/src/nbp.S @@ -30,21 +30,12 @@ a20_enable: // Of all the ways to toggle A20, we only try the Fast A20 Gate. // but as our bootloader exclusively runs on 64-bit machines, // we should not run into any of those systems. // Modern machines apparently don't even have the A20 line anymore. - push $msg_a20 - call dbgmsg - add $2, %sp - inb $0x92, %al or $2, %al outb %al, $0x92 // prot_enter: Set up GDT, switch into 32-bit protected mode. -prot_enter: - push $msg_prot - call dbgmsg - add $2, %sp - - lgdt GDT_PTR +prot_enter: lgdt GDT_PTR PROT PROT32 @@ -52,24 +43,6 @@ prot_enter: .code32 jmp main - .code16 -dbgmsg: push %bp - mov %sp, %bp - push %ax - push %si - mov 4(%bp), %si - -1: lodsb - test %al, %al - jz 2f - outb %al, $0xE9 - jmp 1b - -2: pop %si - pop %ax - pop %bp - ret - .data .global real_ss @@ -92,6 +65,3 @@ GDT_PTR: .word GDT_SIZE - 1 .word GDT .word 0, 0, 0 -msg_start: .asciz "Netboot via fernlader v2 ...\r\n" -msg_a20: .asciz " * Enabling A20 Gate\r\n" -msg_prot: .asciz " * Protected Mode\r\n" diff --git a/src/nbp.ld b/src/nbp.ld index 9f576b0..d1c892b 100644 --- a/src/nbp.ld +++ b/src/nbp.ld @@ -15,7 +15,8 @@ SECTIONS { *(COMMON) *(.bss) . = ALIGN(4K); - *(.bootboot) + bootboot = .; + . += 4K; _bss_end = .; } :all } diff --git a/src/std.c b/src/std.c index e69de29..1bf54b8 100644 --- a/src/std.c +++ b/src/std.c @@ -0,0 +1,12 @@ +#include "std.h" + +void * +memcpy(void *dst, const void *src, size_t n) +{ + void *di = dst; + __asm__ ("rep movsb" + : "+D"(di), "+S"(src), "+c"(n) + : + : "memory"); + return dst; +} diff --git a/src/std.h b/src/std.h index e69de29..7c753b1 100644 --- a/src/std.h +++ b/src/std.h @@ -0,0 +1,41 @@ +#ifndef FERNLADER_STD_H +#define FERNLADER_STD_H + +/* Since fernlader may be built with bog-standard GCC C compiler + * (not a freestanding cross compiler), we can't rely on any of + * the compiler-provided definitions like those in stdint.h. + */ + +// stddef.h + +#define NULL ((void *)0) + +typedef unsigned long size_t; + +// stdint.h + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +// stdbool.h + +#define true ((_Bool)1) +#define false ((_Bool)0) + +typedef _Bool bool; + +// string.h + +void *memcpy (void *dst, const void *src, size_t n); +void *memmove(void *dst, const void *src, size_t n); +void *memset (void *dst, int c, size_t n); +int memcmp (const void *src1, const void *src2, size_t n); + +#endif