| | 599 | |
| | 600 | |
| | 601 | static 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 | |
| | 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 | |