Commit 0824d6fc674084519c856c433887221be099c549

Authored by bellard
1 parent 6c0372d3

for hard core developpers only: a new user mode linux project :-)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@267 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 1387 additions and 0 deletions
Makefile
... ... @@ -135,6 +135,10 @@ ifeq ($(ARCH),alpha)
135 135 echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
136 136 endif
137 137  
  138 +# must use static linking to avoid leaving stuff in virtual address space
  139 +vl: vl.o libqemu.a
  140 + $(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS)
  141 +
138 142 depend: $(SRCS)
139 143 $(CC) -MM $(CFLAGS) $^ 1>.depend
140 144  
... ...
vl.c 0 → 100644
  1 +/*
  2 + * QEMU based User Mode Linux
  3 + *
  4 + * This file is part of proprietary software - it is published here
  5 + * only for demonstration and information purposes.
  6 + *
  7 + * Copyright (c) 2003 Fabrice Bellard
  8 + */
  9 +#include <stdlib.h>
  10 +#include <stdio.h>
  11 +#include <string.h>
  12 +#include <getopt.h>
  13 +#include <inttypes.h>
  14 +#include <unistd.h>
  15 +#include <sys/mman.h>
  16 +#include <fcntl.h>
  17 +#include <signal.h>
  18 +#include <time.h>
  19 +#include <sys/time.h>
  20 +#include <malloc.h>
  21 +#include <termios.h>
  22 +#include <sys/poll.h>
  23 +#include <errno.h>
  24 +
  25 +#include "cpu-i386.h"
  26 +#include "disas.h"
  27 +
  28 +#define DEBUG_LOGFILE "/tmp/vl.log"
  29 +//#define DEBUG_UNUSED_IOPORT
  30 +
  31 +#define PHYS_RAM_BASE 0xa8000000
  32 +#define KERNEL_LOAD_ADDR 0x00100000
  33 +#define INITRD_LOAD_ADDR 0x00400000
  34 +#define KERNEL_PARAMS_ADDR 0x00090000
  35 +
  36 +/* from plex86 (BSD license) */
  37 +struct __attribute__ ((packed)) linux_params {
  38 + // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h.
  39 + // I just padded out the VESA parts, rather than define them.
  40 +
  41 + /* 0x000 */ uint8_t orig_x;
  42 + /* 0x001 */ uint8_t orig_y;
  43 + /* 0x002 */ uint16_t ext_mem_k;
  44 + /* 0x004 */ uint16_t orig_video_page;
  45 + /* 0x006 */ uint8_t orig_video_mode;
  46 + /* 0x007 */ uint8_t orig_video_cols;
  47 + /* 0x008 */ uint16_t unused1;
  48 + /* 0x00a */ uint16_t orig_video_ega_bx;
  49 + /* 0x00c */ uint16_t unused2;
  50 + /* 0x00e */ uint8_t orig_video_lines;
  51 + /* 0x00f */ uint8_t orig_video_isVGA;
  52 + /* 0x010 */ uint16_t orig_video_points;
  53 + /* 0x012 */ uint8_t pad0[0x20 - 0x12]; // VESA info.
  54 + /* 0x020 */ uint16_t cl_magic; // Commandline magic number (0xA33F)
  55 + /* 0x022 */ uint16_t cl_offset; // Commandline offset. Address of commandline
  56 + // is calculated as 0x90000 + cl_offset, bu
  57 + // only if cl_magic == 0xA33F.
  58 + /* 0x024 */ uint8_t pad1[0x40 - 0x24]; // VESA info.
  59 +
  60 + /* 0x040 */ uint8_t apm_bios_info[20]; // struct apm_bios_info
  61 + /* 0x054 */ uint8_t pad2[0x80 - 0x54];
  62 +
  63 + // Following 2 from 'struct drive_info_struct' in drivers/block/cciss.h.
  64 + // Might be truncated?
  65 + /* 0x080 */ uint8_t hd0_info[16]; // hd0-disk-parameter from intvector 0x41
  66 + /* 0x090 */ uint8_t hd1_info[16]; // hd1-disk-parameter from intvector 0x46
  67 +
  68 + // System description table truncated to 16 bytes
  69 + // From 'struct sys_desc_table_struct' in linux/arch/i386/kernel/setup.c.
  70 + /* 0x0a0 */ uint16_t sys_description_len;
  71 + /* 0x0a2 */ uint8_t sys_description_table[14];
  72 + // [0] machine id
  73 + // [1] machine submodel id
  74 + // [2] BIOS revision
  75 + // [3] bit1: MCA bus
  76 +
  77 + /* 0x0b0 */ uint8_t pad3[0x1e0 - 0xb0];
  78 + /* 0x1e0 */ uint32_t alt_mem_k;
  79 + /* 0x1e4 */ uint8_t pad4[4];
  80 + /* 0x1e8 */ uint8_t e820map_entries;
  81 + /* 0x1e9 */ uint8_t eddbuf_entries; // EDD_NR
  82 + /* 0x1ea */ uint8_t pad5[0x1f1 - 0x1ea];
  83 + /* 0x1f1 */ uint8_t setup_sects; // size of setup.S, number of sectors
  84 + /* 0x1f2 */ uint16_t mount_root_rdonly; // MOUNT_ROOT_RDONLY (if !=0)
  85 + /* 0x1f4 */ uint16_t sys_size; // size of compressed kernel-part in the
  86 + // (b)zImage-file (in 16 byte units, rounded up)
  87 + /* 0x1f6 */ uint16_t swap_dev; // (unused AFAIK)
  88 + /* 0x1f8 */ uint16_t ramdisk_flags;
  89 + /* 0x1fa */ uint16_t vga_mode; // (old one)
  90 + /* 0x1fc */ uint16_t orig_root_dev; // (high=Major, low=minor)
  91 + /* 0x1fe */ uint8_t pad6[1];
  92 + /* 0x1ff */ uint8_t aux_device_info;
  93 + /* 0x200 */ uint16_t jump_setup; // Jump to start of setup code,
  94 + // aka "reserved" field.
  95 + /* 0x202 */ uint8_t setup_signature[4]; // Signature for SETUP-header, ="HdrS"
  96 + /* 0x206 */ uint16_t header_format_version; // Version number of header format;
  97 + /* 0x208 */ uint8_t setup_S_temp0[8]; // Used by setup.S for communication with
  98 + // boot loaders, look there.
  99 + /* 0x210 */ uint8_t loader_type;
  100 + // 0 for old one.
  101 + // else 0xTV:
  102 + // T=0: LILO
  103 + // T=1: Loadlin
  104 + // T=2: bootsect-loader
  105 + // T=3: SYSLINUX
  106 + // T=4: ETHERBOOT
  107 + // V=version
  108 + /* 0x211 */ uint8_t loadflags;
  109 + // bit0 = 1: kernel is loaded high (bzImage)
  110 + // bit7 = 1: Heap and pointer (see below) set by boot
  111 + // loader.
  112 + /* 0x212 */ uint16_t setup_S_temp1;
  113 + /* 0x214 */ uint32_t kernel_start;
  114 + /* 0x218 */ uint32_t initrd_start;
  115 + /* 0x21c */ uint32_t initrd_size;
  116 + /* 0x220 */ uint8_t setup_S_temp2[4];
  117 + /* 0x224 */ uint16_t setup_S_heap_end_pointer;
  118 + /* 0x226 */ uint8_t pad7[0x2d0 - 0x226];
  119 +
  120 + /* 0x2d0 : Int 15, ax=e820 memory map. */
  121 + // (linux/include/asm-i386/e820.h, 'struct e820entry')
  122 +#define E820MAX 32
  123 +#define E820_RAM 1
  124 +#define E820_RESERVED 2
  125 +#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
  126 +#define E820_NVS 4
  127 + struct {
  128 + uint64_t addr;
  129 + uint64_t size;
  130 + uint32_t type;
  131 + } e820map[E820MAX];
  132 +
  133 + /* 0x550 */ uint8_t pad8[0x600 - 0x550];
  134 +
  135 + // BIOS Enhanced Disk Drive Services.
  136 + // (From linux/include/asm-i386/edd.h, 'struct edd_info')
  137 + // Each 'struct edd_info is 78 bytes, times a max of 6 structs in array.
  138 + /* 0x600 */ uint8_t eddbuf[0x7d4 - 0x600];
  139 +
  140 + /* 0x7d4 */ uint8_t pad9[0x800 - 0x7d4];
  141 + /* 0x800 */ uint8_t commandline[0x800];
  142 +
  143 + /* 0x1000 */
  144 + uint64_t gdt_table[256];
  145 + uint64_t idt_table[48];
  146 +};
  147 +
  148 +#define KERNEL_CS 0x10
  149 +#define KERNEL_DS 0x18
  150 +
  151 +typedef void (IOPortWriteFunc)(CPUX86State *env, uint32_t address, uint32_t data);
  152 +typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address);
  153 +
  154 +#define MAX_IOPORTS 1024
  155 +
  156 +char phys_ram_file[1024];
  157 +CPUX86State *global_env;
  158 +FILE *logfile = NULL;
  159 +int loglevel;
  160 +IOPortReadFunc *ioport_readb_table[MAX_IOPORTS];
  161 +IOPortWriteFunc *ioport_writeb_table[MAX_IOPORTS];
  162 +IOPortReadFunc *ioport_readw_table[MAX_IOPORTS];
  163 +IOPortWriteFunc *ioport_writew_table[MAX_IOPORTS];
  164 +
  165 +/***********************************************************/
  166 +/* x86 io ports */
  167 +
  168 +uint32_t default_ioport_readb(CPUX86State *env, uint32_t address)
  169 +{
  170 +#ifdef DEBUG_UNUSED_IOPORT
  171 + fprintf(stderr, "inb: port=0x%04x\n", address);
  172 +#endif
  173 + return 0;
  174 +}
  175 +
  176 +void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data)
  177 +{
  178 +#ifdef DEBUG_UNUSED_IOPORT
  179 + fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data);
  180 +#endif
  181 +}
  182 +
  183 +/* default is to make two byte accesses */
  184 +uint32_t default_ioport_readw(CPUX86State *env, uint32_t address)
  185 +{
  186 + uint32_t data;
  187 + data = ioport_readb_table[address](env, address);
  188 + data |= ioport_readb_table[address + 1](env, address + 1) << 8;
  189 + return data;
  190 +}
  191 +
  192 +void default_ioport_writew(CPUX86State *env, uint32_t address, uint32_t data)
  193 +{
  194 + ioport_writeb_table[address](env, address, data & 0xff);
  195 + ioport_writeb_table[address + 1](env, address + 1, (data >> 8) & 0xff);
  196 +}
  197 +
  198 +void init_ioports(void)
  199 +{
  200 + int i;
  201 +
  202 + for(i = 0; i < MAX_IOPORTS; i++) {
  203 + ioport_readb_table[i] = default_ioport_readb;
  204 + ioport_writeb_table[i] = default_ioport_writeb;
  205 + ioport_readw_table[i] = default_ioport_readw;
  206 + ioport_writew_table[i] = default_ioport_writew;
  207 + }
  208 +}
  209 +
  210 +int register_ioport_readb(int start, int length, IOPortReadFunc *func)
  211 +{
  212 + int i;
  213 +
  214 + for(i = start; i < start + length; i++)
  215 + ioport_readb_table[i] = func;
  216 + return 0;
  217 +}
  218 +
  219 +int register_ioport_writeb(int start, int length, IOPortWriteFunc *func)
  220 +{
  221 + int i;
  222 +
  223 + for(i = start; i < start + length; i++)
  224 + ioport_writeb_table[i] = func;
  225 + return 0;
  226 +}
  227 +
  228 +void pstrcpy(char *buf, int buf_size, const char *str)
  229 +{
  230 + int c;
  231 + char *q = buf;
  232 +
  233 + if (buf_size <= 0)
  234 + return;
  235 +
  236 + for(;;) {
  237 + c = *str++;
  238 + if (c == 0 || q >= buf + buf_size - 1)
  239 + break;
  240 + *q++ = c;
  241 + }
  242 + *q = '\0';
  243 +}
  244 +
  245 +/* strcat and truncate. */
  246 +char *pstrcat(char *buf, int buf_size, const char *s)
  247 +{
  248 + int len;
  249 + len = strlen(buf);
  250 + if (len < buf_size)
  251 + pstrcpy(buf + len, buf_size - len, s);
  252 + return buf;
  253 +}
  254 +
  255 +int load_kernel(const char *filename, uint8_t *addr)
  256 +{
  257 + int fd, size, setup_sects;
  258 + uint8_t bootsect[512];
  259 +
  260 + fd = open(filename, O_RDONLY);
  261 + if (fd < 0)
  262 + return -1;
  263 + if (read(fd, bootsect, 512) != 512)
  264 + goto fail;
  265 + setup_sects = bootsect[0x1F1];
  266 + if (!setup_sects)
  267 + setup_sects = 4;
  268 + /* skip 16 bit setup code */
  269 + lseek(fd, (setup_sects + 1) * 512, SEEK_SET);
  270 + size = read(fd, addr, 16 * 1024 * 1024);
  271 + if (size < 0)
  272 + goto fail;
  273 + close(fd);
  274 + return size;
  275 + fail:
  276 + close(fd);
  277 + return -1;
  278 +}
  279 +
  280 +/* return the size or -1 if error */
  281 +int load_image(const char *filename, uint8_t *addr)
  282 +{
  283 + int fd, size;
  284 + fd = open(filename, O_RDONLY);
  285 + if (fd < 0)
  286 + return -1;
  287 + size = lseek(fd, 0, SEEK_END);
  288 + lseek(fd, 0, SEEK_SET);
  289 + if (read(fd, addr, size) != size) {
  290 + close(fd);
  291 + return -1;
  292 + }
  293 + close(fd);
  294 + return size;
  295 +}
  296 +
  297 +void cpu_x86_outb(CPUX86State *env, int addr, int val)
  298 +{
  299 + ioport_writeb_table[addr & (MAX_IOPORTS - 1)](env, addr, val);
  300 +}
  301 +
  302 +void cpu_x86_outw(CPUX86State *env, int addr, int val)
  303 +{
  304 + ioport_writew_table[addr & (MAX_IOPORTS - 1)](env, addr, val);
  305 +}
  306 +
  307 +void cpu_x86_outl(CPUX86State *env, int addr, int val)
  308 +{
  309 + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
  310 +}
  311 +
  312 +int cpu_x86_inb(CPUX86State *env, int addr)
  313 +{
  314 + return ioport_readb_table[addr & (MAX_IOPORTS - 1)](env, addr);
  315 +}
  316 +
  317 +int cpu_x86_inw(CPUX86State *env, int addr)
  318 +{
  319 + return ioport_readw_table[addr & (MAX_IOPORTS - 1)](env, addr);
  320 +}
  321 +
  322 +int cpu_x86_inl(CPUX86State *env, int addr)
  323 +{
  324 + fprintf(stderr, "inl: port=0x%04x\n", addr);
  325 + return 0;
  326 +}
  327 +
  328 +/***********************************************************/
  329 +void ioport80_write(CPUX86State *env, uint32_t addr, uint32_t data)
  330 +{
  331 +}
  332 +
  333 +void hw_error(const char *fmt, ...)
  334 +{
  335 + va_list ap;
  336 +
  337 + va_start(ap, fmt);
  338 + fprintf(stderr, "qemu: hardware error: ");
  339 + vfprintf(stderr, fmt, ap);
  340 + fprintf(stderr, "\n");
  341 +#ifdef TARGET_I386
  342 + cpu_x86_dump_state(global_env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
  343 +#endif
  344 + va_end(ap);
  345 + abort();
  346 +}
  347 +
  348 +/***********************************************************/
  349 +/* vga emulation */
  350 +static uint8_t vga_index;
  351 +static uint8_t vga_regs[256];
  352 +static int last_cursor_pos;
  353 +
  354 +void update_console_messages(void)
  355 +{
  356 + int c, i, cursor_pos, eol;
  357 +
  358 + cursor_pos = vga_regs[0x0f] | (vga_regs[0x0e] << 8);
  359 + eol = 0;
  360 + for(i = last_cursor_pos; i < cursor_pos; i++) {
  361 + c = phys_ram_base[0xb8000 + (i) * 2];
  362 + if (c >= ' ') {
  363 + putchar(c);
  364 + eol = 0;
  365 + } else {
  366 + if (!eol)
  367 + putchar('\n');
  368 + eol = 1;
  369 + }
  370 + }
  371 + fflush(stdout);
  372 + last_cursor_pos = cursor_pos;
  373 +}
  374 +
  375 +/* just to see first Linux console messages, we intercept cursor position */
  376 +void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data)
  377 +{
  378 + switch(addr) {
  379 + case 0x3d4:
  380 + vga_index = data;
  381 + break;
  382 + case 0x3d5:
  383 + vga_regs[vga_index] = data;
  384 + if (vga_index == 0x0f)
  385 + update_console_messages();
  386 + break;
  387 + }
  388 +
  389 +}
  390 +
  391 +/***********************************************************/
  392 +/* cmos emulation */
  393 +
  394 +#define RTC_SECONDS 0
  395 +#define RTC_SECONDS_ALARM 1
  396 +#define RTC_MINUTES 2
  397 +#define RTC_MINUTES_ALARM 3
  398 +#define RTC_HOURS 4
  399 +#define RTC_HOURS_ALARM 5
  400 +#define RTC_ALARM_DONT_CARE 0xC0
  401 +
  402 +#define RTC_DAY_OF_WEEK 6
  403 +#define RTC_DAY_OF_MONTH 7
  404 +#define RTC_MONTH 8
  405 +#define RTC_YEAR 9
  406 +
  407 +#define RTC_REG_A 10
  408 +#define RTC_REG_B 11
  409 +#define RTC_REG_C 12
  410 +#define RTC_REG_D 13
  411 +
  412 +/* PC cmos mappings */
  413 +#define REG_EQUIPMENT_BYTE 0x14
  414 +
  415 +uint8_t cmos_data[128];
  416 +uint8_t cmos_index;
  417 +
  418 +void cmos_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data)
  419 +{
  420 + if (addr == 0x70) {
  421 + cmos_index = data & 0x7f;
  422 + }
  423 +}
  424 +
  425 +uint32_t cmos_ioport_read(CPUX86State *env, uint32_t addr)
  426 +{
  427 + int ret;
  428 +
  429 + if (addr == 0x70) {
  430 + return 0xff;
  431 + } else {
  432 + /* toggle update-in-progress bit for Linux (same hack as
  433 + plex86) */
  434 + ret = cmos_data[cmos_index];
  435 + if (cmos_index == RTC_REG_A)
  436 + cmos_data[RTC_REG_A] ^= 0x80;
  437 + else if (cmos_index == RTC_REG_C)
  438 + cmos_data[RTC_REG_C] = 0x00;
  439 + return ret;
  440 + }
  441 +}
  442 +
  443 +
  444 +static inline int to_bcd(int a)
  445 +{
  446 + return ((a / 10) << 4) | (a % 10);
  447 +}
  448 +
  449 +void cmos_init(void)
  450 +{
  451 + struct tm *tm;
  452 + time_t ti;
  453 +
  454 + ti = time(NULL);
  455 + tm = gmtime(&ti);
  456 + cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec);
  457 + cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min);
  458 + cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour);
  459 + cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday);
  460 + cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday);
  461 + cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon);
  462 + cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100);
  463 +
  464 + cmos_data[RTC_REG_A] = 0x26;
  465 + cmos_data[RTC_REG_B] = 0x02;
  466 + cmos_data[RTC_REG_C] = 0x00;
  467 + cmos_data[RTC_REG_D] = 0x80;
  468 +
  469 + cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */
  470 +
  471 + register_ioport_writeb(0x70, 2, cmos_ioport_write);
  472 + register_ioport_readb(0x70, 2, cmos_ioport_read);
  473 +}
  474 +
  475 +/***********************************************************/
  476 +/* 8259 pic emulation */
  477 +
  478 +typedef struct PicState {
  479 + uint8_t last_irr; /* edge detection */
  480 + uint8_t irr; /* interrupt request register */
  481 + uint8_t imr; /* interrupt mask register */
  482 + uint8_t isr; /* interrupt service register */
  483 + uint8_t priority_add; /* used to compute irq priority */
  484 + uint8_t irq_base;
  485 + uint8_t read_reg_select;
  486 + uint8_t special_mask;
  487 + uint8_t init_state;
  488 + uint8_t auto_eoi;
  489 + uint8_t rotate_on_autoeoi;
  490 + uint8_t init4; /* true if 4 byte init */
  491 +} PicState;
  492 +
  493 +/* 0 is master pic, 1 is slave pic */
  494 +PicState pics[2];
  495 +int pic_irq_requested;
  496 +
  497 +/* set irq level. If an edge is detected, then the IRR is set to 1 */
  498 +static inline void pic_set_irq1(PicState *s, int irq, int level)
  499 +{
  500 + int mask;
  501 + mask = 1 << irq;
  502 + if (level) {
  503 + if ((s->last_irr & mask) == 0)
  504 + s->irr |= mask;
  505 + s->last_irr |= mask;
  506 + } else {
  507 + s->last_irr &= ~mask;
  508 + }
  509 +}
  510 +
  511 +static inline int get_priority(PicState *s, int mask)
  512 +{
  513 + int priority;
  514 + if (mask == 0)
  515 + return -1;
  516 + priority = 7;
  517 + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
  518 + priority--;
  519 + return priority;
  520 +}
  521 +
  522 +/* return the pic wanted interrupt. return -1 if none */
  523 +static int pic_get_irq(PicState *s)
  524 +{
  525 + int mask, cur_priority, priority;
  526 +
  527 + mask = s->irr & ~s->imr;
  528 + priority = get_priority(s, mask);
  529 + if (priority < 0)
  530 + return -1;
  531 + /* compute current priority */
  532 + cur_priority = get_priority(s, s->isr);
  533 + if (priority > cur_priority) {
  534 + /* higher priority found: an irq should be generated */
  535 + return priority;
  536 + } else {
  537 + return -1;
  538 + }
  539 +}
  540 +
  541 +void pic_set_irq(int irq, int level)
  542 +{
  543 + pic_set_irq1(&pics[irq >> 3], irq & 7, level);
  544 +}
  545 +
  546 +/* can be called at any time outside cpu_exec() to raise irqs if
  547 + necessary */
  548 +void pic_handle_irq(void)
  549 +{
  550 + int irq2, irq;
  551 +
  552 + /* first look at slave pic */
  553 + irq2 = pic_get_irq(&pics[1]);
  554 + if (irq2 >= 0) {
  555 + /* if irq request by slave pic, signal master PIC */
  556 + pic_set_irq1(&pics[0], 2, 1);
  557 + pic_set_irq1(&pics[0], 2, 0);
  558 + }
  559 + /* look at requested irq */
  560 + irq = pic_get_irq(&pics[0]);
  561 + if (irq >= 0) {
  562 + if (irq == 2) {
  563 + /* from slave pic */
  564 + pic_irq_requested = 8 + irq2;
  565 + } else {
  566 + /* from master pic */
  567 + pic_irq_requested = irq;
  568 + }
  569 + global_env->hard_interrupt_request = 1;
  570 + }
  571 +}
  572 +
  573 +int cpu_x86_get_pic_interrupt(CPUX86State *env)
  574 +{
  575 + int irq, irq2, intno;
  576 +
  577 + /* signal the pic that the irq was acked by the CPU */
  578 + irq = pic_irq_requested;
  579 + if (irq >= 8) {
  580 + irq2 = irq & 7;
  581 + pics[1].isr |= (1 << irq2);
  582 + pics[1].irr &= ~(1 << irq2);
  583 + irq = 2;
  584 + intno = pics[1].irq_base + irq2;
  585 + } else {
  586 + intno = pics[0].irq_base + irq;
  587 + }
  588 + pics[0].isr |= (1 << irq);
  589 + pics[0].irr &= ~(1 << irq);
  590 + return intno;
  591 +}
  592 +
  593 +void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
  594 +{
  595 + PicState *s;
  596 + int priority;
  597 +
  598 + s = &pics[addr >> 7];
  599 + addr &= 1;
  600 + if (addr == 0) {
  601 + if (val & 0x10) {
  602 + /* init */
  603 + memset(s, 0, sizeof(PicState));
  604 + s->init_state = 1;
  605 + s->init4 = val & 1;
  606 + if (val & 0x02)
  607 + hw_error("single mode not supported");
  608 + if (val & 0x08)
  609 + hw_error("level sensitive irq not supported");
  610 + } else if (val & 0x08) {
  611 + if (val & 0x02)
  612 + s->read_reg_select = val & 1;
  613 + if (val & 0x40)
  614 + s->special_mask = (val >> 5) & 1;
  615 + } else {
  616 + switch(val) {
  617 + case 0x00:
  618 + case 0x80:
  619 + s->rotate_on_autoeoi = val >> 7;
  620 + break;
  621 + case 0x20: /* end of interrupt */
  622 + case 0xa0:
  623 + priority = get_priority(s, s->isr);
  624 + if (priority >= 0) {
  625 + s->isr &= ~(1 << ((priority + s->priority_add) & 7));
  626 + }
  627 + if (val == 0xa0)
  628 + s->priority_add = (s->priority_add + 1) & 7;
  629 + break;
  630 + case 0x60 ... 0x67:
  631 + priority = val & 7;
  632 + s->isr &= ~(1 << priority);
  633 + break;
  634 + case 0xc0 ... 0xc7:
  635 + s->priority_add = (val + 1) & 7;
  636 + break;
  637 + case 0xe0 ... 0xe7:
  638 + priority = val & 7;
  639 + s->isr &= ~(1 << priority);
  640 + s->priority_add = (priority + 1) & 7;
  641 + break;
  642 + }
  643 + }
  644 + } else {
  645 + switch(s->init_state) {
  646 + case 0:
  647 + /* normal mode */
  648 + s->imr = val;
  649 + break;
  650 + case 1:
  651 + s->irq_base = val & 0xf8;
  652 + s->init_state = 2;
  653 + break;
  654 + case 2:
  655 + if (s->init4) {
  656 + s->init_state = 3;
  657 + } else {
  658 + s->init_state = 0;
  659 + }
  660 + break;
  661 + case 3:
  662 + s->auto_eoi = (val >> 1) & 1;
  663 + s->init_state = 0;
  664 + break;
  665 + }
  666 + }
  667 +}
  668 +
  669 +uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr)
  670 +{
  671 + PicState *s;
  672 + s = &pics[addr >> 7];
  673 + addr &= 1;
  674 + if (addr == 0) {
  675 + if (s->read_reg_select)
  676 + return s->isr;
  677 + else
  678 + return s->irr;
  679 + } else {
  680 + return s->imr;
  681 + }
  682 +}
  683 +
  684 +void pic_init(void)
  685 +{
  686 + register_ioport_writeb(0x20, 2, pic_ioport_write);
  687 + register_ioport_readb(0x20, 2, pic_ioport_read);
  688 + register_ioport_writeb(0xa0, 2, pic_ioport_write);
  689 + register_ioport_readb(0xa0, 2, pic_ioport_read);
  690 +}
  691 +
  692 +/***********************************************************/
  693 +/* 8253 PIT emulation */
  694 +
  695 +#define PIT_FREQ 1193182
  696 +
  697 +#define RW_STATE_LSB 0
  698 +#define RW_STATE_MSB 1
  699 +#define RW_STATE_WORD0 2
  700 +#define RW_STATE_WORD1 3
  701 +#define RW_STATE_LATCHED_WORD0 4
  702 +#define RW_STATE_LATCHED_WORD1 5
  703 +
  704 +typedef struct PITChannelState {
  705 + uint16_t count;
  706 + uint16_t latched_count;
  707 + uint8_t rw_state;
  708 + uint8_t mode;
  709 + uint8_t bcd; /* not supported */
  710 + uint8_t gate; /* timer start */
  711 + int64_t count_load_time;
  712 +} PITChannelState;
  713 +
  714 +PITChannelState pit_channels[3];
  715 +int speaker_data_on;
  716 +
  717 +int64_t ticks_per_sec;
  718 +
  719 +int64_t get_clock(void)
  720 +{
  721 + struct timeval tv;
  722 + gettimeofday(&tv, NULL);
  723 + return tv.tv_sec * 1000000LL + tv.tv_usec;
  724 +}
  725 +
  726 +int64_t cpu_get_ticks(void)
  727 +{
  728 + int64_t val;
  729 + asm("rdtsc" : "=A" (val));
  730 + return val;
  731 +}
  732 +
  733 +void cpu_calibrate_ticks(void)
  734 +{
  735 + int64_t usec, ticks;
  736 +
  737 + usec = get_clock();
  738 + ticks = cpu_get_ticks();
  739 + usleep(50 * 1000);
  740 + usec = get_clock() - usec;
  741 + ticks = cpu_get_ticks() - ticks;
  742 + ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec;
  743 +}
  744 +
  745 +static int pit_get_count(PITChannelState *s)
  746 +{
  747 + int64_t d;
  748 + int counter;
  749 +
  750 + d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) /
  751 + ticks_per_sec;
  752 + switch(s->mode) {
  753 + case 0:
  754 + case 1:
  755 + case 4:
  756 + case 5:
  757 + counter = (s->count - d) & 0xffff;
  758 + break;
  759 + default:
  760 + counter = s->count - (d % s->count);
  761 + break;
  762 + }
  763 + return counter;
  764 +}
  765 +
  766 +/* get pit output bit */
  767 +static int pit_get_out(PITChannelState *s)
  768 +{
  769 + int64_t d;
  770 + int out;
  771 +
  772 + d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) /
  773 + ticks_per_sec;
  774 + switch(s->mode) {
  775 + default:
  776 + case 0:
  777 + out = (d >= s->count);
  778 + break;
  779 + case 1:
  780 + out = (d < s->count);
  781 + break;
  782 + case 2:
  783 + if ((d % s->count) == 0 && d != 0)
  784 + out = 1;
  785 + else
  786 + out = 0;
  787 + break;
  788 + case 3:
  789 + out = (d % s->count) < (s->count >> 1);
  790 + break;
  791 + case 4:
  792 + case 5:
  793 + out = (d == s->count);
  794 + break;
  795 + }
  796 + return out;
  797 +}
  798 +
  799 +void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
  800 +{
  801 + int channel, access;
  802 + PITChannelState *s;
  803 +
  804 + addr &= 3;
  805 + if (addr == 3) {
  806 + channel = val >> 6;
  807 + if (channel == 3)
  808 + return;
  809 + s = &pit_channels[channel];
  810 + access = (val >> 4) & 3;
  811 + switch(access) {
  812 + case 0:
  813 + s->latched_count = pit_get_count(s);
  814 + s->rw_state = RW_STATE_LATCHED_WORD0;
  815 + break;
  816 + default:
  817 + s->rw_state = access - 1 + RW_STATE_LSB;
  818 + break;
  819 + }
  820 + s->mode = (val >> 1) & 7;
  821 + s->bcd = val & 1;
  822 + } else {
  823 + s = &pit_channels[addr];
  824 + switch(s->rw_state) {
  825 + case RW_STATE_LSB:
  826 + s->count_load_time = cpu_get_ticks();
  827 + s->count = val;
  828 + break;
  829 + case RW_STATE_MSB:
  830 + s->count_load_time = cpu_get_ticks();
  831 + s->count = (val << 8);
  832 + break;
  833 + case RW_STATE_WORD0:
  834 + case RW_STATE_WORD1:
  835 + if (s->rw_state & 1) {
  836 + s->count_load_time = cpu_get_ticks();
  837 + s->count = (s->latched_count & 0xff) | (val << 8);
  838 + } else {
  839 + s->latched_count = val;
  840 + }
  841 + s->rw_state ^= 1;
  842 + break;
  843 + }
  844 + }
  845 +}
  846 +
  847 +uint32_t pit_ioport_read(CPUX86State *env, uint32_t addr)
  848 +{
  849 + int ret, count;
  850 + PITChannelState *s;
  851 +
  852 + addr &= 3;
  853 + s = &pit_channels[addr];
  854 + switch(s->rw_state) {
  855 + case RW_STATE_LSB:
  856 + case RW_STATE_MSB:
  857 + case RW_STATE_WORD0:
  858 + case RW_STATE_WORD1:
  859 + count = pit_get_count(s);
  860 + if (s->rw_state & 1)
  861 + ret = (count >> 8) & 0xff;
  862 + else
  863 + ret = count & 0xff;
  864 + if (s->rw_state & 2)
  865 + s->rw_state ^= 1;
  866 + break;
  867 + default:
  868 + case RW_STATE_LATCHED_WORD0:
  869 + case RW_STATE_LATCHED_WORD1:
  870 + if (s->rw_state & 1)
  871 + ret = s->latched_count >> 8;
  872 + else
  873 + ret = s->latched_count & 0xff;
  874 + s->rw_state ^= 1;
  875 + break;
  876 + }
  877 + return ret;
  878 +}
  879 +
  880 +void speaker_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
  881 +{
  882 + speaker_data_on = (val >> 1) & 1;
  883 + pit_channels[2].gate = val & 1;
  884 +}
  885 +
  886 +uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr)
  887 +{
  888 + int out;
  889 + out = pit_get_out(&pit_channels[2]);
  890 + return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5);
  891 +}
  892 +
  893 +void pit_init(void)
  894 +{
  895 + pit_channels[0].gate = 1;
  896 + pit_channels[1].gate = 1;
  897 + pit_channels[2].gate = 0;
  898 +
  899 + register_ioport_writeb(0x40, 4, pit_ioport_write);
  900 + register_ioport_readb(0x40, 3, pit_ioport_read);
  901 +
  902 + register_ioport_readb(0x61, 1, speaker_ioport_read);
  903 + register_ioport_writeb(0x61, 1, speaker_ioport_write);
  904 + cpu_calibrate_ticks();
  905 +}
  906 +
  907 +/***********************************************************/
  908 +/* serial port emulation */
  909 +
  910 +#define UART_IRQ 4
  911 +
  912 +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
  913 +
  914 +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
  915 +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
  916 +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
  917 +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
  918 +
  919 +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
  920 +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
  921 +
  922 +#define UART_IIR_MSI 0x00 /* Modem status interrupt */
  923 +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
  924 +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
  925 +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
  926 +
  927 +#define UART_LSR_TEMT 0x40 /* Transmitter empty */
  928 +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
  929 +#define UART_LSR_BI 0x10 /* Break interrupt indicator */
  930 +#define UART_LSR_FE 0x08 /* Frame error indicator */
  931 +#define UART_LSR_PE 0x04 /* Parity error indicator */
  932 +#define UART_LSR_OE 0x02 /* Overrun error indicator */
  933 +#define UART_LSR_DR 0x01 /* Receiver data ready */
  934 +
  935 +typedef struct SerialState {
  936 + uint8_t divider;
  937 + uint8_t rbr; /* receive register */
  938 + uint8_t ier;
  939 + uint8_t iir; /* read only */
  940 + uint8_t lcr;
  941 + uint8_t mcr;
  942 + uint8_t lsr; /* read only */
  943 + uint8_t msr;
  944 + uint8_t scr;
  945 +} SerialState;
  946 +
  947 +SerialState serial_ports[1];
  948 +
  949 +void serial_update_irq(void)
  950 +{
  951 + SerialState *s = &serial_ports[0];
  952 +
  953 + if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
  954 + s->iir = UART_IIR_RDI;
  955 + } else if ((s->lsr & UART_LSR_THRE) && (s->ier & UART_IER_THRI)) {
  956 + s->iir = UART_IIR_THRI;
  957 + } else {
  958 + s->iir = UART_IIR_NO_INT;
  959 + }
  960 + if (s->iir != UART_IIR_NO_INT) {
  961 + pic_set_irq(UART_IRQ, 1);
  962 + } else {
  963 + pic_set_irq(UART_IRQ, 0);
  964 + }
  965 +}
  966 +
  967 +void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
  968 +{
  969 + SerialState *s = &serial_ports[0];
  970 + unsigned char ch;
  971 + int ret;
  972 +
  973 + addr &= 7;
  974 + switch(addr) {
  975 + default:
  976 + case 0:
  977 + if (s->lcr & UART_LCR_DLAB) {
  978 + s->divider = (s->divider & 0xff00) | val;
  979 + } else {
  980 + s->lsr &= ~UART_LSR_THRE;
  981 + serial_update_irq();
  982 +
  983 + ch = val;
  984 + do {
  985 + ret = write(1, &ch, 1);
  986 + } while (ret != 1);
  987 + s->lsr |= UART_LSR_THRE;
  988 + s->lsr |= UART_LSR_TEMT;
  989 + serial_update_irq();
  990 + }
  991 + break;
  992 + case 1:
  993 + if (s->lcr & UART_LCR_DLAB) {
  994 + s->divider = (s->divider & 0x00ff) | (val << 8);
  995 + } else {
  996 + s->ier = val;
  997 + serial_update_irq();
  998 + }
  999 + break;
  1000 + case 2:
  1001 + break;
  1002 + case 3:
  1003 + s->lcr = val;
  1004 + break;
  1005 + case 4:
  1006 + s->mcr = val;
  1007 + break;
  1008 + case 5:
  1009 + break;
  1010 + case 6:
  1011 + s->msr = val;
  1012 + break;
  1013 + case 7:
  1014 + s->scr = val;
  1015 + break;
  1016 + }
  1017 +}
  1018 +
  1019 +uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr)
  1020 +{
  1021 + SerialState *s = &serial_ports[0];
  1022 + uint32_t ret;
  1023 +
  1024 + addr &= 7;
  1025 + switch(addr) {
  1026 + default:
  1027 + case 0:
  1028 + if (s->lcr & UART_LCR_DLAB) {
  1029 + ret = s->divider & 0xff;
  1030 + } else {
  1031 + ret = s->rbr;
  1032 + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
  1033 + serial_update_irq();
  1034 + }
  1035 + break;
  1036 + case 1:
  1037 + if (s->lcr & UART_LCR_DLAB) {
  1038 + ret = (s->divider >> 8) & 0xff;
  1039 + } else {
  1040 + ret = s->ier;
  1041 + }
  1042 + break;
  1043 + case 2:
  1044 + ret = s->iir;
  1045 + break;
  1046 + case 3:
  1047 + ret = s->lcr;
  1048 + break;
  1049 + case 4:
  1050 + ret = s->mcr;
  1051 + break;
  1052 + case 5:
  1053 + ret = s->lsr;
  1054 + break;
  1055 + case 6:
  1056 + ret = s->msr;
  1057 + break;
  1058 + case 7:
  1059 + ret = s->scr;
  1060 + break;
  1061 + }
  1062 + return ret;
  1063 +}
  1064 +
  1065 +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
  1066 +static int term_got_escape;
  1067 +
  1068 +void term_print_help(void)
  1069 +{
  1070 + printf("\n"
  1071 + "C-a h print this help\n"
  1072 + "C-a x exit emulatior\n"
  1073 + "C-a b send break (magic sysrq)\n"
  1074 + "C-a C-a send C-a\n"
  1075 + );
  1076 +}
  1077 +
  1078 +/* called when a char is received */
  1079 +void serial_received_byte(SerialState *s, int ch)
  1080 +{
  1081 + if (term_got_escape) {
  1082 + term_got_escape = 0;
  1083 + switch(ch) {
  1084 + case 'h':
  1085 + term_print_help();
  1086 + break;
  1087 + case 'x':
  1088 + exit(0);
  1089 + break;
  1090 + case 'b':
  1091 + /* send break */
  1092 + s->rbr = 0;
  1093 + s->lsr |= UART_LSR_BI | UART_LSR_DR;
  1094 + serial_update_irq();
  1095 + break;
  1096 + case TERM_ESCAPE:
  1097 + goto send_char;
  1098 + }
  1099 + } else if (ch == TERM_ESCAPE) {
  1100 + term_got_escape = 1;
  1101 + } else {
  1102 + send_char:
  1103 + s->rbr = ch;
  1104 + s->lsr |= UART_LSR_DR;
  1105 + serial_update_irq();
  1106 + }
  1107 +}
  1108 +
  1109 +/* init terminal so that we can grab keys */
  1110 +static struct termios oldtty;
  1111 +
  1112 +static void term_exit(void)
  1113 +{
  1114 + tcsetattr (0, TCSANOW, &oldtty);
  1115 +}
  1116 +
  1117 +static void term_init(void)
  1118 +{
  1119 + struct termios tty;
  1120 +
  1121 + tcgetattr (0, &tty);
  1122 + oldtty = tty;
  1123 +
  1124 + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
  1125 + |INLCR|IGNCR|ICRNL|IXON);
  1126 + tty.c_oflag |= OPOST;
  1127 + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
  1128 + tty.c_cflag &= ~(CSIZE|PARENB);
  1129 + tty.c_cflag |= CS8;
  1130 + tty.c_cc[VMIN] = 1;
  1131 + tty.c_cc[VTIME] = 0;
  1132 +
  1133 + tcsetattr (0, TCSANOW, &tty);
  1134 +
  1135 + atexit(term_exit);
  1136 +
  1137 + fcntl(0, F_SETFL, O_NONBLOCK);
  1138 +}
  1139 +
  1140 +void serial_init(void)
  1141 +{
  1142 + SerialState *s = &serial_ports[0];
  1143 +
  1144 + s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
  1145 +
  1146 + register_ioport_writeb(0x3f8, 8, serial_ioport_write);
  1147 + register_ioport_readb(0x3f8, 8, serial_ioport_read);
  1148 +
  1149 + term_init();
  1150 +}
  1151 +
  1152 +/* cpu signal handler */
  1153 +static void host_segv_handler(int host_signum, siginfo_t *info,
  1154 + void *puc)
  1155 +{
  1156 + if (cpu_signal_handler(host_signum, info, puc))
  1157 + return;
  1158 + term_exit();
  1159 + abort();
  1160 +}
  1161 +
  1162 +static int timer_irq_pending;
  1163 +
  1164 +static void host_alarm_handler(int host_signum, siginfo_t *info,
  1165 + void *puc)
  1166 +{
  1167 + /* just exit from the cpu to have a change to handle timers */
  1168 + cpu_x86_interrupt(global_env);
  1169 + timer_irq_pending = 1;
  1170 +}
  1171 +
  1172 +void help(void)
  1173 +{
  1174 + printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
  1175 + "usage: vl [-h] bzImage initrd [kernel parameters...]\n"
  1176 + "\n"
  1177 + "'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n"
  1178 + "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n"
  1179 + "'initrd' is an initrd image\n"
  1180 + "-m megs set virtual RAM size to megs MB\n"
  1181 + "-d output log in /tmp/vl.log\n"
  1182 + "\n"
  1183 + "During emulation, use C-a h to get terminal commands:\n"
  1184 + );
  1185 + term_print_help();
  1186 + exit(1);
  1187 +}
  1188 +
  1189 +int main(int argc, char **argv)
  1190 +{
  1191 + int c, ret, initrd_size, i;
  1192 + struct linux_params *params;
  1193 + struct sigaction act;
  1194 + struct itimerval itv;
  1195 + CPUX86State *env;
  1196 +
  1197 + /* we never want that malloc() uses mmap() */
  1198 + mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
  1199 +
  1200 + phys_ram_size = 32 * 1024 * 1024;
  1201 + for(;;) {
  1202 + c = getopt(argc, argv, "hm:d");
  1203 + if (c == -1)
  1204 + break;
  1205 + switch(c) {
  1206 + case 'h':
  1207 + help();
  1208 + break;
  1209 + case 'm':
  1210 + phys_ram_size = atoi(optarg) * 1024 * 1024;
  1211 + if (phys_ram_size <= 0)
  1212 + help();
  1213 + break;
  1214 + case 'd':
  1215 + loglevel = 1;
  1216 + break;
  1217 + }
  1218 + }
  1219 + if (optind + 1 >= argc)
  1220 + help();
  1221 +
  1222 + /* init debug */
  1223 + if (loglevel) {
  1224 + logfile = fopen(DEBUG_LOGFILE, "w");
  1225 + if (!logfile) {
  1226 + perror(DEBUG_LOGFILE);
  1227 + _exit(1);
  1228 + }
  1229 + setvbuf(logfile, NULL, _IOLBF, 0);
  1230 + }
  1231 +
  1232 + /* init the memory */
  1233 + strcpy(phys_ram_file, "/tmp/vlXXXXXX");
  1234 + if (mkstemp(phys_ram_file) < 0) {
  1235 + fprintf(stderr, "Could not create temporary memory file\n");
  1236 + exit(1);
  1237 + }
  1238 + phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
  1239 + if (phys_ram_fd < 0) {
  1240 + fprintf(stderr, "Could not open temporary memory file\n");
  1241 + exit(1);
  1242 + }
  1243 + ftruncate(phys_ram_fd, phys_ram_size);
  1244 + unlink(phys_ram_file);
  1245 + phys_ram_base = mmap((void *)PHYS_RAM_BASE, phys_ram_size,
  1246 + PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED,
  1247 + phys_ram_fd, 0);
  1248 + if (phys_ram_base == MAP_FAILED) {
  1249 + fprintf(stderr, "Could not map physical memory\n");
  1250 + exit(1);
  1251 + }
  1252 +
  1253 + /* now we can load the kernel */
  1254 + ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR);
  1255 + if (ret < 0) {
  1256 + fprintf(stderr, "%s: could not load kernel\n", argv[optind]);
  1257 + exit(1);
  1258 + }
  1259 +
  1260 + /* load initrd */
  1261 + initrd_size = load_image(argv[optind + 1], phys_ram_base + INITRD_LOAD_ADDR);
  1262 + if (initrd_size < 0) {
  1263 + fprintf(stderr, "%s: could not load initrd\n", argv[optind + 1]);
  1264 + exit(1);
  1265 + }
  1266 +
  1267 + /* init kernel params */
  1268 + params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR);
  1269 + memset(params, 0, sizeof(struct linux_params));
  1270 + params->mount_root_rdonly = 0;
  1271 + params->cl_magic = 0xA33F;
  1272 + params->cl_offset = params->commandline - (uint8_t *)params;
  1273 + params->ext_mem_k = (phys_ram_size / 1024) - 1024;
  1274 + for(i = optind + 2; i < argc; i++) {
  1275 + if (i != optind + 2)
  1276 + pstrcat(params->commandline, sizeof(params->commandline), " ");
  1277 + pstrcat(params->commandline, sizeof(params->commandline), argv[i]);
  1278 + }
  1279 + params->loader_type = 0x01;
  1280 + if (initrd_size > 0) {
  1281 + params->initrd_start = INITRD_LOAD_ADDR;
  1282 + params->initrd_size = initrd_size;
  1283 + }
  1284 + params->orig_video_lines = 25;
  1285 + params->orig_video_cols = 80;
  1286 +
  1287 + /* init basic PC hardware */
  1288 + init_ioports();
  1289 + register_ioport_writeb(0x80, 1, ioport80_write);
  1290 +
  1291 + register_ioport_writeb(0x3d4, 2, vga_ioport_write);
  1292 +
  1293 + cmos_init();
  1294 + pic_init();
  1295 + pit_init();
  1296 + serial_init();
  1297 +
  1298 + /* setup cpu signal handlers for MMU / self modifying code handling */
  1299 + sigfillset(&act.sa_mask);
  1300 + act.sa_flags = SA_SIGINFO;
  1301 + act.sa_sigaction = host_segv_handler;
  1302 + sigaction(SIGSEGV, &act, NULL);
  1303 + sigaction(SIGBUS, &act, NULL);
  1304 +
  1305 + act.sa_sigaction = host_alarm_handler;
  1306 + sigaction(SIGALRM, &act, NULL);
  1307 +
  1308 + /* init CPU state */
  1309 + env = cpu_init();
  1310 + global_env = env;
  1311 +
  1312 + /* setup basic memory access */
  1313 + env->cr[0] = 0x00000033;
  1314 + cpu_x86_init_mmu(env);
  1315 +
  1316 + memset(params->idt_table, 0, sizeof(params->idt_table));
  1317 +
  1318 + params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */
  1319 + params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */
  1320 +
  1321 + env->idt.base = (void *)params->idt_table;
  1322 + env->idt.limit = sizeof(params->idt_table) - 1;
  1323 + env->gdt.base = (void *)params->gdt_table;
  1324 + env->gdt.limit = sizeof(params->gdt_table) - 1;
  1325 +
  1326 + cpu_x86_load_seg(env, R_CS, KERNEL_CS);
  1327 + cpu_x86_load_seg(env, R_DS, KERNEL_DS);
  1328 + cpu_x86_load_seg(env, R_ES, KERNEL_DS);
  1329 + cpu_x86_load_seg(env, R_SS, KERNEL_DS);
  1330 + cpu_x86_load_seg(env, R_FS, KERNEL_DS);
  1331 + cpu_x86_load_seg(env, R_GS, KERNEL_DS);
  1332 +
  1333 + env->eip = KERNEL_LOAD_ADDR;
  1334 + env->regs[R_ESI] = KERNEL_PARAMS_ADDR;
  1335 + env->eflags = 0x2;
  1336 +
  1337 + itv.it_interval.tv_sec = 0;
  1338 + itv.it_interval.tv_usec = 10 * 1000;
  1339 + itv.it_value.tv_sec = 0;
  1340 + itv.it_value.tv_usec = 10 * 1000;
  1341 + setitimer(ITIMER_REAL, &itv, NULL);
  1342 +
  1343 + for(;;) {
  1344 + struct pollfd ufds[1], *pf;
  1345 + int ret, n, timeout;
  1346 + uint8_t ch;
  1347 +
  1348 + ret = cpu_x86_exec(env);
  1349 +
  1350 + /* if hlt instruction, we wait until the next IRQ */
  1351 + if (ret == EXCP_HLT)
  1352 + timeout = 10;
  1353 + else
  1354 + timeout = 0;
  1355 + /* poll any events */
  1356 + pf = ufds;
  1357 + if (!(serial_ports[0].lsr & UART_LSR_DR)) {
  1358 + pf->fd = 0;
  1359 + pf->events = POLLIN;
  1360 + pf++;
  1361 + }
  1362 + ret = poll(ufds, pf - ufds, timeout);
  1363 + if (ret > 0) {
  1364 + if (ufds[0].revents & POLLIN) {
  1365 + n = read(0, &ch, 1);
  1366 + if (n == 1) {
  1367 + serial_received_byte(&serial_ports[0], ch);
  1368 + }
  1369 + }
  1370 + }
  1371 +
  1372 + /* just for testing */
  1373 + if (timer_irq_pending) {
  1374 + pic_set_irq(0, 1);
  1375 + pic_set_irq(0, 0);
  1376 + timer_irq_pending = 0;
  1377 + }
  1378 +
  1379 + pic_handle_irq();
  1380 + }
  1381 +
  1382 + return 0;
  1383 +}
... ...