boot: Rewrite the legacy BIOS loader
This commit is contained in:
parent
914dc15f02
commit
e680a7a61f
6
Makefile
6
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
|
||||
|
154
boot/ata.h
154
boot/ata.h
@ -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;
|
245
boot/atapi_imp.h
245
boot/atapi_imp.h
@ -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)
|
184
boot/boot.S
184
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:
|
||||
|
@ -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
49
boot/iso9660.c
Normal 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;
|
||||
}
|
||||
|
||||
|
@ -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
11
boot/kbd.c
Normal 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;
|
||||
}
|
48
boot/kbd.h
48
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
|
||||
|
137
boot/menu.c
Normal file
137
boot/menu.c
Normal 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
4
boot/menu.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
extern int boot_mode;
|
||||
void show_menu(void);
|
@ -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
220
boot/multiboot.c
Normal 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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
78
boot/qemu.c
Normal 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
95
boot/text.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
145
boot/text.h
145
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)
|
||||
|
55
boot/util.c
Normal file
55
boot/util.c
Normal 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);
|
||||
}
|
||||
|
68
boot/util.h
68
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
|
||||
|
Loading…
Reference in New Issue
Block a user