This commit is contained in:
parent
612901612c
commit
7b0d0b8084
10
index.html
10
index.html
|
@ -46,7 +46,7 @@
|
||||||
<h4>Setup</h4>
|
<h4>Setup</h4>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="250">CD image</td>
|
<td width="350">CD image</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="file" id="cd_image">
|
<input type="file" id="cd_image">
|
||||||
</td>
|
</td>
|
||||||
|
@ -62,6 +62,14 @@
|
||||||
<td><input type="file" id="hd_image"><br></td>
|
<td><input type="file" id="hd_image"><br></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<tr>
|
||||||
|
<td>Multiboot kernel image (experimental)</td>
|
||||||
|
<td><input type="file" id="multiboot_image"><br></td>
|
||||||
|
</tr>
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><small><small>Disk images are not uploaded to the server</small></small><hr></td>
|
<td colspan="2"><small><small>Disk images are not uploaded to the server</small></small><hr></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -188,6 +188,16 @@
|
||||||
settings.hda = { buffer: hd_file };
|
settings.hda = { buffer: hd_file };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($("multiboot_image"))
|
||||||
|
{
|
||||||
|
var multiboot_file = $("multiboot_image").files[0];
|
||||||
|
if(multiboot_file)
|
||||||
|
{
|
||||||
|
last_file = multiboot_file;
|
||||||
|
settings.multiboot = { buffer: multiboot_file };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(last_file)
|
if(last_file)
|
||||||
{
|
{
|
||||||
set_title(last_file.name);
|
set_title(last_file.name);
|
||||||
|
@ -474,6 +484,7 @@
|
||||||
settings.fda = infos.fda;
|
settings.fda = infos.fda;
|
||||||
settings.cdrom = infos.cdrom;
|
settings.cdrom = infos.cdrom;
|
||||||
settings.hda = infos.hda
|
settings.hda = infos.hda
|
||||||
|
settings.multiboot = infos.multiboot
|
||||||
|
|
||||||
settings.memory_size = infos.memory_size;
|
settings.memory_size = infos.memory_size;
|
||||||
settings.vga_memory_size = infos.vga_memory_size;
|
settings.vga_memory_size = infos.vga_memory_size;
|
||||||
|
@ -689,6 +700,8 @@
|
||||||
"hda": settings.hda,
|
"hda": settings.hda,
|
||||||
"cdrom": settings.cdrom,
|
"cdrom": settings.cdrom,
|
||||||
|
|
||||||
|
"multiboot": settings.multiboot,
|
||||||
|
|
||||||
"initial_state": settings.initial_state,
|
"initial_state": settings.initial_state,
|
||||||
"filesystem": settings.filesystem || {},
|
"filesystem": settings.filesystem || {},
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,10 @@ function V86Starter(options)
|
||||||
settings.fdb = this.disk_images["fdb"] = buffer;
|
settings.fdb = this.disk_images["fdb"] = buffer;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "multiboot":
|
||||||
|
settings.multiboot = this.disk_images["multiboot"] = buffer;
|
||||||
|
break;
|
||||||
|
|
||||||
case "bios":
|
case "bios":
|
||||||
settings.bios = buffer.buffer;
|
settings.bios = buffer.buffer;
|
||||||
break;
|
break;
|
||||||
|
@ -211,7 +215,8 @@ function V86Starter(options)
|
||||||
size: file["size"],
|
size: file["size"],
|
||||||
};
|
};
|
||||||
|
|
||||||
if(name === "bios" || name === "vga_bios" || name === "initial_state")
|
if(name === "bios" || name === "vga_bios" ||
|
||||||
|
name === "initial_state" || name === "multiboot")
|
||||||
{
|
{
|
||||||
// Ignore async for these because they must be availabe before boot.
|
// Ignore async for these because they must be availabe before boot.
|
||||||
// This should make result.buffer available after the object is loaded
|
// This should make result.buffer available after the object is loaded
|
||||||
|
@ -285,7 +290,7 @@ function V86Starter(options)
|
||||||
var image_names = [
|
var image_names = [
|
||||||
"bios", "vga_bios",
|
"bios", "vga_bios",
|
||||||
"cdrom", "hda", "hdb", "fda", "fdb",
|
"cdrom", "hda", "hdb", "fda", "fdb",
|
||||||
"initial_state",
|
"initial_state", "multiboot",
|
||||||
];
|
];
|
||||||
|
|
||||||
for(var i = 0; i < image_names.length; i++)
|
for(var i = 0; i < image_names.length; i++)
|
||||||
|
|
179
src/cpu.js
179
src/cpu.js
|
@ -720,12 +720,191 @@ CPU.prototype.init = function(settings, device_bus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(settings.multiboot)
|
||||||
|
{
|
||||||
|
dbg_assert(settings.multiboot.buffer);
|
||||||
|
this.load_multiboot(settings.multiboot.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
if(DEBUG)
|
if(DEBUG)
|
||||||
{
|
{
|
||||||
this.debug.init();
|
this.debug.init();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CPU.prototype.load_multiboot = function(buffer)
|
||||||
|
{
|
||||||
|
// https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
|
||||||
|
|
||||||
|
dbg_log("Trying multiboot from buffer of size " + buffer.byteLength, LOG_CPU);
|
||||||
|
|
||||||
|
const MAGIC = 0x1BADB002;
|
||||||
|
const ELF_MAGIC = 0x464C457F;
|
||||||
|
const MULTIBOOT_HEADER_ADDRESS = 0x10000;
|
||||||
|
const MULTIBOOT_SEARCH_BYTES = 8192;
|
||||||
|
|
||||||
|
var buf32 = new Int32Array(buffer);
|
||||||
|
|
||||||
|
for(var offset = 0; offset < MULTIBOOT_SEARCH_BYTES; offset += 4)
|
||||||
|
{
|
||||||
|
if(buf32[offset >> 2] === MAGIC)
|
||||||
|
{
|
||||||
|
var flags = buf32[offset + 4 >> 2];
|
||||||
|
var checksum = buf32[offset + 8 >> 2];
|
||||||
|
var total = MAGIC + flags + checksum | 0;
|
||||||
|
|
||||||
|
if(total)
|
||||||
|
{
|
||||||
|
dbg_log("Multiboot checksum check failed", LOG_CPU);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_log("Multiboot magic found, flags: " + h(flags >>> 0, 8), LOG_CPU);
|
||||||
|
dbg_assert((flags & ~MULTIBOOT_HEADER_ADDRESS) === 0, "TODO");
|
||||||
|
|
||||||
|
this.reg32s[reg_eax] = 0x2BADB002;
|
||||||
|
|
||||||
|
let multiboot_info_addr = 0x7C00
|
||||||
|
this.reg32s[reg_ebx] = multiboot_info_addr;
|
||||||
|
this.write32(multiboot_info_addr, 0);
|
||||||
|
|
||||||
|
this.cr[0] = 1;
|
||||||
|
this.protected_mode = true;
|
||||||
|
this.flags = flags_default
|
||||||
|
this.update_cs_size(true);
|
||||||
|
this.stack_size_32 = true;
|
||||||
|
|
||||||
|
for(var i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
this.segment_is_null[i] = 0;
|
||||||
|
this.segment_offsets[i] = 0;
|
||||||
|
this.segment_limits[i] = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
// Value doesn't matter, OS isn't allowed to reload without setting
|
||||||
|
// up a proper GDT
|
||||||
|
this.sreg[i] = 0xB002;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flags & MULTIBOOT_HEADER_ADDRESS)
|
||||||
|
{
|
||||||
|
dbg_log("Multiboot specifies its own address table", LOG_CPU);
|
||||||
|
|
||||||
|
var header_addr = buf32[offset + 12 >> 2];
|
||||||
|
var load_addr = buf32[offset + 16 >> 2];
|
||||||
|
var load_end_addr = buf32[offset + 20 >> 2];
|
||||||
|
var bss_end_addr = buf32[offset + 24 >> 2];
|
||||||
|
var entry_addr = buf32[offset + 28 >> 2];
|
||||||
|
|
||||||
|
dbg_log("header=" + h(header_addr, 8) +
|
||||||
|
" load=" + h(load_addr, 8) +
|
||||||
|
" load_end=" + h(load_end_addr, 8) +
|
||||||
|
" bss_end=" + h(bss_end_addr, 8) +
|
||||||
|
" entry=" + h(entry_addr, 8))
|
||||||
|
|
||||||
|
dbg_assert(load_addr <= header_addr);
|
||||||
|
|
||||||
|
var file_start = offset - (header_addr - load_addr);
|
||||||
|
|
||||||
|
if(load_end_addr === 0)
|
||||||
|
{
|
||||||
|
var length = undefined;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbg_assert(load_end_addr >= load_addr);
|
||||||
|
var length = load_end_addr - load_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let blob = new Uint8Array(buffer, file_start, length);
|
||||||
|
this.write_blob(blob, load_addr);
|
||||||
|
|
||||||
|
this.instruction_pointer = this.get_seg(reg_cs) + entry_addr | 0;
|
||||||
|
}
|
||||||
|
else if(buf32[0] === ELF_MAGIC)
|
||||||
|
{
|
||||||
|
dbg_log("Multiboot image is in elf format", LOG_CPU);
|
||||||
|
|
||||||
|
let elf = read_elf(buffer);
|
||||||
|
|
||||||
|
this.instruction_pointer = this.get_seg(reg_cs) + elf.header.entry | 0;
|
||||||
|
|
||||||
|
for(let program of elf.program_headers)
|
||||||
|
{
|
||||||
|
if(program.type === 0)
|
||||||
|
{
|
||||||
|
// null
|
||||||
|
}
|
||||||
|
else if(program.type === 1)
|
||||||
|
{
|
||||||
|
// load
|
||||||
|
|
||||||
|
// Since multiboot specifies that paging is disabled,
|
||||||
|
// virtual and physical address must be equal
|
||||||
|
dbg_assert(program.paddr === program.vaddr);
|
||||||
|
dbg_assert(program.filesz <= program.memsz);
|
||||||
|
|
||||||
|
let blob = new Uint8Array(buffer, program.offset, program.filesz);
|
||||||
|
this.write_blob(blob, program.paddr);
|
||||||
|
}
|
||||||
|
else if(program.type === 4 ||
|
||||||
|
program.type === 0x6474e550 ||
|
||||||
|
program.type === 0x6474e551)
|
||||||
|
{
|
||||||
|
// ignore for now
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbg_assert(false, "unimplemented elf section type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbg_assert(false, "Not a bootable multiboot format");
|
||||||
|
}
|
||||||
|
|
||||||
|
// only for kvm-unit-test
|
||||||
|
this.io.register_write_consecutive(0xF4, this,
|
||||||
|
function(value)
|
||||||
|
{
|
||||||
|
console.log("Test exited with code " + h(value, 2));
|
||||||
|
throw "HALT";
|
||||||
|
},
|
||||||
|
function() {},
|
||||||
|
function() {},
|
||||||
|
function() {});
|
||||||
|
|
||||||
|
// only for kvm-unit-test
|
||||||
|
for(let i = 0xE; i <= 0xF; i++)
|
||||||
|
{
|
||||||
|
this.io.register_write(0x2000 + i, this,
|
||||||
|
function(value)
|
||||||
|
{
|
||||||
|
dbg_log("kvm-unit-test: Set irq " + h(i) + " to " + h(value, 2));
|
||||||
|
if(value)
|
||||||
|
{
|
||||||
|
this.device_raise_irq(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.device_lower_irq(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_log("Starting multiboot kernel at:", LOG_CPU);
|
||||||
|
this.debug.dump_state();
|
||||||
|
this.debug.dump_regs();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
CPU.prototype.fill_cmos = function(rtc, settings)
|
CPU.prototype.fill_cmos = function(rtc, settings)
|
||||||
{
|
{
|
||||||
var boot_order = settings.boot_order || 0x213;
|
var boot_order = settings.boot_order || 0x213;
|
||||||
|
|
Loading…
Reference in a new issue