Show
Ignore:
Timestamp:
10/29/09 23:13:44 (3 years ago)
Author:
Gert Hulselmans <kimmik999999@…>
Children:
4b4cfe0cd38d6ab371f58d76a171b5edcffd9787
Parents:
d4849a0057a73ac8041e7935dc5ed1598111dcc9
git-committer:
Gert Hulselmans <kimmik999999@yahoo.co.uk> / 2009-10-29T19:13:44Z-0400
Message:

[chain] Add support for chain-loading another isolinux.bin

Add 'isolinux=' option to chain.c32 for chain-loading
another isolinux.bin.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • com32/modules/chain.c

    r3fc312 r39adcc  
    3939 * seg=<segment>: 
    4040 *      loads at and jumps to <seg>:0000 instead of 0000:7C00. 
     41 * 
     42 * isolinux=<loader>: 
     43 *      chainload another version/build of the ISOLINUX bootloader and patch 
     44 *      the loader with appropriate parameters in memory. 
     45 *      This avoids the need for the -eltorito-alt-boot parameter of mkisofs, 
     46 *      when you want more than one ISOLINUX per CD/DVD. 
    4147 * 
    4248 * ntldr=<loader>: 
     
    7884    uint16_t keeppxe; 
    7985    uint16_t seg; 
     86    bool isolinux; 
    8087    bool swap; 
    8188    bool hide; 
     
    590597} 
    591598 
     599 
     600 
     601static uint32_t get_file_lba(const char *filename) 
     602{ 
     603    com32sys_t inregs;  
     604    uint32_t lba; 
     605 
     606    /* Start with clean registers */ 
     607    memset(&inregs, 0, sizeof(com32sys_t)); 
     608 
     609    /* Put the filename in the bounce buffer */ 
     610    strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size); 
     611 
     612    /* Call comapi_open() which returns a structure pointer in SI 
     613     * to a structure whose first member happens to be the LBA. 
     614     */ 
     615    inregs.eax.w[0] = 0x0006; 
     616    inregs.esi.w[0] = OFFS(__com32.cs_bounce); 
     617    inregs.es = SEG(__com32.cs_bounce); 
     618    __com32.cs_intcall(0x22, &inregs, &inregs); 
     619 
     620    if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) { 
     621        return 0; /* Filename not found */ 
     622    } 
     623 
     624    /* Since the first member is the LBA, we simply cast */ 
     625    lba = *((uint32_t*)MK_PTR(inregs.ds, inregs.esi.w[0])); 
     626 
     627    /* Clean the registers for the next call*/ 
     628    memset(&inregs, 0, sizeof(com32sys_t)); 
     629 
     630    /* Put the filename in the bounce buffer */ 
     631    strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size); 
     632 
     633    /* Call comapi_close() to free the structure */ 
     634    inregs.eax.w[0] = 0x0008; 
     635    inregs.esi.w[0] = OFFS(__com32.cs_bounce); 
     636    inregs.es = SEG(__com32.cs_bounce); 
     637    __com32.cs_intcall(0x22, &inregs, &inregs); 
     638 
     639    return lba; 
     640} 
     641 
    592642int main(int argc, char *argv[]) 
    593643{ 
     
    599649    int hd, drive, whichpart; 
    600650    int i; 
     651    uint32_t file_lba = 0; 
     652    unsigned char *isolinux_bin; 
     653    uint32_t *checksum, *chkhead, *chktail; 
    601654    size_t boot_size = SECTOR; 
     655 
    602656 
    603657    openconsole(&dev_null_r, &dev_stdcon_w); 
     
    619673            } 
    620674            opt.seg = segval; 
     675        } else if (!strncmp(argv[i], "isolinux=", 9)) { 
     676            opt.loadfile = argv[i] + 9; 
     677            opt.isolinux = true; 
    621678        } else if (!strncmp(argv[i], "ntldr=", 6)) { 
    622679            opt.seg = 0x2000;   /* NTLDR wants this address */ 
     
    656713                 "         chain.c32 boot [<partition>] [options]\n" 
    657714                 "Options: file=<loader>      load file, instead of boot sector\n" 
     715                 "         isolinux=<loader>  load another version of ISOLINUX\n" 
    658716                 "         ntldr=<loader>     load Windows bootloaders: NTLDR, SETUPLDR, BOOTMGR\n" 
    659717                 "         freedos=<loader>   load FreeDOS kernel.sys\n" 
     
    760818            goto bail; 
    761819        } 
     820 
     821        /* Create boot info table: needed when you want to chainload 
     822           another version of ISOLINUX (or another bootlaoder that needs 
     823           the -boot-info-table switch of mkisofs) 
     824           (will only work when run from ISOLINUX) */ 
     825        if (opt.isolinux) { 
     826            const union syslinux_derivative_info *sdi; 
     827            sdi = syslinux_derivative_info(); 
     828 
     829            if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) { 
     830                /* Boot info table info (integers in little endian format) 
     831 
     832                   Offset Name         Size      Meaning 
     833                     8     bi_pvd       4 bytes   LBA of primary volume descriptor 
     834                    12     bi_file      4 bytes   LBA of boot file 
     835                    16     bi_length    4 bytes   Boot file length in bytes 
     836                    20     bi_csum      4 bytes   32-bit checksum 
     837                    24     bi_reserved  40 bytes  Reserved 
     838 
     839                   The 32-bit checksum is the sum of all the 32-bit words in the 
     840                   boot file starting at byte offset 64. All linear block 
     841                   addresses (LBAs) are given in CD sectors (normally 2048 bytes). 
     842 
     843                   LBA of primary volume descriptor should already be set to 16.  
     844                */ 
     845 
     846                isolinux_bin = (unsigned char*)boot_sector; 
     847 
     848                /* Get LBA address of bootfile */ 
     849                file_lba = get_file_lba(opt.loadfile); 
     850 
     851                if (file_lba == 0) { 
     852                    error("Failed to find LBA offset of the boot file\n"); 
     853                    goto bail; 
     854                } 
     855                /* Set it */ 
     856                *((uint32_t*)&isolinux_bin[12]) = file_lba; 
     857 
     858                /* Set boot file length */               
     859                *((uint32_t*)&isolinux_bin[16]) = boot_size; 
     860 
     861                /* Calculate checksum */ 
     862                checksum = (uint32_t*)&isolinux_bin[20]; 
     863                chkhead = (uint32_t*)&isolinux_bin[64]; 
     864                chktail = (uint32_t*)&isolinux_bin[boot_size-1]; 
     865                /* Fresh checksum and clear possibly fractional uint32_t at the end */ 
     866                *checksum = *((uint32_t*)&isolinux_bin[boot_size]) = 0; 
     867 
     868                while (chkhead <= chktail) 
     869                { 
     870                        *checksum += *chkhead++; 
     871                } 
     872            } 
     873            else { 
     874                error("The isolinux= option is only valid when run from ISOLINUX\n"); 
     875                goto bail; 
     876            } 
     877        }  
     878             
    762879    } else if (partinfo) { 
    763880        /* Actually read the boot sector */ 
     
    788905    return 255; 
    789906} 
     907