boot: Jump back to real mode to load sectors?

This commit is contained in:
K. Lange 2021-10-19 20:10:59 +09:00
parent 6ed0e72278
commit a9b853d24c
3 changed files with 168 additions and 61 deletions

View File

@ -73,16 +73,6 @@ can_long:
jmp _oh_no
good_memory:
/* Print "Loading..." */
movl $str_Loading, %esi
call print_string
/* 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
@ -102,52 +92,7 @@ _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
/* Update spinner */
movl ind_Spinny, %ecx
inc %ecx
and $0x3FF, %ecx
movl %ecx, ind_Spinny
shr $8, %ecx
movb str_Spinny(%ecx), %ah
mov $0xb8016, %ecx
movb %ah, (%ecx)
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
@ -240,6 +185,100 @@ print_string.loop:
print_string.exit:
ret
pm_stack:
.quad 0
.global do_bios_call
do_bios_call:
.code32
/* Standard function entry point stuff */
push %ebp
mov %esp, %ebp
push %ebx
push %edi
push %esi
/* Save stack because bios might mess it up? */
movl %esp, %eax
movl %eax, (pm_stack)
/* Prepare intermediary mode */
mov $0x20, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
/* Enable intermediary mode */
ljmp $0x18,$do_bios_call.0
do_bios_call.0:
.code16
/* Disable protected mode */
mov %cr0, %eax
and $~1, %eax
mov %eax, %cr0
/* Jump to deactivate protected mode */
ljmp $0x0,$do_bios_call.1
do_bios_call.1:
/* Set up real mode segments */
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
/* Enable interrupts while BIOS is active */
sti
/* Perform disk read */
mov $0x42, %ah /* Extended read */
mov boot_disk, %dl /* Using our boot disk */
mov $dap, %si /* From the DAP below */
int $0x13
/* Disable interrupts again */
cli
/* Restore data segment, gdt */
xor %ax,%ax
mov %ax, %ds
lgdtw gdtr
/* Enable protected mode */
mov %cr0, %eax
or $1, %eax
mov %eax, %cr0
/* Jump to activate protected mode */
ljmp $0x08,$do_bios_call.2
do_bios_call.2:
.code32
/* Restore protected mode data segments */
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
/* Restore stack */
movl (pm_stack), %eax
movl %eax, %esp
/* Pop callee-saved registers we may messed with */
pop %esi
pop %edi
pop %ebx
pop %ebp
/* Return */
ret
.align 8
gdtr:
.word gdt_end - gdt_base - 1
@ -253,12 +292,27 @@ gdt_base:
.byte 0x9a
.byte 0xcf
.byte 0
.word 0xffff
.word 0
.byte 0
.byte 0x92
.byte 0xcf
.byte 0
.word 0xffff
.word 0
.byte 0
.byte 0x9e
.byte 0
.byte 0
.word 0xffff
.word 0
.byte 0
.byte 0x92
.byte 0
.byte 0
gdt_end:
.global boot_disk
@ -286,8 +340,10 @@ dap_sectors:
.global dap_buffer
dap_buffer:
.long 0x0
.global dap_lba_low
dap_lba_low:
.long 0
.global dap_lba_high
dap_lba_high:
.long 0
@ -305,13 +361,13 @@ drive_params_bps:
str_Bad:
.asciz "The boot disk does not seem to be a CD."
str_Loading:
.asciz "Loading... "
str_Need_long:
.asciz "ToaruOS 2.0 requires a 64-bit processor."
str_More_mem:
.asciz "ToaruOS 2.0 needs at least 128MiB of RAM, and 1GiB is recommended."
str_Spinny:
.byte '|','/','-','\\'
ind_Spinny:
.long 0
str_Out_of_modes:
.asciz "Out of display modes"
.global disk_space
disk_space:
.zero 2048

View File

@ -589,10 +589,26 @@ static void finish_boot(void) {
);
}
extern int bios_call(char * into, uint32_t sector);
static int spin_x = 0;
static void spin(void) {
static char spinchars[] = "/-\\|";
static char tmp[] = "x";
static int spincnt = 0;
x = spin_x;
spincnt = (spincnt + 1) & 0x3;
tmp[0] = spinchars[spincnt];
print_(tmp);
}
void boot(void) {
clear_();
print("Looking for ISO9660 filesystem... ");
for (int i = 0x10; i < 0x15; ++i) {
bios_call((char*)(DATA_LOAD_BASE + ISO_SECTOR_SIZE * i), i);
root = (void*)(DATA_LOAD_BASE + ISO_SECTOR_SIZE * i);
switch (root->type) {
case 1:
@ -612,6 +628,14 @@ done:
kernel_load_start = (char*)(DATA_LOAD_BASE + dir_entry->extent_start_LSB * ISO_SECTOR_SIZE);
print_("Loading kernel... "); spin_x = x;
for (int i = 0, j = 0; i < dir_entry->extent_length_LSB; j++) {
if (!(j & 0x3FF)) spin();
bios_call(kernel_load_start + i, dir_entry->extent_start_LSB + j);
i += ISO_SECTOR_SIZE;
}
print_("\n");
print("Looking for ramdisk... ");
if (!navigate(ramdisk_path)) {
print_("Failed to locate ramdisk.\n");
@ -620,6 +644,15 @@ done:
print("found.\n");
ramdisk_off = DATA_LOAD_BASE + dir_entry->extent_start_LSB * ISO_SECTOR_SIZE;
print_("Loading ramdisk... "); spin_x = x;
for (int i = 0, j = 0; i < dir_entry->extent_length_LSB; j++) {
if (!(j & 0x3FF)) spin();
bios_call((char*)(ramdisk_off + i), dir_entry->extent_start_LSB + j);
i += ISO_SECTOR_SIZE;
}
print_("\n");
ramdisk_len = dir_entry->extent_length_LSB;
multiboot_header.cmdline = (uintptr_t)cmdline;

View File

@ -64,13 +64,31 @@ int bios_main(void) {
return kmain();
}
extern void do_bios_call(void);
extern volatile uint16_t dap_sectors;
extern volatile uint32_t dap_buffer;
extern volatile uint32_t dap_lba_low;
extern volatile uint32_t dap_lba_high;
extern uint8_t disk_space[];
int bios_call(char * into, uint32_t sector) {
dap_buffer = (uint32_t)disk_space;
dap_lba_low = sector;
dap_lba_high = 0;
dap_sectors = 1;
do_bios_call();
memcpy(into, disk_space, 2048);
}
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);
bios_call(dir_entries, dir_entry->extent_start_LSB);
long offset = 0;
while (1) {
iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)(dir_entries + offset);