Annotation of qemu/roms/openbios/arch/x86/linux_load.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.