boot: Rewrite the legacy BIOS loader

This commit is contained in:
K. Lange 2021-06-14 11:11:37 +09:00
parent 914dc15f02
commit e680a7a61f
20 changed files with 870 additions and 1218 deletions

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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:

View File

@ -1,29 +1,24 @@
#include <stdint.h>
#include <stddef.h>
#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 <Enter> 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 <Enter> 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[];

49
boot/iso9660.c Normal file
View File

@ -0,0 +1,49 @@
#include <stddef.h>
#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;
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <stdint.h>
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);

11
boot/kbd.c Normal file
View File

@ -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;
}

View File

@ -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

137
boot/menu.c Normal file
View File

@ -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);
}

4
boot/menu.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
extern int boot_mode;
void show_menu(void);

View File

@ -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);
}

220
boot/multiboot.c Normal file
View File

@ -0,0 +1,220 @@
#include <stdint.h>
#include <stddef.h>
#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();
}

View File

@ -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);

View File

@ -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[];

78
boot/qemu.c Normal file
View File

@ -0,0 +1,78 @@
#include <stdint.h>
#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;
}

95
boot/text.c Normal file
View File

@ -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);
}
}
}

View File

@ -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)

55
boot/util.c Normal file
View File

@ -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);
}

View File

@ -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