~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/openbios/arch/amd64/linux_load.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Linux/i386 loader
 
3
 * Supports bzImage, zImage and Image format.
 
4
 *
 
5
 * Based on work by Steve Gehlbach.
 
6
 * Portions are taken from mkelfImage.
 
7
 *
 
8
 * 2003-09 by SONE Takeshi
 
9
 */
 
10
 
 
11
#include "config.h"
 
12
#include "kernel/kernel.h"
 
13
#include "libopenbios/bindings.h"
 
14
#include "libopenbios/sys_info.h"
 
15
#include "context.h"
 
16
#include "segment.h"
 
17
#include "loadfs.h"
 
18
 
 
19
#define printf printk
 
20
#define debug printk
 
21
#define strtoull_with_suffix strtol
 
22
 
 
23
#define LINUX_PARAM_LOC 0x90000
 
24
#define COMMAND_LINE_LOC 0x91000
 
25
#define GDT_LOC 0x92000
 
26
#define STACK_LOC 0x93000
 
27
 
 
28
#define E820MAX 32              /* number of entries in E820MAP */
 
29
struct e820entry {
 
30
        unsigned long long addr;        /* start of memory segment */
 
31
        unsigned long long size;        /* size of memory segment */
 
32
        unsigned long type;             /* type of memory segment */
 
33
#define E820_RAM        1
 
34
#define E820_RESERVED   2
 
35
#define E820_ACPI       3 /* usable as RAM once ACPI tables have been read */
 
36
#define E820_NVS        4
 
37
};
 
38
 
 
39
/* The header of Linux/i386 kernel */
 
40
struct linux_header {
 
41
    uint8_t  reserved1[0x1f1];          /* 0x000 */
 
42
    uint8_t  setup_sects;               /* 0x1f1 */
 
43
    uint16_t root_flags;                /* 0x1f2 */
 
44
    uint8_t  reserved2[6];              /* 0x1f4 */
 
45
    uint16_t vid_mode;                  /* 0x1fa */
 
46
    uint16_t root_dev;                  /* 0x1fc */
 
47
    uint16_t boot_sector_magic;         /* 0x1fe */
 
48
    /* 2.00+ */
 
49
    uint8_t  reserved3[2];              /* 0x200 */
 
50
    uint8_t  header_magic[4];           /* 0x202 */
 
51
    uint16_t protocol_version;          /* 0x206 */
 
52
    uint32_t realmode_swtch;            /* 0x208 */
 
53
    uint16_t start_sys;                 /* 0x20c */
 
54
    uint16_t kver_addr;                 /* 0x20e */
 
55
    uint8_t  type_of_loader;            /* 0x210 */
 
56
    uint8_t  loadflags;                 /* 0x211 */
 
57
    uint16_t setup_move_size;           /* 0x212 */
 
58
    uint32_t code32_start;              /* 0x214 */
 
59
    uint32_t ramdisk_image;             /* 0x218 */
 
60
    uint32_t ramdisk_size;              /* 0x21c */
 
61
    uint8_t  reserved4[4];              /* 0x220 */
 
62
    /* 2.01+ */
 
63
    uint16_t heap_end_ptr;              /* 0x224 */
 
64
    uint8_t  reserved5[2];              /* 0x226 */
 
65
    /* 2.02+ */
 
66
    uint32_t cmd_line_ptr;              /* 0x228 */
 
67
    /* 2.03+ */
 
68
    uint32_t initrd_addr_max;           /* 0x22c */
 
69
} __attribute__ ((packed));
 
70
 
 
71
 
 
72
/* Paramters passed to 32-bit part of Linux
 
73
 * This is another view of the structure above.. */
 
74
struct linux_params {
 
75
    uint8_t  orig_x;                    /* 0x00 */
 
76
    uint8_t  orig_y;                    /* 0x01 */
 
77
    uint16_t ext_mem_k;                 /* 0x02 -- EXT_MEM_K sits here */
 
78
    uint16_t orig_video_page;           /* 0x04 */
 
79
    uint8_t  orig_video_mode;           /* 0x06 */
 
80
    uint8_t  orig_video_cols;           /* 0x07 */
 
81
    uint16_t unused2;                   /* 0x08 */
 
82
    uint16_t orig_video_ega_bx;         /* 0x0a */
 
83
    uint16_t unused3;                   /* 0x0c */
 
84
    uint8_t  orig_video_lines;          /* 0x0e */
 
85
    uint8_t  orig_video_isVGA;          /* 0x0f */
 
86
    uint16_t orig_video_points;         /* 0x10 */
 
87
 
 
88
    /* VESA graphic mode -- linear frame buffer */
 
89
    uint16_t lfb_width;                 /* 0x12 */
 
90
    uint16_t lfb_height;                /* 0x14 */
 
91
    uint16_t lfb_depth;                 /* 0x16 */
 
92
    uint32_t lfb_base;                  /* 0x18 */
 
93
    uint32_t lfb_size;                  /* 0x1c */
 
94
    uint16_t cl_magic;                  /* 0x20 */
 
95
#define CL_MAGIC_VALUE 0xA33F
 
96
    uint16_t cl_offset;                 /* 0x22 */
 
97
    uint16_t lfb_linelength;            /* 0x24 */
 
98
    uint8_t  red_size;                  /* 0x26 */
 
99
    uint8_t  red_pos;                   /* 0x27 */
 
100
    uint8_t  green_size;                /* 0x28 */
 
101
    uint8_t  green_pos;                 /* 0x29 */
 
102
    uint8_t  blue_size;                 /* 0x2a */
 
103
    uint8_t  blue_pos;                  /* 0x2b */
 
104
    uint8_t  rsvd_size;                 /* 0x2c */
 
105
    uint8_t  rsvd_pos;                  /* 0x2d */
 
106
    uint16_t vesapm_seg;                /* 0x2e */
 
107
    uint16_t vesapm_off;                /* 0x30 */
 
108
    uint16_t pages;                     /* 0x32 */
 
109
    uint8_t  reserved4[12];             /* 0x34 -- 0x3f reserved for future expansion */
 
110
 
 
111
    //struct apm_bios_info apm_bios_info;       /* 0x40 */
 
112
    uint8_t  apm_bios_info[0x40];
 
113
    //struct drive_info_struct drive_info;      /* 0x80 */
 
114
    uint8_t  drive_info[0x20];
 
115
    //struct sys_desc_table sys_desc_table;     /* 0xa0 */
 
116
    uint8_t  sys_desc_table[0x140];
 
117
    uint32_t alt_mem_k;                 /* 0x1e0 */
 
118
    uint8_t  reserved5[4];              /* 0x1e4 */
 
119
    uint8_t  e820_map_nr;               /* 0x1e8 */
 
120
    uint8_t  reserved6[9];              /* 0x1e9 */
 
121
    uint16_t mount_root_rdonly;         /* 0x1f2 */
 
122
    uint8_t  reserved7[4];              /* 0x1f4 */
 
123
    uint16_t ramdisk_flags;             /* 0x1f8 */
 
124
#define RAMDISK_IMAGE_START_MASK        0x07FF
 
125
#define RAMDISK_PROMPT_FLAG             0x8000
 
126
#define RAMDISK_LOAD_FLAG               0x4000
 
127
    uint8_t  reserved8[2];              /* 0x1fa */
 
128
    uint16_t orig_root_dev;             /* 0x1fc */
 
129
    uint8_t  reserved9[1];              /* 0x1fe */
 
130
    uint8_t  aux_device_info;           /* 0x1ff */
 
131
    uint8_t  reserved10[2];             /* 0x200 */
 
132
    uint8_t  param_block_signature[4];  /* 0x202 */
 
133
    uint16_t param_block_version;       /* 0x206 */
 
134
    uint8_t  reserved11[8];             /* 0x208 */
 
135
    uint8_t  loader_type;               /* 0x210 */
 
136
#define LOADER_TYPE_LOADLIN         1
 
137
#define LOADER_TYPE_BOOTSECT_LOADER 2
 
138
#define LOADER_TYPE_SYSLINUX        3
 
139
#define LOADER_TYPE_ETHERBOOT       4
 
140
#define LOADER_TYPE_KERNEL          5
 
141
    uint8_t  loader_flags;              /* 0x211 */
 
142
    uint8_t  reserved12[2];             /* 0x212 */
 
143
    uint32_t kernel_start;              /* 0x214 */
 
144
    uint32_t initrd_start;              /* 0x218 */
 
145
    uint32_t initrd_size;               /* 0x21c */
 
146
    uint8_t  reserved12_5[8];           /* 0x220 */
 
147
    uint32_t cmd_line_ptr;              /* 0x228 */
 
148
    uint8_t  reserved13[164];           /* 0x22c */
 
149
    struct e820entry e820_map[E820MAX]; /* 0x2d0 */
 
150
    uint8_t  reserved16[688];           /* 0x550 */
 
151
#define COMMAND_LINE_SIZE 256
 
152
    /* Command line is copied here by 32-bit i386/kernel/head.S.
 
153
     * So I will follow the boot protocol, rather than putting it
 
154
     * directly here. --ts1 */
 
155
    uint8_t  command_line[COMMAND_LINE_SIZE]; /* 0x800 */
 
156
    uint8_t  reserved17[1792];          /* 0x900 - 0x1000 */
 
157
};
 
158
 
 
159
uint64_t forced_memsize;
 
160
 
 
161
/* Load the first part the file and check if it's Linux */
 
162
static uint32_t load_linux_header(struct linux_header *hdr)
 
163
{
 
164
    int load_high;
 
165
    uint32_t kern_addr;
 
166
 
 
167
    if (lfile_read(hdr, sizeof *hdr) != sizeof *hdr) {
 
168
        debug("Can't read Linux header\n");
 
169
        return 0;
 
170
    }
 
171
    if (hdr->boot_sector_magic != 0xaa55) {
 
172
        debug("Not a Linux kernel image\n");
 
173
        return 0;
 
174
    }
 
175
 
 
176
    /* Linux is found. Print some information */
 
177
    if (memcmp(hdr->header_magic, "HdrS", 4) != 0) {
 
178
        /* This may be floppy disk image or something.
 
179
         * Perform a simple (incomplete) sanity check. */
 
180
        if (hdr->setup_sects >= 16
 
181
                || file_size() - (hdr->setup_sects<<9) >= 512<<10) {
 
182
            debug("This looks like a bootdisk image but not like Linux...\n");
 
183
            return 0;
 
184
        }
 
185
 
 
186
        printf("Possible very old Linux");
 
187
        /* This kernel does not even have a protocol version.
 
188
         * Force the value. */
 
189
        hdr->protocol_version = 0; /* pre-2.00 */
 
190
    } else
 
191
        printf("Found Linux");
 
192
    if (hdr->protocol_version >= 0x200 && hdr->kver_addr) {
 
193
        char kver[256];
 
194
        file_seek(hdr->kver_addr + 0x200);
 
195
        if (lfile_read(kver, sizeof kver) != 0) {
 
196
            kver[255] = 0;
 
197
            printf(" version %s", kver);
 
198
        }
 
199
    }
 
200
    debug(" (protocol %#x)", hdr->protocol_version);
 
201
    load_high = 0;
 
202
    if (hdr->protocol_version >= 0x200) {
 
203
        debug(" (loadflags %#x)", hdr->loadflags);
 
204
        load_high = hdr->loadflags & 1;
 
205
    }
 
206
    if (load_high) {
 
207
        printf(" bzImage");
 
208
        kern_addr = 0x100000;
 
209
    } else {
 
210
        printf(" zImage or Image");
 
211
        kern_addr = 0x1000;
 
212
    }
 
213
    printf(".\n");
 
214
 
 
215
    return kern_addr;
 
216
}
 
217
 
 
218
/* Set up parameters for 32-bit kernel */
 
219
static void
 
220
init_linux_params(struct linux_params *params, struct linux_header *hdr)
 
221
{
 
222
    debug("Setting up parameters at %#lx\n", virt_to_phys(params));
 
223
    memset(params, 0, sizeof *params);
 
224
 
 
225
    /* Copy some useful values from header */
 
226
    params->mount_root_rdonly = hdr->root_flags;
 
227
    params->orig_root_dev = hdr->root_dev;
 
228
 
 
229
    /* Video parameters.
 
230
     * This assumes we have VGA in standard 80x25 text mode,
 
231
     * just like our vga.c does.
 
232
     * Cursor position is filled later to allow some more printf's. */
 
233
    params->orig_video_mode = 3;
 
234
    params->orig_video_cols = 80;
 
235
    params->orig_video_lines = 25;
 
236
    params->orig_video_isVGA = 1;
 
237
    params->orig_video_points = 16;
 
238
 
 
239
    params->loader_type = 0xff; /* Unregistered Linux loader */
 
240
}
 
241
 
 
242
/* Memory map */
 
243
static void
 
244
set_memory_size(struct linux_params *params, struct sys_info *info)
 
245
{
 
246
    int i;
 
247
    uint64_t end;
 
248
    uint32_t ramtop = 0;
 
249
    struct e820entry *linux_map;
 
250
    struct memrange *filo_map;
 
251
 
 
252
    linux_map = params->e820_map;
 
253
    filo_map = info->memrange;
 
254
    for (i = 0; i < info->n_memranges; i++, linux_map++, filo_map++) {
 
255
        if (i < E820MAX) {
 
256
            /* Convert to BIOS e820 style */
 
257
            linux_map->addr = filo_map->base;
 
258
            linux_map->size = filo_map->size;
 
259
            linux_map->type = E820_RAM;
 
260
            debug("%016Lx - %016Lx\n", linux_map->addr,
 
261
                    linux_map->addr + linux_map->size);
 
262
            params->e820_map_nr = i+1;
 
263
        }
 
264
 
 
265
        /* Find out top of RAM. XXX This ignores hole above 1MB */
 
266
        end = filo_map->base + filo_map->size;
 
267
        if (end < (1ULL << 32)) { /* don't count memory above 4GB */
 
268
            if (end > ramtop)
 
269
                ramtop = (uint32_t) end;
 
270
        }
 
271
    }
 
272
    debug("ramtop=%#x\n", ramtop);
 
273
    /* Size of memory above 1MB in KB */
 
274
    params->alt_mem_k = (ramtop - (1<<20)) >> 10;
 
275
    /* old style, 64MB max */
 
276
    if (ramtop >= (64<<20))
 
277
        params->ext_mem_k = (63<<10);
 
278
    else
 
279
        params->ext_mem_k = params->alt_mem_k;
 
280
    debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k);
 
281
}
 
282
 
 
283
/*
 
284
 * Parse command line
 
285
 * Some parameters, like initrd=<file>, are not passed to kernel,
 
286
 * we are responsible to process them.
 
287
 * Parameters for kernel are copied to kern_cmdline. Returns name of initrd.
 
288
 */
 
289
static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline)
 
290
{
 
291
    const char *start, *sep, *end, *val;
 
292
    char name[64];
 
293
    int len;
 
294
    int k_len;
 
295
    int to_kern;
 
296
    char *initrd = 0;
 
297
    int toolong = 0;
 
298
 
 
299
    forced_memsize = 0;
 
300
 
 
301
    if (!orig_cmdline) {
 
302
        *kern_cmdline = 0;
 
303
        return 0;
 
304
    }
 
305
 
 
306
    k_len = 0;
 
307
    debug("original command line: \"%s\"\n", orig_cmdline);
 
308
    debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline));
 
309
 
 
310
    start = orig_cmdline;
 
311
    while (*start == ' ')
 
312
        start++;
 
313
    while (*start) {
 
314
        end = strchr(start, ' ');
 
315
        if (!end)
 
316
            end = start + strlen(start);
 
317
        sep = strchr(start, '=');
 
318
        if (!sep || sep > end)
 
319
            sep = end;
 
320
        len = sep - start;
 
321
        if (len >= sizeof(name))
 
322
            len = sizeof(name) - 1;
 
323
        memcpy(name, start, len);
 
324
        name[len] = 0;
 
325
 
 
326
        if (*sep == '=') {
 
327
            val = sep + 1;
 
328
            len = end - val;
 
329
        } else {
 
330
            val = 0;
 
331
            len = 0;
 
332
        }
 
333
 
 
334
        /* Only initrd= and mem= are handled here. vga= is not,
 
335
         * which I believe is a paramter to the realmode part of Linux,
 
336
         * which we don't execute. */
 
337
        if (strcmp(name, "initrd") == 0) {
 
338
            if (!val)
 
339
                printf("Missing filename to initrd parameter\n");
 
340
            else {
 
341
                initrd = malloc(len + 1);
 
342
                memcpy(initrd, val, len);
 
343
                initrd[len] = 0;
 
344
                debug("initrd=%s\n", initrd);
 
345
            }
 
346
            /* Don't pass this to kernel */
 
347
            to_kern = 0;
 
348
        } else if (strcmp(name, "mem") == 0) {
 
349
            if (!val)
 
350
                printf("Missing value for mem parameter\n");
 
351
            else {
 
352
                forced_memsize = strtoull_with_suffix(val, (char**)&val, 0);
 
353
                if (forced_memsize == 0)
 
354
                    printf("Invalid mem option, ignored\n");
 
355
                if (val != end) {
 
356
                    printf("Garbage after mem=<size>, ignored\n");
 
357
                    forced_memsize = 0;
 
358
                }
 
359
                debug("mem=%Lu\n", forced_memsize);
 
360
            }
 
361
            /* mem= is for both loader and kernel */
 
362
            to_kern = 1;
 
363
        } else
 
364
            to_kern = 1;
 
365
 
 
366
        if (to_kern) {
 
367
            /* Copy to kernel command line buffer */
 
368
            if (k_len != 0)
 
369
                kern_cmdline[k_len++] = ' '; /* put separator */
 
370
            len = end - start;
 
371
            if (k_len + len >= COMMAND_LINE_SIZE) {
 
372
                len = COMMAND_LINE_SIZE - k_len - 1;
 
373
                if (!toolong) {
 
374
                    printf("Kernel command line is too long; truncated to "
 
375
                            "%d bytes\n", COMMAND_LINE_SIZE-1);
 
376
                    toolong = 1;
 
377
                }
 
378
            }
 
379
            memcpy(kern_cmdline + k_len, start, len);
 
380
            k_len += len;
 
381
        }
 
382
 
 
383
        start = end;
 
384
        while (*start == ' ')
 
385
            start++;
 
386
    }
 
387
    kern_cmdline[k_len] = 0;
 
388
    debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline);
 
389
 
 
390
    return initrd;
 
391
}
 
392
 
 
393
/* Set command line location */
 
394
static void set_command_line_loc(struct linux_params *params,
 
395
        struct linux_header *hdr)
 
396
{
 
397
    if (hdr->protocol_version >= 0x202) {
 
398
        /* new style */
 
399
        params->cmd_line_ptr = COMMAND_LINE_LOC;
 
400
    } else {
 
401
        /* old style */
 
402
        params->cl_magic = CL_MAGIC_VALUE;
 
403
        params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC;
 
404
    }
 
405
}
 
406
 
 
407
/* Load 32-bit part of kernel */
 
408
static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr)
 
409
{
 
410
    uint32_t kern_offset, kern_size;
 
411
 
 
412
    if (hdr->setup_sects == 0)
 
413
        hdr->setup_sects = 4;
 
414
    kern_offset = (hdr->setup_sects + 1) * 512;
 
415
    file_seek(kern_offset);
 
416
    kern_size = file_size() - kern_offset;
 
417
    debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size);
 
418
 
 
419
#if 0
 
420
    if (using_devsize) {
 
421
        printf("Attempt to load up to end of device as kernel; "
 
422
                "specify the image size\n");
 
423
        return 0;
 
424
    }
 
425
#endif
 
426
 
 
427
    printf("Loading kernel... ");
 
428
    if (lfile_read(phys_to_virt(kern_addr), kern_size) != kern_size) {
 
429
        printf("Can't read kernel\n");
 
430
        return 0;
 
431
    }
 
432
    printf("ok\n");
 
433
 
 
434
    return kern_size;
 
435
}
 
436
 
 
437
static int load_initrd(struct linux_header *hdr, struct sys_info *info,
 
438
        uint32_t kern_end, struct linux_params *params, const char *initrd_file)
 
439
{
 
440
    uint32_t max;
 
441
    uint32_t start, end, size;
 
442
    uint64_t forced;
 
443
    extern char _start[], _end[];
 
444
 
 
445
    if (!file_open(initrd_file)) {
 
446
        printf("Can't open initrd: %s\n", initrd_file);
 
447
        return -1;
 
448
    }
 
449
 
 
450
#if 0
 
451
    if (using_devsize) {
 
452
        printf("Attempt to load up to end of device as initrd; "
 
453
                "specify the image size\n");
 
454
        return -1;
 
455
    }
 
456
#endif
 
457
 
 
458
    size = file_size();
 
459
 
 
460
 
 
461
    /* Find out the kernel's restriction on how high the initrd can be
 
462
     * placed */
 
463
    if (hdr->protocol_version >= 0x203)
 
464
        max = hdr->initrd_addr_max;
 
465
    else
 
466
        max = 0x38000000; /* Hardcoded value for older kernels */
 
467
 
 
468
    /* FILO itself is at the top of RAM. (relocated)
 
469
     * So, try putting initrd just below us. */
 
470
    end = virt_to_phys(_start);
 
471
    if (end > max)
 
472
        end = max;
 
473
 
 
474
    /* If "mem=" option is given, we have to put the initrd within
 
475
     * the specified range. */
 
476
    if (forced_memsize) {
 
477
        forced = forced_memsize;
 
478
        if (forced > max)
 
479
            forced = max;
 
480
        /* If the "mem=" is lower, it's easy */
 
481
        if (forced <= end)
 
482
            end = forced;
 
483
        else {
 
484
            /* Otherwise, see if we can put it above us */
 
485
            if (virt_to_phys(_end) + size <= forced)
 
486
                end = forced; /* Ok */
 
487
        }
 
488
    }
 
489
 
 
490
    start = end - size;
 
491
    start &= ~0xfff; /* page align */
 
492
    end = start + size;
 
493
 
 
494
    debug("start=%#x end=%#x\n", start, end);
 
495
 
 
496
    if (start < kern_end) {
 
497
        printf("Initrd is too big to fit in memory\n");
 
498
        return -1;
 
499
    }
 
500
 
 
501
    printf("Loading initrd... ");
 
502
    if (lfile_read(phys_to_virt(start), size) != size) {
 
503
        printf("Can't read initrd\n");
 
504
        return -1;
 
505
    }
 
506
    printf("ok\n");
 
507
 
 
508
    params->initrd_start = start;
 
509
    params->initrd_size = size;
 
510
 
 
511
    return 0;
 
512
}
 
513
 
 
514
static void hardware_setup(void)
 
515
{
 
516
    /* Disable nmi */
 
517
    outb(0x80, 0x70);
 
518
 
 
519
    /* Make sure any coprocessor is properly reset.. */
 
520
    outb(0, 0xf0);
 
521
    outb(0, 0xf1);
 
522
 
 
523
    /* we're getting screwed again and again by this problem of the 8259.
 
524
     * so we're going to leave this lying around for inclusion into
 
525
     * crt0.S on an as-needed basis.
 
526
     *
 
527
     * well, that went ok, I hope. Now we have to reprogram the interrupts :-(
 
528
     * we put them right after the intel-reserved hardware interrupts, at
 
529
     * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
 
530
     * messed this up with the original PC, and they haven't been able to
 
531
     * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
 
532
     * which is used for the internal hardware interrupts as well. We just
 
533
     * have to reprogram the 8259's, and it isn't fun.
 
534
     */
 
535
 
 
536
    outb(0x11, 0x20);           /* initialization sequence to 8259A-1 */
 
537
    outb(0x11, 0xA0);           /* and to 8259A-2 */
 
538
 
 
539
    outb(0x20, 0x21);           /* start of hardware int's (0x20) */
 
540
    outb(0x28, 0xA1);           /* start of hardware int's 2 (0x28) */
 
541
 
 
542
    outb(0x04, 0x21);           /* 8259-1 is master */
 
543
    outb(0x02, 0xA1);           /* 8259-2 is slave */
 
544
 
 
545
    outb(0x01, 0x21);           /* 8086 mode for both */
 
546
    outb(0x01, 0xA1);
 
547
 
 
548
    outb(0xFF, 0xA1);           /* mask off all interrupts for now */
 
549
    outb(0xFB, 0x21);           /* mask all irq's but irq2 which is cascaded */
 
550
}
 
551
 
 
552
/* Start Linux */
 
553
static int start_linux(uint32_t kern_addr, struct linux_params *params)
 
554
{
 
555
    struct segment_desc *linux_gdt;
 
556
    struct context *ctx;
 
557
    //extern int cursor_x, cursor_y;
 
558
 
 
559
    ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0);
 
560
 
 
561
    /* Linux expects GDT being in low memory */
 
562
    linux_gdt = phys_to_virt(GDT_LOC);
 
563
    memset(linux_gdt, 0, 13*sizeof(struct segment_desc));
 
564
    /* Normal kernel code/data segments */
 
565
    linux_gdt[2] = gdt[FLAT_CODE];
 
566
    linux_gdt[3] = gdt[FLAT_DATA];
 
567
    /* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible
 
568
     * segments (2 and 3), so it SHOULD not be a problem.
 
569
     * However, some distro kernels (eg. RH9) with backported threading
 
570
     * patch use 12 and 13 also when booting... */
 
571
    linux_gdt[12] = gdt[FLAT_CODE];
 
572
    linux_gdt[13] = gdt[FLAT_DATA];
 
573
    ctx->gdt_base = GDT_LOC;
 
574
    ctx->gdt_limit = 14*8-1;
 
575
    ctx->cs = 0x10;
 
576
    ctx->ds = 0x18;
 
577
    ctx->es = 0x18;
 
578
    ctx->fs = 0x18;
 
579
    ctx->gs = 0x18;
 
580
    ctx->ss = 0x18;
 
581
 
 
582
    /* Parameter location */
 
583
    ctx->esi = virt_to_phys(params);
 
584
 
 
585
    /* Entry point */
 
586
    ctx->eip = kern_addr;
 
587
 
 
588
    debug("eip=%#x\n", kern_addr);
 
589
    printf("Jumping to entry point...\n");
 
590
 
 
591
#ifdef VGA_CONSOLE
 
592
    /* Update VGA cursor position.
 
593
     * This must be here because the printf changes the value! */
 
594
    params->orig_x = cursor_x;
 
595
    params->orig_y = cursor_y;
 
596
#endif
 
597
 
 
598
    /* Go... */
 
599
    ctx = switch_to(ctx);
 
600
 
 
601
    /* It's impossible but... */
 
602
    printf("Returned with eax=%#x\n", ctx->eax);
 
603
 
 
604
    return ctx->eax;
 
605
}
 
606
 
 
607
int linux_load(struct sys_info *info, const char *file, const char *cmdline)
 
608
{
 
609
    struct linux_header hdr;
 
610
    struct linux_params *params;
 
611
    uint32_t kern_addr, kern_size;
 
612
    char *initrd_file = 0;
 
613
 
 
614
    if (!file_open(file))
 
615
        return -1;
 
616
 
 
617
    kern_addr = load_linux_header(&hdr);
 
618
    if (kern_addr == 0)
 
619
        return LOADER_NOT_SUPPORT;
 
620
 
 
621
    params = phys_to_virt(LINUX_PARAM_LOC);
 
622
    init_linux_params(params, &hdr);
 
623
    set_memory_size(params, info);
 
624
    initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC));
 
625
    set_command_line_loc(params, &hdr);
 
626
 
 
627
    kern_size = load_linux_kernel(&hdr, kern_addr);
 
628
    if (kern_size == 0) {
 
629
        if (initrd_file)
 
630
            free(initrd_file);
 
631
        return -1;
 
632
    }
 
633
 
 
634
    if (initrd_file) {
 
635
        if (load_initrd(&hdr, info, kern_addr+kern_size, params, initrd_file)
 
636
                != 0) {
 
637
            free(initrd_file);
 
638
            return -1;
 
639
        }
 
640
        free(initrd_file);
 
641
    }
 
642
 
 
643
    hardware_setup();
 
644
 
 
645
    start_linux(kern_addr, params);
 
646
    return 0;
 
647
}