diff options
Diffstat (limited to 'tools/ioemu/iodev/load32bitOShack.cc')
-rw-r--r-- | tools/ioemu/iodev/load32bitOShack.cc | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/tools/ioemu/iodev/load32bitOShack.cc b/tools/ioemu/iodev/load32bitOShack.cc new file mode 100644 index 0000000000..6a0a4904d8 --- /dev/null +++ b/tools/ioemu/iodev/load32bitOShack.cc @@ -0,0 +1,322 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: load32bitOShack.cc,v 1.14 2003/08/08 00:05:53 cbothamy Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + + +#include "bochs.h" +#define LOG_THIS genlog-> + + + +static void bx_load_linux_hack(void); +static void bx_load_null_kernel_hack(void); +static Bit32u bx_load_kernel_image(char *path, Bit32u paddr); + + void +bx_load32bitOSimagehack(void) +{ + // Replay IO from log to initialize IO devices to + // a reasonable state needed for the OS. This is done + // in lieu of running the 16-bit BIOS to init things, + // since we want to test straight 32bit stuff for + // freemware. + +#ifndef BX_USE_VMX + FILE *fp; + + fp = fopen(bx_options.load32bitOSImage.Oiolog->getptr (), "r"); + + if (fp == NULL) { + BX_PANIC(("could not open IO init file.")); + } + + while (1) { + unsigned len, op, port, val; + int ret; + ret = fscanf(fp, "%u %u %x %x\n", + &len, &op, &port, &val); + if (ret != 4) { + BX_PANIC(("could not open IO init file.")); + } + if (op == 0) { + // read + (void) bx_devices.inp(port, len); + } + else if (op == 1) { + // write + bx_devices.outp(port, val, len); + } + else { + BX_PANIC(("bad IO op in init filen")); + } + if (feof(fp)) break; + } +#endif + + // Invoke proper hack depending on which OS image we're loading + switch (bx_options.load32bitOSImage.OwhichOS->get ()) { + case Load32bitOSLinux: + bx_load_linux_hack(); + break; + case Load32bitOSNullKernel: + bx_load_null_kernel_hack(); + break; + default: + BX_PANIC(("load32bitOSImage: OS not recognized")); + } +} + +struct gdt_entry +{ + Bit32u low; + Bit32u high; +}; +struct linux_setup_params +{ + /* 0x000 */ Bit8u orig_x; + /* 0x001 */ Bit8u orig_y; + /* 0x002 */ Bit16u memory_size_std; + /* 0x004 */ Bit16u orig_video_page; + /* 0x006 */ Bit8u orig_video_mode; + /* 0x007 */ Bit8u orig_video_cols; + /* 0x008 */ Bit16u unused1; + /* 0x00a */ Bit16u orig_video_ega_bx; + /* 0x00c */ Bit16u unused2; + /* 0x00e */ Bit8u orig_video_lines; + /* 0x00f */ Bit8u orig_video_isVGA; + /* 0x010 */ Bit16u orig_video_points; + /* 0x012 */ Bit8u pad1[0x40 - 0x12]; + /* 0x040 */ Bit8u apm_info[0x80 - 0x40]; + /* 0x080 */ Bit8u hd0_info[16]; + /* 0x090 */ Bit8u hd1_info[16]; + /* 0x0a0 */ Bit8u pad2[0x1e0 - 0xa0]; + /* 0x1e0 */ Bit32u memory_size_ext; + /* 0x1e4 */ Bit8u pad3[0x1f1 - 0x1e4]; + /* 0x1f1 */ Bit8u setup_sects; + /* 0x1f2 */ Bit16u mount_root_rdonly; + /* 0x1f4 */ Bit16u sys_size; + /* 0x1f6 */ Bit16u swap_dev; + /* 0x1f8 */ Bit16u ramdisk_flags; + /* 0x1fa */ Bit16u vga_mode; + /* 0x1fc */ Bit16u orig_root_dev; + /* 0x1fe */ Bit16u bootsect_magic; + /* 0x200 */ Bit8u pad4[0x210 - 0x200]; + /* 0x210 */ Bit32u loader_type; + /* 0x214 */ Bit32u kernel_start; + /* 0x218 */ Bit32u initrd_start; + /* 0x21c */ Bit32u initrd_size; + /* 0x220 */ Bit8u pad5[0x400 - 0x220]; + /* 0x400 */ struct gdt_entry gdt[128]; + /* 0x800 */ Bit8u commandline[2048]; +}; + + static void +bx_load_linux_setup_params( Bit32u initrd_start, Bit32u initrd_size ) +{ + BX_MEM_C *mem = BX_MEM(0); + struct linux_setup_params *params = + (struct linux_setup_params *) &mem->vector[0x00090000]; + + memset( params, '\0', sizeof(*params) ); + + /* Video settings (standard VGA) */ + params->orig_x = 0; + params->orig_y = 0; + params->orig_video_page = 0; + params->orig_video_mode = 3; + params->orig_video_cols = 80; + params->orig_video_lines = 25; + params->orig_video_points = 16; + params->orig_video_isVGA = 1; + params->orig_video_ega_bx = 3; + + /* Memory size (total mem - 1MB, in KB) */ + params->memory_size_ext = (mem->megabytes - 1) * 1024; + + /* Boot parameters */ + params->loader_type = 1; + params->bootsect_magic = 0xaa55; + params->mount_root_rdonly = 0; + params->orig_root_dev = 0x0100; + params->initrd_start = initrd_start; + params->initrd_size = initrd_size; + + /* Initial GDT */ + params->gdt[2].high = 0x00cf9a00; + params->gdt[2].low = 0x0000ffff; + params->gdt[3].high = 0x00cf9200; + params->gdt[3].low = 0x0000ffff; +} + + void +bx_load_linux_hack(void) +{ +#ifndef BX_USE_VMX + Bit32u initrd_start = 0, initrd_size = 0; + + // The RESET function will have been called first. + // Set CPU and memory features which are assumed at this point. + + // Load Linux kernel image + bx_load_kernel_image( bx_options.load32bitOSImage.Opath->getptr (), 0x100000 ); + + // Load initial ramdisk image if requested + if ( bx_options.load32bitOSImage.Oinitrd->getptr () ) + { + initrd_start = 0x00800000; /* FIXME: load at top of memory */ + initrd_size = bx_load_kernel_image( bx_options.load32bitOSImage.Oinitrd->getptr (), initrd_start ); + } + + // Setup Linux startup parameters buffer + bx_load_linux_setup_params( initrd_start, initrd_size ); +#endif + + // Enable A20 line + BX_SET_ENABLE_A20( 1 ); + + // Setup PICs the way Linux likes it + BX_OUTP( 0x20, 0x11, 1 ); + BX_OUTP( 0xA0, 0x11, 1 ); + BX_OUTP( 0x21, 0x20, 1 ); + BX_OUTP( 0xA1, 0x28, 1 ); + BX_OUTP( 0x21, 0x04, 1 ); + BX_OUTP( 0xA1, 0x02, 1 ); + BX_OUTP( 0x21, 0x01, 1 ); + BX_OUTP( 0xA1, 0x01, 1 ); + BX_OUTP( 0x21, 0xFF, 1 ); + BX_OUTP( 0xA1, 0xFB, 1 ); + +#ifndef BX_USE_VMX + // Disable interrupts and NMIs + BX_CPU(0)->clear_IF (); +#endif + + BX_OUTP( 0x70, 0x80, 1 ); + +#ifndef BX_USE_VMX + // Enter protected mode + // Fixed by george (kyriazis at nvidia.com) + // BX_CPU(0)->cr0.pe = 1; + // BX_CPU(0)->cr0.val32 |= 0x01; + + BX_CPU(0)->SetCR0(BX_CPU(0)->cr0.val32 | 0x01); + + // load esi with real_mode + BX_CPU(0)->gen_reg[BX_32BIT_REG_ESI].dword.erx = 0x90000; + + // Set up initial GDT + BX_CPU(0)->gdtr.limit = 0x400; + BX_CPU(0)->gdtr.base = 0x00090400; + + // Jump to protected mode entry point + BX_CPU(0)->jump_protected( NULL, 0x10, 0x00100000 ); +#endif +} + + void +bx_load_null_kernel_hack(void) +{ +#ifndef BX_USE_VMX + // The RESET function will have been called first. + // Set CPU and memory features which are assumed at this point. + + bx_load_kernel_image(bx_options.load32bitOSImage.Opath->getptr (), 0x100000); + + // EIP deltas + BX_CPU(0)->prev_eip = + BX_CPU(0)->dword.eip = 0x00100000; + + // CS deltas + BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.base = 0x00000000; + BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFFF; + BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; + BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // page gran + BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1; // 32bit + + // DS deltas + BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.base = 0x00000000; + BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.limit = 0xFFFFF; + BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled = 0xFFFFFFFF; + BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.g = 1; // page gran + BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.d_b = 1; // 32bit + + // CR0 deltas + BX_CPU(0)->cr0.pe = 1; // protected mode +#endif // BX_USE_VMX +} + + Bit32u +bx_load_kernel_image(char *path, Bit32u paddr) +{ + struct stat stat_buf; + int fd, ret; + unsigned long size, offset; + Bit32u page_size; + + // read in ROM BIOS image file + fd = open(path, O_RDONLY +#ifdef O_BINARY + | O_BINARY +#endif + ); + if (fd < 0) { + BX_INFO(( "load_kernel_image: couldn't open image file '%s'.", path )); + BX_EXIT(1); + } + ret = fstat(fd, &stat_buf); + if (ret) { + BX_INFO(( "load_kernel_image: couldn't stat image file '%s'.", path )); + BX_EXIT(1); + } + + size = stat_buf.st_size; + page_size = ((Bit32u)size + 0xfff) & ~0xfff; + + BX_MEM_C *mem = BX_MEM(0); + if ( (paddr + size) > mem->len ) { + BX_INFO(( "load_kernel_image: address range > physical memsize!" )); + BX_EXIT(1); + } + + offset = 0; + while (size > 0) { + ret = read(fd, (bx_ptr_t) &mem->vector[paddr + offset], size); + if (ret <= 0) { + BX_INFO(( "load_kernel_image: read failed on image" )); + BX_EXIT(1); + } + size -= ret; + offset += ret; + } + close(fd); + BX_INFO(( "#(%u) load_kernel_image: '%s', size=%u read into memory at %08x", + BX_SIM_ID, path, + (unsigned) stat_buf.st_size, + (unsigned) paddr )); + + return page_size; +} |