diff --git a/bootboot.h b/bootboot.h new file mode 100644 index 0000000..406023f --- /dev/null +++ b/bootboot.h @@ -0,0 +1,155 @@ +/* + * bootboot.h + * https://gitlab.com/bztsrc/bootboot + * + * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the BOOTBOOT Protocol package. + * @brief The BOOTBOOT structure + * + */ + +#ifndef _BOOTBOOT_H_ +#define _BOOTBOOT_H_ + +#ifdef __cplusplus +extern "C" { +#endif +#ifndef _MSC_VER +#define _pack __attribute__((packed)) +#else +#define _pack +#pragma pack(push) +#pragma pack(1) +#endif + +#define BOOTBOOT_MAGIC "BOOT" + +/* default virtual addresses for level 0 and 1 static loaders */ +#define BOOTBOOT_MMIO 0xfffffffff8000000 /* memory mapped IO virtual address */ +#define BOOTBOOT_FB 0xfffffffffc000000 /* frame buffer virtual address */ +#define BOOTBOOT_INFO 0xffffffffffe00000 /* bootboot struct virtual address */ +#define BOOTBOOT_ENV 0xffffffffffe01000 /* environment string virtual address */ +#define BOOTBOOT_CORE 0xffffffffffe02000 /* core loadable segment start */ + +/* minimum protocol level: + * hardcoded kernel name, static kernel memory addresses */ +#define PROTOCOL_MINIMAL 0 +/* static protocol level: + * kernel name parsed from environment, static kernel memory addresses */ +#define PROTOCOL_STATIC 1 +/* dynamic protocol level: + * kernel name parsed, kernel memory addresses from ELF or PE symbols */ +#define PROTOCOL_DYNAMIC 2 +/* big-endian flag */ +#define PROTOCOL_BIGENDIAN 0x80 + +/* loader types, just informational */ +#define LOADER_BIOS (0<<2) +#define LOADER_UEFI (1<<2) +#define LOADER_RPI (2<<2) +#define LOADER_COREBOOT (3<<2) + +/* framebuffer pixel format, only 32 bits supported */ +#define FB_ARGB 0 +#define FB_RGBA 1 +#define FB_ABGR 2 +#define FB_BGRA 3 + +/* mmap entry, type is stored in least significant tetrad (half byte) of size + * this means size described in 16 byte units (not a problem, most modern + * firmware report memory in pages, 4096 byte units anyway). */ +typedef struct { + uint64_t ptr; + uint64_t size; +} _pack MMapEnt; +#define MMapEnt_Ptr(a) ((a)->ptr) +#define MMapEnt_Size(a) ((a)->size & 0xFFFFFFFFFFFFFFF0) +#define MMapEnt_Type(a) ((a)->size & 0xF) +#define MMapEnt_IsFree(a) (((a)->size&0xF)==1) + +#define MMAP_USED 0 /* don't use. Reserved or unknown regions */ +#define MMAP_FREE 1 /* usable memory */ +#define MMAP_ACPI 2 /* acpi memory, volatile and non-volatile as well */ +#define MMAP_MMIO 3 /* memory mapped IO region */ + +#define INITRD_MAXSIZE 16 /* Mb */ + +typedef struct { + /* first 64 bytes is platform independent */ + uint8_t magic[4]; /* 'BOOT' magic */ + uint32_t size; /* length of bootboot structure, minimum 128 */ + uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */ + uint8_t fb_type; /* framebuffer type, see FB_* above */ + uint16_t numcores; /* number of processor cores */ + uint16_t bspid; /* Bootsrap processor ID (Local APIC Id on x86_64) */ + int16_t timezone; /* in minutes -1440..1440 */ + uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */ + uint64_t initrd_ptr; /* ramdisk image position and size */ + uint64_t initrd_size; + uint64_t fb_ptr; /* framebuffer pointer and dimensions */ + uint32_t fb_size; + uint32_t fb_width; + uint32_t fb_height; + uint32_t fb_scanline; + + /* the rest (64 bytes) is platform specific */ + union { + struct { + uint64_t acpi_ptr; + uint64_t smbi_ptr; + uint64_t efi_ptr; + uint64_t mp_ptr; + uint64_t unused0; + uint64_t unused1; + uint64_t unused2; + uint64_t unused3; + } x86_64; + struct { + uint64_t acpi_ptr; + uint64_t mmio_ptr; + uint64_t efi_ptr; + uint64_t unused0; + uint64_t unused1; + uint64_t unused2; + uint64_t unused3; + uint64_t unused4; + } aarch64; + } arch; + + /* from 128th byte, MMapEnt[], more records may follow */ + MMapEnt mmap; + /* use like this: + * MMapEnt *mmap_ent = &bootboot.mmap; mmap_ent++; + * until you reach bootboot->size, while(mmap_ent < bootboot + bootboot->size) */ +} _pack BOOTBOOT; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lboot.S b/lboot.S index 5274e6f..7d984cd 100644 --- a/lboot.S +++ b/lboot.S @@ -4,6 +4,7 @@ .text .code16 + // _start: entry point _start: cli cld @@ -24,14 +25,20 @@ _start: cli call print call unreal - mov $msg_memmap, %si + mov $msg_getmap, %si call print - call memmap + call getmap + + mov $msg_paging, %si + call print + call paging mov $msg_fin, %si call print -1: hlt - jmp 1b + + // hang: sleep indefinitely +hang: hlt + jmp hang .set COM1, 0x3F8 .macro com1_write offset=0, byte @@ -40,6 +47,7 @@ _start: cli outb %al, %dx .endm + // init_com1: Set up COM1 port for debug output init_com1: com1_write 1, 0x00 // clear interrupts com1_write 3, 0x80 // set DLAB to 1 com1_write 0, 0x0C // 9600 baud rate @@ -47,67 +55,124 @@ init_com1: com1_write 1, 0x00 // clear interrupts com1_write 3, 0x07 // 8 bit data + 1 parity bit ret + // enable_a20: Allow use of 'high' memory enable_a20: // TODO more thorough implementation inb $0x92, %al or $2, %al outb %al, $0x92 ret + // unreal: Enter unreal mode unreal: push %ds lgdt gdt_ptr mov %cr0, %eax or $0x01, %al mov %eax, %cr0 - ljmp $0x8, $1f + ljmp $0x8, $_prot -1: mov $0x10, %cx +_prot: mov $0x10, %cx mov %cx, %ds and $0xFE, %al mov %eax, %cr0 - ljmp $0x0, $2f + ljmp $0x0, $_unreal -2: pop %ds +_unreal: pop %ds ret -memmap: push %bp - mov %sp, %bp - sub $24, %sp - - mov %ss, %ax + // getmap: Retrieve memory map using e820 BIOS function +getmap: mov %ds, %ax mov %ax, %es - mov %sp, %di + mov $memmap, %di xor %ebx, %ebx - mov $0x534D4150, %edx + mov $0x534D4150, %edx // e820 magic number +_nextmap: movl $0, 20(%di) mov $24, %ecx mov $0xE820, %eax int $0x15 - - mov %bp, %sp - pop %bp + jc _endmap + test %ebx, %ebx + jz _endmap + add $24, %di + jmp _nextmap +_endmap: add $24, %di + mov %di, memmap_end ret + // paging: Set up initial page tables for long mode +paging: + mov $4*4096, %ecx + call alloc + mov %eax, pd_ptr + mov $4096, %ecx + call alloc + mov %eax, pdp_ptr + mov $4096, %ecx + call alloc + mov %eax, pml4_ptr + + mov pd_ptr, %edi + xor %ecx, %ecx +_pgnext: mov %ecx, %eax + shl $21, %eax + or $0b110000111, %eax + movl %eax, 0(%edi) + //movl %eax, 0(%edi,%ecx,8) + //movl $0, 4(%edi,%ecx,8) + inc %ecx + cmp $4*512, %ecx + jne _pgnext + + //mov pml4_ptr, %edi + //movl 0(%edi) + //movl $0, 4(%edi) + + ret + + // alloc: take ECX bytes from usable space in memmap + // No realignment is performed, so only alloc aligned sizes. +alloc: mov $memmap-24, %si +_anext: add $24, %si + cmp memmap_end, %si // ran over end of memmap? + jae _aerr + cmpl $1, 16(%si) + jne _anext + // TODO check that entry has enough space + cmpl $0, 4(%si) // memory is above 4Gb? + jne _aerr + mov 0(%si), %eax + addl %ecx, 0(%si) + adcl $0, 4(%si) + subl %ecx, 8(%si) + sbbl $0, 12(%si) + ret +_aerr: mov $msg_aerr, %si + call print + jmp hang + + // print: print NUL-terminated string pointed to by SI print: xor %bx, %bx -1: mov $COM1+5, %dx +_nextchr: mov $COM1+5, %dx inb %dx, %al test $0x20, %al - jz 1b + jz _nextchr lodsb or %al, %al - jz 2f + jz _endprint mov $COM1, %dx outb %al, %dx mov $0x0E, %ah int $0x10 - jmp 1b + jmp _nextchr -2: ret +_endprint: ret + // gdt: Protected mode / Unreal mode 16-bit GDT gdt: // entry 0: null descriptor .word 0 .word 0 @@ -133,8 +198,21 @@ gdt: // entry 0: null descriptor gdt_ptr: .word gdt_size-1 .long gdt + // Messages to print msg_start: .asciz "Netboot via fernlader v1 ...\r\n" msg_a20: .asciz " * Enabling A20\r\n" msg_unreal: .asciz " * Unreal Mode\r\n" -msg_memmap: .asciz " * Fetching Memory Map\r\n" +msg_getmap: .asciz " * Memory Map\r\n" +msg_paging: .asciz " * Paging\r\n" msg_fin: .asciz "Finished.\r\n" +msg_aerr: .asciz "panic: Unable to allocate memory.\r\n" + + // Long mode initial page tables +pd_ptr: .long 0 +pdp_ptr: .long 0 +pml4_ptr: .long 0 + + // Memory map area +memmap_end: .word 0 + .align 8 +memmap: // begins at end of binary diff --git a/run-qemu.sh b/run-qemu.sh index 0cc4dc7..d82f8a1 100755 --- a/run-qemu.sh +++ b/run-qemu.sh @@ -1,2 +1,2 @@ #!/bin/sh -qemu-system-x86_64 -netdev user,id=n1,net=10.0.0.5/24,tftp=netboot,bootfile=/boot.bin -device virtio-net-pci,netdev=n1 +qemu-system-x86_64 -netdev user,id=n1,net=10.0.0.5/24,tftp=.,bootfile=/boot.bin -device virtio-net-pci,netdev=n1,bootindex=0 "$@"