diff --git a/Makefile b/Makefile index e49fe375..3980df84 100644 --- a/Makefile +++ b/Makefile @@ -256,10 +256,10 @@ fatbase/kernel: misaka-kernel cdrom/fat.img: fatbase/ramdisk.igz fatbase/kernel util/mkdisk.sh | dirs util/mkdisk.sh $@ fatbase -cdrom/boot.sys: boot/boot.o boot/cstuff.o boot/link.ld | dirs - ${LD} -melf_i386 -T boot/link.ld -o $@ boot/boot.o boot/cstuff.o +cdrom/boot.sys: boot/boot.o $(patsubst %.c,%.o,$(wildcard boot/*.c)) boot/link.ld | dirs + ${LD} -melf_i386 -T boot/link.ld -o $@ boot/boot.o $(patsubst %.c,%.o,$(wildcard boot/*.c)) -boot/cstuff.o: boot/cstuff.c boot/*.h +boot/%.o: boot/%.c boot/*.h ${CC} -m32 -c -Os -fno-strict-aliasing -finline-functions -ffreestanding -mgeneral-regs-only -o $@ $< boot/boot.o: boot/boot.S diff --git a/boot/ata.h b/boot/ata.h deleted file mode 100644 index 303dadc1..00000000 --- a/boot/ata.h +++ /dev/null @@ -1,154 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * Values for ATA / PATA devices - */ - -#pragma once - -#define ATA_SR_BSY 0x80 -#define ATA_SR_DRDY 0x40 -#define ATA_SR_DF 0x20 -#define ATA_SR_DSC 0x10 -#define ATA_SR_DRQ 0x08 -#define ATA_SR_CORR 0x04 -#define ATA_SR_IDX 0x02 -#define ATA_SR_ERR 0x01 - -#define ATA_ER_BBK 0x80 -#define ATA_ER_UNC 0x40 -#define ATA_ER_MC 0x20 -#define ATA_ER_IDNF 0x10 -#define ATA_ER_MCR 0x08 -#define ATA_ER_ABRT 0x04 -#define ATA_ER_TK0NF 0x02 -#define ATA_ER_AMNF 0x01 - -#define ATA_CMD_READ_PIO 0x20 -#define ATA_CMD_READ_PIO_EXT 0x24 -#define ATA_CMD_READ_DMA 0xC8 -#define ATA_CMD_READ_DMA_EXT 0x25 -#define ATA_CMD_WRITE_PIO 0x30 -#define ATA_CMD_WRITE_PIO_EXT 0x34 -#define ATA_CMD_WRITE_DMA 0xCA -#define ATA_CMD_WRITE_DMA_EXT 0x35 -#define ATA_CMD_CACHE_FLUSH 0xE7 -#define ATA_CMD_CACHE_FLUSH_EXT 0xEA -#define ATA_CMD_PACKET 0xA0 -#define ATA_CMD_IDENTIFY_PACKET 0xA1 -#define ATA_CMD_IDENTIFY 0xEC - -#define ATAPI_CMD_READ 0xA8 -#define ATAPI_CMD_EJECT 0x1B - -#define ATA_IDENT_DEVICETYPE 0 -#define ATA_IDENT_CYLINDERS 2 -#define ATA_IDENT_HEADS 6 -#define ATA_IDENT_SECTORS 12 -#define ATA_IDENT_SERIAL 20 -#define ATA_IDENT_MODEL 54 -#define ATA_IDENT_CAPABILITIES 98 -#define ATA_IDENT_FIELDVALID 106 -#define ATA_IDENT_MAX_LBA 120 -#define ATA_IDENT_COMMANDSETS 164 -#define ATA_IDENT_MAX_LBA_EXT 200 - -#define IDE_ATA 0x00 -#define IDE_ATAPI 0x01 - -#define ATA_MASTER 0x00 -#define ATA_SLAVE 0x01 - -#define ATA_REG_DATA 0x00 -#define ATA_REG_ERROR 0x01 -#define ATA_REG_FEATURES 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_REG_SECCOUNT1 0x08 -#define ATA_REG_LBA3 0x09 -#define ATA_REG_LBA4 0x0A -#define ATA_REG_LBA5 0x0B -#define ATA_REG_CONTROL 0x0C -#define ATA_REG_ALTSTATUS 0x0C -#define ATA_REG_DEVADDRESS 0x0D - -// Channels: -#define ATA_PRIMARY 0x00 -#define ATA_SECONDARY 0x01 - -// Directions: -#define ATA_READ 0x00 -#define ATA_WRITE 0x01 - -typedef struct { - uint16_t base; - uint16_t ctrl; - uint16_t bmide; - uint16_t nien; -} ide_channel_regs_t; - -typedef struct { - uint8_t reserved; - uint8_t channel; - uint8_t drive; - uint16_t type; - uint16_t signature; - uint16_t capabilities; - uint32_t command_sets; - uint32_t size; - uint8_t model[41]; -} ide_device_t; - -typedef struct { - uint8_t status; - uint8_t chs_first_sector[3]; - uint8_t type; - uint8_t chs_last_sector[3]; - uint32_t lba_first_sector; - uint32_t sector_count; -} partition_t; - -typedef struct { - uint16_t flags; - uint16_t unused1[9]; - char serial[20]; - uint16_t unused2[3]; - char firmware[8]; - char model[40]; - uint16_t sectors_per_int; - uint16_t unused3; - uint16_t capabilities[2]; - uint16_t unused4[2]; - uint16_t valid_ext_data; - uint16_t unused5[5]; - uint16_t size_of_rw_mult; - uint32_t sectors_28; - uint16_t unused6[38]; - uint64_t sectors_48; - uint16_t unused7[152]; -} __attribute__((packed)) ata_identify_t; - -typedef struct { - uint8_t boostrap[446]; - partition_t partitions[4]; - uint8_t signature[2]; -} __attribute__((packed)) mbr_t; - -struct ata_device { - int io_base; - int control; - int slave; - int is_atapi; - ata_identify_t identity; - unsigned int atapi_lba; - unsigned int atapi_sector_size; -}; - -typedef union { - uint8_t command_bytes[12]; - uint16_t command_words[6]; -} atapi_command_t; diff --git a/boot/atapi_imp.h b/boot/atapi_imp.h deleted file mode 100644 index 07990fff..00000000 --- a/boot/atapi_imp.h +++ /dev/null @@ -1,245 +0,0 @@ -#pragma once - -static struct ata_device ata_primary_master = {.io_base = 0x1F0, .control = 0x3F6, .slave = 0}; -static struct ata_device ata_primary_slave = {.io_base = 0x1F0, .control = 0x3F6, .slave = 1}; -static struct ata_device ata_secondary_master = {.io_base = 0x170, .control = 0x376, .slave = 0}; -static struct ata_device ata_secondary_slave = {.io_base = 0x170, .control = 0x376, .slave = 1}; - -static void ata_io_wait(struct ata_device * dev) { - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); -} - -static int ata_status_wait(struct ata_device * dev, int timeout) { - int status; - if (timeout > 0) { - int i = 0; - while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY && (i < timeout)) i++; - } else { - while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY); - } - return status; -} - -static void ata_soft_reset(struct ata_device * dev) { - outportb(dev->control, 0x04); - ata_io_wait(dev); - outportb(dev->control, 0x00); -} - -static int ata_wait(struct ata_device * dev, int advanced) { - uint8_t status = 0; - - ata_io_wait(dev); - - status = ata_status_wait(dev, -1); - - if (advanced) { - status = inportb(dev->io_base + ATA_REG_STATUS); - if (status & ATA_SR_ERR) return 1; - if (status & ATA_SR_DF) return 1; - if (!(status & ATA_SR_DRQ)) return 1; - } - - return 0; -} - -static void atapi_device_init(struct ata_device * dev) { - - dev->is_atapi = 1; - - outportb(dev->io_base + 1, 1); - outportb(dev->control, 0); - - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - - outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); - ata_io_wait(dev); - - ata_wait(dev, 0); - - uint16_t * buf = (uint16_t *)&dev->identity; - - for (int i = 0; i < 256; ++i) { - buf[i] = inports(dev->io_base); - } - - /* Detect medium */ - atapi_command_t command; - command.command_bytes[0] = 0x25; - command.command_bytes[1] = 0; - command.command_bytes[2] = 0; - command.command_bytes[3] = 0; - command.command_bytes[4] = 0; - command.command_bytes[5] = 0; - command.command_bytes[6] = 0; - command.command_bytes[7] = 0; - command.command_bytes[8] = 0; /* bit 0 = PMI (0, last sector) */ - command.command_bytes[9] = 0; /* control */ - command.command_bytes[10] = 0; - command.command_bytes[11] = 0; - - uint16_t bus = dev->io_base; - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_LBA1, 0x08); - outportb(bus + ATA_REG_LBA2, 0x08); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); - - /* poll */ - int timeout = 100; - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error; - if (timeout-- < 0) goto atapi_timeout; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; - } - - for (int i = 0; i < 6; ++i) { - outports(bus, command.command_words[i]); - } - - /* poll */ - timeout = 100; - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_read; - if (timeout-- < 0) goto atapi_timeout; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; - if ((status & ATA_SR_DRQ)) break; - } - - uint16_t data[4]; - - for (int i = 0; i < 4; ++i) { - data[i] = inports(bus); - } - -#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24)) - uint32_t lba, blocks; - memcpy(&lba, &data[0], sizeof(uint32_t)); - lba = htonl(lba); - memcpy(&blocks, &data[2], sizeof(uint32_t)); - blocks = htonl(blocks); - - dev->atapi_lba = lba; - dev->atapi_sector_size = blocks; - - return; - -atapi_error_read: - print_("ATAPI read error.\n"); - return; - -atapi_error: - dev->is_atapi = 0; - print_("ATAPI error.\n"); - return; - -atapi_timeout: - dev->is_atapi = 0; - return; -} - -static int ata_device_detect(struct ata_device * dev) { - ata_soft_reset(dev); - ata_io_wait(dev); - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - ata_status_wait(dev, 10000); - - unsigned char cl = inportb(dev->io_base + ATA_REG_LBA1); /* CYL_LO */ - unsigned char ch = inportb(dev->io_base + ATA_REG_LBA2); /* CYL_HI */ - - if (cl == 0xFF && ch == 0xFF) { - /* Nothing here */ - return 0; - } - if ((cl == 0x00 && ch == 0x00) || - (cl == 0x3C && ch == 0xC3)) { - return 1; - } else if ((cl == 0x14 && ch == 0xEB) || - (cl == 0x69 && ch == 0x96)) { - atapi_device_init(dev); - return 2; - } - - return 0; -} - -static void ata_device_read_sectors_atapi(struct ata_device * dev, uint32_t lba, uint8_t * buf, int sectors) { - - if (!dev->is_atapi) return; - - - uint16_t bus = dev->io_base; - -//_try_again: - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_LBA1, dev->atapi_sector_size & 0xFF); - outportb(bus + ATA_REG_LBA2, dev->atapi_sector_size >> 8); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); - - /* poll */ - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; - } - - atapi_command_t command; - command.command_bytes[0] = 0x28; - command.command_bytes[1] = 0; - command.command_bytes[2] = (lba >> 0x18) & 0xFF; - command.command_bytes[3] = (lba >> 0x10) & 0xFF; - command.command_bytes[4] = (lba >> 0x08) & 0xFF; - command.command_bytes[5] = (lba >> 0x00) & 0xFF; - command.command_bytes[6] = sectors >> 16; - command.command_bytes[7] = sectors >> 8; - command.command_bytes[8] = sectors; /* bit 0 = PMI (0, last sector) */ - command.command_bytes[9] = 0; /* control */ - command.command_bytes[10] = 0; - command.command_bytes[11] = 0; - - for (int i = 0; i < 6; ++i) { - outports(bus, command.command_words[i]); - } - - uint16_t size_to_read = dev->atapi_sector_size; - - for (int i = 0; i < sectors; ++i) { - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup_cmd; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; - } - - inportsm(bus,buf,size_to_read/2); - - buf += size_to_read; - - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; - } - } - - return; - -atapi_error_on_read_setup: - print("error on setup\n"); - return; -atapi_error_on_read_setup_cmd: - print("error on cmd\n"); - return; -} - - -#define ata_device_read_sector_atapi(a,b,c) ata_device_read_sectors_atapi(a,b,c,1) diff --git a/boot/boot.S b/boot/boot.S index b0d19eae..a7402397 100644 --- a/boot/boot.S +++ b/boot/boot.S @@ -1,39 +1,133 @@ .code16 main: - ljmp $0x0,$0x7c05 -main2: - mov $0x0, %ax + ljmp $0x0,$entry + +entry: + /* Set up initial segments */ + xor %ax, %ax mov %ax, %ds mov %ax, %ss - mov $0x7b00, %ax + + /* Don't lose dl */ + mov %dl, boot_disk + + /* Initialize stack to just below us */ + mov $0x7c00, %ax mov %ax, %sp - mov $0x500, %ax - mov %ax, %es - - clc - int $0x12 - mov %ax, (lower_mem) - - mov $0x0, %di - call do_e820 - jc hang + /* Prepare to switch to unreal mode */ cli + push %ds + push %es + /* Enable A20 */ in $0x92, %al or $2, %al out %al, $0x92 - xor %eax, %eax - mov %ds, %ax - shl $4, %eax - add $gdt_base, %eax - mov %eax, gdtr+2 - mov $gdt_end, %eax - sub $gdt_base, %eax - mov %ax, gdtr + /* Switch to unreal mode */ lgdtw gdtr + mov %cr0, %eax + or $1, %al + mov %eax, %cr0 + jmp pmode +pmode: + mov $0x10, %bx + mov %bx, %ds + mov %bx, %es + and $0xfe, %al + mov %eax, %cr0 + jmp unrealmode +unrealmode: + pop %es + pop %ds + /* Clear the screen */ + mov $0, %al + movl $3840, %ecx + movl $0xb8000, %edi + addr32 rep stosb + + /* Print "Loading..." */ + movl $str_Loading, %esi + movl $str_Loading_end - str_Loading, %ecx + movl $0xb8000, %edi + addr32 rep movsb + + /* Use BIOS disk reads to locate the kernel and ramdisk + * and load them around the 2MB mark (by loading them + * in smaller chunks and copying those up thanks to + * our unreal mode %ds) */ + + /* Ask for drive params */ + mov $0x48, %ah + mov boot_disk, %dl + mov $drive_params, %si + int $0x13 + + /* Are we a CD? Do we need to load more of ourselves? */ + mov drive_params_bps, %ax + cmp $0x800, %ax + je boot_from_cd + + movl $str_Bad, %esi + movl $str_Bad_end - str_Bad, %ecx + movl $0xb8000, %edi + addr32 rep movsb + +_oh_no: + jmp _oh_no + +.extern _bss_start + + /* To load from the CD, we have 2048 byte sectors */ +boot_from_cd: + movl $0x4000000, %ebx + movl $0x0, dap_lba_low /* Sector 10h generally has our primary boot descriptor */ + movw $_bss_start, dap_buffer /* Load into root_data */ + + /* Load one sector */ +load_one: + mov $0x42, %ah /* Extended read */ + mov boot_disk, %dl /* Using our boot disk */ + mov $dap, %si /* From the DAP below */ + int $0x13 + + cmp $0, %ah + jnz done + + /* Move the sector up */ + movl $_bss_start, %esi + movl %ebx, %edi + xor %ecx, %ecx + movw drive_params_bps, %cx + addr32 rep movsb + + /* Increment */ + movl dap_lba_low, %ecx + add $1, %ecx + movl %ecx, dap_lba_low + xor %ecx, %ecx + movw drive_params_bps, %cx + add %ecx, %ebx + jmp load_one + +done: + /* The entire CD is now in memory at 64MiB, hopefully. */ + + /* Collect information on lower memory. */ + mov $0x500, %ax + mov %ax, %es + clc + int $0x12 + mov %ax, lower_mem + + /* Collect information on upper memory. */ + mov $0x0, %di + call do_e820 + jc hang + + /* Actually switch to protected mode. */ mov %cr0, %eax or $1, %eax mov %eax, %cr0 @@ -45,6 +139,8 @@ main2: mov %ax, %gs mov %ax, %ss + cli + .global kmain ljmp $0x08,$kmain @@ -98,8 +194,8 @@ do_e820.failed: .align 8 gdtr: - .word 0 - .long 0 + .word gdt_end - gdt_base - 1 + .long gdt_base gdt_base: .quad 0 @@ -117,6 +213,10 @@ gdt_base: .byte 0 gdt_end: +.global boot_disk +boot_disk: + .byte 0 + .global mmap_ent mmap_ent: .byte 0 @@ -126,3 +226,39 @@ mmap_ent: lower_mem: .byte 0 .byte 0 + +.align 4 +.global dap +dap: + .byte 16 + .byte 0 /* always 0 */ +.global dap_sectors +dap_sectors: + .word 1 +.global dap_buffer +dap_buffer: + .long 0x0 +dap_lba_low: + .long 0 +dap_lba_high: + .long 0 + +.align 4 +drive_params: + .word 0x1A + .word 0 /* flags */ + .long 0 /* cylinders */ + .long 0 /* heads */ + .long 0 /* sectors */ + .quad 0 /* total sectors */ +.global drive_params_bps +drive_params_bps: + .word 0 /* bytes per sector */ + +str_Bad: + .byte 'B',7,'a',7,'d',7,' ',7,'d',7,'i',7,'s',7,'k',7 +str_Bad_end: + +str_Loading: + .byte 'L',7,'o',7,'a',7,'d',7,'i',7,'n',7,'g',7,'.',7,'.',7,'.',7 +str_Loading_end: diff --git a/boot/cstuff.c b/boot/config.c similarity index 84% rename from boot/cstuff.c rename to boot/config.c index 5844df52..8a27b842 100644 --- a/boot/cstuff.c +++ b/boot/config.c @@ -1,29 +1,24 @@ #include #include -#define _BOOT_LOADER -#include "ata.h" -#include "text.h" -#include "util.h" -#include "atapi_imp.h" -#include "iso9660.h" -#include "elf.h" -#include "multiboot.h" -#include "kbd.h" #include "options.h" +#include "util.h" +#include "menu.h" +#include "text.h" +#include "multiboot.h" /* Basic text strings */ #define BASE_VERSION "ToaruOS Bootloader v3.0" -#define VERSION_TEXT BASE_VERSION " (BIOS)" -#define HELP_TEXT "Press or select a menu option with \030/\031/\032/\033." -#define COPYRIGHT_TEXT "ToaruOS is free software under the NCSA license." -#define LINK_TEXT "https://toaruos.org - https://github.com/klange/toaruos" +char * VERSION_TEXT = BASE_VERSION " (BIOS)"; +char * HELP_TEXT = "Press or select a menu option with \030/\031/\032/\033."; +char * COPYRIGHT_TEXT = "ToaruOS is free software under the NCSA license."; +char * LINK_TEXT = "https://toaruos.org - https://github.com/klange/toaruos"; /* Boot command line strings */ #define DEFAULT_ROOT_CMDLINE "root=/dev/ram0 " #define DEFAULT_GRAPHICAL_CMDLINE "start=live-session " #define DEFAULT_SINGLE_CMDLINE "start=terminal\037-F " -#define DEFAULT_TEXT_CMDLINE "start=--vga " +#define DEFAULT_TEXT_CMDLINE "start=--vga vid=text " #define DEFAULT_VID_CMDLINE "vid=auto,1440,900 " #define DEFAULT_PRESET_VID_CMDLINE "vid=preset " #define MIGRATE_CMDLINE "migrate " @@ -31,16 +26,17 @@ char * kernel_path = "KERNEL."; char * ramdisk_path = "RAMDISK.IGZ"; +char cmdline[1024] = {0}; /* Names of the available boot modes. */ -static struct bootmode boot_mode_names[] = { +struct bootmode boot_mode_names[] = { {1, "normal", "Normal Boot"}, + {2, "vga", "VGA Text Mode"}, {3, "single", "Single-User Graphical Terminal"}, {4, "headless", "Headless"}, }; -/* More bootloader implementation that depends on the module config */ -#include "moremultiboot.h" +int base_sel = BASE_SEL; extern char _bss_start[]; extern char _bss_end[]; diff --git a/boot/iso9660.c b/boot/iso9660.c new file mode 100644 index 00000000..71cebeb7 --- /dev/null +++ b/boot/iso9660.c @@ -0,0 +1,49 @@ +#include +#include "iso9660.h" +#include "util.h" +#include "text.h" + +iso_9660_volume_descriptor_t * root = NULL; +iso_9660_directory_entry_t * dir_entry = NULL; +static char * dir_entries = NULL; + +int navigate(char * name) { + dir_entry = (iso_9660_directory_entry_t*)&root->root; + dir_entries = (char*)(DATA_LOAD_BASE + dir_entry->extent_start_LSB * ISO_SECTOR_SIZE); + long offset = 0; + while (1) { + iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)(dir_entries + offset); + if (dir->length == 0) { + if (offset < dir_entry->extent_length_LSB) { + offset += 1; // this->block_size - ((uintptr_t)offset % this->block_size); + goto try_again; + } + break; + } + if (!(dir->flags & FLAG_HIDDEN)) { + char file_name[dir->name_len + 1]; + memcpy(file_name, dir->name, dir->name_len); + file_name[dir->name_len] = 0; + char * s = strchr(file_name,';'); + if (s) { + *s = '\0'; + } +#if 1 + print("Found a file: "); + print(" Name: "); + print(file_name); print("\n"); +#endif + if (!strcmp(file_name, name)) { + dir_entry = dir; + return 1; + } + } + offset += dir->length; +try_again: + if ((long)(offset) > dir_entry->extent_length_LSB) break; + } + + return 0; +} + + diff --git a/boot/iso9660.h b/boot/iso9660.h index b5b1c314..f0139fde 100644 --- a/boot/iso9660.h +++ b/boot/iso9660.h @@ -1,5 +1,7 @@ #pragma once +#include + typedef struct { char year[4]; char month[2]; @@ -111,77 +113,8 @@ typedef struct { #define FLAG_PERMISSIONS 0x10 #define FLAG_CONTINUES 0x80 -static int root_sector = 0; -static iso_9660_volume_descriptor_t * root = (iso_9660_volume_descriptor_t *)((char *)0x20000); -static iso_9660_directory_entry_t * dir_entry = (iso_9660_directory_entry_t *)((char *)0x20800); -static char * mod_dir = (char *)0x21000; -static char * dir_entries = (char *)(0x30000); -static struct ata_device * device = 0; +extern char root_data[ISO_SECTOR_SIZE]; +extern iso_9660_volume_descriptor_t * root; +extern iso_9660_directory_entry_t * dir_entry; -static int navigate(char * name) { - memset(dir_entries, 2048, 0xA5); - //print("reading from sector "); - //print_hex(dir_entry->extent_start_LSB); - //print("\n"); - ata_device_read_sector_atapi(device, dir_entry->extent_start_LSB, dir_entries); - ata_device_read_sector_atapi(device, dir_entry->extent_start_LSB+1, dir_entries + 2048); - ata_device_read_sector_atapi(device, dir_entry->extent_start_LSB+2, dir_entries + 4096); - - long offset = 0; - while (1) { - iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)(dir_entries + offset); - if (dir->length == 0) { - if (offset < dir_entry->extent_length_LSB) { - offset += 1; // this->block_size - ((uintptr_t)offset % this->block_size); - goto try_again; - } - break; - } - if (!(dir->flags & FLAG_HIDDEN)) { - char file_name[dir->name_len + 1]; - memcpy(file_name, dir->name, dir->name_len); - file_name[dir->name_len] = 0; - char * s = strchr(file_name,';'); - if (s) { - *s = '\0'; - } -#if 0 - print("Found a file: "); - print(" Name: "); - print(file_name); print("\n"); -#endif - if (!strcmp(file_name, name)) { - memcpy(dir_entry, dir, sizeof(iso_9660_directory_entry_t)); - return 1; - } - } - offset += dir->length; -try_again: - if ((long)(offset) > dir_entry->extent_length_LSB) break; - } - - return 0; -} - -static void restore_root(void) { - memcpy(dir_entry, (iso_9660_directory_entry_t *)&root->root, sizeof(iso_9660_directory_entry_t)); - -#if 0 - print("Root restored."); - print("\n Entry len: "); print_hex( dir_entry->length); - print("\n File start: "); print_hex( dir_entry->extent_start_LSB); - print("\n File len: "); print_hex( dir_entry->extent_length_LSB); - print("\n"); -#endif -} - -static void restore_mod(void) { - memcpy(dir_entry, (iso_9660_directory_entry_t *)mod_dir, sizeof(iso_9660_directory_entry_t)); -#if 0 - print("mod restored."); - print("\n Entry len: "); print_hex( dir_entry->length); - print("\n File start: "); print_hex( dir_entry->extent_start_LSB); - print("\n File len: "); print_hex( dir_entry->extent_length_LSB); - print("\n"); -#endif -} +int navigate(char * name); diff --git a/boot/kbd.c b/boot/kbd.c new file mode 100644 index 00000000..0e7e4e63 --- /dev/null +++ b/boot/kbd.c @@ -0,0 +1,11 @@ +#include "kbd.h" +#include "util.h" + +int read_scancode(void) { + while (!(inportb(0x64) & 1)); + int out; + while (inportb(0x64) & 1) { + out = inportb(0x60); + } + return out; +} diff --git a/boot/kbd.h b/boot/kbd.h index 3ce28e44..440dab39 100644 --- a/boot/kbd.h +++ b/boot/kbd.h @@ -8,51 +8,5 @@ #define KBD_SCAN_1 2 #define KBD_SCAN_9 10 -#ifdef EFI_PLATFORM +int read_scancode(void); -static int read_scancode(void) { - EFI_INPUT_KEY Key; - unsigned long int index; - uefi_call_wrapper(ST->BootServices->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index); - uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &Key); - switch (Key.ScanCode) { - case 0: - switch (Key.UnicodeChar) { - case L'\r': - return KBD_SCAN_ENTER; - case L'1': - case L'2': - case L'3': - case L'4': - case L'5': - case L'6': - case L'7': - case L'8': - case L'9': - return Key.UnicodeChar - L'1' + KBD_SCAN_1; - case L'y': - return 'y'; - case L'n': - return 'n'; - default: - return 0xFF; - } - break; - case 0x01: return KBD_SCAN_UP; - case 0x02: return KBD_SCAN_DOWN; - case 0x03: return KBD_SCAN_RIGHT; - case 0x04: return KBD_SCAN_LEFT; - default: - return 0xFF; - } -} -#else -static int read_scancode(void) { - while (!(inportb(0x64) & 1)); - int out; - while (inportb(0x64) & 1) { - out = inportb(0x60); - } - return out; -} -#endif diff --git a/boot/menu.c b/boot/menu.c new file mode 100644 index 00000000..b0f74983 --- /dev/null +++ b/boot/menu.c @@ -0,0 +1,137 @@ +#include "options.h" +#include "text.h" +#include "util.h" +#include "kbd.h" + +struct option boot_options[20] = {{0}}; + +int sel_max = 0; +int sel = 0; +int boot_mode = 0; + +void toggle(int ndx, int value, char *str) { + set_attr(sel == ndx ? 0x70 : 0x07); + if (value) { + print_(" [X] "); + } else { + print_(" [ ] "); + } + print_(str); + if (x < 40) { + while (x < 39) { + print_(" "); + } + x = 40; + } else { + print_("\n"); + } +} + +void show_menu(void) { + /* Determine number of options */ + sel_max = 0; + while (boot_options[sel_max].value) { + sel_max++; + } + sel_max += base_sel + 1; + + outportb(0x3D4, 14); + outportb(0x3D5, 0xFF); + outportb(0x3D4, 15); + outportb(0x3D5, 0xFF); + + inportb(0x3DA); + outportb(0x3C0, 0x30); + char b = inportb(0x3C1); + b &= ~8; + outportb(0x3c0, b); + + clear_(); + + do { + move_cursor(0,0); + set_attr(0x1f); + print_banner(VERSION_TEXT); + set_attr(0x07); + print_("\n"); + + for (int i = 0; i < base_sel + 1; ++i) { + set_attr(sel == i ? 0x70 : 0x07); + print_(" "); + char tmp[] = {'0' + (i + 1), '.', ' ', '\0'}; + print_(tmp); + print_(boot_mode_names[i].title); + print_("\n"); + } + + // put a gap + set_attr(0x07); + print_("\n"); + + for (int i = 0; i < sel_max - base_sel - 1; ++i) { + toggle(base_sel + 1 + i, *boot_options[i].value, boot_options[i].title); + } + + set_attr(0x07); + move_cursor(x,17); + print_("\n"); + print_banner(HELP_TEXT); + print_("\n"); + + if (sel > base_sel) { + print_banner(boot_options[sel - base_sel - 1].description_1); + print_banner(boot_options[sel - base_sel - 1].description_2); + print_("\n"); + } else { + print_banner(COPYRIGHT_TEXT); + print_("\n"); + print_banner(LINK_TEXT); + } + + int s = read_scancode(); + if (s == 0x50) { /* DOWN */ + if (sel > base_sel && sel < sel_max - 1) { + sel = (sel + 2) % sel_max; + } else { + sel = (sel + 1) % sel_max; + } + } else if (s == 0x48) { /* UP */ + if (sel > base_sel + 1) { + sel = (sel_max + sel - 2) % sel_max; + } else { + sel = (sel_max + sel - 1) % sel_max; + } + } else if (s == 0x4B) { /* LEFT */ + if (sel > base_sel) { + if ((sel - base_sel) % 2) { + sel = (sel + 1) % sel_max; + } else { + sel -= 1; + } + } + } else if (s == 0x4D) { /* RIGHT */ + if (sel > base_sel) { + if ((sel - base_sel) % 2) { + sel = (sel + 1) % sel_max; + } else { + sel -= 1; + } + } + } else if (s == 0x1c) { + if (sel <= base_sel) { + boot_mode = boot_mode_names[sel].index; + break; + } else { + int index = sel - base_sel - 1; + *boot_options[index].value = !*boot_options[index].value; + } + } else if (s >= 2 && s <= 10) { + int i = s - 2; + if (i <= base_sel) { + boot_mode = boot_mode_names[i].index; + break; + } + } + } while (1); +} + diff --git a/boot/menu.h b/boot/menu.h new file mode 100644 index 00000000..6fe0b9c9 --- /dev/null +++ b/boot/menu.h @@ -0,0 +1,4 @@ +#pragma once + +extern int boot_mode; +void show_menu(void); diff --git a/boot/moremultiboot.h b/boot/moremultiboot.h deleted file mode 100644 index c3ecd393..00000000 --- a/boot/moremultiboot.h +++ /dev/null @@ -1,441 +0,0 @@ - -static mboot_mod_t modules_mboot[1] = { - {0,0,0,1} -}; - -static struct multiboot multiboot_header = { - /* flags; */ MULTIBOOT_FLAG_CMDLINE | MULTIBOOT_FLAG_MODS | MULTIBOOT_FLAG_MEM | MULTIBOOT_FLAG_MMAP | MULTIBOOT_FLAG_LOADER, - /* mem_lower; */ 0x100000, - /* mem_upper; */ 0x640000, - /* boot_device; */ 0, - /* cmdline; */ 0, - /* mods_count; */ 1, - /* mods_addr; */ 0, - /* num; */ 0, - /* size; */ 0, - /* addr; */ 0, - /* shndx; */ 0, - /* mmap_length; */ 0, - /* mmap_addr; */ 0, - /* drives_length; */ 0, - /* drives_addr; */ 0, - /* config_table; */ 0, - /* boot_loader_name; */ 0, - /* apm_table; */ 0, - /* vbe_control_info; */ 0, - /* vbe_mode_info; */ 0, - /* vbe_mode; */ 0, - /* vbe_interface_seg; */ 0, - /* vbe_interface_off; */ 0, - /* vbe_interface_len; */ 0, -}; - -static long ramdisk_off = 1; -static long ramdisk_len = 1; - -int _eax = 1; -int _ebx = 1; -int _xmain = 1; - -struct mmap_entry { - uint64_t base; - uint64_t len; - uint32_t type; - uint32_t reserved; -}; - -extern unsigned short mmap_ent; -extern unsigned short lower_mem; - -char * final_offset = NULL; - -extern char do_the_nasty[]; - -static int strlen(char * s) { - int out = 0; - while (*s) { - s++; - out++; - } - return out; -} - -#define KERNEL_LOAD_START 0x300000 - -static void move_kernel(void) { - clear(); - print("Relocating kernel...\n"); - - Elf32_Header * header = (Elf32_Header *)KERNEL_LOAD_START; - - if (header->e_ident[0] != ELFMAG0 || - header->e_ident[1] != ELFMAG1 || - header->e_ident[2] != ELFMAG2 || - header->e_ident[3] != ELFMAG3) { - print_("Kernel is invalid?\n"); - while (1) {}; - } - - uintptr_t entry = (uintptr_t)header->e_entry; - - for (uintptr_t x = 0; x < (uint32_t)header->e_phentsize * header->e_phnum; x += header->e_phentsize) { - Elf32_Phdr * phdr = (Elf32_Phdr *)((uint8_t*)KERNEL_LOAD_START + header->e_phoff + x); - if (phdr->p_type == PT_LOAD) { - //read_fs(file, phdr->p_offset, phdr->p_filesz, (uint8_t *)phdr->p_vaddr); - print("Loading a Phdr... "); - print_hex(phdr->p_vaddr); - print(" "); - print_hex(phdr->p_offset); - print(" "); - print_hex(phdr->p_filesz); - print("\n"); - memcpy((uint8_t*)(uintptr_t)phdr->p_vaddr, (uint8_t*)KERNEL_LOAD_START + phdr->p_offset, phdr->p_filesz); - long r = phdr->p_filesz; - while (r < phdr->p_memsz) { - *(char *)(phdr->p_vaddr + r) = 0; - r++; - } - } - } - - print("Setting up memory map...\n"); - print_hex(mmap_ent); - print("\n"); - memset((void*)KERNEL_LOAD_START, 0x00, 1024); - mboot_memmap_t * mmap = (void*)KERNEL_LOAD_START; - multiboot_header.mmap_addr = (uintptr_t)mmap; - multiboot_header.mods_addr = (uintptr_t)&modules_mboot; - multiboot_header.boot_loader_name = (uintptr_t)VERSION_TEXT; - - struct mmap_entry * e820 = (void*)0x5000; - - uint64_t upper_mem = 0; - for (int i = 0; i < mmap_ent; ++i) { - print("entry "); print_hex(i); - print(" "); print_hex((uint32_t)(e820[i].base >> 32ULL)); print_hex((uint32_t)e820[i].base); - print(" "); print_hex((uint32_t)(e820[i].len >> 32ULL)); print_hex((uint32_t)e820[i].len); - print(" "); print_hex(e820[i].type); print("\n"); - - mmap->size = sizeof(uint64_t) * 2 + sizeof(uintptr_t); - mmap->base_addr = e820[i].base; - mmap->length = e820[i].len; - mmap->type = e820[i].type; - if (mmap->type == 1 && mmap->base_addr >= 0x100000) { - upper_mem += mmap->length; - } - mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uintptr_t)); - } - multiboot_header.mmap_length = (uintptr_t)mmap - multiboot_header.mmap_addr; - - print("lower "); print_hex(lower_mem); print("KB\n"); - multiboot_header.mem_lower = 1024; - print("upper "); - print_hex(upper_mem >> 32); - print_hex(upper_mem); - print("\n"); - - multiboot_header.mem_upper = upper_mem / 1024; - - _ebx = (unsigned int)&multiboot_header; - _eax = MULTIBOOT_EAX_MAGIC; - _xmain = entry; - - print_("Jumping...\n"); - - uint32_t foo[3]; - foo[0] = _eax; - foo[1] = _ebx; - foo[2] = _xmain; - __asm__ __volatile__ ( - "mov %%cr0,%%eax\n" - /* Disable paging */ - "and $0x7FFeFFFF, %%eax\n" - "mov %%eax,%%cr0\n" - /* Ensure PAE is not enabled */ - "mov %%cr4,%%eax\n" - "and $0xffffffdf, %%eax\n" - "mov %%eax,%%cr4\n" - "mov %1,%%eax \n" - "mov %2,%%ebx \n" - "jmp *%0" : : "g"(foo[2]), "g"(foo[0]), "g"(foo[1]) : "eax", "ebx" - ); -} - -static void do_it(struct ata_device * _device) { - device = _device; - if (device->atapi_sector_size != 2048) { - print_hex_(device->atapi_sector_size); - print_("\n - bad sector size\n"); - return; - } - for (int i = 0x10; i < 0x15; ++i) { - ata_device_read_sector_atapi(device, i, (uint8_t *)root); - switch (root->type) { - case 1: - root_sector = i; - goto done; - case 0xFF: - print_("Bad read\n"); - return; - } - } - print_("Early return?\n"); - return; -done: - restore_root(); - - if (navigate(kernel_path)) { - print("Found kernel.\n"); - print_hex(dir_entry->extent_start_LSB); print(" "); - print_hex(dir_entry->extent_length_LSB); print("\n"); - long offset = 0; - for (int i = dir_entry->extent_start_LSB; i < dir_entry->extent_start_LSB + dir_entry->extent_length_LSB / 2048 + 1; ++i, offset += 2048) { - ata_device_read_sector_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset); - } - while (offset % 4096) offset++; - restore_root(); - print_("Loading ramdisk"); - if (navigate(ramdisk_path)) { - ramdisk_off = KERNEL_LOAD_START + offset; - ramdisk_len = dir_entry->extent_length_LSB; - modules_mboot[0].mod_start = ramdisk_off; - modules_mboot[0].mod_end = ramdisk_off + ramdisk_len; - int i = dir_entry->extent_start_LSB; - int sectors = dir_entry->extent_length_LSB / 2048 + 1; -#define SECTORS 512 - while (sectors >= SECTORS) { - print_("."); - ata_device_read_sectors_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset, SECTORS); - - sectors -= SECTORS; - offset += 2048 * SECTORS; - i += SECTORS; - } - if (sectors > 0) { - print_("!"); - ata_device_read_sectors_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset, sectors); - offset += 2048 * sectors; - } - print_("\n"); - final_offset = (uint8_t *)KERNEL_LOAD_START + offset; - set_attr(0x07); - move_kernel(); - } else { - print_("... failed to locate ramdisk.\n"); - } - } else { - print("... failed to locate kernel.\n"); - } - - return; -} - -struct fw_cfg_file { - uint32_t size; - uint16_t select; - uint16_t reserved; - char name[56]; -}; - -static int boot_mode = 0; - -void swap_bytes(void * in, int count) { - char * bytes = in; - if (count == 4) { - uint32_t * t = in; - *t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3]; - } else if (count == 2) { - uint16_t * t = in; - *t = (bytes[0] << 8) | bytes[1]; - } -} - -void show_menu(void) { - -#if 1 - /* Try to detect qemu headless boot */ - outports(0x510, 0x0000); - if (inportb(0x511) == 'Q' && - inportb(0x511) == 'E' && - inportb(0x511) == 'M' && - inportb(0x511) == 'U') { - uint32_t count = 0; - uint8_t * bytes = (uint8_t *)&count; - outports(0x510,0x0019); - for (int i = 0; i < 4; ++i) { - bytes[i] = inportb(0x511); - } - swap_bytes(&count, 4); - - unsigned int bootmode_size = 0; - int bootmode_index = -1; - for (unsigned int i = 0; i < count; ++i) { - struct fw_cfg_file file; - uint8_t * tmp = (uint8_t *)&file; - for (int j = 0; j < sizeof(struct fw_cfg_file); ++j) { - tmp[j] = inportb(0x511); - } - if (!strcmp(file.name,"opt/org.toaruos.bootmode")) { - swap_bytes(&file.size, 4); - swap_bytes(&file.select, 2); - bootmode_size = file.size; - bootmode_index = file.select; - } - } - - if (bootmode_index != -1) { - outports(0x510, bootmode_index); - char tmp[33] = {0}; - for (int i = 0; i < 32 && i < bootmode_size; ++i) { - tmp[i] = inportb(0x511); - } - for (int i = 0; i < BASE_SEL+1; ++i) { - if (!strcmp(tmp,boot_mode_names[i].key)) { - boot_mode = boot_mode_names[i].index; - return; - } - } - print_("fw_cfg boot mode not recognized: "); - print_(tmp); - print_("\n"); - } - } -#endif - - /* Determine number of options */ - sel_max = 0; - while (boot_options[sel_max].value) { - sel_max++; - } - sel_max += BASE_SEL + 1; - - outportb(0x3D4, 14); - outportb(0x3D5, 0xFF); - outportb(0x3D4, 15); - outportb(0x3D5, 0xFF); - - inportb(0x3DA); - outportb(0x3C0, 0x30); - char b = inportb(0x3C1); - b &= ~8; - outportb(0x3c0, b); - - clear_(); - - do { - move_cursor(0,0); - set_attr(0x1f); - print_banner(VERSION_TEXT); - set_attr(0x07); - print_("\n"); - - for (int i = 0; i < BASE_SEL+1; ++i) { - set_attr(sel == i ? 0x70 : 0x07); - print_(" "); - char tmp[] = {'0' + (i + 1), '.', ' ', '\0'}; - print_(tmp); - print_(boot_mode_names[i].title); - print_("\n"); - } - - // put a gap - set_attr(0x07); - print_("\n"); - - for (int i = 0; i < sel_max - BASE_SEL - 1; ++i) { - toggle(BASE_SEL + 1 + i, *boot_options[i].value, boot_options[i].title); - } - - set_attr(0x07); - move_cursor(x,17); - print_("\n"); - print_banner(HELP_TEXT); - print_("\n"); - - if (sel > BASE_SEL) { - print_banner(boot_options[sel-BASE_SEL-1].description_1); - print_banner(boot_options[sel-BASE_SEL-1].description_2); - print_("\n"); - } else { - print_banner(COPYRIGHT_TEXT); - print_("\n"); - print_banner(LINK_TEXT); - } - - int s = read_scancode(); - if (s == 0x50) { /* DOWN */ - if (sel > BASE_SEL && sel < sel_max - 1) { - sel = (sel + 2) % sel_max; - } else { - sel = (sel + 1) % sel_max; - } - } else if (s == 0x48) { /* UP */ - if (sel > BASE_SEL + 1) { - sel = (sel_max + sel - 2) % sel_max; - } else { - sel = (sel_max + sel - 1) % sel_max; - } - } else if (s == 0x4B) { /* LEFT */ - if (sel > BASE_SEL) { - if ((sel - BASE_SEL) % 2) { - sel = (sel + 1) % sel_max; - } else { - sel -= 1; - } - } - } else if (s == 0x4D) { /* RIGHT */ - if (sel > BASE_SEL) { - if ((sel - BASE_SEL) % 2) { - sel = (sel + 1) % sel_max; - } else { - sel -= 1; - } - } - } else if (s == 0x1c) { - if (sel <= BASE_SEL) { - boot_mode = boot_mode_names[sel].index; - break; - } else { - int index = sel - BASE_SEL - 1; - *boot_options[index].value = !*boot_options[index].value; - } - } else if (s >= 2 && s <= 10) { - int i = s - 2; - if (i <= BASE_SEL) { - boot_mode = boot_mode_names[i].index; - break; - } - } - } while (1); -} - -/* BIOS boot uses native ATAPI drivers, need to find boot drive. */ -static void boot(void) { - - clear_(); - - multiboot_header.cmdline = (uintptr_t)cmdline; - - ata_device_detect(&ata_primary_master); - ata_device_detect(&ata_primary_slave); - ata_device_detect(&ata_secondary_master); - ata_device_detect(&ata_secondary_slave); - - if (ata_primary_master.is_atapi) { - do_it(&ata_primary_master); - } - if (ata_primary_slave.is_atapi) { - do_it(&ata_primary_slave); - } - if (ata_secondary_master.is_atapi) { - do_it(&ata_secondary_master); - } - if (ata_secondary_slave.is_atapi) { - do_it(&ata_secondary_slave); - } - - print_("Unable to find boot drive, can not continue.\n"); - print_("Please try GRUB or the EFI loader instead.\n"); - - while (1); -} diff --git a/boot/multiboot.c b/boot/multiboot.c new file mode 100644 index 00000000..3788b931 --- /dev/null +++ b/boot/multiboot.c @@ -0,0 +1,220 @@ +#include +#include +#include "multiboot.h" +#include "text.h" +#include "util.h" +#include "menu.h" +#include "elf.h" +#include "options.h" +#include "iso9660.h" + +char * kernel_load_start = 0; + +mboot_mod_t modules_mboot[1] = { + {0,0,0,1} +}; + +struct multiboot multiboot_header = { + /* flags; */ MULTIBOOT_FLAG_CMDLINE | MULTIBOOT_FLAG_MODS | MULTIBOOT_FLAG_MEM | MULTIBOOT_FLAG_MMAP | MULTIBOOT_FLAG_LOADER, + /* mem_lower; */ 0x100000, + /* mem_upper; */ 0x640000, + /* boot_device; */ 0, + /* cmdline; */ 0, + /* mods_count; */ 1, + /* mods_addr; */ 0, + /* num; */ 0, + /* size; */ 0, + /* addr; */ 0, + /* shndx; */ 0, + /* mmap_length; */ 0, + /* mmap_addr; */ 0, + /* drives_length; */ 0, + /* drives_addr; */ 0, + /* config_table; */ 0, + /* boot_loader_name; */ 0, + /* apm_table; */ 0, + /* vbe_control_info; */ 0, + /* vbe_mode_info; */ 0, + /* vbe_mode; */ 0, + /* vbe_interface_seg; */ 0, + /* vbe_interface_off; */ 0, + /* vbe_interface_len; */ 0, +}; + +static uintptr_t ramdisk_off = 0; +static uintptr_t ramdisk_len = 0; + +uint32_t _eax = 1; +uint32_t _ebx = 1; +uint32_t _xmain = 1; + +struct mmap_entry { + uint64_t base; + uint64_t len; + uint32_t type; + uint32_t reserved; +}; + +extern unsigned short mmap_ent; +extern unsigned short lower_mem; + +uintptr_t final_offset = 0; + +static int load_kernel(void) { + clear(); + Elf32_Header * header = (Elf32_Header *)kernel_load_start; + + if (header->e_ident[0] != ELFMAG0 || + header->e_ident[1] != ELFMAG1 || + header->e_ident[2] != ELFMAG2 || + header->e_ident[3] != ELFMAG3) { + print_("Not a valid ELF32.\n"); + return 0; + } + + uintptr_t entry = (uintptr_t)header->e_entry; + for (uintptr_t x = 0; x < (uint32_t)header->e_phentsize * header->e_phnum; x += header->e_phentsize) { + Elf32_Phdr * phdr = (Elf32_Phdr *)(kernel_load_start + header->e_phoff + x); + if (phdr->p_type == PT_LOAD) { + memcpy((uint8_t*)(uintptr_t)phdr->p_vaddr, kernel_load_start + phdr->p_offset, phdr->p_filesz); + uintptr_t r = phdr->p_filesz; + while (r < phdr->p_memsz) { + *(char *)(phdr->p_vaddr + r) = 0; + r++; + } + if (phdr->p_vaddr + r > final_offset) final_offset = phdr->p_vaddr + r; + } + } + + _xmain = entry; + + /* Round final offset */ + final_offset = (final_offset & ~(0xFFF)) + ((final_offset & 0xFFF) ? 0x1000 : 0); + + print_("Loaded with end at 0x"); print_hex_(final_offset); print_("\n"); + return 1; +} + +static void relocate_ramdisk(void) { + char * dest = (char*)final_offset; + char * src = (char*)ramdisk_off; + for (size_t s = 0; s < ramdisk_len; ++s) { + dest[s] = src[s]; + } + + modules_mboot[0].mod_start = final_offset; + modules_mboot[0].mod_end = final_offset + ramdisk_len; + + final_offset += ramdisk_len; + final_offset = (final_offset & ~(0xFFF)) + ((final_offset & 0xFFF) ? 0x1000 : 0); +} + +static void finish_boot(void) { + print("Setting up memory map...\n"); + print_hex(mmap_ent); + print("\n"); + memset(kernel_load_start, 0x00, 1024); + mboot_memmap_t * mmap = (void*)final_offset; + multiboot_header.mmap_addr = (uintptr_t)mmap; + multiboot_header.mods_addr = (uintptr_t)&modules_mboot; + multiboot_header.boot_loader_name = (uintptr_t)VERSION_TEXT; + + struct mmap_entry * e820 = (void*)0x5000; + + uint64_t upper_mem = 0; + for (int i = 0; i < mmap_ent; ++i) { + print("entry "); print_hex(i); + print(" "); print_hex((uint32_t)(e820[i].base >> 32ULL)); print_hex((uint32_t)e820[i].base); + print(" "); print_hex((uint32_t)(e820[i].len >> 32ULL)); print_hex((uint32_t)e820[i].len); + print(" "); print_hex(e820[i].type); print("\n"); + + mmap->size = sizeof(uint64_t) * 2 + sizeof(uintptr_t); + mmap->base_addr = e820[i].base; + mmap->length = e820[i].len; + mmap->type = e820[i].type; + if (mmap->type == 1 && mmap->base_addr >= 0x100000) { + upper_mem += mmap->length; + } + mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uintptr_t)); + } + multiboot_header.mmap_length = (uintptr_t)mmap - multiboot_header.mmap_addr; + + print("lower "); print_hex(lower_mem); print("KB\n"); + multiboot_header.mem_lower = 1024; + print("upper "); + print_hex(upper_mem >> 32); + print_hex(upper_mem); + print("\n"); + + multiboot_header.mem_upper = upper_mem / 1024; + + _ebx = (unsigned int)&multiboot_header; + _eax = MULTIBOOT_EAX_MAGIC; + + print_("Jumping...\n"); + + uint32_t foo[3]; + foo[0] = _eax; + foo[1] = _ebx; + foo[2] = _xmain; + __asm__ __volatile__ ( + "mov %%cr0,%%eax\n" + /* Disable paging */ + "and $0x7FFeFFFF, %%eax\n" + "mov %%eax,%%cr0\n" + /* Ensure PAE is not enabled */ + "mov %%cr4,%%eax\n" + "and $0xffffffdf, %%eax\n" + "mov %%eax,%%cr4\n" + "mov %1,%%eax \n" + "mov %2,%%ebx \n" + "jmp *%0" : : "g"(foo[2]), "g"(foo[0]), "g"(foo[1]) : "eax", "ebx" + ); +} + +void boot(void) { + clear_(); + print_("Looking for ISO9660 filesystem... "); + for (int i = 0x10; i < 0x15; ++i) { + root = (void*)(DATA_LOAD_BASE + ISO_SECTOR_SIZE * i); + switch (root->type) { + case 1: + print_("found.\n"); + goto done; + } + } + return; +done: + + print_("Looking for kernel... "); + if (!navigate(kernel_path)) { + print_("Failed to locate kernel.\n"); + return; + } + print_("found.\n"); + + kernel_load_start = (char*)(DATA_LOAD_BASE + dir_entry->extent_start_LSB * ISO_SECTOR_SIZE); + + print_("Looking for ramdisk... "); + if (!navigate(ramdisk_path)) { + print_("Failed to locate ramdisk.\n"); + return; + } + print_("found.\n"); + + ramdisk_off = DATA_LOAD_BASE + dir_entry->extent_start_LSB * ISO_SECTOR_SIZE; + ramdisk_len = dir_entry->extent_length_LSB; + + multiboot_header.cmdline = (uintptr_t)cmdline; + + print_("Loading kernel from 0x"); print_hex_((uint32_t)kernel_load_start); print_("... "); + if (!load_kernel()) { + print_("Failed to load kernel.\n"); + return; + } + + print_("Relocating ramdisk from 0x"); print_hex_((uint32_t)ramdisk_off); print_(":0x"); print_hex_(ramdisk_len); print_(" to 0x"); print_hex_(final_offset); print_("... "); + relocate_ramdisk(); + finish_boot(); +} + diff --git a/boot/multiboot.h b/boot/multiboot.h index 32f75f6f..39f866ee 100644 --- a/boot/multiboot.h +++ b/boot/multiboot.h @@ -93,4 +93,4 @@ extern struct multiboot *copy_multiboot(struct multiboot *mboot_ptr); extern void dump_multiboot(struct multiboot *mboot_ptr); extern char * ramdisk; extern struct multiboot * mboot_ptr; -static char cmdline[1024] = {0}; +extern void boot(void); diff --git a/boot/options.h b/boot/options.h index 7199ed83..d458f651 100644 --- a/boot/options.h +++ b/boot/options.h @@ -1,39 +1,22 @@ -static int sel_max = 0; -static int sel = 0; - -void toggle(int ndx, int value, char *str) { - set_attr(sel == ndx ? 0x70 : 0x07); - if (value) { - print_(" [X] "); - } else { - print_(" [ ] "); - } - print_(str); - if (x < 40) { - while (x < 39) { - print_(" "); - } - x = 40; - } else { - print_("\n"); - } -} +#pragma once struct option { int * value; char * title; char * description_1; char * description_2; -} boot_options[20] = {{0}}; /* can't really hold more than that */ +}; +extern struct option boot_options[20]; static int _boot_offset = 0; + #define BOOT_OPTION(_value, default_val, option, d1, d2) \ int _value = default_val;\ boot_options[_boot_offset].value = &_value; \ boot_options[_boot_offset].title = option; \ boot_options[_boot_offset].description_1 = d1; \ boot_options[_boot_offset].description_2 = d2; \ - _boot_offset++ + _boot_offset++; struct bootmode { int index; @@ -42,4 +25,14 @@ struct bootmode { }; #define BASE_SEL ((sizeof(boot_mode_names)/sizeof(*boot_mode_names))-1) +extern int base_sel; +extern char * VERSION_TEXT; +extern char * HELP_TEXT; +extern char * COPYRIGHT_TEXT; +extern char * LINK_TEXT; +extern char * kernel_path; +extern char * ramdisk_path; +extern char cmdline[1024]; + +extern struct bootmode boot_mode_names[]; diff --git a/boot/qemu.c b/boot/qemu.c new file mode 100644 index 00000000..6d60db19 --- /dev/null +++ b/boot/qemu.c @@ -0,0 +1,78 @@ +#include +#include "util.h" +#include "menu.h" +#include "options.h" +#include "text.h" + +struct fw_cfg_file { + uint32_t size; + uint16_t select; + uint16_t reserved; + char name[56]; +}; + + +void swap_bytes(void * in, int count) { + char * bytes = in; + if (count == 4) { + uint32_t * t = in; + *t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3]; + } else if (count == 2) { + uint16_t * t = in; + *t = (bytes[0] << 8) | bytes[1]; + } +} + +int detect_qemu(void) { +#if 1 + /* Try to detect qemu headless boot */ + outports(0x510, 0x0000); + if (inportb(0x511) == 'Q' && + inportb(0x511) == 'E' && + inportb(0x511) == 'M' && + inportb(0x511) == 'U') { + uint32_t count = 0; + uint8_t * bytes = (uint8_t *)&count; + outports(0x510,0x0019); + for (int i = 0; i < 4; ++i) { + bytes[i] = inportb(0x511); + } + swap_bytes(&count, 4); + + unsigned int bootmode_size = 0; + int bootmode_index = -1; + for (unsigned int i = 0; i < count; ++i) { + struct fw_cfg_file file; + uint8_t * tmp = (uint8_t *)&file; + for (int j = 0; j < sizeof(struct fw_cfg_file); ++j) { + tmp[j] = inportb(0x511); + } + if (!strcmp(file.name,"opt/org.toaruos.bootmode")) { + swap_bytes(&file.size, 4); + swap_bytes(&file.select, 2); + bootmode_size = file.size; + bootmode_index = file.select; + } + } + + if (bootmode_index != -1) { + outports(0x510, bootmode_index); + char tmp[33] = {0}; + for (int i = 0; i < 32 && i < bootmode_size; ++i) { + tmp[i] = inportb(0x511); + } + for (int i = 0; i < base_sel + 1; ++i) { + if (!strcmp(tmp,boot_mode_names[i].key)) { + boot_mode = boot_mode_names[i].index; + return 1; + } + } + print_("fw_cfg boot mode not recognized: "); + print_(tmp); + print_("\n"); + } + } +#endif + return 0; +} + diff --git a/boot/text.c b/boot/text.c new file mode 100644 index 00000000..4813c844 --- /dev/null +++ b/boot/text.c @@ -0,0 +1,95 @@ +#include "text.h" + +int txt_debug = 0; + +static unsigned short * textmemptr = (unsigned short *)0xB8000; + +static void placech(unsigned char c, int x, int y, int attr) { + unsigned short *where; + unsigned att = attr << 8; + where = textmemptr + (y * 80 + x); + *where = c | att; +} + +int x = 0; +int y = 0; +int attr = 0x07; + +void print_(char * str) { + while (*str) { + if (*str == '\n') { + for (; x < 80; ++x) { + placech(' ', x, y, attr); + } + x = 0; + y += 1; + if (y == 24) { + y = 0; + } + } else { + placech(*str, x, y, attr); + x++; + if (x == 80) { + x = 0; + y += 1; + if (y == 24) { + y = 0; + } + } + } + str++; + } +} + +void move_cursor(int _x, int _y) { + x = _x; + y = _y; +} + +void set_attr(int _attr) { + attr = _attr; +} + +void print_banner(char * str) { + if (!str) { + for (int i = 0; i < 80; ++i) { + placech(' ', i, y, attr); + } + y++; + return; + } + int len = 0; + char *c = str; + while (*c) { + len++; + c++; + } + int off = (80 - len) / 2; + + for (int i = 0; i < 80; ++i) { + placech(' ', i, y, attr); + } + for (int i = 0; i < len; ++i) { + placech(str[i], i + off, y, attr); + } + + y++; +} + +void print_hex_(unsigned int value) { + char out[9] = {0}; + for (int i = 7; i > -1; i--) { + out[i] = "0123456789abcdef"[(value >> (4 * (7 - i))) & 0xF]; + } + print_(out); +} + +void clear_() { + x = 0; + y = 0; + for (int y = 0; y < 24; ++y) { + for (int x = 0; x < 80; ++x) { + placech(' ', x, y, 0x00); + } + } +} diff --git a/boot/text.h b/boot/text.h index 776ecf76..eb50292c 100644 --- a/boot/text.h +++ b/boot/text.h @@ -1,145 +1,14 @@ #pragma once -static int txt_debug = 0; +extern int txt_debug, x, y, attr; -unsigned short * textmemptr = (unsigned short *)0xB8000; -static void placech(unsigned char c, int x, int y, int attr) { -#ifdef EFI_PLATFORM - unsigned short ch; - switch (c) { - case '\030': - ch = L'↑'; - break; - case '\031': - ch = L'↓'; - break; - case '\032': - ch = L'←'; - break; - case '\033': - ch = L'→'; - break; - default: - ch = c; - break; - } - uint16_t string[] = {ch, 0}; - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, attr); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x, y); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, string); -#else - unsigned short *where; - unsigned att = attr << 8; - where = textmemptr + (y * 80 + x); - *where = c | att; -#endif -} +void move_cursor(int _x, int _y); +void set_attr(int _attr); +void print_(char * str); +void print_hex_(unsigned int value); +void clear_(); -static int x = 0; -static int y = 0; -static int attr = 0x07; -static void print_(char * str) { - while (*str) { - if (*str == '\n') { - for (; x < 80; ++x) { - placech(' ', x, y, attr); - } - x = 0; - y += 1; - if (y == 24) { - y = 0; - } - } else { - placech(*str, x, y, attr); - x++; - if (x == 80) { - x = 0; - y += 1; - if (y == 24) { - y = 0; - } - } - } - str++; - } -} - -static void move_cursor(int _x, int _y) { - x = _x; - y = _y; -} - -static void set_attr(int _attr) { - attr = _attr; -} - -static void print_banner(char * str) { - if (!str) { - for (int i = 0; i < 80; ++i) { - placech(' ', i, y, attr); - } - y++; - return; - } - int len = 0; - char *c = str; - while (*c) { - len++; - c++; - } - int off = (80 - len) / 2; - - for (int i = 0; i < 80; ++i) { - placech(' ', i, y, attr); - } - for (int i = 0; i < len; ++i) { - placech(str[i], i + off, y, attr); - } - - y++; -} - -#ifdef EFI_PLATFORM -static void print_int_(unsigned int value) { - unsigned int n_width = 1; - unsigned int i = 9; - while (value > i && i < UINT32_MAX) { - n_width += 1; - i *= 10; - i += 9; - } - - char buf[n_width+1]; - buf[n_width] = 0; - i = n_width; - while (i > 0) { - unsigned int n = value / 10; - int r = value % 10; - buf[i - 1] = r + '0'; - i--; - value = n; - } - print_(buf); -} -#endif - -static void print_hex_(unsigned int value) { - char out[9] = {0}; - for (int i = 7; i > -1; i--) { - out[i] = "0123456789abcdef"[(value >> (4 * (7 - i))) & 0xF]; - } - print_(out); -} - -static void clear_() { - x = 0; - y = 0; - for (int y = 0; y < 24; ++y) { - for (int x = 0; x < 80; ++x) { - placech(' ', x, y, 0x00); - } - } -} +void print_banner(char * str); #define print(s) do {if (txt_debug) {print_(s);}} while(0) #define clear() do {if (txt_debug) {clear_();}} while(0) diff --git a/boot/util.c b/boot/util.c new file mode 100644 index 00000000..c1710cf1 --- /dev/null +++ b/boot/util.c @@ -0,0 +1,55 @@ +#include "util.h" + +void * memcpy(void * restrict dest, const void * restrict src, long n) { + asm volatile("cld; rep movsb" + : "=c"((int){0}) + : "D"(dest), "S"(src), "c"(n) + : "flags", "memory"); + return dest; +} + +void * memset(void * dest, int c, long n) { + asm volatile("cld; rep stosb" + : "=c"((int){0}) + : "D"(dest), "a"(c), "c"(n) + : "flags", "memory"); + return dest; +} + +int strcmp(const char * l, const char * r) { + for (; *l == *r && *l; l++, r++); + return *(unsigned char *)l - *(unsigned char *)r; +} + +char * strchr(const char * s, int c) { + while (*s) { + if (*s == c) { + return (char *)s; + } + s++; + } + return 0; +} + +char * strcat(char *dest, const char *src) { + char * end = dest; + while (*end != '\0') { + ++end; + } + while (*src) { + *end = *src; + end++; + src++; + } + *end = '\0'; + return dest; +} + +void copy_sectors(unsigned long lba, unsigned char * buf, int sectors) { + memcpy(buf, (char*)(lba * 2048 + DATA_LOAD_BASE), sectors * 2048); +} + +void copy_sector(unsigned long lba, unsigned char * buf) { + memcpy(buf, (char*)(lba * 2048 + DATA_LOAD_BASE), 2048); +} + diff --git a/boot/util.h b/boot/util.h index 1de1a451..40a45234 100644 --- a/boot/util.h +++ b/boot/util.h @@ -1,83 +1,45 @@ #pragma once -#define _inline inline __attribute__((always_inline)) - -static _inline unsigned short inports(unsigned short _port) { +static inline unsigned short inports(unsigned short _port) { unsigned short rv; asm volatile ("inw %1, %0" : "=a" (rv) : "dN" (_port)); return rv; } -static _inline void outports(unsigned short _port, unsigned short _data) { +static inline void outports(unsigned short _port, unsigned short _data) { asm volatile ("outw %1, %0" : : "dN" (_port), "a" (_data)); } -static _inline unsigned int inportl(unsigned short _port) { +static inline unsigned int inportl(unsigned short _port) { unsigned int rv; asm volatile ("inl %%dx, %%eax" : "=a" (rv) : "dN" (_port)); return rv; } -static _inline void outportl(unsigned short _port, unsigned int _data) { +static inline void outportl(unsigned short _port, unsigned int _data) { asm volatile ("outl %%eax, %%dx" : : "dN" (_port), "a" (_data)); } -static _inline unsigned char inportb(unsigned short _port) { +static inline unsigned char inportb(unsigned short _port) { unsigned char rv; asm volatile ("inb %1, %0" : "=a" (rv) : "dN" (_port)); return rv; } -static _inline void outportb(unsigned short _port, unsigned char _data) { +static inline void outportb(unsigned short _port, unsigned char _data) { asm volatile ("outb %1, %0" : : "dN" (_port), "a" (_data)); } - -static _inline void inportsm(unsigned short port, unsigned char * data, unsigned long size) { +static inline void inportsm(unsigned short port, unsigned char * data, unsigned long size) { asm volatile ("rep insw" : "+D" (data), "+c" (size) : "d" (port) : "memory"); } -static void * memcpy(void * restrict dest, const void * restrict src, long n) { - asm volatile("cld; rep movsb" - : "=c"((int){0}) - : "D"(dest), "S"(src), "c"(n) - : "flags", "memory"); - return dest; -} +void * memcpy(void * restrict dest, const void * restrict src, long n); +void * memset(void * dest, int c, long n); +int strcmp(const char * l, const char * r); +char * strchr(const char * s, int c); +char * strcat(char *dest, const char *src); +void copy_sectors(unsigned long lba, unsigned char * buf, int sectors); +void copy_sector(unsigned long lba, unsigned char * buf); -static void * memset(void * dest, int c, long n) { - asm volatile("cld; rep stosb" - : "=c"((int){0}) - : "D"(dest), "a"(c), "c"(n) - : "flags", "memory"); - return dest; -} - -static int strcmp(const char * l, const char * r) { - for (; *l == *r && *l; l++, r++); - return *(unsigned char *)l - *(unsigned char *)r; -} - -static char * strchr(const char * s, int c) { - while (*s) { - if (*s == c) { - return (char *)s; - } - s++; - } - return 0; -} - -static char * strcat(char *dest, const char *src) { - char * end = dest; - while (*end != '\0') { - ++end; - } - while (*src) { - *end = *src; - end++; - src++; - } - *end = '\0'; - return dest; -} +#define DATA_LOAD_BASE 0x4000000