diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-09-02 11:27:11 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-09-02 11:27:11 -0700 |
commit | 8a33d6742b1c76c0cf86fe0154e761ff2353dc39 (patch) | |
tree | 1b300a29cbd983267163e9158ab8cee3192ef321 | |
parent | bb1023d5da5914999484164205f383412bf3ca5e (diff) | |
parent | 25fb8ebda235fad14d64949180405877a3a394df (diff) | |
download | syslinux-8a33d6742b1c76c0cf86fe0154e761ff2353dc39.tar.gz |
Merge branch 'fsc' into elflink
Resolved Conflicts:
MCONFIG.embedded
com32/MCONFIG
com32/lib/Makefile
core/Makefile
core/extern.inc
core/extlinux.asm
core/isolinux.asm
core/syslinux.ld
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
143 files changed, 12829 insertions, 11069 deletions
diff --git a/MCONFIG.embedded b/MCONFIG.embedded index b74d8da7..bb718963 100644 --- a/MCONFIG.embedded +++ b/MCONFIG.embedded @@ -25,6 +25,7 @@ GCCOPT += -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3 \ -msoft-float GCCOPT += $(call gcc_ok,-fno-exceptions,) GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,) +GCCOPT += $(call gcc_ok,-fno-strict-aliasing,) GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0) GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0) GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0) @@ -12,6 +12,12 @@ Changes in 3.83: * MEMDISK: fix problems booting from USB on Thinkpads, and possibly other machines or hardware combinations. * isohybrid: fix the -id option. + * HDT: updated to version 0.3.4. + * MEMDISK: the stack size is now configurable, with the stack= + option. + * Simple menu: fix Ctrl-W (word erase) in command-line edit. + * Simple menu: fix crash on some platforms. + * Gfxboot: fixes to the configuration file parsing. Changes in 3.82: * isohybrid: fix the -partok logic for loading from a partition. diff --git a/com32/MCONFIG b/com32/MCONFIG index 5d2e747a..aa55741e 100644 --- a/com32/MCONFIG +++ b/com32/MCONFIG @@ -26,6 +26,9 @@ GCCOPT += -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3 GCCOPT += $(call gcc_ok,-fno-exceptions,) GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,) GCCOPT += $(call gcc_ok,-fPIE,-fPIC) +GCCOPT += $(call gcc_ok,-fno-exceptions,) +GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,) +GCCOPT += $(call gcc_ok,-fno-strict-aliasing,) GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0) GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0) GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0) diff --git a/com32/cmenu/libmenu/com32io.h b/com32/cmenu/libmenu/com32io.h index ba955e99..cdaf0a84 100644 --- a/com32/cmenu/libmenu/com32io.h +++ b/com32/cmenu/libmenu/com32io.h @@ -71,7 +71,7 @@ static inline unsigned char readbiosb(unsigned int ofs) static inline char getnumrows() { - return readbiosb(0x484); // Actually numrows - 1 + return readbiosb(0x484)+1; // Actually numrows - 1 } static inline char getnumcols(void) diff --git a/com32/gplinclude/disk/common.h b/com32/gplinclude/disk/common.h new file mode 100644 index 00000000..c6df2f4e --- /dev/null +++ b/com32/gplinclude/disk/common.h @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include <stdint.h> + +#define SECTOR 512 /* bytes/sector */ + +#undef PAGE_SIZE +#define PAGE_SIZE (1<<12) + +struct ebios_dapa { + uint16_t len; + uint16_t count; + uint16_t off; + uint16_t seg; + uint64_t lba; +}; + +#endif /* _COMMON_H_ */ diff --git a/com32/gplinclude/disk/errno_disk.h b/com32/gplinclude/disk/errno_disk.h new file mode 100644 index 00000000..60b511fc --- /dev/null +++ b/com32/gplinclude/disk/errno_disk.h @@ -0,0 +1,50 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _ERRNO_DISK_H +#define _ERRNO_DISK_H + +extern int errno_disk; + +/* Prefix with ED to avoid confusion with errno */ +#define EDINV 0x01 /* Invalid function in AH or invalid parameter */ +#define EDADDR 0x02 /* Address mark not found */ +#define EDRO 0x03 /* Disk write-protected */ +#define EDNOFND 0x04 /* Sector not found/read error */ +#define EDRFAIL 0x05 /* Reset failed (hard disk) */ +#define EDCHANG 0x06 /* Disk changed (floppy) */ +#define EDFAIL 0x07 /* Drive parameter activity failed (hard disk) */ +#define EDDMA 0x08 /* DMA overrun */ +#define EDBOUND 0x09 /* Data boundary error (attempted DMA across 64K boundary or >80h sectors) */ +#define EDBADS 0x0A /* Bad sector detected (hard disk) */ +#define EDBADT 0x0B /* Bad track detected (hard disk) */ +#define EDINVM 0x0C /* Unsupported track or invalid media */ +#define EDINVS 0x0D /* Invalid number of sectors on format (PS/2 hard disk) */ +#define EDADDRM 0x0E /* Control data address mark detected (hard disk) */ +#define EDDMARG 0x0F /* DMA arbitration level out of range (hard disk) */ +#define EDCRCF 0x10 /* Uncorrectable CRC or ECC error on read */ +#define EDCRCV 0x11 /* Data ECC corrected (hard disk) */ +#define EDCTRL 0x20 /* Controller failure */ +#define EDMEDIA 0x31 /* No media in drive (IBM/MS INT 13 extensions) */ +#define EDCMOS 0x32 /* Incorrect drive type stored in CMOS (Compaq) */ +#define EDSEEKF 0x40 /* Seek failed */ +#define EDTIME 0x80 /* Timeout (not ready) */ +#define EDREADY 0xAA /* Drive not ready (hard disk) */ +#define EDNLOCK 0xB0 /* Volume not locked in drive (INT 13 extensions) */ +#define EDLOCK 0xB1 /* Volume locked in drive (INT 13 extensions) */ +#define EDREMOV 0xB2 /* Volume not removable (INT 13 extensions) */ +#define EDUSED 0xB3 /* Volume in use (INT 13 extensions) */ +#define EDCOUNT 0xB4 /* Lock count exceeded (INT 13 extensions) */ +#define EDEJF 0xB5 /* Valid eject request failed (INT 13 extensions) */ +#define EDUNKOWN 0xBB /* Undefined error (hard disk) */ +#define EDWF 0xCC /* Write fault (hard disk) */ +#define EDRF 0xE0 /* Status register error (hard disk) */ +#define EDSF 0xFF /* Sense operation failed (hard disk) */ + +#endif /* _ERRNO_DISK_H */ diff --git a/com32/gplinclude/disk/error.h b/com32/gplinclude/disk/error.h new file mode 100644 index 00000000..f9e319c4 --- /dev/null +++ b/com32/gplinclude/disk/error.h @@ -0,0 +1,13 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _ERROR_H_ +#define _ERROR_H_ +void get_error(void*); +#endif /* _UTIL_H_ */ diff --git a/com32/gplinclude/disk/geom.h b/com32/gplinclude/disk/geom.h new file mode 100644 index 00000000..0d3eed57 --- /dev/null +++ b/com32/gplinclude/disk/geom.h @@ -0,0 +1,325 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * Some parts borrowed from Linux: + * + * Copyright (C) 2002, 2003, 2004 Dell Inc. + * by Matt Domsch <Matt_Domsch@dell.com> + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _GEOM_H_ +#define _GEOM_H_ + +#include <stdint.h> + +/** + * INT 13 Extensions + * + * Note: if the size is less than 30 on call, the final DWORD will not be + * returned by a v2.x implementation; similarly for the Device Path info + **/ +struct edd_device_parameters { + uint16_t len; /* size of returned data */ + /** + * Bitfields for IBM/MS INT 13 Extensions information flags: + * Bit(s) Description (Table 00274) + * 0 DMA boundary errors handled transparently + * 1 cylinder/head/sectors-per-track information is valid + * 2 removable drive + * 3 write with verify supported + * 4 drive has change-line support (required if drive >= 80h is removable) + * 5 drive can be locked (required if drive >= 80h is removable) + * 6 CHS information set to maximum supported values, not current media + * 15-7 reserved (0) + **/ + uint16_t info; /* information flags */ + uint32_t cylinders; /* number of physical cylinders on drive */ + uint32_t heads; /* number of physical heads on drive */ + uint32_t sectors_per_track; /* number of physical sectors per track */ + uint64_t sectors; /* total number of sectors on drive */ + uint16_t bytes_per_sector; /* bytes per sector */ + /* --- v2.0+ --- */ + uint32_t dpte_pointer; /* EDD configuration parameters, FFFFh:FFFFh if not available */ + /* --- v3.0 --- */ + uint16_t device_path_information; /* signature BEDDh to indicate presence of Device Path info */ + uint8_t device_path_length; /* length of Device Path information, including signature and this byte (24h for v3.0) */ + uint8_t device_path_reserved; /* reserved (0) */ + uint16_t device_path_reserved_2; /* reserved (0) */ + uint8_t host_bus_type[4]; /* ASCIZ name of host bus ("ISA" or "PCI") */ + uint8_t interface_type[8]; /* ASCIZ name of interface type + * "ATA" + * "ATAPI" + * "SCSI" + * "USB" + * "1394" IEEE 1394 (FireWire) + * "FIBRE" Fibre Channel + */ + /** + * Format of EDD v3.0 Interface Path: + * Offset Size Description (Table 00275) + * ---ISA--- + * 00h WORD 16-bit base address + * 02h 6 BYTEs reserved (0) + * ---PCI--- + * 00h BYTE PCI bus number + * 01h BYTE PCI device number + * 02h BYTE PCI function number + * 03h 5 BYTEs reserved (0) + **/ + union { + struct { + uint16_t base_address; + uint16_t reserved1; + uint32_t reserved2; + } __attribute__ ((packed)) isa; + struct { + uint8_t bus; + uint8_t slot; + uint8_t function; + uint8_t channel; + uint32_t reserved; + } __attribute__ ((packed)) pci; + /* pcix is same as pci */ + struct { + uint64_t reserved; + } __attribute__ ((packed)) ibnd; + struct { + uint64_t reserved; + } __attribute__ ((packed)) xprs; + struct { + uint64_t reserved; + } __attribute__ ((packed)) htpt; + struct { + uint64_t reserved; + } __attribute__ ((packed)) unknown; + } interface_path; + /** + * Format of EDD v3.0 Device Path: + * Offset Size Description (Table 00276) + * ---ATA--- + * 00h BYTE flag: 00h = master, 01h = slave + * 01h 7 BYTEs reserved (0) + * ---ATAPI--- + * 00h BYTE flag: 00h = master, 01h = slave + * 01h BYTE logical unit number + * 02h 6 BYTEs reserved (0) + * ---SCSI--- + * 00h BYTE logical unit number + * 01h 7 BYTEs reserved (0) + * ---USB--- + * 00h BYTE to be determined + * 01h 7 BYTEs reserved (0) + * ---IEEE1394--- + * 00h QWORD 64-bit FireWire General Unique Identifier (GUID) + * ---FibreChannel--- + * 00h QWORD Word Wide Number (WWN) + **/ + union { + struct { + uint8_t device; + uint8_t reserved1; + uint16_t reserved2; + uint32_t reserved3; + uint64_t reserved4; + } __attribute__ ((packed)) ata; + struct { + uint8_t device; + uint8_t lun; + uint8_t reserved1; + uint8_t reserved2; + uint32_t reserved3; + uint64_t reserved4; + } __attribute__ ((packed)) atapi; + struct { + uint16_t id; + uint64_t lun; + uint16_t reserved1; + uint32_t reserved2; + } __attribute__ ((packed)) scsi; + struct { + uint64_t serial_number; + uint64_t reserved; + } __attribute__ ((packed)) usb; + struct { + uint64_t eui; + uint64_t reserved; + } __attribute__ ((packed)) i1394; + struct { + uint64_t wwid; + uint64_t lun; + } __attribute__ ((packed)) fibre; + struct { + uint64_t identity_tag; + uint64_t reserved; + } __attribute__ ((packed)) i2o; + struct { + uint32_t array_number; + uint32_t reserved1; + uint64_t reserved2; + } __attribute__ ((packed)) raid; + struct { + uint8_t device; + uint8_t reserved1; + uint16_t reserved2; + uint32_t reserved3; + uint64_t reserved4; + } __attribute__ ((packed)) sata; + struct { + uint64_t reserved1; + uint64_t reserved2; + } __attribute__ ((packed)) unknown; + } device_path; + uint8_t reserved; /* reserved (0) */ + uint8_t checksum; /* checksum of bytes 1Eh-40h (two's complement of sum, which makes + * the 8-bit sum of bytes 1Eh-41h equal 00h) */ +} __attribute__ ((packed)); + +/* + * Disk parameters + */ +struct driveinfo { + int disk; /* Disk port (0x80 - 0xff) */ + /* Legacy C/H/S */ + int cbios; /* CHS geometry is valid */ + int legacy_max_head; + int legacy_max_cylinder; + int legacy_sectors_per_track; + int legacy_max_drive; + int legacy_type; /* Drive type (AT/PS2 floppies only) */ + /* EDD support */ + int ebios; /* EBIOS supported on this disk */ + int edd_version; /* EBIOS major version */ + int edd_functionality_subset; + struct edd_device_parameters edd_params;/* EDD parameters */ +}; + +/** + * Format of Phoenix Enhanced Disk Drive Spec translated drive parameter table: + * Offset Size Description (Table 00277) + * 00h WORD number of cylinders + * 02h BYTE number of heads + * 03h BYTE A0h (signature indicating translated table) + * 04h BYTE number of physical sectors per track + * 05h WORD starting write precompensation cylinder number + * 07h BYTE reserved + * 08h BYTE control byte (see #03198 at INT 41"DISK 0") + * 09h WORD number of physical cylinders + * 0Bh BYTE number of physical heads + * 0Ch WORD cylinder number of landing zone + * 0Eh BYTE number of logical sectors per track + * 0Fh BYTE checksum + * Program: the Phoenix Enhanced Disk Drive Specification is an addition to the + * IBM/MS INT 13 extensions + * + * Format of Phoenix Enhanced Disk Drive Spec Fixed Disk Parameter Table: + * Offset Size Description (Table 00278) + * 00h WORD physical I/O port base address + * 02h WORD disk-drive control port address + * 04h BYTE drive flags (see #00279) + * 05h BYTE proprietary information + * bits 7-4 reserved (0) + * bits 3-0: Phoenix proprietary (used by BIOS) + * 06h BYTE IRQ for drive (bits 3-0; bits 7-4 reserved and must be 0) + * 07h BYTE sector count for multi-sector transfers + * 08h BYTE DMA control + * bits 7-4: DMA type (0-2) as per ATA-2 specification + * bits 3-0: DMA channel + * 09h BYTE programmed I/O control + * bits 7-4: reserved (0) + * bits 3-0: PIO type (1-4) as per ATA-2 specification + * 0Ah WORD drive options (see #00280) + * 0Ch 2 BYTEs reserved (0) + * 0Eh BYTE extension revision level (high nybble=major, low nybble=minor) + * (currently 10h for v1.0 and 11h for v1.1-3.0) + * 0Fh BYTE 2's complement checksum of bytes 00h-0Eh + * 8-bit sum of all bytes 00h-0Fh should equal 00h + * SeeAlso: #00277 + * + * Bitfields for Phoenix Enhanced Disk Drive Spec drive flags: + * Bit(s) Description (Table 00279) + * 7 reserved (1) + * 6 LBA enabled + * 5 reserved (1) + * 4 drive is slave + * 3-0 reserved (0) + * SeeAlso: #00278,#00280 + * + * Bitfields for Phoenix Enhanced Disk Drive Spec drive options: + * Bit(s) Description (Table 00280) + * 0 fast PIO enabled + * 1 fast DMA access enabled + * 2 block PIO (multi-sector transfers) enabled + * 3 CHS translation enabled + * 4 LBA translation enabled + * 5 removable media + * 6 ATAPI device (CD-ROM) + * 7 32-bit transfer mode + * ---v1.1+ --- + * 8 ATAPI device uses DRQ to signal readiness for packet command + * (must be 0 if bit 6 is 0) + * 10-9 translation type (must be 00 if bit 3 is 0) + * 00 Phoenix bit-shifting translation + * 01 LBA-assisted translation + * 10 reserved + * 11 proprietary translation + * ---v3.0--- + * 11 Ultra DMA access enabled + * 15-12 reserved + **/ + +/* + * Values for diskette drive type: + * 01h 360K + * 02h 1.2M + * 03h 720K + * 04h 1.44M + * 05h ??? + * reportedly an obscure drive type shipped on some IBM machines, + * 2.88M on some machines (at least AMI 486 BIOS) + * 06h 2.88M + * 10h ATAPI Removable Media Device + */ +enum diskette_drive_types { + DISKETTE_360K = 1, + DISKETTE_1_2M = 2, + DISKETTE_720K = 3, + DISKETTE_1_44M = 4, + DISKETTE_2_88M = 6, + DISKETTE_ATAPI = 10, +}; + +/** + * chs_to_lba - compute lba value from cylinder, head and sector number + **/ +static inline int chs_to_lba(const struct driveinfo* drive_info, + const unsigned int cylinder, const unsigned int head, + const unsigned int sector) +{ + /* Use EDD, if valid */ + if (drive_info->edd_params.sectors_per_track > 0 && + drive_info->edd_params.heads > 0) + return (sector - 1) + (head * drive_info->edd_params.sectors_per_track) + + (cylinder * (drive_info->edd_params.heads) * + drive_info->edd_params.sectors_per_track); + else if (drive_info->cbios) + return (sector - 1) + (head * drive_info->legacy_sectors_per_track) + + (cylinder * (drive_info->legacy_max_head + 1) * + drive_info->legacy_sectors_per_track); +} + +void lba_to_chs(const struct driveinfo* drive_info, const int lba, + unsigned int* cylinder, unsigned int* head, + unsigned int* sector); +int get_drive_parameters(struct driveinfo *drive_info); + +#endif /* _GEOM_H */ diff --git a/com32/gplinclude/disk/msdos.h b/com32/gplinclude/disk/msdos.h new file mode 100644 index 00000000..405b9b99 --- /dev/null +++ b/com32/gplinclude/disk/msdos.h @@ -0,0 +1,19 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _MSDOS_H_ +#define _MSDOS_H_ + +#include <disk/geom.h> +#include <disk/partition.h> + +typedef void (*p_callback)(struct driveinfo *, struct part_entry *, int, int); +int parse_partition_table(struct driveinfo *, p_callback); + +#endif /* _MSDOS_H_ */ diff --git a/com32/gplinclude/disk/partition.h b/com32/gplinclude/disk/partition.h new file mode 100644 index 00000000..be6bfaab --- /dev/null +++ b/com32/gplinclude/disk/partition.h @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _PARTITION_H_ +#define _PARTITION_H_ + +#include <stdint.h> + +#define PARTITION_TABLES_OFFSET 0x1be + +/* A DOS partition table entry */ +struct part_entry { + uint8_t active_flag; /* 0x80 if "active" */ + uint8_t start_head; + uint8_t start_sect; + uint8_t start_cyl; + uint8_t ostype; + uint8_t end_head; + uint8_t end_sect; + uint8_t end_cyl; + uint32_t start_lba; + uint32_t length; +} __attribute__((packed)); + +void get_label(int label, char** buffer_label); +#endif /* _PARTITION_H_ */ diff --git a/com32/gplinclude/disk/read.h b/com32/gplinclude/disk/read.h new file mode 100644 index 00000000..43762a68 --- /dev/null +++ b/com32/gplinclude/disk/read.h @@ -0,0 +1,18 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _READ_H_ +#define _READ_H_ + +#include <disk/geom.h> + +int read_mbr(int, void*); +int dev_read(int, void*, unsigned int, int); +int read_sectors(struct driveinfo*, void*, const unsigned int, const int); +#endif /* _READ_H */ diff --git a/com32/gplinclude/disk/swsusp.h b/com32/gplinclude/disk/swsusp.h new file mode 100644 index 00000000..1d77c878 --- /dev/null +++ b/com32/gplinclude/disk/swsusp.h @@ -0,0 +1,19 @@ +#ifndef _SWSUSP_H_ +#define _SWSUSP_H_ + +#include <disk/geom.h> +#include <disk/common.h> +#include <disk/partition.h> + +#define SWSUSP_SIG "S1SUSPEND" + +struct swsusp_header { + char reserved[PAGE_SIZE - 20 - sizeof(unsigned long) - sizeof(int)]; + unsigned long image; + unsigned int flags; /* Flags to pass to the "boot" kernel */ + char orig_sig[10]; + char sig[10]; +} __attribute__((packed)); + +int swsusp_check(struct driveinfo*, struct part_entry*); +#endif /* _SWSUSP_H */ diff --git a/com32/gplinclude/disk/util.h b/com32/gplinclude/disk/util.h new file mode 100644 index 00000000..df2eadda --- /dev/null +++ b/com32/gplinclude/disk/util.h @@ -0,0 +1,22 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include <com32.h> + +int int13_retry(const com32sys_t *inreg, com32sys_t *outreg); +void get_error(const int, char**); +#endif /* _UTIL_H_ */ diff --git a/com32/gplinclude/disk/write.h b/com32/gplinclude/disk/write.h new file mode 100644 index 00000000..faa80c7d --- /dev/null +++ b/com32/gplinclude/disk/write.h @@ -0,0 +1,28 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _WRITE_H_ +#define _WRITE_H_ + +#include <disk/geom.h> + +int write_sectors(const struct driveinfo*, const unsigned int, + const void *, const int); +int write_verify_sector(struct driveinfo* drive_info, + const unsigned int, + const void *); +int write_verify_sectors(struct driveinfo*, + const unsigned int, + const void *, const int); +#endif diff --git a/com32/gplinclude/dmi/dmi.h b/com32/gplinclude/dmi/dmi.h index 71372f3e..def0a8ea 100644 --- a/com32/gplinclude/dmi/dmi.h +++ b/com32/gplinclude/dmi/dmi.h @@ -14,6 +14,9 @@ #define DMI_H #include <inttypes.h> #define MAX_DMI_MEMORY_ITEMS 32 +#define MAX_DMI_CACHE_ITEMS 32 +#define OEM_STRINGS_SIZE 512 +#define HARDWARE_SECURITY_SIZE 16 #define PAGE_SIZE 4096 @@ -34,6 +37,7 @@ enum { DMI_TABLE_PRESENT = 100, ENODMITABLE }; #include "dmi_memory.h" #include "dmi_battery.h" #include "dmi_ipmi.h" +#include "dmi_cache.h" extern char display_line; #define moreprintf(...) do { display_line++; if (display_line == 24) { char tempbuf[10]; display_line=0; printf("Press enter to continue"); fgets(tempbuf, sizeof tempbuf, stdin);} printf ( __VA_ARGS__); } while (0); @@ -55,16 +59,28 @@ struct dmi_header { }; typedef struct { - s_bios bios; - s_system system; - s_base_board base_board; - s_chassis chassis; - s_processor processor; - s_battery battery; - s_memory memory[MAX_DMI_MEMORY_ITEMS]; - s_ipmi ipmi; - int memory_count; - dmi_table dmitable; + s_bios bios; + s_system system; + s_base_board base_board; + s_chassis chassis; + s_processor processor; + s_battery battery; + s_memory_module memory_module[MAX_DMI_MEMORY_ITEMS]; + s_memory memory[MAX_DMI_MEMORY_ITEMS]; + s_ipmi ipmi; + s_cache cache[MAX_DMI_CACHE_ITEMS]; + int memory_module_count; + int memory_count; + int cache_count; + dmi_table dmitable; + char oem_strings[OEM_STRINGS_SIZE]; + struct { + char power_on_passwd_status[HARDWARE_SECURITY_SIZE]; + char keyboard_passwd_status[HARDWARE_SECURITY_SIZE]; + char administrator_passwd_status[HARDWARE_SECURITY_SIZE]; + char front_panel_reset_status[HARDWARE_SECURITY_SIZE]; + bool filled; + } hardware_security; } s_dmi; void to_dmi_header(struct dmi_header *h, uint8_t * data); diff --git a/com32/gplinclude/dmi/dmi_base_board.h b/com32/gplinclude/dmi/dmi_base_board.h index 9fe35440..ff4dd8a9 100644 --- a/com32/gplinclude/dmi/dmi_base_board.h +++ b/com32/gplinclude/dmi/dmi_base_board.h @@ -30,24 +30,29 @@ extern const char *base_board_features_strings[]; /* this struct have BASE_BOARD_NB_ELEMENTS */ /* each bool is associated to the relevant message above */ typedef struct { - bool hosting; - bool board_needs_daughter; - bool removable; - bool replaceable; - bool hot_swappable; + bool hosting; + bool board_needs_daughter; + bool removable; + bool replaceable; + bool hot_swappable; } __attribute__ ((__packed__)) s_base_board_features; typedef struct { - char manufacturer[BASE_BOARD_MANUFACTURER_SIZE]; - char product_name[BASE_BOARD_PRODUCT_NAME_SIZE]; - char version[BASE_BOARD_VERSION_SIZE]; - char serial[BASE_BOARD_SERIAL_SIZE]; - char asset_tag[BASE_BOARD_ASSET_TAG_SIZE]; - char location[BASE_BOARD_LOCATION_SIZE]; - char type[BASE_BOARD_TYPE_SIZE]; - s_base_board_features features; + char manufacturer[BASE_BOARD_MANUFACTURER_SIZE]; + char product_name[BASE_BOARD_PRODUCT_NAME_SIZE]; + char version[BASE_BOARD_VERSION_SIZE]; + char serial[BASE_BOARD_SERIAL_SIZE]; + char asset_tag[BASE_BOARD_ASSET_TAG_SIZE]; + char location[BASE_BOARD_LOCATION_SIZE]; + char type[BASE_BOARD_TYPE_SIZE]; + s_base_board_features features; /* The filled field have to be set to true when the dmitable implement that item */ - bool filled; + bool filled; + struct { + char type[16]; + uint8_t status; + char description[10]; + } devices_information[10]; } s_base_board; #endif diff --git a/com32/gplinclude/dmi/dmi_cache.h b/com32/gplinclude/dmi/dmi_cache.h new file mode 100644 index 00000000..50f93afd --- /dev/null +++ b/com32/gplinclude/dmi/dmi_cache.h @@ -0,0 +1,47 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved + * + * Some part borrowed from DMI Decode: + * + * (C) 2000-2002 Alan Cox <alan@redhat.com> + * (C) 2002-2007 Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef DMI_CACHE_H +#define DMI_CACHE_H + +#include <stdint.h> + +#include "stdbool.h" + +typedef struct { + char socket_designation[32]; + char configuration[32]; + char mode[32]; + char location[8]; + uint16_t installed_size; + uint16_t max_size; + char supported_sram_types[32]; + char installed_sram_types[32]; + uint16_t speed; + char error_correction_type[32]; + char system_type[16]; + char associativity[32]; +} __attribute__((__packed__)) s_cache; + +const char *dmi_cache_mode(uint8_t code); +const char *dmi_cache_location(uint8_t code); +uint16_t dmi_cache_size(uint16_t code); +void dmi_cache_types(uint16_t code, const char *sep, char* array); +const char *dmi_cache_ec_type(uint8_t code); +const char *dmi_cache_type(uint8_t code); +const char *dmi_cache_associativity(uint8_t code); +#endif /* DMI_CACHE_H */ diff --git a/com32/gplinclude/dmi/dmi_memory.h b/com32/gplinclude/dmi/dmi_memory.h index ed4eb6f4..f9c2b561 100644 --- a/com32/gplinclude/dmi/dmi_memory.h +++ b/com32/gplinclude/dmi/dmi_memory.h @@ -49,6 +49,17 @@ typedef struct { bool filled; } s_memory; +typedef struct { +char socket_designation[8]; +char bank_connections[8]; +char speed[8]; +char type[16]; +char installed_size[8]; +char enabled_size[8]; +char error_status[8]; +bool filled; +} s_memory_module; + void dmi_memory_array_error_handle(uint16_t code, char *array); void dmi_memory_device_width(uint16_t code, char *width); void dmi_memory_device_size(uint16_t code, char *size); @@ -58,4 +69,9 @@ const char *dmi_memory_device_type(uint8_t code); void dmi_memory_device_type_detail(uint16_t code, char *type_detail); void dmi_memory_device_speed(uint16_t code, char *speed); +void dmi_memory_module_connections(uint8_t, char*); +void dmi_memory_module_speed(uint8_t, char*); +void dmi_memory_module_types(uint16_t, const char*, char*); +void dmi_memory_module_size(uint8_t, char*); +void dmi_memory_module_error(uint8_t, const char*, char*); #endif diff --git a/com32/gplinclude/dmi/dmi_system.h b/com32/gplinclude/dmi/dmi_system.h index 9c313ebb..28a562de 100644 --- a/com32/gplinclude/dmi/dmi_system.h +++ b/com32/gplinclude/dmi/dmi_system.h @@ -22,6 +22,9 @@ #define SYSTEM_SKU_NUMBER_SIZE 32 #define SYSTEM_FAMILY_SIZE 32 +#define SYSTEM_BOOT_STATUS_SIZE 50 +#define SYSTEM_CONFIGURATION_OPTIONS_SIZE 50 + typedef struct { char manufacturer[SYSTEM_MANUFACTURER_SIZE]; char product_name[SYSTEM_PRODUCT_NAME_SIZE]; @@ -32,7 +35,19 @@ typedef struct { char sku_number[SYSTEM_SKU_NUMBER_SIZE]; char family[SYSTEM_FAMILY_SIZE]; /* The filled field have to be set to true when the dmitable implement that item */ - bool filled; +bool filled; +char system_boot_status[SYSTEM_BOOT_STATUS_SIZE]; +char configuration_options[SYSTEM_CONFIGURATION_OPTIONS_SIZE]; +struct { + bool filled; + uint8_t status; + uint8_t watchdog; + char boot_option[17]; + char boot_option_on_limit[17]; + char reset_count[8]; + char reset_limit[8]; + char timer_interval[8]; + char timeout[8]; +} system_reset; } s_system; - #endif diff --git a/com32/gplinclude/memory.h b/com32/gplinclude/memory.h new file mode 100644 index 00000000..c9f386d4 --- /dev/null +++ b/com32/gplinclude/memory.h @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from meminfo.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * Some parts borrowed from Linux: + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#ifndef _MEMORY_H_ +#define _MEMORY_H_ +#include <stdint.h> + +struct e820entry { + uint64_t addr; /* start of memory segment */ + uint64_t size; /* size of memory segment */ + uint64_t type; /* type of memory segment */ +} __attribute__((packed)); + +const char * const e820_types[5]; + +void get_type(int, char*, int); +void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found); +int detect_memory_e801(int*, int*); +int detect_memory_88(int*); +#endif diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile index 8e47d93f..fa866dba 100644 --- a/com32/gpllib/Makefile +++ b/com32/gpllib/Makefile @@ -8,9 +8,8 @@ include ../lib/MCONFIG REQFLAGS += -I../gplinclude -LIBOBJS = dmi/dmi_battery.o dmi/dmi_chassis.o dmi/dmi_memory.o \ - dmi/dmi_processor.o dmi/dmi.o dmi/dmi_bios.o dmi/dmi_base_board.o \ - dmi/dmi_ipmi.o cpuid.o vpd/vpd.o +GPLDIRS := . disk dmi vpd +LIBOBJS := $(foreach dir,$(GPLDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c))) BINDIR = /usr/bin LIBDIR = /usr/lib diff --git a/com32/gpllib/disk/ata.c b/com32/gpllib/disk/ata.c new file mode 100644 index 00000000..d74dda8f --- /dev/null +++ b/com32/gpllib/disk/ata.c @@ -0,0 +1,61 @@ +#include <inttypes.h> + +/** + * ata_id_string - Convert IDENTIFY DEVICE page into string + * @id: IDENTIFY DEVICE results we will examine + * @s: string into which data is output + * @ofs: offset into identify device page + * @len: length of string to return. must be an even number. + * + * The strings in the IDENTIFY DEVICE page are broken up into + * 16-bit chunks. Run through the string, and output each + * 8-bit chunk linearly, regardless of platform. + * + * LOCKING: + * caller. + */ +void ata_id_string(const uint16_t * id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +/** + * ata_id_c_string - Convert IDENTIFY DEVICE page into C string + * @id: IDENTIFY DEVICE results we will examine + * @s: string into which data is output + * @ofs: offset into identify device page + * @len: length of string to return. must be an odd number. + * + * This function is identical to ata_id_string except that it + * trims trailing spaces and terminates the resulting string with + * null. @len must be actual maximum length (even number) + 1. + * + * LOCKING: + * caller. + */ +void ata_id_c_string(const uint16_t * id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned char *p; + + ata_id_string(id, s, ofs, len - 1); + + p = s + strnlen(s, len - 1); + while (p > s && p[-1] == ' ') + p--; + *p = '\0'; +} diff --git a/com32/gpllib/disk/errno_disk.c b/com32/gpllib/disk/errno_disk.c new file mode 100644 index 00000000..8a68802f --- /dev/null +++ b/com32/gpllib/disk/errno_disk.c @@ -0,0 +1,12 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <disk/errno_disk.h> + +int errno_disk; diff --git a/com32/gpllib/disk/error.c b/com32/gpllib/disk/error.c new file mode 100644 index 00000000..1853092b --- /dev/null +++ b/com32/gpllib/disk/error.c @@ -0,0 +1,23 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <stdio.h> +#include <string.h> +#include <disk/errno_disk.h> + +/** + * get_error - decode a disk error status + * @buffer_ptr: Preallocated buffer + * + * Fill @buffer_ptr with the last errno_disk + **/ +void get_error(const char* s) +{ + fprintf(stderr, "%s: error %d\n", s, errno_disk); +} diff --git a/com32/gpllib/disk/geom.c b/com32/gpllib/disk/geom.c new file mode 100644 index 00000000..2305ed16 --- /dev/null +++ b/com32/gpllib/disk/geom.c @@ -0,0 +1,272 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <com32.h> +#include <string.h> +#include <stdio.h> +#include <disk/geom.h> + +#include <stdio.h> + +/** + * lba_to_chs - split given lba into cylinders/heads/sectors + **/ +void lba_to_chs(const struct driveinfo* drive_info, const int lba, + unsigned int* cylinder, unsigned int* head, + unsigned int* sector) +{ + unsigned int track; + + /* Use EDD, if valid */ + if (drive_info->edd_params.sectors_per_track > 0 && + drive_info->edd_params.heads > 0) { + *cylinder = (lba % drive_info->edd_params.sectors_per_track) + 1; + track = lba / drive_info->edd_params.sectors_per_track; + *head = track % drive_info->edd_params.heads; + *sector = track / drive_info->edd_params.heads; + } else if (drive_info->cbios) { + *cylinder = (lba % drive_info->legacy_sectors_per_track) + 1; + track = lba / drive_info->legacy_sectors_per_track; + *head = track % (drive_info->legacy_max_head + 1); + *sector = track / (drive_info->legacy_max_head + 1); + } +} + +/** + * detect_extensions - detect if we can use extensions + * + * INT 13 - IBM/MS INT 13 Extensions - INSTALLATION CHECK + * AH = 41h + * BX = 55AAh + * DL = drive (80h-FFh) + * + * Return: CF set on error (extensions not supported) + * AH = 01h (invalid function) + * CF clear if successful + * BX = AA55h if installed + * AH = major version of extensions + * 01h = 1.x + * 20h = 2.0 / EDD-1.0 + * 21h = 2.1 / EDD-1.1 + * 30h = EDD-3.0 + * AL = internal use + * CX = API subset support bitmap (see #00271) + * DH = extension version (v2.0+ ??? -- not present in 1.x) + * + * Note: the Phoenix Enhanced Disk Drive Specification v1.0 uses version 2.0 of + * the INT 13 Extensions API + * + * Bitfields for IBM/MS INT 13 Extensions API support bitmap: + * Bit(s) Description (Table 00271) + * 0 extended disk access functions (AH=42h-44h,47h,48h) supported + * 1 removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) + * supported + * 2 enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported + * extended drive parameter table is valid (see #00273,#00278) + * 3-15 reserved (0) + **/ +static int detect_extensions(struct driveinfo* drive_info) +{ + com32sys_t getebios, ebios; + + memset(&getebios, 0, sizeof getebios); + memset(&ebios, 0, sizeof ebios); + + getebios.eflags.b[0] = 0x3; /* CF set */ + getebios.ebx.w[0] = 0x55aa; + getebios.edx.b[0] = drive_info->disk; + getebios.eax.b[1] = 0x41; + + __intcall(0x13, &getebios, &ebios); + + if ( !(ebios.eflags.l & EFLAGS_CF) && + ebios.ebx.w[0] == 0xaa55 ) { + drive_info->ebios = 1; + drive_info->edd_version = ebios.eax.b[1]; + drive_info->edd_functionality_subset = ebios.ecx.w[0]; + return 0; + } else + return -1; /* Drive does not exist? */ +} + +/** + * get_drive_parameters_with_extensions - retrieve disk parameters via AH=48h + * + * INT 13 - IBM/MS INT 13 Extensions - GET DRIVE PARAMETERS + * AH = 48h + * DL = drive (80h-FFh) + * DS:SI -> buffer for drive parameters + * Return: CF clear if successful + * AH = 00h + * DS:SI buffer filled + * CF set on error + * AH = error code (see #00234) + * BUG: several different Compaq BIOSes incorrectly report high-numbered + * drives (such as 90h, B0h, D0h, and F0h) as present, giving them the + * same geometry as drive 80h; as a workaround, scan through disk + * numbers, stopping as soon as the number of valid drives encountered + * equals the value in 0040h:0075h + **/ +static int get_drive_parameters_with_extensions(struct driveinfo* drive_info) +{ + com32sys_t inreg, outreg; + struct edd_device_parameters *dp = __com32.cs_bounce; + + memset(&inreg, 0, sizeof inreg); + + /* + * The caller shall set this value to the maximum Result Buffer + * length, in bytes. If the length of this buffer is less than 30 + * bytes, this function shall not return the pointer to Drive Parameter + * Table (DPT) extension. If the buffer length is 30 or greater on + * entry, it shall be set to 30 on exit. If the buffer length is + * between 26 and 29, it shall be set to 26 on exit. + * If the buffer length is less than 26 on entry an error shall be + * returned. + */ + dp->len = sizeof(struct edd_device_parameters); + + inreg.esi.w[0] = OFFS(dp); + inreg.ds = SEG(dp); + inreg.edx.b[0] = drive_info->disk; + inreg.eax.b[1] = 0x48; + + __intcall(0x13, &inreg, &outreg); + + /* CF set on error */ + if ( outreg.eflags.l & EFLAGS_CF ) + return outreg.eax.b[1]; + + memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params); + + return 0; +} + +/** + * get_drive_parameters_without_extensions - retrieve drive parameters via AH=08h + * + * INT 13 - DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI) + * AH = 08h + * DL = drive (bit 7 set for hard disk) + * + * Return: CF set on error + * AH = status (07h) (see #00234) + * CF clear if successful + * AH = 00h + * AL = 00h on at least some BIOSes + * BL = drive type (AT/PS2 floppies only) (see #00242) + * CH = low eight bits of maximum cylinder number + * CL = maximum sector number (bits 5-0) + * high two bits of maximum cylinder number (bits 7-6) + * DH = maximum head number + * DL = number of drives + * ES:DI -> drive parameter table (floppies only) + * + * Notes: + * - may return successful even though specified drive is greater than the + * number of attached drives of that type (floppy/hard); check DL to + * ensure validity + * - for systems predating the IBM AT, this call is only valid for hard + * disks, as it is implemented by the hard disk BIOS rather than the + * ROM BIOS + * - Toshiba laptops with HardRAM return DL=02h when called with DL=80h, + * but fail on DL=81h. The BIOS data at 40h:75h correctly reports 01h. + * may indicate only two drives present even if more are attached; to + * ensure a correct count, one can use AH=15h to scan through possible + * drives + * - for BIOSes which reserve the last cylinder for testing purposes, the + * cylinder count is automatically decremented + * on PS/1s with IBM ROM DOS 4, nonexistent drives return CF clear, + * BX=CX=0000h, and ES:DI = 0000h:0000h + * - the PC-Tools PCFORMAT program requires that AL=00h before it will + * proceed with the formatting + * + * BUG: several different Compaq BIOSes incorrectly report high-numbered + * drives (such as 90h, B0h, D0h, and F0h) as present, giving them the + * same geometry as drive 80h; as a workaround, scan through disk + * numbers, stopping as soon as the number of valid drives encountered + * equals the value in 0040h:0075h + * + * SeeAlso: AH=06h"Adaptec",AH=13h"SyQuest",AH=48h,AH=15h,INT 1E + * SeeAlso: INT 41"HARD DISK 0" + **/ +static int get_drive_parameters_without_extensions(struct driveinfo* drive_info) +{ + com32sys_t getparm, parm; + + memset(&getparm, 0, sizeof getparm); + memset(&parm, 0, sizeof parm); + + /* Ralf Brown recommends setting ES:DI to 0:0 */ + getparm.esi.w[0] = 0; + getparm.ds = 0; + getparm.edx.b[0] = drive_info->disk; + getparm.eax.b[1] = 0x08; + + __intcall(0x13, &getparm, &parm); + + /* CF set on error */ + if ( parm.eflags.l & EFLAGS_CF ) + return parm.eax.b[1]; + + /* DL contains the maximum drive number (it starts at 0) */ + drive_info->legacy_max_drive = parm.edx.b[0]; + + // XXX broken + /* Drive specified greater than the bumber of attached drives */ + //if (drive_info->disk > drive_info->drives) + // return -1; + + drive_info->legacy_type = parm.ebx.b[0]; + + /* DH contains the maximum head number (it starts at 0) */ + drive_info->legacy_max_head = parm.edx.b[1]; + + /* Maximum sector number (bits 5-0) per track */ + drive_info->legacy_sectors_per_track = parm.ecx.b[0] & 0x3f; + + /* + * Maximum cylinder number: + * CH = low eight bits of maximum cylinder number + * CL = high two bits of maximum cylinder number (bits 7-6) + */ + drive_info->legacy_max_cylinder = parm.ecx.b[1] + + ((parm.ecx.b[0] & 0xc0) << 2); + + if ( drive_info->legacy_sectors_per_track > 0 ) + drive_info->cbios = 1; /* Valid geometry */ + + return 0; +} + +/** + * get_drive_parameters - retrieve drive parameters + * @drive_info: driveinfo structure to fill + **/ +int get_drive_parameters(struct driveinfo *drive_info) +{ + int return_code; + + if (detect_extensions(drive_info)) + return -1; + + return_code = get_drive_parameters_without_extensions(drive_info); + + /* If geometry isn't valid, no need to try to get more info about the drive*/ + /* Looks like in can confuse some optical drives */ + if (drive_info->ebios && drive_info->cbios) + get_drive_parameters_with_extensions(drive_info); + + return return_code; +} diff --git a/com32/gpllib/disk/labels.c b/com32/gpllib/disk/labels.c new file mode 100644 index 00000000..7efe1ad1 --- /dev/null +++ b/com32/gpllib/disk/labels.c @@ -0,0 +1,254 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <stdlib.h> +#include <string.h> + +void get_label(int label, char** buffer_label) +{ + int buffer_size = (80 * sizeof(char)); + char* buffer = malloc(buffer_size); + *buffer_label = buffer; + + switch (label) { + case 0x01: strncpy(buffer, "DOS 12-bit fat", buffer_size); break; + case 0x02: strncpy(buffer, "XENIX root", buffer_size); break; + case 0x03: strncpy(buffer, "XENIX /usr", buffer_size); break; + case 0x04: strncpy(buffer, "DOS 3.0+ 16-bit FAT (up to 32M)", buffer_size); break; + case 0x05: strncpy(buffer, "DOS 3.3+ Extended Partition", buffer_size); break; + case 0x06: strncpy(buffer, "DOS 3.31+ 16-bit FAT (over 32M)", buffer_size); break; + case 0x07: strncpy(buffer, "OS/2 IFS (e.g., HPFS)", buffer_size); break; + //case 0x07: strncpy(buffer, "Advanced Unix", buffer_size); break; + //case 0x07: strncpy(buffer, "Windows NT NTFS", buffer_size); break; + //case 0x07: strncpy(buffer, "QNX2.x (pre-1988)", buffer_size); break; + case 0x08: strncpy(buffer, "OS/2 (v1.0-1.3 only)", buffer_size); break; + //case 0x08: strncpy(buffer, "AIX boot partition", buffer_size); break; + //case 0x08: strncpy(buffer, "SplitDrive", buffer_size); break; + //case 0x08: strncpy(buffer, "DELL partition spanning multiple drives", buffer_size); break; + //case 0x08: strncpy(buffer, "Commodore DOS", buffer_size); break; + //case 0x08: strncpy(buffer, "QNX 1.x and 2.x ("qny")", buffer_size); break; + case 0x09: strncpy(buffer, "AIX data partition", buffer_size); break; + //case 0x09: strncpy(buffer, "Coherent filesystem", buffer_size); break; + //case 0x09: strncpy(buffer, "QNX 1.x and 2.x ("qnz")", buffer_size); break; + case 0x0a: strncpy(buffer, "OS/2 Boot Manager", buffer_size); break; + //case 0x0a: strncpy(buffer, "Coherent swap partition", buffer_size); break; + //case 0x0a: strncpy(buffer, "OPUS", buffer_size); break; + case 0x0b: strncpy(buffer, "WIN95 OSR2 32-bit FAT", buffer_size); break; + case 0x0c: strncpy(buffer, "WIN95 OSR2 32-bit FAT, LBA-mapped", buffer_size); break; + case 0x0e: strncpy(buffer, "WIN95: DOS 16-bit FAT, LBA-mapped", buffer_size); break; + case 0x0f: strncpy(buffer, "WIN95: Extended partition, LBA-mapped", buffer_size); break; + case 0x10: strncpy(buffer, "OPUS (?)", buffer_size); break; + case 0x11: strncpy(buffer, "Hidden DOS 12-bit FAT", buffer_size); break; + case 0x12: strncpy(buffer, "Compaq config partition", buffer_size); break; + case 0x14: strncpy(buffer, "Hidden DOS 16-bit FAT <32M", buffer_size); break; + case 0x16: strncpy(buffer, "Hidden DOS 16-bit FAT >=32M", buffer_size); break; + case 0x17: strncpy(buffer, "Hidden IFS (e.g., HPFS)", buffer_size); break; + case 0x18: strncpy(buffer, "AST SmartSleep Partition", buffer_size); break; + case 0x19: strncpy(buffer, "Unused (Claimed for Willowtech Photon COS)", buffer_size); break; + case 0x1b: strncpy(buffer, "Hidden WIN95 OSR2 32-bit FAT", buffer_size); break; + case 0x1c: strncpy(buffer, "Hidden WIN95 OSR2 32-bit FAT, LBA-mapped", buffer_size); break; + case 0x1e: strncpy(buffer, "Hidden WIN95 16-bit FAT, LBA-mapped", buffer_size); break; + case 0x20: strncpy(buffer, "Unused", buffer_size); break; + case 0x21: strncpy(buffer, "Reserved", buffer_size); break; + //case 0x21: strncpy(buffer, "Unused", buffer_size); break; + case 0x22: strncpy(buffer, "Unused", buffer_size); break; + case 0x23: strncpy(buffer, "Reserved", buffer_size); break; + case 0x24: strncpy(buffer, "NEC DOS 3.x", buffer_size); break; + case 0x26: strncpy(buffer, "Reserved", buffer_size); break; + case 0x31: strncpy(buffer, "Reserved", buffer_size); break; + case 0x32: strncpy(buffer, "NOS", buffer_size); break; + case 0x33: strncpy(buffer, "Reserved", buffer_size); break; + case 0x34: strncpy(buffer, "Reserved", buffer_size); break; + case 0x35: strncpy(buffer, "JFS on OS/2 or eCS", buffer_size); break; + case 0x36: strncpy(buffer, "Reserved", buffer_size); break; + case 0x38: strncpy(buffer, "THEOS ver 3.2 2gb partition", buffer_size); break; + case 0x39: strncpy(buffer, "Plan 9 partition", buffer_size); break; + //case 0x39: strncpy(buffer, "THEOS ver 4 spanned partition", buffer_size); break; + case 0x3a: strncpy(buffer, "THEOS ver 4 4gb partition", buffer_size); break; + case 0x3b: strncpy(buffer, "THEOS ver 4 extended partition", buffer_size); break; + case 0x3c: strncpy(buffer, "PartitionMagic recovery partition", buffer_size); break; + case 0x3d: strncpy(buffer, "Hidden NetWare", buffer_size); break; + case 0x40: strncpy(buffer, "Venix 80286", buffer_size); break; + case 0x41: strncpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size); break; + //case 0x41: strncpy(buffer, "Personal RISC Boot", buffer_size); break; + //case 0x41: strncpy(buffer, "PPC PReP (Power PC Reference Platform) Boot", buffer_size); break; + case 0x42: strncpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size); break; + //case 0x42: strncpy(buffer, "SFS (Secure Filesystem)", buffer_size); break; + //case 0x42: strncpy(buffer, "Windows 2000 marker", buffer_size); break; + case 0x43: strncpy(buffer, "Linux native (sharing disk with DRDOS)", buffer_size); break; + case 0x44: strncpy(buffer, "GoBack partition", buffer_size); break; + case 0x45: strncpy(buffer, "Boot-US boot manager", buffer_size); break; + //case 0x45: strncpy(buffer, "Priam", buffer_size); break; + //case 0x45: strncpy(buffer, "EUMEL/Elan", buffer_size); break; + case 0x46: strncpy(buffer, "EUMEL/Elan", buffer_size); break; + case 0x47: strncpy(buffer, "EUMEL/Elan", buffer_size); break; + case 0x48: strncpy(buffer, "EUMEL/Elan", buffer_size); break; + case 0x4a: strncpy(buffer, "AdaOS Aquila (Default)", buffer_size); break; + //case 0x4a: strncpy(buffer, "ALFS/THIN lightweight filesystem for DOS", buffer_size); break; + case 0x4c: strncpy(buffer, "Oberon partition", buffer_size); break; + case 0x4d: strncpy(buffer, "QNX4.x", buffer_size); break; + case 0x4e: strncpy(buffer, "QNX4.x 2nd part", buffer_size); break; + case 0x4f: strncpy(buffer, "QNX4.x 3rd part", buffer_size); break; + //case 0x4f: strncpy(buffer, "Oberon partition", buffer_size); break; + case 0x50: strncpy(buffer, "OnTrack Disk Manager (older versions) RO", buffer_size); break; + //case 0x50: strncpy(buffer, "Lynx RTOS", buffer_size); break; + //case 0x50: strncpy(buffer, "Native Oberon (alt)", buffer_size); break; + case 0x51: strncpy(buffer, "OnTrack Disk Manager RW (DM6 Aux1)", buffer_size); break; + //case 0x51: strncpy(buffer, "Novell", buffer_size); break; + case 0x52: strncpy(buffer, "CP/M", buffer_size); break; + //case 0x52: strncpy(buffer, "Microport SysV/AT", buffer_size); break; + case 0x53: strncpy(buffer, "Disk Manager 6.0 Aux3", buffer_size); break; + case 0x54: strncpy(buffer, "Disk Manager 6.0 Dynamic Drive Overlay", buffer_size); break; + case 0x55: strncpy(buffer, "EZ-Drive", buffer_size); break; + case 0x56: strncpy(buffer, "Golden Bow VFeature Partitioned Volume.", buffer_size); break; + //case 0x56: strncpy(buffer, "DM converted to EZ-BIOS", buffer_size); break; + case 0x57: strncpy(buffer, "DrivePro", buffer_size); break; + //case 0x57: strncpy(buffer, "VNDI Partition", buffer_size); break; + case 0x5c: strncpy(buffer, "Priam EDisk", buffer_size); break; + case 0x61: strncpy(buffer, "SpeedStor", buffer_size); break; + case 0x63: strncpy(buffer, "Unix System V (SCO, ISC Unix, UnixWare, ...), Mach, GNU Hurd", buffer_size); break; + case 0x64: strncpy(buffer, "PC-ARMOUR protected partition", buffer_size); break; + //case 0x64: strncpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break; + case 0x65: strncpy(buffer, "Novell Netware 386, 3.xx or 4.xx", buffer_size); break; + case 0x66: strncpy(buffer, "Novell Netware SMS Partition", buffer_size); break; + case 0x67: strncpy(buffer, "Novell", buffer_size); break; + case 0x68: strncpy(buffer, "Novell", buffer_size); break; + case 0x69: strncpy(buffer, "Novell Netware 5+, Novell Netware NSS Partition", buffer_size); break; + case 0x70: strncpy(buffer, "DiskSecure Multi-Boot", buffer_size); break; + case 0x71: strncpy(buffer, "Reserved", buffer_size); break; + case 0x73: strncpy(buffer, "Reserved", buffer_size); break; + case 0x74: strncpy(buffer, "Reserved", buffer_size); break; + //case 0x74: strncpy(buffer, "Scramdisk partition", buffer_size); break; + case 0x75: strncpy(buffer, "IBM PC/IX", buffer_size); break; + case 0x76: strncpy(buffer, "Reserved", buffer_size); break; + case 0x77: strncpy(buffer, "M2FS/M2CS partition", buffer_size); break; + //case 0x77: strncpy(buffer, "VNDI Partition", buffer_size); break; + case 0x78: strncpy(buffer, "XOSL FS", buffer_size); break; + case 0x7E: strncpy(buffer, " ", buffer_size); break; + case 0x80: strncpy(buffer, "MINIX until 1.4a", buffer_size); break; + case 0x81: strncpy(buffer, "MINIX since 1.4b, early Linux", buffer_size); break; + //case 0x81: strncpy(buffer, "Mitac disk manager", buffer_size); break; + //case 0x82: strncpy(buffer, "Prime", buffer_size); break; + //case 0x82: strncpy(buffer, "Solaris x86", buffer_size); break; + case 0x82: strncpy(buffer, "Linux swap", buffer_size); break; + case 0x83: strncpy(buffer, "Linux native (usually ext2fs)", buffer_size); break; + case 0x84: strncpy(buffer, "OS/2 hidden C: drive", buffer_size); break; + //case 0x84: strncpy(buffer, "Hibernation partition", buffer_size); break; + case 0x85: strncpy(buffer, "Linux extended partition", buffer_size); break; + //case 0x86: strncpy(buffer, "Old Linux RAID partition superblock", buffer_size); break; + case 0x86: strncpy(buffer, "NTFS volume set", buffer_size); break; + case 0x87: strncpy(buffer, "NTFS volume set", buffer_size); break; + case 0x8a: strncpy(buffer, "Linux Kernel Partition (used by AiR-BOOT)", buffer_size); break; + case 0x8b: strncpy(buffer, "Legacy Fault Tolerant FAT32 volume", buffer_size); break; + case 0x8c: strncpy(buffer, "Legacy Fault Tolerant FAT32 volume using BIOS extd INT 13h", buffer_size); break; + case 0x8d: strncpy(buffer, "Free FDISK hidden Primary DOS FAT12 partitition", buffer_size); break; + case 0x8e: strncpy(buffer, "Linux Logical Volume Manager partition", buffer_size); break; + case 0x90: strncpy(buffer, "Free FDISK hidden Primary DOS FAT16 partitition", buffer_size); break; + case 0x91: strncpy(buffer, "Free FDISK hidden DOS extended partitition", buffer_size); break; + case 0x92: strncpy(buffer, "Free FDISK hidden Primary DOS large FAT16 partitition", buffer_size); break; + case 0x93: strncpy(buffer, "Hidden Linux native partition", buffer_size); break; + //case 0x93: strncpy(buffer, "Amoeba", buffer_size); break; + case 0x94: strncpy(buffer, "Amoeba bad block table", buffer_size); break; + case 0x95: strncpy(buffer, "MIT EXOPC native partitions", buffer_size); break; + case 0x97: strncpy(buffer, "Free FDISK hidden Primary DOS FAT32 partitition", buffer_size); break; + case 0x98: strncpy(buffer, "Free FDISK hidden Primary DOS FAT32 partitition (LBA)", buffer_size); break; + case 0x99: strncpy(buffer, "DCE376 logical drive", buffer_size); break; + case 0x9a: strncpy(buffer, "Free FDISK hidden Primary DOS FAT16 partitition (LBA)", buffer_size); break; + case 0x9b: strncpy(buffer, "Free FDISK hidden DOS extended partitition (LBA)", buffer_size); break; + case 0x9f: strncpy(buffer, "BSD/OS", buffer_size); break; + case 0xa0: strncpy(buffer, "Laptop hibernation partition", buffer_size); break; + case 0xa1: strncpy(buffer, "Laptop hibernation partition", buffer_size); break; + //case 0xa1: strncpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break; + case 0xa3: strncpy(buffer, "Reserved", buffer_size); break; + case 0xa4: strncpy(buffer, "Reserved", buffer_size); break; + case 0xa5: strncpy(buffer, "BSD/386, 386BSD, NetBSD, FreeBSD", buffer_size); break; + case 0xa6: strncpy(buffer, "OpenBSD", buffer_size); break; + case 0xa7: strncpy(buffer, "NEXTSTEP", buffer_size); break; + case 0xa8: strncpy(buffer, "Mac OS-X", buffer_size); break; + case 0xa9: strncpy(buffer, "NetBSD", buffer_size); break; + case 0xaa: strncpy(buffer, "Olivetti Fat 12 1.44Mb Service Partition", buffer_size); break; + case 0xab: strncpy(buffer, "Mac OS-X Boot partition", buffer_size); break; + //case 0xab: strncpy(buffer, "GO! partition", buffer_size); break; + case 0xae: strncpy(buffer, "ShagOS filesystem", buffer_size); break; + case 0xaf: strncpy(buffer, "ShagOS swap partition", buffer_size); break; + case 0xb0: strncpy(buffer, "BootStar Dummy", buffer_size); break; + case 0xb1: strncpy(buffer, "Reserved", buffer_size); break; + case 0xb3: strncpy(buffer, "Reserved", buffer_size); break; + case 0xb4: strncpy(buffer, "Reserved", buffer_size); break; + case 0xb6: strncpy(buffer, "Reserved", buffer_size); break; + case 0xb7: strncpy(buffer, "BSDI BSD/386 filesystem", buffer_size); break; + case 0xb8: strncpy(buffer, "BSDI BSD/386 swap partition", buffer_size); break; + case 0xbb: strncpy(buffer, "Boot Wizard hidden", buffer_size); break; + case 0xbe: strncpy(buffer, "Solaris 8 boot partition", buffer_size); break; + case 0xc0: strncpy(buffer, "CTOS", buffer_size); break; + //case 0xc0: strncpy(buffer, "REAL/32 secure small partition", buffer_size); break; + //case 0xc0: strncpy(buffer, "NTFT Partition", buffer_size); break; + case 0xc1: strncpy(buffer, "DRDOS/secured (FAT-12)", buffer_size); break; + case 0xc2: strncpy(buffer, "Reserved for DR-DOS 7+", buffer_size); break; + //case 0xc2: strncpy(buffer, "Hidden Linux", buffer_size); break; + case 0xc3: strncpy(buffer, "Hidden Linux swap", buffer_size); break; + case 0xc4: strncpy(buffer, "DRDOS/secured (FAT-16, < 32M)", buffer_size); break; + case 0xc5: strncpy(buffer, "DRDOS/secured (extended)", buffer_size); break; + case 0xc6: strncpy(buffer, "DRDOS/secured (FAT-16, >= 32M)", buffer_size); break; + //case 0xc6: strncpy(buffer, "Windows NT corrupted FAT16 volume/stripe set", buffer_size); break; + case 0xc7: strncpy(buffer, "Windows NT corrupted NTFS volume/stripe set", buffer_size); break; + //case 0xc7: strncpy(buffer, "Syrinx boot", buffer_size); break; + case 0xc8: strncpy(buffer, "(See also ID c2.)", buffer_size); break; + case 0xc9: strncpy(buffer, "(See also ID c2.)", buffer_size); break; + case 0xca: strncpy(buffer, "(See also ID c2.)", buffer_size); break; + case 0xcb: strncpy(buffer, "reserved for DRDOS/secured (FAT32)", buffer_size); break; + case 0xcc: strncpy(buffer, "reserved for DRDOS/secured (FAT32, LBA)", buffer_size); break; + case 0xcd: strncpy(buffer, "CTOS Memdump?", buffer_size); break; + case 0xce: strncpy(buffer, "reserved for DRDOS/secured (FAT16, LBA)", buffer_size); break; + case 0xd0: strncpy(buffer, "REAL/32 secure big partition", buffer_size); break; + case 0xd1: strncpy(buffer, "Old Multiuser DOS secured FAT12", buffer_size); break; + case 0xd4: strncpy(buffer, "Old Multiuser DOS secured FAT16 <32M", buffer_size); break; + case 0xd5: strncpy(buffer, "Old Multiuser DOS secured extended partition", buffer_size); break; + case 0xd6: strncpy(buffer, "Old Multiuser DOS secured FAT16 >=32M", buffer_size); break; + case 0xd8: strncpy(buffer, "CP/M-86", buffer_size); break; + case 0xda: strncpy(buffer, "Non-FS Data", buffer_size); break; + case 0xdb: strncpy(buffer, "Digital Research CP/M, Concurrent CP/M, Concurrent DOS", buffer_size); break; + //case 0xdb: strncpy(buffer, "CTOS (Convergent Technologies OS -Unisys)", buffer_size); break; + //case 0xdb: strncpy(buffer, "KDG Telemetry SCPU boot", buffer_size); break; + case 0xdd: strncpy(buffer, "Hidden CTOS Memdump?", buffer_size); break; + case 0xde: strncpy(buffer, "Dell PowerEdge Server utilities (FAT fs)", buffer_size); break; + case 0xdf: strncpy(buffer, "DG/UX virtual disk manager partition", buffer_size); break; + //case 0xdf: strncpy(buffer, "BootIt EMBRM", buffer_size); break; + case 0xe0: strncpy(buffer, "Reserved by STMicroelectronics for a filesystem called ST AVFS.", buffer_size); break; + case 0xe1: strncpy(buffer, "DOS access or SpeedStor 12-bit FAT extended partition", buffer_size); break; + case 0xe3: strncpy(buffer, "DOS R/O or SpeedStor", buffer_size); break; + case 0xe4: strncpy(buffer, "SpeedStor 16-bit FAT extended partition < 1024 cyl.", buffer_size); break; + case 0xe5: strncpy(buffer, "Tandy DOS with logical sectored FAT (According to Powerquest.)", buffer_size); break; + //case 0xe5: strncpy(buffer, "Reserved", buffer_size); break; + case 0xe6: strncpy(buffer, "Reserved", buffer_size); break; + case 0xeb: strncpy(buffer, "BFS (aka BeFS)", buffer_size); break; + case 0xed: strncpy(buffer, "Reserved for Matthias Paul's Sprytix", buffer_size); break; + case 0xee: strncpy(buffer, "Indication that this legacy MBR is followed by an EFI header", buffer_size); break; + case 0xef: strncpy(buffer, "Partition that contains an EFI file system", buffer_size); break; + case 0xf0: strncpy(buffer, "Linux/PA-RISC boot loader", buffer_size); break; + case 0xf1: strncpy(buffer, "SpeedStor", buffer_size); break; + case 0xf2: strncpy(buffer, "DOS 3.3+ secondary partition (Powerquest writes: Unisys DOS with logical sectored FAT.)", buffer_size); break; + case 0xf3: strncpy(buffer, "Reserved (Powerquest writes: Storage Dimensions SpeedStor.)", buffer_size); break; + case 0xf4: strncpy(buffer, "SpeedStor large partition", buffer_size); break; + //case 0xf4: strncpy(buffer, "Prologue single-volume partition", buffer_size); break; + case 0xf5: strncpy(buffer, "Prologue multi-volume partition", buffer_size); break; + case 0xf6: strncpy(buffer, "Reserved (Powerquest writes: Storage Dimensions SpeedStor. )", buffer_size); break; + case 0xfa: strncpy(buffer, "Bochs", buffer_size); break; + case 0xfb: strncpy(buffer, "VMware File System partition", buffer_size); break; + case 0xfc: strncpy(buffer, "VMware Swap partition", buffer_size); break; + case 0xfd: strncpy(buffer, "Linux raid partition with autodetect using persistent superblock (Powerquest writes: Reserved for FreeDOS. )", buffer_size); break; + case 0xfe: strncpy(buffer, "SpeedStor > 1024 cyl.", buffer_size); break; + //case 0xfe: strncpy(buffer, "LANstep", buffer_size); break; + //case 0xfe: strncpy(buffer, "IBM PS/2 IML (Initial Microcode Load) partition, located at the end of the disk.", buffer_size); break; + //case 0xfe: strncpy(buffer, "Windows NT Disk Administrator hidden partition", buffer_size); break; + //case 0xfe: strncpy(buffer, "Linux Logical Volume Manager partition (old)", buffer_size); break; + case 0xff: strncpy(buffer, "Xenix Bad Block Table ", buffer_size); break; + default: strncpy(buffer, "Unknown", buffer_size); break; + } +} diff --git a/com32/gpllib/disk/msdos.c b/com32/gpllib/disk/msdos.c new file mode 100644 index 00000000..1d1ef4df --- /dev/null +++ b/com32/gpllib/disk/msdos.c @@ -0,0 +1,167 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <stdlib.h> + +#include <disk/common.h> +#include <disk/geom.h> +#include <disk/msdos.h> +#include <disk/partition.h> +#include <disk/read.h> + +static inline int is_extended_partition(struct part_entry *ptab) +{ + return (ptab->ostype == 0x05 || + ptab->ostype == 0x0f || + ptab->ostype == 0x85); +} +static inline int msdos_magic_present(const char *ptab) +{ + return ( *(uint16_t *)(ptab + 0x1fe) == 0xaa55 ); +} + +/** + * process_extended_partition - execute a callback for each partition contained listed in an ebr + * @drive_info: driveinfo struct describing the drive + * @partition_offset: Absolute start (lba) of the extended partition + * @ebr_offset: Relative start (lba) of the current ebr processed within + * the extended partition + * @callback: Callback to execute + * @error: Buffer for I/O errors + * @nb_part_seen: Number of partitions found on the disk so far + **/ +static int process_extended_partition(struct driveinfo *drive_info, + const int partition_offset, + const int ebr_offset, + p_callback callback, + int nb_part_seen) +{ + int status = 0; + /* The ebr is located at the first sector of the extended partition */ + char* ebr = malloc(SECTOR * sizeof(char)); + + if (read_sectors(drive_info, ebr, partition_offset + ebr_offset, 1) == -1) + goto abort; + + /* Check msdos magic signature */ + if (!msdos_magic_present(ebr)) + goto abort; + + struct part_entry *ptab = (struct part_entry *)(ebr + PARTITION_TABLES_OFFSET); + + for (int i = 0; i < 4; i++) { + if (status == -1) + goto abort; + + if (!is_extended_partition(&ptab[i])) { + /* + * This EBR partition table entry points to the + * logical partition associated to that EBR + */ + int logical_partition_start = ebr_offset + ptab[i].start_lba; + + /* Last EBR in the extended partition? */ + if (!logical_partition_start) + continue; + + /* + * Check for garbage: + * 3rd and 4th entries in an EBR should be zero + * Some (malformed) partitioning software still add some + * data partitions there. + */ + if (ptab[i].start_lba <= 0 || ptab[i].length <= 0) + continue; + + nb_part_seen++; + callback(drive_info, + &ptab[i], + partition_offset + logical_partition_start, + nb_part_seen); + } else + status = process_extended_partition(drive_info, + partition_offset, + ptab[i].start_lba, + callback, + nb_part_seen); + } + + free(ebr); + return 0; + +abort: + free(ebr); + return -1; +} + +/** + * process_mbr - execute a callback for each partition contained in an {m,e}br + * @drive_info: driveinfo struct describing the drive + * @ptab: Pointer to the partition table + * @callback: Callback to execute + **/ +static int process_mbr(struct driveinfo *drive_info, struct part_entry *ptab, + p_callback callback) +{ + int status = 0; + + for (int i = 0; i < 4; i++) { + if (status == -1) + return -1; + + if (ptab[i].start_sect > 0) { + if (is_extended_partition(&ptab[i])) { + callback(drive_info, + &ptab[i], + ptab[i].start_lba, + i+1); + status = process_extended_partition(drive_info, ptab[i].start_lba, 0, callback, 4); + } else + callback(drive_info, + &ptab[i], + ptab[i].start_lba, + i+1); + } + } + + return 0; +} + +/** + * parse_partition_table - execute a callback for each partition entry + * @d: driveinfo struct describing the drive + * @callback: Callback to execute + * + * The signature of the callback should be the following: + * + * void callback(struct driveinfo *drive_info, + * struct part_entry *ptab, + * int offset_root, + * int nb_part_seen) + **/ +int parse_partition_table(struct driveinfo *d, p_callback callback) +{ + char *mbr = malloc(SECTOR * sizeof(char)); + + if (read_mbr(d->disk, mbr) == -1) + return -1; + else { + /* Check msdos magic signature */ + if (!msdos_magic_present(mbr)) + return -1; + + struct part_entry *ptab = (struct part_entry *)(mbr + PARTITION_TABLES_OFFSET); + return process_mbr(d, ptab, callback); + } +} diff --git a/com32/gpllib/disk/read.c b/com32/gpllib/disk/read.c new file mode 100644 index 00000000..74840829 --- /dev/null +++ b/com32/gpllib/disk/read.c @@ -0,0 +1,133 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <com32.h> +#include <stdlib.h> +#include <string.h> + +#include <disk/errno_disk.h> +#include <disk/geom.h> +#include <disk/read.h> +#include <disk/util.h> +#include <disk/common.h> + +/* + * TODO: implement file descriptors to cache metadata (geometry, ...) + */ + +/** + * read_mbr - return a pointer to a malloced buffer containing the mbr + * @drive: Drive number + * @buf: Pre-allocated buffer for output + * + * Return the number of sectors read on success or -1 on failure. + * errno_disk contains the error number. + **/ +int read_mbr(int drive, void *buf) +{ + struct driveinfo drive_info; + drive_info.disk = drive; + + /* MBR: lba = 0, 1 sector */ + return read_sectors(&drive_info, buf, 0, 1); +} + +/** + * dev_read - read from a drive + * @drive: Drive number + * @buf: Pre-allocated buffer for output + * @lba: Position to start reading from + * @sectors: Number of sectors to read + * + * High-level routine to read from a hard drive. + * Return the number of sectors read on success or -1 on failure. + * errno_disk contains the error number. + **/ +int dev_read(int drive, void * buf, unsigned int lba, int sectors) +{ + struct driveinfo drive_info; + drive_info.disk = drive; + + return read_sectors(&drive_info, buf, lba, sectors); +} + +/** + * read_sectors - read several sectors from disk + * @drive_info: driveinfo struct describing the disk + * @data: Pre-allocated buffer for output + * @lba: Position to read + * @sectors: Number of sectors to read + * + * Return the number of sectors read on success or -1 on failure. + * errno_disk contains the error number. + **/ +int read_sectors(struct driveinfo* drive_info, void *data, + const unsigned int lba, const int sectors) +{ + com32sys_t inreg, outreg; + struct ebios_dapa *dapa = __com32.cs_bounce; + void *buf = (char *)__com32.cs_bounce + sectors * SECTOR; + char *bufp = data; + + if (get_drive_parameters(drive_info) == -1) + return -1; + + memset(&inreg, 0, sizeof inreg); + + if (drive_info->ebios) { + dapa->len = sizeof(*dapa); + dapa->count = sectors; + dapa->off = OFFS(buf); + dapa->seg = SEG(buf); + dapa->lba = lba; + + inreg.esi.w[0] = OFFS(dapa); + inreg.ds = SEG(dapa); + inreg.edx.b[0] = drive_info->disk; + inreg.eax.b[1] = 0x42; /* Extended read */ + } else { + unsigned int c, h, s; + + if (!drive_info->cbios) { // XXX errno + /* We failed to get the geometry */ + if (lba) + return -1; /* Can only read MBR */ + + s = 1; h = 0; c = 0; + } else + lba_to_chs(drive_info, lba, &s, &h, &c); + + // XXX errno + if ( s > 63 || h > 256 || c > 1023 ) + return -1; + + inreg.eax.w[0] = 0x0201; /* Read one sector */ + inreg.ecx.b[1] = c & 0xff; + inreg.ecx.b[0] = s + (c >> 6); + inreg.edx.b[1] = h; + inreg.edx.b[0] = drive_info->disk; + inreg.ebx.w[0] = OFFS(buf); + inreg.es = SEG(buf); + } + + /* Perform the read */ + if (int13_retry(&inreg, &outreg)) { + errno_disk = outreg.eax.b[1]; + return -1; /* Give up */ + } + + memcpy(bufp, buf, sectors * SECTOR); + + return sectors; +} diff --git a/com32/gpllib/disk/swsusp.c b/com32/gpllib/disk/swsusp.c new file mode 100644 index 00000000..ac9724aa --- /dev/null +++ b/com32/gpllib/disk/swsusp.c @@ -0,0 +1,27 @@ +#include <stdlib.h> +#include <string.h> + +#include <disk/swsusp.h> +#include <disk/read.h> +#include <disk/geom.h> + +/** + * swsusp_check - check if a (swap) partition contains the swsusp signature + * @drive_info: driveinfo struct describing the disk containing the partition + * @ptab; Partition table of the partition + **/ +int swsusp_check(struct driveinfo *drive_info, struct part_entry *ptab) +{ + struct swsusp_header header_p; + int offset; + int found; + + /* Read first page of the swap device */ + offset = ptab->start_lba; + if (read_sectors(drive_info, &header_p, offset, PAGE_SIZE/SECTOR) == -1) { + return -1; + } else { + found = !memcmp(SWSUSP_SIG, header_p.sig, 10); + return found; + } +} diff --git a/com32/gpllib/disk/util.c b/com32/gpllib/disk/util.c new file mode 100644 index 00000000..6faac399 --- /dev/null +++ b/com32/gpllib/disk/util.c @@ -0,0 +1,44 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <com32.h> +#include <stdlib.h> +#include <string.h> +#include <disk/geom.h> + +#define MAX_NB_RETRIES 6 + +/** + * int13_retry - int13h with error handling + * @inreg: int13h function parameters + * @outreg: output registers + * + * Call int 13h, but with retry on failure. Especially floppies need this. + **/ +int int13_retry(const com32sys_t *inreg, com32sys_t *outreg) +{ + int retry = MAX_NB_RETRIES; /* Number of retries */ + com32sys_t tmpregs; + + if ( !outreg ) outreg = &tmpregs; + + while ( retry-- ) { + __intcall(0x13, inreg, outreg); + if ( !(outreg->eflags.l & EFLAGS_CF) ) + return 0; /* CF=0 => OK */ + } + + /* If we get here: error */ + return -1; +} diff --git a/com32/gpllib/disk/write.c b/com32/gpllib/disk/write.c new file mode 100644 index 00000000..a236f37d --- /dev/null +++ b/com32/gpllib/disk/write.c @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from chain.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <com32.h> +#include <stdlib.h> +#include <string.h> + +#include <disk/common.h> +#include <disk/errno_disk.h> +#include <disk/read.h> +#include <disk/util.h> +#include <disk/write.h> + +/** + * write_sectors - write several sectors from disk + * @drive_info: driveinfo struct describing the disk + * @lba: Position to write + * @data: Buffer to write + * @size: Size of the buffer (number of sectors) + * + * Return the number of sectors write on success or -1 on failure. + * errno_disk contains the error number. + **/ +int write_sectors(const struct driveinfo* drive_info, const unsigned int lba, + const void *data, const int size) +{ + com32sys_t inreg, outreg; + struct ebios_dapa *dapa = __com32.cs_bounce; + void *buf = (char *)__com32.cs_bounce + size; + + memcpy(buf, data, size); + memset(&inreg, 0, sizeof inreg); + + if (drive_info->ebios) { + dapa->len = sizeof(*dapa); + dapa->count = size; + dapa->off = OFFS(buf); + dapa->seg = SEG(buf); + dapa->lba = lba; + + inreg.esi.w[0] = OFFS(dapa); + inreg.ds = SEG(dapa); + inreg.edx.b[0] = drive_info->disk; + inreg.eax.w[0] = 0x4300; /* Extended write */ + } else { + unsigned int c, h, s; + + if (!drive_info->cbios) { // XXX errno + /* We failed to get the geometry */ + if (lba) + return -1; /* Can only write MBR */ + + s = 1; h = 0; c = 0; + } else + lba_to_chs(drive_info, lba, &s, &h, &c); + + // XXX errno + if ( s > 63 || h > 256 || c > 1023 ) + return -1; + + inreg.eax.w[0] = 0x0301; /* Write one sector */ + inreg.ecx.b[1] = c & 0xff; + inreg.ecx.b[0] = s + (c >> 6); + inreg.edx.b[1] = h; + inreg.edx.b[0] = drive_info->disk; + inreg.ebx.w[0] = OFFS(buf); + inreg.es = SEG(buf); + } + + /* Perform the write */ + if (int13_retry(&inreg, &outreg)) { + errno_disk = outreg.eax.b[1]; + return -1; /* Give up */ + } else + return size; +} + +/** + * write_verify_sectors - write several sectors from disk + * @drive_info: driveinfo struct describing the disk + * @lba: Position to write + * @data: Buffer to write + **/ +int write_verify_sector(struct driveinfo* drive_info, + const unsigned int lba, + const void *data) +{ + return write_verify_sectors(drive_info, lba, data, SECTOR); +} + +/** + * write_verify_sectors - write several sectors from disk + * @drive_info: driveinfo struct describing the disk + * @lba: Position to write + * @data: Buffer to write + * @size: Size of the buffer (number of sectors) + **/ +int write_verify_sectors(struct driveinfo* drive_info, + const unsigned int lba, + const void *data, const int size) +{ + char *rb = malloc(SECTOR * size * sizeof(char)); + int status; + + if (write_sectors(drive_info, lba, data, size) == -1) + return -1; /* Write failure */ + + if (read_sectors(drive_info, rb, lba, size) == -1) + return -1; /* Readback failure */ + + status = memcmp(data, rb, SECTOR * size); + free(rb); + return status ? -1 : 0; +} diff --git a/com32/gpllib/dmi/dmi.c b/com32/gpllib/dmi/dmi.c index 70ddd455..ebf3c527 100644 --- a/com32/gpllib/dmi/dmi.c +++ b/com32/gpllib/dmi/dmi.c @@ -33,7 +33,153 @@ const char *out_of_spec = "<OUT OF SPEC>"; const char *bad_index = "<BAD INDEX>"; -void dmi_bios_runtime_size(uint32_t code, s_dmi * dmi) +/* + * Misc. util stuff + */ + +/* + * 3.3.11 On Board Devices Information (Type 10) + */ + +static const char *dmi_on_board_devices_type(uint8_t code) +{ + /* 3.3.11.1 */ + static const char *type[]={ + "Other", /* 0x01 */ + "Unknown", + "Video", + "SCSI Controller", + "Ethernet", + "Token Ring", + "Sound", + "PATA Controller", + "SATA Controller", + "SAS Controller" /* 0x0A */ + }; + + if (code>=0x01 && code<=0x0A) + return type[code-0x01]; + return out_of_spec; +} + +static void dmi_on_board_devices(struct dmi_header *h, s_dmi* dmi) +{ + uint8_t *p = h->data+4; + uint8_t count = (h->length-0x04)/2; + unsigned int i; + + for (i=0; i<count && i<sizeof dmi->base_board.devices_information/sizeof *dmi->base_board.devices_information; i++) { + strncpy(dmi->base_board.devices_information[i].type, + dmi_on_board_devices_type(p[2*i]&0x7F), + sizeof dmi->base_board.devices_information[i].type); + dmi->base_board.devices_information[i].status = p[2*i]&0x80; + strncpy(dmi->base_board.devices_information[i].description, + dmi_string(h, p[2*i+1]), + sizeof dmi->base_board.devices_information[i].description); + } +} + +/* + * 3.3.24 System Reset (Type 23) + */ + +static const char *dmi_system_reset_boot_option(uint8_t code) +{ + static const char *option[]={ + "Operating System", /* 0x1 */ + "System Utilities", + "Do Not Reboot" /* 0x3 */ + }; + + if (code >= 0x1) + return option[code-0x1]; + return out_of_spec; +} + +static void dmi_system_reset_count(uint16_t code, char* array) +{ + if (code == 0xFFFF) + strncpy(array, "Unknown", sizeof array); + else + snprintf(array, sizeof array, "%u", code); +} + +static void dmi_system_reset_timer(uint16_t code, char* array) +{ + if (code == 0xFFFF) + strncpy(array, "Unknown", sizeof array); + else + snprintf(array, sizeof array, "%u min", code); +} + +/* + * 3.3.25 Hardware Security (Type 24) + */ + +static const char *dmi_hardware_security_status(uint8_t code) +{ + static const char *status[]={ + "Disabled", /* 0x00 */ + "Enabled", + "Not Implemented", + "Unknown" /* 0x03 */ + }; + + return status[code]; +} + +/* + * 3.3.12 OEM Strings (Type 11) + */ + +static void dmi_oem_strings(struct dmi_header *h, const char *prefix, s_dmi *dmi) +{ + uint8_t *p=h->data+4; + uint8_t count=p[0x00]; + int i; + + for(i=1; i<=count; i++) + snprintf(dmi->oem_strings, OEM_STRINGS_SIZE, "%s %s %s\n", + dmi->oem_strings, prefix, dmi_string(h, i)); +} + +/* + * 3.3.13 System Configuration Options (Type 12) + */ +static void dmi_system_configuration_options(struct dmi_header *h, const char *prefix, s_dmi *dmi) +{ + uint8_t *p = h->data+4; + uint8_t count = p[0x00]; + int i; + + for (i=1; i<=count; i++) + snprintf(dmi->system.configuration_options, SYSTEM_CONFIGURATION_OPTIONS_SIZE, "%s %s %s\n", + dmi->system.configuration_options, prefix, dmi_string(h, i)); +} + +static void dmi_system_boot_status(uint8_t code, char* array) +{ + static const char *status[]={ + "No errors detected", /* 0 */ + "No bootable media", + "Operating system failed to load", + "Firmware-detected hardware failure", + "Operating system-detected hardware failure", + "User-requested boot", + "System security violation", + "Previously-requested image", + "System watchdog timer expired" /* 8 */ + }; + + if (code<=8) + strncpy(array, status[code], SYSTEM_BOOT_STATUS_SIZE); + if (code>=128 && code<=191) + strncpy(array, "OEM-specific", SYSTEM_BOOT_STATUS_SIZE); + if (code>=192) + strncpy(array, "Product-specific", SYSTEM_BOOT_STATUS_SIZE); +} + +void dmi_bios_runtime_size(uint32_t code, s_dmi *dmi) { if (code & 0x000003FF) { dmi->bios.runtime_size = code; @@ -444,155 +590,232 @@ void dmi_decode(struct dmi_header *h, uint16_t ver, s_dmi * dmi) break; case 3: /* 3.3.4 Chassis Information */ // printf("Chassis Information\n"); - if (h->length < 0x09) - break; - dmi->chassis.filled = true; - strcpy(dmi->chassis.manufacturer, dmi_string(h, data[0x04])); - strcpy(dmi->chassis.type, dmi_chassis_type(data[0x05] & 0x7F)); - strcpy(dmi->chassis.lock, dmi_chassis_lock(data[0x05] >> 7)); - strcpy(dmi->chassis.version, dmi_string(h, data[0x06])); - strcpy(dmi->chassis.serial, dmi_string(h, data[0x07])); - strcpy(dmi->chassis.asset_tag, dmi_string(h, data[0x08])); - if (h->length < 0x0D) - break; - strcpy(dmi->chassis.boot_up_state, dmi_chassis_state(data[0x09])); - strcpy(dmi->chassis.power_supply_state, dmi_chassis_state(data[0x0A])); - strcpy(dmi->chassis.thermal_state, dmi_chassis_state(data[0x0B])); - strcpy(dmi->chassis.security_status, - dmi_chassis_security_status(data[0x0C])); - if (h->length < 0x11) - break; - sprintf(dmi->chassis.oem_information, "0x%08X\n", DWORD(data + 0x0D)); - if (h->length < 0x15) - break; - dmi->chassis.height = data[0x11]; - dmi->chassis.nb_power_cords = data[0x12]; - break; - - case 4: /* 3.3.5 Processor Information */ + if(h->length<0x09) break; + dmi->chassis.filled=true; + strcpy(dmi->chassis.manufacturer,dmi_string(h,data[0x04])); + strcpy(dmi->chassis.type,dmi_chassis_type(data[0x05]&0x7F)); + strcpy(dmi->chassis.lock,dmi_chassis_lock(data[0x05]>>7)); + strcpy(dmi->chassis.version,dmi_string(h,data[0x06])); + strcpy(dmi->chassis.serial,dmi_string(h,data[0x07])); + strcpy(dmi->chassis.asset_tag,dmi_string(h,data[0x08])); + if(h->length<0x0D) break; + strcpy(dmi->chassis.boot_up_state,dmi_chassis_state(data[0x09])); + strcpy(dmi->chassis.power_supply_state,dmi_chassis_state(data[0x0A])); + strcpy(dmi->chassis.thermal_state,dmi_chassis_state(data[0x0B])); + strcpy(dmi->chassis.security_status,dmi_chassis_security_status(data[0x0C])); + if(h->length<0x11) break; + sprintf(dmi->chassis.oem_information,"0x%08X",DWORD(data+0x0D)); + if(h->length<0x15) break; + dmi->chassis.height=data[0x11]; + dmi->chassis.nb_power_cords=data[0x12]; + break; + + case 4: /* 3.3.5 Processor Information */ // printf("Processor Information\n"); - if (h->length < 0x1A) - break; - dmi->processor.filled = true; - strcpy(dmi->processor.socket_designation, dmi_string(h, data[0x04])); - strcpy(dmi->processor.type, dmi_processor_type(data[0x05])); - strcpy(dmi->processor.manufacturer, dmi_string(h, data[0x07])); - strcpy(dmi->processor.family, - dmi_processor_family(data[0x06], dmi->processor.manufacturer)); - dmi_processor_id(data[0x06], data + 8, dmi_string(h, data[0x10]), dmi); - strcpy(dmi->processor.version, dmi_string(h, data[0x10])); - dmi_processor_voltage(data[0x11], dmi); - dmi->processor.external_clock = WORD(data + 0x12); - dmi->processor.max_speed = WORD(data + 0x14); - dmi->processor.current_speed = WORD(data + 0x16); - if (data[0x18] & (1 << 6)) - strcpy(dmi->processor.status, - dmi_processor_status(data[0x18] & 0x07)); - else - sprintf(dmi->processor.status, "Unpopulated"); - sprintf(dmi->processor.upgrade, dmi_processor_upgrade(data[0x19])); - if (h->length < 0x20) - break; - dmi_processor_cache(WORD(data + 0x1A), "L1", ver, - dmi->processor.cache1); - dmi_processor_cache(WORD(data + 0x1C), "L2", ver, - dmi->processor.cache2); - dmi_processor_cache(WORD(data + 0x1E), "L3", ver, - dmi->processor.cache3); - if (h->length < 0x23) - break; - strcpy(dmi->processor.serial, dmi_string(h, data[0x20])); - strcpy(dmi->processor.asset_tag, dmi_string(h, data[0x21])); - strcpy(dmi->processor.part_number, dmi_string(h, data[0x22])); - break; - case 17: /* 3.3.18 Memory Device */ - if (h->length < 0x15) - break; - dmi->memory_count++; - s_memory *mem = &dmi->memory[dmi->memory_count - 1]; - dmi->memory[dmi->memory_count - 1].filled = true; - dmi_memory_array_error_handle(WORD(data + 0x06), mem->error); - dmi_memory_device_width(WORD(data + 0x08), mem->total_width); - dmi_memory_device_width(WORD(data + 0x0A), mem->data_width); - dmi_memory_device_size(WORD(data + 0x0C), mem->size); - strcpy(mem->form_factor, dmi_memory_device_form_factor(data[0x0E])); - dmi_memory_device_set(data[0x0F], mem->device_set); - strcpy(mem->device_locator, dmi_string(h, data[0x10])); - strcpy(mem->bank_locator, dmi_string(h, data[0x11])); - strcpy(mem->type, dmi_memory_device_type(data[0x12])); - dmi_memory_device_type_detail(WORD(data + 0x13), mem->type_detail); - if (h->length < 0x17) - break; - dmi_memory_device_speed(WORD(data + 0x15), mem->speed); - if (h->length < 0x1B) - break; - strcpy(mem->manufacturer, dmi_string(h, data[0x17])); - strcpy(mem->serial, dmi_string(h, data[0x18])); - strcpy(mem->asset_tag, dmi_string(h, data[0x19])); - strcpy(mem->part_number, dmi_string(h, data[0x1A])); - break; - case 22: /* 3.3.23 Portable Battery */ - if (h->length < 0x10) - break; - dmi->battery.filled = true; - strcpy(dmi->battery.location, dmi_string(h, data[0x04])); - strcpy(dmi->battery.manufacturer, dmi_string(h, data[0x05])); - - if (data[0x06] || h->length < 0x1A) - strcpy(dmi->battery.manufacture_date, dmi_string(h, data[0x06])); - - if (data[0x07] || h->length < 0x1A) - strcpy(dmi->battery.serial, dmi_string(h, data[0x07])); - - strcpy(dmi->battery.name, dmi_string(h, data[0x08])); - - if (data[0x09] != 0x02 || h->length < 0x1A) - strcpy(dmi->battery.chemistry, dmi_battery_chemistry(data[0x09])); - - if (h->length < 0x1A) - dmi_battery_capacity(WORD(data + 0x0A), 1, - dmi->battery.design_capacity); - else - dmi_battery_capacity(WORD(data + 0x0A), data[0x15], - dmi->battery.design_capacity); - dmi_battery_voltage(WORD(data + 0x0C), dmi->battery.design_voltage); - strcpy(dmi->battery.sbds, dmi_string(h, data[0x0E])); - dmi_battery_maximum_error(data[0x0F], dmi->battery.maximum_error); - if (h->length < 0x1A) - break; - if (data[0x07] == 0) - sprintf(dmi->battery.sbds_serial, "%04X", WORD(data + 0x10)); - - if (data[0x06] == 0) - sprintf(dmi->battery.sbds_manufacture_date, "%u-%02u-%02u", - 1980 + (WORD(data + 0x12) >> 9), - (WORD(data + 0x12) >> 5) & 0x0F, WORD(data + 0x12) & 0x1F); - if (data[0x09] == 0x02) - strcpy(dmi->battery.sbds_chemistry, dmi_string(h, data[0x14])); - - // sprintf(dmi->battery.oem_info,"0x%08X",DWORD(h, data+0x16)); - break; - case 38: /* 3.3.39 IPMI Device Information */ - if (h->length < 0x10) - break; - dmi->ipmi.filled = true; - snprintf(dmi->ipmi.interface_type, sizeof(dmi->ipmi.interface_type), - "%s", dmi_ipmi_interface_type(data[0x04])); - dmi->ipmi.major_specification_version = data[0x05] >> 4; - dmi->ipmi.minor_specification_version = data[0x05] & 0x0F; - dmi->ipmi.I2C_slave_address = data[0x06] >> 1; - if (data[0x07] != 0xFF) - dmi->ipmi.nv_address = data[0x07]; - else - dmi->ipmi.nv_address = 0; /* Not Present */ - dmi_ipmi_base_address(data[0x04], data + 0x08, &dmi->ipmi); - if (h->length < 0x12) - break; - if (data[0x11] != 0x00) { - dmi->ipmi.irq = data[0x11]; - } - break; - } + if(h->length<0x1A) break; + dmi->processor.filled=true; + strcpy(dmi->processor.socket_designation,dmi_string(h, data[0x04])); + strcpy(dmi->processor.type,dmi_processor_type(data[0x05])); + strcpy(dmi->processor.manufacturer,dmi_string(h, data[0x07])); + strcpy(dmi->processor.family,dmi_processor_family(data[0x06],dmi->processor.manufacturer)); + dmi_processor_id(data[0x06], data+8, dmi_string(h, data[0x10]), dmi); + strcpy(dmi->processor.version,dmi_string(h, data[0x10])); + dmi_processor_voltage(data[0x11],dmi); + dmi->processor.external_clock=WORD(data+0x12); + dmi->processor.max_speed=WORD(data+0x14); + dmi->processor.current_speed=WORD(data+0x16); + if(data[0x18]&(1<<6)) + strcpy(dmi->processor.status,dmi_processor_status(data[0x18]&0x07)); + else + sprintf(dmi->processor.status,"Unpopulated"); + sprintf(dmi->processor.upgrade,dmi_processor_upgrade(data[0x19])); + if(h->length<0x20) break; + dmi_processor_cache(WORD(data+0x1A), "L1", ver,dmi->processor.cache1); + dmi_processor_cache(WORD(data+0x1C), "L2", ver,dmi->processor.cache2); + dmi_processor_cache(WORD(data+0x1E), "L3", ver,dmi->processor.cache3); + if(h->length<0x23) break; + strcpy(dmi->processor.serial,dmi_string(h, data[0x20])); + strcpy(dmi->processor.asset_tag,dmi_string(h, data[0x21])); + strcpy(dmi->processor.part_number,dmi_string(h, data[0x22])); + break; + case 6: /* 3.3.7 Memory Module Information */ + if(h->length<0x0C) break; + dmi->memory_module_count++; + s_memory_module *module = &dmi->memory_module[dmi->memory_module_count-1]; + dmi->memory_module[dmi->memory_module_count-1].filled=true; + strncpy(module->socket_designation, dmi_string(h, data[0x04]), + sizeof(module->socket_designation)); + dmi_memory_module_connections(data[0x05], module->bank_connections); + dmi_memory_module_speed(data[0x06], module->speed); + dmi_memory_module_types(WORD(data+0x07), " ", module->type); + dmi_memory_module_size(data[0x09], module->installed_size); + dmi_memory_module_size(data[0x0A], module->enabled_size); + dmi_memory_module_error(data[0x0B], "\t\t", module->error_status); + break; + case 7: /* 3.3.8 Cache Information */ + if(h->length<0x0F) break; + dmi->cache_count++; + if (dmi->cache_count > MAX_DMI_CACHE_ITEMS) break; + strcpy(dmi->cache[dmi->cache_count-1].socket_designation, + dmi_string(h, data[0x04])); + sprintf(dmi->cache[dmi->cache_count-1].configuration, + "%s, %s, %u", + WORD(data+0x05)&0x0080?"Enabled":"Disabled", + WORD(data+0x05)&0x0008?"Socketed":"Not Socketed", + (WORD(data+0x05)&0x0007)+1); + strcpy(dmi->cache[dmi->cache_count-1].mode, + dmi_cache_mode((WORD(data+0x05)>>8)&0x0003)); + strcpy(dmi->cache[dmi->cache_count-1].location, + dmi_cache_location((WORD(data+0x05)>>5)&0x0003)); + dmi->cache[dmi->cache_count-1].installed_size = + dmi_cache_size(WORD(data+0x09)); + dmi->cache[dmi->cache_count-1].max_size = + dmi_cache_size(WORD(data+0x07)); + dmi_cache_types(WORD(data+0x0B), " ", + dmi->cache[dmi->cache_count-1].supported_sram_types); + dmi_cache_types(WORD(data+0x0D), " ", + dmi->cache[dmi->cache_count-1].installed_sram_types); + if(h->length<0x13) break; + dmi->cache[dmi->cache_count-1].speed = data[0x0F]; /* ns */ + strcpy(dmi->cache[dmi->cache_count-1].error_correction_type, + dmi_cache_ec_type(data[0x10])); + strcpy(dmi->cache[dmi->cache_count-1].system_type, + dmi_cache_type(data[0x11])); + strcpy(dmi->cache[dmi->cache_count-1].associativity, + dmi_cache_associativity(data[0x12])); + break; + case 10: /* 3.3.11 On Board Devices Information */ + dmi_on_board_devices(h, dmi); + break; + case 11: /* 3.3.12 OEM Strings */ + if (h->length<0x05) break; + dmi_oem_strings(h, "\t", dmi); + break; + case 12: /* 3.3.13 System Configuration Options */ + if (h->length < 0x05) break; + dmi_system_configuration_options(h, "\t", dmi); + break; + case 17: /* 3.3.18 Memory Device */ + if (h->length < 0x15) break; + dmi->memory_count++; + if (dmi->memory_count > MAX_DMI_MEMORY_ITEMS) break; + s_memory *mem = &dmi->memory[dmi->memory_count-1]; + dmi->memory[dmi->memory_count-1].filled=true; + dmi_memory_array_error_handle(WORD(data + 0x06),mem->error); + dmi_memory_device_width(WORD(data + 0x08),mem->total_width); + dmi_memory_device_width(WORD(data + 0x0A),mem->data_width); + dmi_memory_device_size(WORD(data + 0x0C),mem->size); + strcpy(mem->form_factor,dmi_memory_device_form_factor(data[0x0E])); + dmi_memory_device_set(data[0x0F],mem->device_set); + strcpy(mem->device_locator,dmi_string(h, data[0x10])); + strcpy(mem->bank_locator,dmi_string(h, data[0x11])); + strcpy(mem->type,dmi_memory_device_type(data[0x12])); + dmi_memory_device_type_detail(WORD(data + 0x13),mem->type_detail); + if (h->length < 0x17) break; + dmi_memory_device_speed(WORD(data + 0x15),mem->speed); + if (h->length < 0x1B) break; + strcpy(mem->manufacturer, dmi_string(h, data[0x17])); + strcpy(mem->serial,dmi_string(h, data[0x18])); + strcpy(mem->asset_tag,dmi_string(h, data[0x19])); + strcpy(mem->part_number,dmi_string(h, data[0x1A])); + break; + case 22: /* 3.3.23 Portable Battery */ + if (h->length < 0x10) break; + dmi->battery.filled=true; + strcpy(dmi->battery.location,dmi_string(h, data[0x04])); + strcpy(dmi->battery.manufacturer,dmi_string(h, data[0x05])); + + if (data[0x06] || h->length < 0x1A) + strcpy(dmi->battery.manufacture_date, dmi_string(h, data[0x06])); + + if (data[0x07] || h->length < 0x1A) + strcpy(dmi->battery.serial, dmi_string(h, data[0x07])); + + strcpy(dmi->battery.name,dmi_string(h, data[0x08])); + + if (data[0x09] != 0x02 || h->length < 0x1A) + strcpy(dmi->battery.chemistry,dmi_battery_chemistry(data[0x09])); + + if (h->length < 0x1A) + dmi_battery_capacity(WORD(data + 0x0A), 1,dmi->battery.design_capacity); + else + dmi_battery_capacity(WORD(data + 0x0A), data[0x15],dmi->battery.design_capacity); + dmi_battery_voltage(WORD(data + 0x0C),dmi->battery.design_voltage); + strcpy(dmi->battery.sbds,dmi_string(h, data[0x0E])); + dmi_battery_maximum_error(data[0x0F],dmi->battery.maximum_error); + if (h->length < 0x1A) break; + if (data[0x07] == 0) + sprintf(dmi->battery.sbds_serial,"%04X", WORD(data + 0x10)); + + if (data[0x06] == 0) + sprintf(dmi->battery.sbds_manufacture_date,"%u-%02u-%02u", + 1980 + (WORD(data + 0x12) >> 9), + (WORD(data + 0x12) >> 5) & 0x0F, + WORD(data + 0x12) & 0x1F); + if (data[0x09] == 0x02) + strcpy(dmi->battery.sbds_chemistry, dmi_string(h, data[0x14])); + + // sprintf(dmi->battery.oem_info,"0x%08X",DWORD(h, data+0x16)); + break; + case 23: /* 3.3.24 System Reset */ + if(h->length<0x0D) break; + dmi->system.system_reset.filled = true; + dmi->system.system_reset.status = data[0x04]&(1<<0); + dmi->system.system_reset.watchdog = data[0x04]&(1<<5); + if (!(data[0x04]&(1<<5))) + break; + strncpy(dmi->system.system_reset.boot_option, + dmi_system_reset_boot_option((data[0x04]>>1)&0x3), + sizeof dmi->system.system_reset.boot_option); + strncpy(dmi->system.system_reset.boot_option_on_limit, + dmi_system_reset_boot_option((data[0x04]>>3)&0x3), + sizeof dmi->system.system_reset.boot_option_on_limit); + dmi_system_reset_count(WORD(data+0x05), dmi->system.system_reset.reset_count); + dmi_system_reset_count(WORD(data+0x07), dmi->system.system_reset.reset_limit); + dmi_system_reset_timer(WORD(data+0x09), dmi->system.system_reset.timer_interval); + dmi_system_reset_timer(WORD(data+0x0B), dmi->system.system_reset.timeout); + break; + case 24: /* 3.3.25 Hardware Security */ + if (h->length<0x05) break; + dmi->hardware_security.filled = true; + strncpy(dmi->hardware_security.power_on_passwd_status, + dmi_hardware_security_status(data[0x04]>>6), + sizeof dmi->hardware_security.power_on_passwd_status); + strncpy(dmi->hardware_security.keyboard_passwd_status, + dmi_hardware_security_status((data[0x04]>>4)&0x3), + sizeof dmi->hardware_security.keyboard_passwd_status); + strncpy(dmi->hardware_security.administrator_passwd_status, + dmi_hardware_security_status((data[0x04]>>2)&0x3), + sizeof dmi->hardware_security.administrator_passwd_status); + strncpy(dmi->hardware_security.front_panel_reset_status, + dmi_hardware_security_status(data[0x04]&0x3), + sizeof dmi->hardware_security.front_panel_reset_status); + break; + case 32: /* 3.3.33 System Boot Information */ + if (h->length < 0x0B) break; + dmi_system_boot_status(data[0x0A], + dmi->system.system_boot_status); + case 38: /* 3.3.39 IPMI Device Information */ + if (h->length < 0x10) break; + dmi->ipmi.filled=true; + snprintf(dmi->ipmi.interface_type,sizeof(dmi->ipmi.interface_type), + "%s", dmi_ipmi_interface_type(data[0x04])); + dmi->ipmi.major_specification_version=data[0x05] >> 4; + dmi->ipmi.minor_specification_version=data[0x05] & 0x0F; + dmi->ipmi.I2C_slave_address=data[0x06] >> 1; + if (data[0x07] != 0xFF) + dmi->ipmi.nv_address=data[0x07]; + else + dmi->ipmi.nv_address=0; /* Not Present */ + dmi_ipmi_base_address(data[0x04], data + 0x08, + &dmi->ipmi); + if (h->length < 0x12) break; + if (data[0x11] != 0x00) + { + dmi->ipmi.irq=data[0x11]; + } + break; + } } void parse_dmitable(s_dmi * dmi) diff --git a/com32/gpllib/dmi/dmi_cache.c b/com32/gpllib/dmi/dmi_cache.c new file mode 100644 index 00000000..bc1fc45f --- /dev/null +++ b/com32/gpllib/dmi/dmi_cache.c @@ -0,0 +1,135 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved + * + * Some part borrowed from DMI Decode: + * + * (C) 2000-2002 Alan Cox <alan@redhat.com> + * (C) 2002-2007 Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <dmi/dmi.h> +#include <dmi/dmi_cache.h> +#include <stdio.h> + +/* + * 3.3.8 Cache Information (Type 7) + */ + +const char *dmi_cache_mode(uint8_t code) +{ + static const char *mode[]={ + "Write Through", /* 0x00 */ + "Write Back", + "Varies With Memory Address", + "Unknown" /* 0x03 */ + }; + + return mode[code]; +} + +const char *dmi_cache_location(uint8_t code) +{ + static const char *location[4]={ + "Internal", /* 0x00 */ + "External", + NULL, /* 0x02 */ + "Unknown" /* 0x03 */ + }; + + if(location[code]!=NULL) + return location[code]; + return out_of_spec; +} + +uint16_t dmi_cache_size(uint16_t code) +{ + if(code&0x8000) + return (code&0x7FFF)<<6; /* KB */ + else + return code; /* KB */ +} + +void dmi_cache_types(uint16_t code, const char *sep, char* array) +{ + /* 3.3.8.2 */ + static const char *types[]={ + "Other", /* 0 */ + "Unknown", + "Non-burst", + "Burst", + "Pipeline Burst", + "Synchronous", + "Asynchronous" /* 6 */ + }; + + if((code&0x007F)==0) + strcpy(array, "None"); + else + { + int i; + + for(i=0; i<=6; i++) + if(code&(1<<i)) + sprintf(array, "%s%s", sep, types[i]); + } +} + +const char *dmi_cache_ec_type(uint8_t code) +{ + /* 3.3.8.3 */ + static const char *type[]={ + "Other", /* 0x01 */ + "Unknown", + "None", + "Parity", + "Single-bit ECC", + "Multi-bit ECC" /* 0x06 */ + }; + + if(code>=0x01 && code<=0x06) + return type[code-0x01]; + return out_of_spec; +} + +const char *dmi_cache_type(uint8_t code) +{ + /* 3.3.8.4 */ + static const char *type[]={ + "Other", /* 0x01 */ + "Unknown", + "Instruction", + "Data", + "Unified" /* 0x05 */ + }; + + if(code>=0x01 && code<=0x05) + return type[code-0x01]; + return out_of_spec; +} + +const char *dmi_cache_associativity(uint8_t code) +{ + /* 3.3.8.5 */ + static const char *type[]={ + "Other", /* 0x01 */ + "Unknown", + "Direct Mapped", + "2-way Set-associative", + "4-way Set-associative", + "Fully Associative", + "8-way Set-associative", + "16-way Set-associative" /* 0x08 */ + }; + + if(code>=0x01 && code<=0x08) + return type[code-0x01]; + return out_of_spec; +} diff --git a/com32/gpllib/dmi/dmi_memory.c b/com32/gpllib/dmi/dmi_memory.c index b04dabbe..588e4ad6 100644 --- a/com32/gpllib/dmi/dmi_memory.c +++ b/com32/gpllib/dmi/dmi_memory.c @@ -168,3 +168,95 @@ void dmi_memory_device_speed(uint16_t code, char *speed) else sprintf(speed, "%u MHz", code); } + +/* + * 3.3.7 Memory Module Information (Type 6) + */ + +void dmi_memory_module_types(uint16_t code, const char *sep, char *type) +{ + /* 3.3.7.1 */ + static const char *types[]={ + "Other", /* 0 */ + "Unknown", + "Standard", + "FPM", + "EDO", + "Parity", + "ECC", + "SIMM", + "DIMM", + "Burst EDO", + "SDRAM" /* 10 */ + }; + + if((code&0x07FF)==0) + sprintf(type, "%s", "None"); + else + { + int i; + + for(i=0; i<=10; i++) + if(code&(1<<i)) + sprintf(type, "%s%s", sep, types[i]); + } +} + +void dmi_memory_module_connections(uint8_t code, char* connection) +{ + if(code==0xFF) + sprintf(connection, "%s", "None"); + else + { + if((code&0xF0)!=0xF0) + sprintf(connection, "%u", code>>4); + if((code&0x0F)!=0x0F) + sprintf(connection, "%u", code&0x0F); + } +} + +void dmi_memory_module_speed(uint8_t code, char* speed) +{ + if(code==0) + sprintf(speed, "%s", "Unknown"); + else + sprintf(speed, "%u ns", code); +} + +void dmi_memory_module_size(uint8_t code, char* size) +{ + /* 3.3.7.2 */ + switch(code&0x7F) + { + case 0x7D: + sprintf(size, "%s", "Not Determinable"); + break; + case 0x7E: + sprintf(size, "%s", "Disabled"); + break; + case 0x7F: + sprintf(size, "%s", "Not Installed"); + return; + default: + sprintf(size, "%u MB", 1<<(code&0x7F)); + } + + if(code&0x80) + printf(size, "%s", "(Double-bank Connection)"); + else + printf(size, "%s", "(Single-bank Connection)"); +} + +void dmi_memory_module_error(uint8_t code, const char *prefix, char *error) +{ + if(code&(1<<2)) + sprintf(error, "%s", "See Event Log\n"); + else + { if((code&0x03)==0) + printf(error, "%s", "OK\n"); + if(code&(1<<0)) + printf(error, "%sUncorrectable Errors\n", prefix); + if(code&(1<<1)) + printf(error, "%sCorrectable Errors\n", prefix); + } +} diff --git a/com32/gpllib/memory.c b/com32/gpllib/memory.c new file mode 100644 index 00000000..6c6e351c --- /dev/null +++ b/com32/gpllib/memory.c @@ -0,0 +1,216 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer + * + * Some parts borrowed from meminfo.c32: + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * Some parts borrowed from Linux: + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * Interrupt list from Ralf Brown (http://www.cs.cmu.edu/~ralf/files.html) + * + * This file is part of Syslinux, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +#include <stdint.h> +#include <com32.h> +#include <string.h> +#include <memory.h> + +const char * const e820_types[] = { + "usable", + "reserved", + "ACPI reclaim", + "ACPI NVS", + "unusable", +}; + +struct e820_ext_entry { + struct e820entry std; + uint32_t ext_flags; +} __attribute__((packed)); + +#define SMAP 0x534d4150 /* ASCII "SMAP" */ + +void get_type(int type, char *type_ptr, int type_ptr_sz) +{ + unsigned int real_type = type - 1; + if (real_type < sizeof(e820_types)/sizeof(e820_types[0])) + strncpy(type_ptr, e820_types[real_type], type_ptr_sz); +} + +/** + *INT 15 - newer BIOSes - GET SYSTEM MEMORY MAP + * AX = E820h + * EAX = 0000E820h + * EDX = 534D4150h ('SMAP') + * EBX = continuation value or 00000000h to start at beginning of map + * ECX = size of buffer for result, in bytes (should be >= 20 bytes) + * ES:DI -> buffer for result (see #00581) + * + * Return: CF clear if successful + * EAX = 534D4150h ('SMAP') + * ES:DI buffer filled + * EBX = next offset from which to copy or 00000000h if all done + * ECX = actual length returned in bytes + * CF set on error + * AH = error code (86h) (see #00496 at INT 15/AH=80h) + * + * Notes: originally introduced with the Phoenix BIOS v4.0, this function is + * now supported by most newer BIOSes, since various versions of Windows + * call it to find out about the system memory + * a maximum of 20 bytes will be transferred at one time, even if ECX is + * higher; some BIOSes (e.g. Award Modular BIOS v4.50PG) ignore the + * value of ECX on entry, and always copy 20 bytes + * some BIOSes expect the high word of EAX to be clear on entry, i.e. + * EAX=0000E820h + * if this function is not supported, an application should fall back + * to AX=E802h, AX=E801h, and then AH=88h + * the BIOS is permitted to return a nonzero continuation value in EBX + * and indicate that the end of the list has already been reached by + * returning with CF set on the next iteration + * this function will return base memory and ISA/PCI memory contiguous + * with base memory as normal memory ranges; it will indicate + * chipset-defined address holes which are not in use and motherboard + * memory-mapped devices, and all occurrences of the system BIOS as + * reserved; standard PC address ranges will not be reported + **/ +void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found) +{ + int count = 0; + static struct e820_ext_entry buf; /* static so it is zeroed */ + + com32sys_t ireg, oreg; + memset(&ireg, 0, sizeof ireg); + + ireg.eax.w[0] = 0xe820; + ireg.edx.l = SMAP; + ireg.ecx.l = sizeof(struct e820_ext_entry); + ireg.edi.w[0] = OFFS(__com32.cs_bounce); + ireg.es = SEG(__com32.cs_bounce); + + /* + * Set this here so that if the BIOS doesn't change this field + * but still doesn't change %ecx, we're still okay... + */ + memset(&buf, 0, sizeof buf); + buf.ext_flags = 1; + + do { + memcpy(__com32.cs_bounce, &buf, sizeof buf); + + /* Important: %edx and %esi are clobbered by some BIOSes, + so they must be either used for the error output + or explicitly marked clobbered. Given that, assume there + is something out there clobbering %ebp and %edi, too. */ + __intcall(0x15, &ireg, &oreg); + + /* Some BIOSes stop returning SMAP in the middle of + the search loop. We don't know exactly how the BIOS + screwed up the map at that point, we might have a + partial map, the full map, or complete garbage, so + just return failure. */ + if (oreg.eax.l != SMAP) { + count = 0; + break; + } + + if (oreg.eflags.l & EFLAGS_CF || + oreg.ecx.l < 20) + break; + + memcpy(&buf, __com32.cs_bounce, sizeof buf); + + /* + * ACPI 3.0 added the extended flags support. If bit 0 + * in the extended flags is zero, we're supposed to simply + * ignore the entry -- a backwards incompatible change! + */ + if (oreg.ecx.l > 20 && !(buf.ext_flags & 1)) + continue; + + memcpy(&desc[count], &buf, sizeof buf); + count++; + + /* Set continuation value */ + ireg.ebx.l = oreg.ebx.l; + } while (ireg.ebx.l && count < size_map); + + *size_found = count; +} + +/** + * detect_memory_e801 + * + *INT 15 - Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS + * AX = E801h + * + * Return: CF clear if successful + * AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB) + * BX = extended memory above 16M, in 64K blocks + * CX = configured memory 1M to 16M, in K + * DX = configured memory above 16M, in 64K blocks + * CF set on error + * + * Notes: supported by the A03 level (6/14/94) and later XPS P90 BIOSes, as well + * as the Compaq Contura, 3/8/93 DESKPRO/i, and 7/26/93 LTE Lite 386 ROM + * BIOS + * supported by AMI BIOSes dated 8/23/94 or later + * on some systems, the BIOS returns AX=BX=0000h; in this case, use CX + * and DX instead of AX and BX + * this interface is used by Windows NT 3.1, OS/2 v2.11/2.20, and is + * used as a fall-back by newer versions if AX=E820h is not supported + * this function is not used by MS-DOS 6.0 HIMEM.SYS when an EISA machine + * (for example with parameter /EISA) (see also MEM F000h:FFD9h), or no + * Compaq machine was detected, or parameter /NOABOVE16 was given. + **/ +int detect_memory_e801(int* mem_size_below_16, int* mem_size_above_16) +{ + com32sys_t ireg, oreg; + memset(&ireg, 0, sizeof ireg); + + ireg.eax.w[0] = 0xe801; + + __intcall(0x15, &ireg, &oreg); + + if (oreg.eflags.l & EFLAGS_CF) + return -1; + + if (oreg.eax.w[0] > 0x3c00) + return -1; /* Bogus! */ + + /* Linux seems to use ecx and edx by default if they are defined */ + if (oreg.eax.w[0] || oreg.eax.w[0]) { + oreg.eax.w[0] = oreg.ecx.w[0]; + oreg.ebx.w[0] = oreg.edx.w[0]; + } + + *mem_size_below_16 = oreg.eax.w[0]; /* 1K blocks */ + *mem_size_above_16 = oreg.ebx.w[0]; /* 64K blocks */ + + return 0; +} + +int detect_memory_88(int* mem_size) +{ + com32sys_t ireg, oreg; + memset(&ireg, 0, sizeof ireg); + + ireg.eax.w[0] = 0x8800; + + __intcall(0x15, &ireg, &oreg); + + if (oreg.eflags.l & EFLAGS_CF) + return -1; + + *mem_size = oreg.eax.w[0]; + return 0; +} diff --git a/com32/hdt/hdt-ata.c b/com32/hdt/hdt-ata.c index e0d6015c..9ba17ba8 100644 --- a/com32/hdt/hdt-ata.c +++ b/com32/hdt/hdt-ata.c @@ -30,252 +30,9 @@ #include <stdio.h> #include <stdlib.h> #include <console.h> -#include <getkey.h> +#include <disk/geom.h> +#include <disk/util.h> #include "com32io.h" #include "hdt-common.h" #include "hdt-ata.h" - -#ifdef ATA -/** - * ata_id_string - Convert IDENTIFY DEVICE page into string - * @id: IDENTIFY DEVICE results we will examine - * @s: string into which data is output - * @ofs: offset into identify device page - * @len: length of string to return. must be an even number. - * - * The strings in the IDENTIFY DEVICE page are broken up into - * 16-bit chunks. Run through the string, and output each - * 8-bit chunk linearly, regardless of platform. - * - * LOCKING: - * caller. - */ -void ata_id_string(const uint16_t * id, unsigned char *s, - unsigned int ofs, unsigned int len) -{ - unsigned int c; - - while (len > 0) { - c = id[ofs] >> 8; - *s = c; - s++; - - c = id[ofs] & 0xff; - *s = c; - s++; - - ofs++; - len -= 2; - } -} - -/** - * ata_id_c_string - Convert IDENTIFY DEVICE page into C string - * @id: IDENTIFY DEVICE results we will examine - * @s: string into which data is output - * @ofs: offset into identify device page - * @len: length of string to return. must be an odd number. - * - * This function is identical to ata_id_string except that it - * trims trailing spaces and terminates the resulting string with - * null. @len must be actual maximum length (even number) + 1. - * - * LOCKING: - * caller. - */ -void ata_id_c_string(const uint16_t * id, unsigned char *s, - unsigned int ofs, unsigned int len) -{ - unsigned char *p; - - //WARN_ON(!(len & 1)); - - ata_id_string(id, s, ofs, len - 1); - - p = s + strnlen(s, len - 1); - while (p > s && p[-1] == ' ') - p--; - *p = '\0'; -} -#endif - -/** - * Call int 13h, but with retry on failure. Especially floppies need this. - */ -int int13_retry(const com32sys_t * inreg, com32sys_t * outreg) -{ - int retry = 6; /* Number of retries */ - com32sys_t tmpregs; - - if (!outreg) - outreg = &tmpregs; - - while (retry--) { - __intcall(0x13, inreg, outreg); - if (!(outreg->eflags.l & EFLAGS_CF)) - return 0; /* CF=0, OK */ - } - - return -1; /* Error */ -} - -/* Display CPU registers for debugging purposes */ -void printregs(const com32sys_t * r) -{ - printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n" - "eax = %08x ebx = %08x ecx = %08x edx = %08x\n" - "ebp = %08x esi = %08x edi = %08x esp = %08x\n", - r->eflags.l, r->ds, r->es, r->fs, r->gs, - r->eax.l, r->ebx.l, r->ecx.l, r->edx.l, - r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l); -} - -/* Try to get information for a given disk */ -int get_disk_params(int disk, struct diskinfo *disk_info) -{ - static com32sys_t getparm, parm, getebios, ebios, inreg, outreg; - struct device_parameter dp; -#ifdef ATA - struct ata_identify_device aid; -#endif - - memset(&(disk_info[disk]), 0, sizeof(struct diskinfo)); - - disk_info[disk].disk = disk; - disk_info[disk].ebios = disk_info[disk].cbios = 0; - - /* Sending int 13h func 41h to query EBIOS information */ - memset(&getebios, 0, sizeof(com32sys_t)); - memset(&ebios, 0, sizeof(com32sys_t)); - - /* Get EBIOS support */ - getebios.eax.w[0] = 0x4100; - getebios.ebx.w[0] = 0x55aa; - getebios.edx.b[0] = disk; - getebios.eflags.b[0] = 0x3; /* CF set */ - - __intcall(0x13, &getebios, &ebios); - - /* Detecting EDD support */ - if (!(ebios.eflags.l & EFLAGS_CF) && - ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) { - disk_info[disk].ebios = 1; - switch (ebios.eax.b[1]) { - case 32: - strlcpy(disk_info[disk].edd_version, "1.0", 3); - break; - case 33: - strlcpy(disk_info[disk].edd_version, "1.1", 3); - break; - case 48: - strlcpy(disk_info[disk].edd_version, "3.0", 3); - break; - default: - strlcpy(disk_info[disk].edd_version, "0", 1); - break; - } - } - /* Get disk parameters -- really only useful for - * hard disks, but if we have a partitioned floppy - * it's actually our best chance... - */ - memset(&getparm, 0, sizeof(com32sys_t)); - memset(&parm, 0, sizeof(com32sys_t)); - getparm.eax.b[1] = 0x08; - getparm.edx.b[0] = disk; - - __intcall(0x13, &getparm, &parm); - - if (parm.eflags.l & EFLAGS_CF) - return disk_info[disk].ebios ? 0 : -1; - - disk_info[disk].heads = parm.edx.b[1] + 1; - disk_info[disk].sectors_per_track = parm.ecx.b[0] & 0x3f; - if (disk_info[disk].sectors_per_track == 0) { - disk_info[disk].sectors_per_track = 1; - } else { - disk_info[disk].cbios = 1; /* Valid geometry */ - } - - /* If geometry isn't valid, no need to try to get more info about the drive*/ - /* Looks like in can confuse some optical drives */ - if (disk_info[disk].cbios != 1) return 0; - -/* FIXME: memset to 0 make it fails - * memset(__com32.cs_bounce, 0, sizeof(struct device_pairameter)); */ - memset(&dp, 0, sizeof(struct device_parameter)); - memset(&inreg, 0, sizeof(com32sys_t)); - - /* Requesting Extended Read Drive Parameters via int13h func 48h */ - inreg.esi.w[0] = OFFS(__com32.cs_bounce); - inreg.ds = SEG(__com32.cs_bounce); - inreg.eax.w[0] = 0x4800; - inreg.edx.b[0] = disk; - - __intcall(0x13, &inreg, &outreg); - - /* Saving bounce buffer before anything corrupt it */ - memcpy(&dp, __com32.cs_bounce, sizeof(struct device_parameter)); - - if (outreg.eflags.l & EFLAGS_CF) { - more_printf("Disk 0x%X doesn't supports EDD 3.0\n", disk); - return -1; - } - - /* Copying result to the disk_info structure - * host_bus_type, interface_type, sectors & cylinders */ - snprintf(disk_info[disk].host_bus_type, - sizeof disk_info[disk].host_bus_type, "%c%c%c%c", - dp.host_bus_type[0], dp.host_bus_type[1], dp.host_bus_type[2], - dp.host_bus_type[3]); - snprintf(disk_info[disk].interface_type, - sizeof disk_info[disk].interface_type, "%c%c%c%c%c%c%c%c", - dp.interface_type[0], dp.interface_type[1], - dp.interface_type[2], dp.interface_type[3], - dp.interface_type[4], dp.interface_type[5], - dp.interface_type[6], dp.interface_type[7]); - disk_info[disk].sectors = dp.sectors; - disk_info[disk].cylinders = dp.cylinders; - - /*FIXME: we have to find a way to grab the model & fw - * We do put dummy data until we found a solution */ - snprintf(disk_info[disk].aid.model, sizeof disk_info[disk].aid.model, - "0x%X", disk); - snprintf(disk_info[disk].aid.fw_rev, sizeof disk_info[disk].aid.fw_rev, - "%s", "N/A"); - snprintf(disk_info[disk].aid.serial_no, - sizeof disk_info[disk].aid.serial_no, "%s", "N/A"); - - /* Useless stuff before I figure how to send ata packets */ -#ifdef ATA - memset(__com32.cs_bounce, 0, sizeof(struct device_parameter)); - memset(&aid, 0, sizeof(struct ata_identify_device)); - memset(&inreg, 0, sizeof inreg); - inreg.ebx.w[0] = OFFS(__com32.cs_bounce + 1024); - inreg.es = SEG(__com32.cs_bounce + 1024); - inreg.eax.w[0] = 0x2500; - inreg.edx.b[0] = disk; - - __intcall(0x13, &inreg, &outreg); - - memcpy(&aid, __com32.cs_bounce, sizeof(struct ata_identify_device)); - - if (outreg.eflags.l & EFLAGS_CF) { - more_printf("Disk 0x%X: Failed to Identify Device\n", disk); - //FIXME - return 0; - } -// ata_id_c_string(aid, disk_info[disk].fwrev, ATA_ID_FW_REV, sizeof(disk_info[disk].fwrev)); -// ata_id_c_string(aid, disk_info[disk].model, ATA_ID_PROD, sizeof(disk_info[disk].model)); - - char buff[sizeof(struct ata_identify_device)]; - memcpy(buff, &aid, sizeof(struct ata_identify_device)); - for (int j = 0; j < sizeof(struct ata_identify_device); j++) - more_printf("model=|%c|\n", buff[j]); - more_printf("Disk 0x%X : %s %s %s\n", disk, aid.model, aid.fw_rev, - aid.serial_no); -#endif - - return 0; -} diff --git a/com32/hdt/hdt-ata.h b/com32/hdt/hdt-ata.h index fee4d598..a9550837 100644 --- a/com32/hdt/hdt-ata.h +++ b/com32/hdt/hdt-ata.h @@ -30,6 +30,7 @@ #define DEFINE_HDT_ATA_H #include <com32io.h> +#include <disk/geom.h> #include "hdt.h" struct ata_identify_device { @@ -50,58 +51,13 @@ struct ata_identify_device { unsigned short words088_255[168]; } ATTR_PACKED; -struct diskinfo { - int disk; - int ebios; /* EBIOS supported on this disk */ - int cbios; /* CHS geometry is valid */ - int heads; - int sectors_per_track; - int sectors; - int cylinders; - char edd_version[4]; +struct ata_driveinfo { struct ata_identify_device aid; /* IDENTIFY xxx DEVICE data */ char host_bus_type[5]; char interface_type[9]; char interface_port; } ATTR_PACKED; -/* - * Get a disk block and return a malloc'd buffer. - * Uses the disk number and information from disk_info. - */ -struct ebios_dapa { - uint16_t len; - uint16_t count; - uint16_t off; - uint16_t seg; - uint64_t lba; -}; - -// BYTE=8 -// WORD=16 -// DWORD=32 -// QWORD=64 -struct device_parameter { - uint16_t len; - uint16_t info; - uint32_t cylinders; - uint32_t heads; - uint32_t sectors_per_track; - uint64_t sectors; - uint16_t bytes_per_sector; - uint32_t dpte_pointer; - uint16_t device_path_information; - uint8_t device_path_lenght; - uint8_t device_path_reserved; - uint16_t device_path_reserved_2; - uint8_t host_bus_type[4]; - uint8_t interface_type[8]; - uint64_t interace_path; - uint64_t device_path[2]; - uint8_t reserved; - uint8_t cheksum; -} ATTR_PACKED; - /* Useless stuff until I manage how to send ata packets */ #ifdef ATA enum { @@ -114,9 +70,7 @@ void ata_id_c_string(const uint16_t * id, unsigned char *s, unsigned int ofs, unsigned int len); void ata_id_string(const uint16_t * id, unsigned char *s, unsigned int ofs, unsigned int len); -int int13_retry(const com32sys_t * inreg, com32sys_t * outreg); void printregs(const com32sys_t * r); #endif -int get_disk_params(int disk, struct diskinfo *disk_info); #endif diff --git a/com32/hdt/hdt-cli-disk.c b/com32/hdt/hdt-cli-disk.c new file mode 100644 index 00000000..4e2994d9 --- /dev/null +++ b/com32/hdt/hdt-cli-disk.c @@ -0,0 +1,222 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include <disk/errno_disk.h> +#include <disk/geom.h> +#include <disk/read.h> +#include <disk/error.h> +#include <disk/swsusp.h> +#include <disk/msdos.h> + +#include "hdt-cli.h" +#include "hdt-common.h" +#include "hdt-util.h" + +/** + * show_partition_information - print information about a partition + * @ptab: part_entry describing the partition + * @i: Partition number (UI purposes only) + * @ptab_root: part_entry describing the root partition (extended only) + * @drive_info: driveinfo struct describing the drive on which the partition + * is + * + * Note on offsets (from hpa, see chain.c32): + * + * To make things extra confusing: data partition offsets are relative to where + * the data partition record is stored, whereas extended partition offsets + * are relative to the beginning of the extended partition all the way back + * at the MBR... but still not absolute! + **/ +static void show_partition_information(struct driveinfo *drive_info, + struct part_entry *ptab, + int partition_offset, + int nb_partitions_seen) +{ + char size[9]; + char *parttype; + unsigned int start, end; + + int i = nb_partitions_seen; + + start = partition_offset; + end = start + ptab->length - 1; + + if (ptab->length > 0) + sectors_to_size(ptab->length, size); + else + memset(size, 0, sizeof size); + + if (i == 1) + more_printf(" # B Start End Size Id Type\n"); + + get_label(ptab->ostype, &parttype); + more_printf(" %2d %s %11d %11d %s %02X %s", + i, (ptab->active_flag == 0x80) ? "x" : " ", + start, + end, + size, + ptab->ostype, parttype); + + /* Extra info */ + if (ptab->ostype == 0x82 && swsusp_check(drive_info, ptab)) + more_printf("%s", " (Swsusp sig. detected)"); + + more_printf("\n"); + + free(parttype); +} + +void main_show_disk(int argc, char **argv, + struct s_hardware *hardware) +{ + reset_more_printf(); + if (!argc) { + more_printf("Which disk?\n"); + return; + } + + int drive = strtol(argv[0], (char**) NULL, 16); + + if (drive < 0x80 || drive >= 0xff) { + more_printf("Invalid disk: %d.\n", drive); + return; + } + + int i = drive - 0x80; + struct driveinfo *d = &hardware->disk_info[i]; + char disk_size[9]; + + detect_disks(hardware); + if (!hardware->disk_info[i].cbios) + return; /* Invalid geometry */ + + if ((int) d->edd_params.sectors > 0) + sectors_to_size((int) d->edd_params.sectors, disk_size); + else + memset(disk_size, 0, sizeof disk_size); + + more_printf("DISK 0x%X:\n" + " C/H/S: %d cylinders, %d heads, %d sectors/track\n" + " EDD: Version: %X\n" + " Size: %s, %d bytes/sector, %d sectors/track\n" + " Host bus: %s, Interface type: %s\n\n", + d->disk, + d->legacy_max_cylinder + 1, d->legacy_max_head + 1, d->legacy_sectors_per_track, + d->edd_version, + disk_size, (int) d->edd_params.bytes_per_sector, (int) d->edd_params.sectors_per_track, + remove_spaces(d->edd_params.host_bus_type), remove_spaces(d->edd_params.interface_type)); + + if (parse_partition_table(d, &show_partition_information)) { + if (errno_disk) { + fprintf(stderr, "I/O error parsing disk 0x%X\n", d->disk); + get_error("parse_partition_table"); + } else { + fprintf(stderr, "Disk 0x%X: unrecognized partition layout\n", d->disk); + } + fprintf(stderr, "\n"); + } +} + +void main_show_disks(int argc __unused, char **argv __unused, + struct s_hardware *hardware) +{ + reset_more_printf(); + detect_disks(hardware); + + for (int drive = 0x80; drive < 0xff; drive++) { + char buf[5] = ""; + sprintf(buf, "0x%x", drive); + char *argv[1] = { buf }; + main_show_disk(1, argv, hardware); + } +} + +void disks_summary(int argc __unused, char** argv __unused, + struct s_hardware *hardware) +{ + int i = -1; + + detect_disks(hardware); + + for (int drive = 0x80; drive < 0xff; drive++) { + i++; + if (!hardware->disk_info[i].cbios) + continue; /* Invalid geometry */ + struct driveinfo *d = &hardware->disk_info[i]; + char disk_size[9]; + + if ((int) d->edd_params.sectors > 0) + sectors_to_size((int) d->edd_params.sectors, disk_size); + else + memset(disk_size, 0, sizeof disk_size); + + more_printf("DISK 0x%X:\n", d->disk); + more_printf(" C/H/S: %d cylinders, %d heads, %d sectors/track\n", + d->legacy_max_cylinder + 1, d->legacy_max_head + 1, + d->legacy_sectors_per_track); + more_printf(" EDD: Version: %X, size: %s\n", d->edd_version, + disk_size); + more_printf(" Host bus: %s, Interface type: %s\n\n", + remove_spaces(d->edd_params.host_bus_type), + remove_spaces(d->edd_params.interface_type)); + } +} + +struct cli_callback_descr list_disk_show_modules[] = { + { + .name = "disks", + .exec = main_show_disks, + }, + { + .name = "disk", + .exec = main_show_disk, + }, + { + .name = NULL, + .exec = NULL, + }, +}; + + +struct cli_module_descr disk_show_modules = { + .modules = list_disk_show_modules, + .default_callback = disks_summary, +}; + +struct cli_mode_descr disk_mode = { + .mode = DISK_MODE, + .name = CLI_DISK, + .default_modules = NULL, + .show_modules = &disk_show_modules, + .set_modules = NULL, +}; diff --git a/com32/hdt/hdt-cli-dmi.c b/com32/hdt/hdt-cli-dmi.c index d395c672..fca94cdc 100644 --- a/com32/hdt/hdt-cli-dmi.c +++ b/com32/hdt/hdt-cli-dmi.c @@ -55,12 +55,24 @@ static void show_dmi_modules(int argc __unused, char** argv __unused, break; } } + for (int i = 0; i < hardware->dmi.memory_module_count; i++) { + if (hardware->dmi.memory_module[i].filled == true) { + printf("\tmodule <number>\n"); + break; + } + } if (hardware->dmi.processor.filled == true) printf("\t%s\n", CLI_DMI_PROCESSOR); if (hardware->dmi.system.filled == true) printf("\t%s\n", CLI_DMI_SYSTEM); if (hardware->dmi.ipmi.filled == true) printf("\t%s\n", CLI_DMI_IPMI); + if (hardware->dmi.cache_count) + printf("\t%s\n", CLI_DMI_CACHE); + if (strlen(hardware->dmi.oem_strings)) + more_printf("\t%s\n", CLI_DMI_OEM); + if (hardware->dmi.hardware_security.filled) + printf("\t%s\n", CLI_DMI_SECURITY); } static void show_dmi_base_board(int argc __unused, char** argv __unused, @@ -87,6 +99,15 @@ static void show_dmi_base_board(int argc __unused, char** argv __unused, more_printf(" %s\n", base_board_features_strings[i]); } } + + for (unsigned int i=0; i<sizeof hardware->dmi.base_board.devices_information/sizeof *hardware->dmi.base_board.devices_information; i++) { + if (strlen(hardware->dmi.base_board.devices_information[i].type)) { + more_printf("On Board Device #%u Information\n", i) + more_printf(" Type : %s\n", hardware->dmi.base_board.devices_information[i].type); + more_printf(" Status : %s\n", hardware->dmi.base_board.devices_information[i].status ? "Enabled" : "Disabled"); + more_printf(" Description : %s\n", hardware->dmi.base_board.devices_information[i].description); + } + } } static void show_dmi_system(int argc __unused, char** argv __unused, @@ -106,6 +127,34 @@ static void show_dmi_system(int argc __unused, char** argv __unused, printf(" Wakeup Type : %s\n", hardware->dmi.system.wakeup_type); printf(" SKU Number : %s\n", hardware->dmi.system.sku_number); printf(" Family : %s\n", hardware->dmi.system.family); + + if (strlen(hardware->dmi.system.configuration_options)) { + printf("System Configuration Options\n"); + printf("%s\n", hardware->dmi.system.configuration_options); + } + + if (hardware->dmi.system.system_reset.filled) { + printf("System Reset\n"); + printf(" Status : %s\n", + (hardware->dmi.system.system_reset.status ? "Enabled" : "Disabled")); + printf(" Watchdog Timer : %s\n", + (hardware->dmi.system.system_reset.watchdog ? "Present" : "Not Present")); + if (strlen(hardware->dmi.system.system_reset.boot_option)) + printf(" Boot Option : %s\n", hardware->dmi.system.system_reset.boot_option); + if (strlen(hardware->dmi.system.system_reset.boot_option_on_limit)) + printf(" Boot Option On Limit : %s\n", hardware->dmi.system.system_reset.boot_option_on_limit); + if (strlen(hardware->dmi.system.system_reset.reset_count)) + printf(" Reset Count : %s\n", hardware->dmi.system.system_reset.reset_count); + if (strlen(hardware->dmi.system.system_reset.reset_limit)) + printf(" Reset Limit : %s\n", hardware->dmi.system.system_reset.reset_limit); + if (strlen(hardware->dmi.system.system_reset.timer_interval)) + printf(" Timer Interval : %s\n", hardware->dmi.system.system_reset.timer_interval); + if (strlen(hardware->dmi.system.system_reset.timeout)) + printf(" Timeout : %s\n", hardware->dmi.system.system_reset.timeout); + } + + printf("System Boot Information\n"); + printf(" Status : %s\n", hardware->dmi.system.system_boot_status); } static void show_dmi_bios(int argc __unused, char** argv __unused, @@ -120,12 +169,13 @@ static void show_dmi_bios(int argc __unused, char** argv __unused, more_printf("BIOS\n"); more_printf(" Vendor : %s\n", hardware->dmi.bios.vendor); more_printf(" Version : %s\n", hardware->dmi.bios.version); - more_printf(" Release : %s\n", + more_printf(" Release Date : %s\n", hardware->dmi.bios.release_date); more_printf(" Bios Revision : %s\n", hardware->dmi.bios.bios_revision); - more_printf(" Firmware Revision : %s\n", - hardware->dmi.bios.firmware_revision); + if (strlen(hardware->dmi.bios.firmware_revision)) + more_printf(" Firmware Revision : %s\n", + hardware->dmi.bios.firmware_revision); more_printf(" Address : 0x%04X0\n", hardware->dmi.bios.address); more_printf(" Runtime address : %u %s\n", @@ -303,7 +353,7 @@ static void show_dmi_cpu(int argc __unused, char** argv __unused, } } -static void show_dmi_memory_bank(int argc, char** argv, +void show_dmi_memory_bank(int argc, char** argv, struct s_hardware *hardware) { int bank = -1; @@ -354,6 +404,97 @@ static void show_dmi_memory_bank(int argc, char** argv, hardware->dmi.memory[bank].part_number); } +static void show_dmi_cache(int argc, char** argv, + struct s_hardware *hardware) +{ + if (!hardware->dmi.cache_count) { + printf("cache information not found on your system, see " + "`show list' to see which module is available.\n"); + return; + } + + int cache = strtol(argv[0], NULL, 10); + + if (argc != 1 || cache > hardware->dmi.cache_count) { + printf("show cache [0-%d]\n", hardware->dmi.cache_count-1); + return; + } + + reset_more_printf(); + + more_printf("Cache Information #%d\n", cache); + more_printf(" Socket Designation : %s\n", + hardware->dmi.cache[cache].socket_designation); + more_printf(" Configuration : %s\n", + hardware->dmi.cache[cache].configuration); + more_printf(" Operational Mode : %s\n", + hardware->dmi.cache[cache].mode); + more_printf(" Location : %s\n", + hardware->dmi.cache[cache].location); + more_printf(" Installed Size : %u KB", + hardware->dmi.cache[cache].installed_size); + more_printf("\n"); + more_printf(" Maximum Size : %u KB", + hardware->dmi.cache[cache].max_size); + more_printf("\n"); + more_printf(" Supported SRAM Types : %s", + hardware->dmi.cache[cache].supported_sram_types); + more_printf("\n"); + more_printf(" Installed SRAM Type : %s", + hardware->dmi.cache[cache].installed_sram_types); + more_printf("\n"); + more_printf(" Speed : %u ns", + hardware->dmi.cache[cache].speed); + more_printf("\n"); + more_printf(" Error Correction Type : %s\n", + hardware->dmi.cache[cache].error_correction_type); + more_printf(" System Type : %s\n", + hardware->dmi.cache[cache].system_type); + more_printf(" Associativity : %s\n", + hardware->dmi.cache[cache].associativity); +} + +void show_dmi_memory_module(int argc, char** argv, + struct s_hardware *hardware) +{ + int module = -1; + + /* Sanitize arguments */ + if (argc > 0) + module = strtol(argv[0], (char **)NULL, 10); + + if (errno == ERANGE || module < 0) { + printf("This module number is incorrect\n"); + return; + } + + if ((module >= hardware->dmi.memory_module_count) || (module < 0)) { + printf("Module number %d doesn't exist\n", module); + return; + } + + if (hardware->dmi.memory_module[module].filled == false) { + printf("Module %d doesn't contain any information\n", module); + return; + } + + printf("Memory Module %d\n", module); + printf(" Socket Designation : %s\n", + hardware->dmi.memory_module[module].socket_designation); + printf(" Bank Connections : %s\n", + hardware->dmi.memory_module[module].bank_connections); + printf(" Current Speed : %s\n", + hardware->dmi.memory_module[module].speed); + printf(" Type : %s\n", + hardware->dmi.memory_module[module].type); + printf(" Installed Size : %s\n", + hardware->dmi.memory_module[module].installed_size); + printf(" Enabled Size : %s\n", + hardware->dmi.memory_module[module].enabled_size); + printf(" Error Status : %s\n", + hardware->dmi.memory_module[module].error_status); +} + void main_show_dmi(int argc __unused, char **argv __unused, struct s_hardware *hardware) { @@ -374,19 +515,16 @@ void main_show_dmi(int argc __unused, char **argv __unused, void show_dmi_memory_modules(int argc __unused, char** argv __unused, struct s_hardware *hardware) { - int clear = 1, show_free_banks = 1; + int show_free_banks = 1; + + /* Needed, if called by the memory mode */ + detect_dmi(hardware); /* Sanitize arguments */ if (argc > 0) { - clear = strtol(argv[0], NULL, 10); - if (errno == ERANGE || clear < 0 || clear > 1) - goto usage; - - if (argc > 1) { - show_free_banks = strtol(argv[1], NULL, 10); + show_free_banks = strtol(argv[0], NULL, 10); if (errno == ERANGE || show_free_banks < 0 || show_free_banks > 1) goto usage; - } } char bank_number[10]; @@ -398,8 +536,6 @@ void show_dmi_memory_modules(int argc __unused, char** argv __unused, return; } - if (clear) - clear_screen(); more_printf("Memory Banks\n"); for (int i = 0; i < hardware->dmi.memory_count; i++) { if (hardware->dmi.memory[i].filled == true) { @@ -434,6 +570,34 @@ usage: return; } +void show_dmi_oem_strings(int argc __unused, char** argv __unused, + struct s_hardware *hardware) +{ + reset_more_printf(); + + if (strlen(hardware->dmi.oem_strings)) + more_printf("OEM Strings\n%s", hardware->dmi.oem_strings); +} + +void show_dmi_hardware_security(int argc __unused, char** argv __unused, + struct s_hardware *hardware) +{ + reset_more_printf(); + + if (!hardware->dmi.hardware_security.filled) + return; + + more_printf("Hardware Security\n"); + more_printf(" Power-On Password Status : %s\n", + hardware->dmi.hardware_security.power_on_passwd_status); + more_printf(" Keyboard Password Status : %s\n", + hardware->dmi.hardware_security.keyboard_passwd_status); + more_printf(" Administrator Password Status : %s\n", + hardware->dmi.hardware_security.administrator_passwd_status); + more_printf(" Front Panel Reset Status : %s\n", + hardware->dmi.hardware_security.front_panel_reset_status); +} + struct cli_callback_descr list_dmi_show_modules[] = { { .name = CLI_DMI_BASE_BOARD, @@ -460,6 +624,10 @@ struct cli_callback_descr list_dmi_show_modules[] = { .exec = show_dmi_memory_bank, }, { + .name = "module", + .exec = show_dmi_memory_module, + }, + { .name = CLI_DMI_PROCESSOR, .exec = show_dmi_cpu, }, @@ -468,10 +636,22 @@ struct cli_callback_descr list_dmi_show_modules[] = { .exec = show_dmi_system, }, { + .name = CLI_DMI_OEM, + .exec = show_dmi_oem_strings, + }, + { + .name = CLI_DMI_SECURITY, + .exec = show_dmi_hardware_security, + }, + { .name = CLI_DMI_IPMI, .exec = show_dmi_ipmi, }, { + .name = CLI_DMI_CACHE, + .exec = show_dmi_cache, + }, + { .name = CLI_DMI_LIST, .exec = show_dmi_modules, }, diff --git a/com32/hdt/hdt-cli-hdt.c b/com32/hdt/hdt-cli-hdt.c index 46f3669a..5bebf584 100644 --- a/com32/hdt/hdt-cli-hdt.c +++ b/com32/hdt/hdt-cli-hdt.c @@ -54,9 +54,10 @@ static void main_show_modes(int argc __unused, char** argv __unused, printf("Available modes:\n"); while (list_modes[i]) { - printf("\t%s\n", list_modes[i]->name); + printf("%s ", list_modes[i]->name); i++; } + printf("\n"); } /** @@ -132,25 +133,27 @@ static void show_cli_help(int argc __unused, char** argv __unused, /* List secondly the show modules of the mode */ if (current_mode->show_modules && current_mode->show_modules->modules) { - printf("show commands:\n"); + printf("\nshow commands:\n"); j = 0; while (current_mode->show_modules->modules[j].name) { - printf("\t%s\n", + printf("%s ", current_mode->show_modules->modules[j].name); j++; } + printf("\n"); } /* List thirdly the set modules of the mode */ if (current_mode->set_modules && current_mode->set_modules->modules) { - printf("set commands:\n"); + printf("\nset commands:\n"); j = 0; while (current_mode->set_modules->modules[j].name) { - printf("\t%s\n", + printf("%s ", current_mode->set_modules->modules[j].name); j++; } + printf("\n"); } /* List finally the default modules of the hdt mode */ @@ -177,6 +180,7 @@ static void show_cli_help(int argc __unused, char** argv __unused, printf("\n"); } + printf("\n"); main_show_modes(argc, argv, hardware); } @@ -217,8 +221,8 @@ void main_show_summary(int argc __unused, char **argv __unused, more_printf(" Release : %s\n", hardware->dmi.bios.release_date); - int argc = 2; - char *argv[2] = { "0", "0" }; + int argc = 1; + char *argv[1] = { "0" }; show_dmi_memory_modules(argc, argv, hardware); } main_show_pci(argc, argv, hardware); @@ -285,6 +289,10 @@ struct cli_callback_descr list_hdt_show_modules[] = { .exec = main_show_cpu, }, { + .name = CLI_DISK, + .exec = disks_summary, + }, + { .name = CLI_PXE, .exec = main_show_pxe, }, @@ -305,6 +313,14 @@ struct cli_callback_descr list_hdt_show_modules[] = { .exec = main_show_hdt, }, { + .name = CLI_VPD, + .exec = main_show_vpd, + }, + { + .name = CLI_MEMORY, + .exec = show_dmi_memory_modules, + }, + { .name = "modes", .exec = main_show_modes, }, diff --git a/com32/hdt/hdt-cli-kernel.c b/com32/hdt/hdt-cli-kernel.c index d9ba27f8..41c80bea 100644 --- a/com32/hdt/hdt-cli-kernel.c +++ b/com32/hdt/hdt-cli-kernel.c @@ -50,8 +50,9 @@ void main_show_kernel(int argc __unused, char **argv __unused, // more_printf(" PCI device no: %d \n", p->pci_device_pos); - if (hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) { - more_printf(" modules.pcimap is missing\n"); + if ((hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) + && (hardware->modules_alias_return_code == -ENOMODULESALIAS)) { + more_printf(" modules.pcimap and modules.alias files are missing\n"); return; } diff --git a/com32/hdt/hdt-cli-memory.c b/com32/hdt/hdt-cli-memory.c new file mode 100644 index 00000000..89f871e1 --- /dev/null +++ b/com32/hdt/hdt-cli-memory.c @@ -0,0 +1,116 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <memory.h> + +#include "hdt-cli.h" +#include "hdt-common.h" + +#define E820MAX 128 + +static void show_memory_e820(int argc __unused, char **argv __unused, + struct s_hardware *hardware __unused) +{ + struct e820entry map[E820MAX]; + int count = 0; + char type[14]; + + detect_memory_e820(map, E820MAX, &count); + printf("BIOS-provided physical RAM e820 map:\n"); + reset_more_printf(); + for (int i = 0; i < count; i++) { + get_type(map[i].type, type, 14); + more_printf("%016llx - %016llx %016llx (%s)\n", + map[i].addr, map[i].size, map[i].addr+map[i].size, + remove_spaces(type)); + } +} + +static void show_memory_e801(int argc __unused, char **argv __unused, + struct s_hardware *hardware __unused) +{ + int mem_low, mem_high = 0; + + reset_more_printf(); + if (detect_memory_e801(&mem_low, &mem_high)) { + more_printf("e801 bogus!\n"); + } else { + more_printf("e801: %d Kb (%d MiB) - %d Kb (%d MiB)\n", + mem_low, mem_low >> 10, mem_high << 6, mem_high >> 4); + } +} + +static void show_memory_88(int argc __unused, char **argv __unused, + struct s_hardware *hardware __unused) +{ + int mem_size = 0; + + reset_more_printf(); + if (detect_memory_88(&mem_size)) { + more_printf("8800h bogus!\n"); + } else { + more_printf("8800h memory size: %d Kb (%d MiB)\n", mem_size, + mem_size >> 10); + } +} + +struct cli_callback_descr list_memory_show_modules[] = { + { + .name = "e820", + .exec = show_memory_e820, + }, + { + .name = "e801", + .exec = show_memory_e801, + }, + { + .name = "88", + .exec = show_memory_88, + }, + { + .name = CLI_DMI_MEMORY_BANK, + .exec = show_dmi_memory_bank, + }, + { + .name = NULL, + .exec = NULL, + }, +}; + +struct cli_module_descr memory_show_modules = { + .modules = list_memory_show_modules, + .default_callback = show_dmi_memory_modules, +}; + +struct cli_mode_descr memory_mode = { + .mode = MEMORY_MODE, + .name = CLI_MEMORY, + .default_modules = NULL, + .show_modules = &memory_show_modules, + .set_modules = NULL, +}; diff --git a/com32/hdt/hdt-cli-pci.c b/com32/hdt/hdt-cli-pci.c index 1213c326..2de43fe3 100644 --- a/com32/hdt/hdt-cli-pci.c +++ b/com32/hdt/hdt-cli-pci.c @@ -50,6 +50,8 @@ static void show_pci_device(int argc, char **argv, int pcidev = -1; bool nopciids = false; bool nomodulespcimap = false; + bool nomodulesalias = false; + bool nomodulesfiles = false; char kernel_modules[LINUX_KERNEL_MODULE_SIZE * MAX_KERNEL_MODULES_PER_PCI_DEVICE]; int bus = 0, slot = 0, func = 0; @@ -75,7 +77,10 @@ static void show_pci_device(int argc, char **argv, if (hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) { nomodulespcimap = true; } - + if (hardware->modules_alias_return_code == -ENOMODULESALIAS) { + nomodulesalias = true; + } + nomodulesfiles=nomodulespcimap && nomodulesalias; for_each_pci_func(temp_pci_device, hardware->pci_domain) { i++; if (i == pcidev) { @@ -115,7 +120,7 @@ static void show_pci_device(int argc, char **argv, pci_device->dev_info->class_name); } - if (nomodulespcimap == false) { + if (nomodulesfiles == false) { printf("Kernel module : %s\n", kernel_modules); } @@ -152,6 +157,8 @@ static void show_pci_devices(int argc __unused, char **argv __unused, MAX_KERNEL_MODULES_PER_PCI_DEVICE]; bool nopciids = false; bool nomodulespcimap = false; + bool nomodulesalias = false; + bool nomodulesfile = false; char first_line[81]; char second_line[81]; @@ -164,6 +171,11 @@ static void show_pci_devices(int argc __unused, char **argv __unused, if (hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) { nomodulespcimap = true; } + if (hardware->modules_pcimap_return_code == -ENOMODULESALIAS) { + nomodulesalias = true; + } + + nomodulesfile = nomodulespcimap && nomodulesalias; /* For every detected pci device, compute its submenu */ for_each_pci_func(pci_device, hardware->pci_domain) { @@ -186,7 +198,7 @@ static void show_pci_devices(int argc __unused, char **argv __unused, "%02d: %s %s \n", i, pci_device->dev_info->vendor_name, pci_device->dev_info->product_name); - if (nomodulespcimap == false) + if (nomodulesfile == false) snprintf(second_line, sizeof(second_line), " # %-25s # Kmod: %s\n", pci_device->dev_info->class_name, @@ -204,7 +216,7 @@ static void show_pci_devices(int argc __unused, char **argv __unused, more_printf(second_line); more_printf("\n"); } else if (nopciids == true) { - if (nomodulespcimap == true) { + if (nomodulesfile == true) { more_printf("%02d: %04x:%04x [%04x:%04x] \n", i, pci_device->vendor, pci_device->product, @@ -298,10 +310,11 @@ void cli_detect_pci(struct s_hardware *hardware) printf("Please put one in same dir as hdt\n"); error = true; } - if (hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) { + if ((hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) && + (hardware->modules_alias_return_code == -ENOMODULESALIAS)) { printf - ("The modules.pcimap file is missing, device names can't be computed.\n"); - printf("Please put one in same dir as hdt\n"); + ("The modules.pcimap or modules.alias files are missing, device names can't be computed.\n"); + printf("Please put one of them in same dir as hdt\n"); error = true; } if (error == true) { diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c index 871fd76c..0d38fb2b 100644 --- a/com32/hdt/hdt-cli.c +++ b/com32/hdt/hdt-cli.c @@ -43,7 +43,9 @@ struct cli_mode_descr *list_modes[] = { &cpu_mode, &pci_mode, &vesa_mode, + &disk_mode, &vpd_mode, + &memory_mode, NULL, }; @@ -179,6 +181,12 @@ void set_mode(cli_mode_t mode, struct s_hardware* hardware) snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_DMI); break; + case DISK_MODE: + detect_disks(hardware); + hdt_cli.mode = mode; + snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", + CLI_DISK); + break; case VPD_MODE: detect_vpd(hardware); if (!hardware->is_vpd_valid) { @@ -189,7 +197,11 @@ void set_mode(cli_mode_t mode, struct s_hardware* hardware) snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_VPD); break; - + case MEMORY_MODE: + hdt_cli.mode = mode; + snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", + CLI_MEMORY); + break; default: /* Invalid mode */ printf("Unknown mode, please choose among:\n"); @@ -424,16 +436,14 @@ void find_cli_callback_descr(const char* module_name, struct cli_callback_descr** module_found) { int modules_iter = 0; - int module_len = strlen(module_name); if (modules_list == NULL) goto not_found; /* Find the callback to execute */ while (modules_list->modules[modules_iter].name && - strncmp(module_name, - modules_list->modules[modules_iter].name, - module_len) != 0) + strcmp(module_name, + modules_list->modules[modules_iter].name) != 0) modules_iter++; if (modules_list->modules[modules_iter].name) { @@ -765,16 +775,23 @@ void start_cli_mode(struct s_hardware *hardware) printf("Entering CLI mode\n"); - /* Display the cursor */ - display_cursor(true); - reset_prompt(); while (hdt_cli.mode != EXIT_MODE) { - //fgets(cli_line, sizeof cli_line, stdin); + /* Display the cursor */ + display_cursor(true); + + /* Let's put the cursor blinking until we get an input */ + set_cursor_blink(true); + + /* We wait endlessly for a keyboard input*/ current_key = get_key(stdin, 0); + /* We have to cancel the blinking mode to prevent + * input text to blink */ + set_cursor_blink(false); + /* Reset autocomplete buffer unless TAB is pressed */ if (current_key != KEY_TAB) autocomplete_destroy_list(); @@ -967,14 +984,10 @@ void start_cli_mode(struct s_hardware *hardware) /* Print the resulting buffer */ printf("%s", hdt_cli.input + hdt_cli.cursor_pos - 1); - /* Realing to the place we were */ - move_cursor_left(strlen(hdt_cli.input + hdt_cli.cursor_pos - 1)); - move_cursor_right(1); + /* Realing to a char before the place we were */ + hdt_cli.cursor_pos--; + move_cursor_to_column(strlen(hdt_cli.prompt)+hdt_cli.cursor_pos+1); - /* Don't decrement the position unless - * if we are at then end of the line*/ - if (hdt_cli.cursor_pos > (int)strlen(hdt_cli.input)) - hdt_cli.cursor_pos--; break; case KEY_F1: diff --git a/com32/hdt/hdt-cli.h b/com32/hdt/hdt-cli.h index 516d2fc8..47137cca 100644 --- a/com32/hdt/hdt-cli.h +++ b/com32/hdt/hdt-cli.h @@ -40,9 +40,6 @@ # define dprintf(f, ...) ((void)0) #endif -/* Declare a variable or data structure as unused. */ -#define __unused __attribute__ (( unused )) - #define MAX_LINE_SIZE 256 #define CLI_SPACE " " @@ -64,10 +61,12 @@ #define CLI_COMMANDS "commands" #define CLI_DMI "dmi" #define CLI_CPU "cpu" +#define CLI_DISK "disk" #define CLI_SHOW_LIST "list" #define CLI_IRQ "irq" #define CLI_MODES "modes" #define CLI_VPD "vpd" +#define CLI_MEMORY "memory" typedef enum { INVALID_MODE, @@ -80,7 +79,9 @@ typedef enum { KERNEL_MODE, SYSLINUX_MODE, VESA_MODE, + DISK_MODE, VPD_MODE, + MEMORY_MODE, } cli_mode_t; #define PROMPT_SIZE 32 @@ -138,7 +139,9 @@ struct cli_mode_descr kernel_mode; struct cli_mode_descr cpu_mode; struct cli_mode_descr pci_mode; struct cli_mode_descr vesa_mode; +struct cli_mode_descr disk_mode; struct cli_mode_descr vpd_mode; +struct cli_mode_descr memory_mode; /* cli helpers */ void find_cli_mode_descr(cli_mode_t mode, struct cli_mode_descr **mode_found); @@ -161,9 +164,13 @@ void main_show(char *item, struct s_hardware *hardware); #define CLI_DMI_PROCESSOR "cpu" #define CLI_DMI_SYSTEM "system" #define CLI_DMI_IPMI "ipmi" +#define CLI_DMI_CACHE "cache" +#define CLI_DMI_OEM "oem" +#define CLI_DMI_SECURITY "security" #define CLI_DMI_LIST CLI_SHOW_LIST void main_show_dmi(int argc, char **argv, struct s_hardware *hardware); void show_dmi_memory_modules(int argc, char** argv, struct s_hardware *hardware); +void show_dmi_memory_bank(int argc, char** argv, struct s_hardware *hardware); // PCI STUFF #define CLI_PCI_DEVICE "device" @@ -173,6 +180,9 @@ void cli_detect_pci(struct s_hardware *hardware); // CPU STUFF void main_show_cpu(int argc, char **argv, struct s_hardware *hardware); +// DISK STUFF +void disks_summary(int argc, char **argv, struct s_hardware *hardware); + // PXE STUFF void main_show_pxe(int argc, char **argv, struct s_hardware *hardware); @@ -184,4 +194,7 @@ void main_show_syslinux(int argc, char **argv, struct s_hardware *hardware); // VESA STUFF void main_show_vesa(int argc, char **argv, struct s_hardware *hardware); + +// VPD STUFF +void main_show_vpd(int argc __unused, char **argv __unused, struct s_hardware *hardware); #endif diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c index 8cda7f06..80305a3e 100644 --- a/com32/hdt/hdt-common.c +++ b/com32/hdt/hdt-common.c @@ -34,6 +34,7 @@ #include "../lib/sys/vesa/vesa.h" #include "hdt-common.h" #include "lib-ansi.h" +#include <disk/util.h> /* ISOlinux requires a 8.3 format */ void convert_isolinux_filename(char *filename, struct s_hardware *hardware) { @@ -55,14 +56,18 @@ void detect_parameters(const int argc, const char *argv[], struct s_hardware *hardware) { for (int i = 1; i < argc; i++) { - if (!strncmp(argv[i], "modules=", 8)) { - strncpy(hardware->modules_pcimap_path, argv[i] + 8, + if (!strncmp(argv[i], "modules_pcimap=", 15)) { + strncpy(hardware->modules_pcimap_path, argv[i] + 15, sizeof(hardware->modules_pcimap_path)); convert_isolinux_filename(hardware->modules_pcimap_path,hardware); } else if (!strncmp(argv[i], "pciids=", 7)) { strncpy(hardware->pciids_path, argv[i] + 7, sizeof(hardware->pciids_path)); convert_isolinux_filename(hardware->pciids_path,hardware); + } else if (!strncmp(argv[i], "modules_alias=", 14)) { + strncpy(hardware->modules_alias_path, argv[i] + 14, + sizeof(hardware->modules_alias_path)); + convert_isolinux_filename(hardware->modules_alias_path,hardware); } else if (!strncmp(argv[i], "memtest=", 8)) { strncpy(hardware->memtest_label, argv[i] + 8, sizeof(hardware->memtest_label)); @@ -99,6 +104,7 @@ void init_hardware(struct s_hardware *hardware) { hardware->pci_ids_return_code = 0; hardware->modules_pcimap_return_code = 0; + hardware->modules_alias_return_code = 0; hardware->cpu_detection = false; hardware->pci_detection = false; hardware->disk_detection = false; @@ -124,9 +130,12 @@ void init_hardware(struct s_hardware *hardware) memset(hardware->pciids_path, 0, sizeof hardware->pciids_path); memset(hardware->modules_pcimap_path, 0, sizeof hardware->modules_pcimap_path); + memset(hardware->modules_alias_path, 0, + sizeof hardware->modules_alias_path); memset(hardware->memtest_label, 0, sizeof hardware->memtest_label); strcat(hardware->pciids_path, "pci.ids"); strcat(hardware->modules_pcimap_path, "modules.pcimap"); + strcat(hardware->modules_alias_path, "modules.alias"); strcat(hardware->memtest_label, "memtest"); } @@ -241,18 +250,27 @@ int detect_vesa(struct s_hardware *hardware) { /* Try to detect disks from port 0x80 to 0xff */ void detect_disks(struct s_hardware *hardware) { - hardware->disk_detection = true; - for (int drive = 0x80; drive < 0xff; drive++) { - if (get_disk_params(drive, hardware->disk_info) != 0) - continue; - struct diskinfo *d = &hardware->disk_info[drive]; - hardware->disks_count++; - printf - (" DISK 0x%X: %s : %s %s: sectors=%d, s/t=%d head=%d : EDD=%s\n", - drive, d->aid.model, d->host_bus_type, d->interface_type, - d->sectors, d->sectors_per_track, d->heads, - d->edd_version); - } + int i = -1; + int err; + + if (hardware->disk_detection) + return; + + hardware->disk_detection = true; + for (int drive = 0x80; drive < 0xff; drive++) { + i++; + hardware->disk_info[i].disk = drive; + err = get_drive_parameters(&hardware->disk_info[i]); + + /* + * Do not print output when drive does not exist or + * doesn't support int13 (cdrom, ...) + */ + if (err == -1 || !hardware->disk_info[i].cbios) + continue; + + hardware->disks_count++; + } } int detect_pxe(struct s_hardware *hardware) @@ -437,11 +455,17 @@ void detect_pci(struct s_hardware *hardware) hardware->pciids_path); printf("PCI: Resolving module names\n"); - /* Detecting which kernel module should match each device */ + /* Detecting which kernel module should match each device using modules.pcimap*/ hardware->modules_pcimap_return_code = get_module_name_from_pcimap(hardware->pci_domain, hardware->modules_pcimap_path); + /* Detecting which kernel module should match each device using modules.alias*/ + hardware->modules_alias_return_code = + get_module_name_from_alias(hardware->pci_domain, + hardware->modules_alias_path); + + /* We try to detect the pxe stuff to populate the PXE: field of pci devices */ detect_pxe(hardware); } diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h index 7e3dc7d8..2b67f9ca 100644 --- a/com32/hdt/hdt-common.h +++ b/com32/hdt/hdt-common.h @@ -32,12 +32,17 @@ #include <syslinux/pxe.h> #include "sys/pci.h" +#include <disk/geom.h> + #include "cpuid.h" #include "dmi/dmi.h" #include "hdt-ata.h" #include "../lib/sys/vesa/vesa.h" #include <vpd/vpd.h> +/* Declare a variable or data structure as unused. */ +#define __unused __attribute__ (( unused )) + /* This two values are used for switching for the menu to the CLI mode */ #define HDT_SWITCH_TO_CLI "hdt_switch_to_cli" #define HDT_RETURN_TO_CLI 100 @@ -55,6 +60,17 @@ extern int display_line_nb; display_line_nb++; \ } while (0); +/* Display CPU registers for debugging purposes */ +static inline void printregs(const com32sys_t * r) +{ + printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n" + "eax = %08x ebx = %08x ecx = %08x edx = %08x\n" + "ebp = %08x esi = %08x edi = %08x esp = %08x\n", + r->eflags.l, r->ds, r->es, r->fs, r->gs, + r->eax.l, r->ebx.l, r->ecx.l, r->edx.l, + r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l); +} + struct s_pxe { uint16_t vendor_id; uint16_t product_id; @@ -97,13 +113,14 @@ struct s_hardware { s_cpu cpu; /* CPU information */ s_vpd vpd; /* VPD information */ struct pci_domain *pci_domain; /* PCI Devices */ - struct diskinfo disk_info[256]; /* Disk Information */ + struct driveinfo disk_info[256]; /* Disk Information */ int disks_count; /* Number of detected disks */ struct s_pxe pxe; struct s_vesa vesa; int pci_ids_return_code; int modules_pcimap_return_code; + int modules_alias_return_code; int nb_pci_devices; bool is_dmi_valid; bool is_pxe_valid; @@ -121,6 +138,7 @@ struct s_hardware { char syslinux_fs[22]; const struct syslinux_version *sv; char modules_pcimap_path[255]; + char modules_alias_path[255]; char pciids_path[255]; char memtest_label[255]; }; diff --git a/com32/hdt/hdt-menu-disk.c b/com32/hdt/hdt-menu-disk.c index 02f12f75..bd33bdf3 100644 --- a/com32/hdt/hdt-menu-disk.c +++ b/com32/hdt/hdt-menu-disk.c @@ -26,133 +26,200 @@ * ----------------------------------------------------------------------- */ +#include <stdlib.h> +#include <disk/errno_disk.h> +#include <disk/geom.h> +#include <disk/read.h> +#include <disk/partition.h> +#include <disk/error.h> +#include <disk/msdos.h> +#include <disk/swsusp.h> + #include "hdt-menu.h" +#include "hdt-util.h" + +static int dn; + +static void show_partition_information(struct driveinfo *drive_info, + struct part_entry *ptab __unused, + int partition_offset __unused, + int nb_partitions_seen) +{ + char menu_title[MENULEN + 1]; + char menu_title_ref[MENULEN + 1]; + + if (nb_partitions_seen == 1) + add_sep(); + + memset(menu_title,0,sizeof menu_title); + memset(menu_title_ref,0,sizeof menu_title_ref); + snprintf(menu_title_ref, sizeof menu_title_ref, "disk_%x_part_%d", + drive_info[dn].disk, nb_partitions_seen); + snprintf(menu_title, sizeof menu_title, "Partition %d", nb_partitions_seen); + + add_item(menu_title, "Partition information (start, end, length, type, ...)", + OPT_SUBMENU, menu_title_ref, 0); +} +/** + * compute_partition_information - print information about a partition + * @ptab: part_entry describing the partition + * @i: Partition number (UI purposes only) + * @ptab_root: part_entry describing the root partition (extended only) + * @drive_info: driveinfo struct describing the drive on which the partition + * is + * + * Note on offsets (from hpa, see chain.c32): + * + * To make things extra confusing: data partition offsets are relative to where + * the data partition record is stored, whereas extended partition offsets + * are relative to the beginning of the extended partition all the way back + * at the MBR... but still not absolute! + **/ +static void compute_partition_information(struct driveinfo *drive_info, + struct part_entry *ptab, + int partition_offset, + int nb_partitions_seen) +{ + char size[9]; + char *parttype; + unsigned int start, end; + char buffer[SUBMENULEN+1]; + char statbuffer[STATLEN+1]; + char menu_title[MENULEN + 1]; + char menu_title_ref[MENULEN + 1]; + + memset(buffer,0,sizeof buffer); + memset(statbuffer,0,sizeof statbuffer); + memset(menu_title,0,sizeof menu_title); + memset(menu_title_ref,0,sizeof menu_title_ref); + snprintf(menu_title_ref, sizeof menu_title_ref, "disk_%x_part_%d", drive_info[dn].disk, nb_partitions_seen); + snprintf(menu_title, sizeof menu_title, "Partition %d", nb_partitions_seen); + + add_named_menu(menu_title_ref,menu_title,-1); + set_menu_pos(SUBMENU_Y,SUBMENU_X); + + start = partition_offset; + end = start + ptab->length - 1; + + if (ptab->length > 0) + sectors_to_size(ptab->length, size); + else + memset(size, 0, sizeof size); + + get_label(ptab->ostype, &parttype); + + snprintf(buffer, sizeof buffer, "Size : %s", + remove_spaces(size)); + snprintf(statbuffer, sizeof statbuffer, "Size : %s", + remove_spaces(size)); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + + snprintf(buffer, sizeof buffer, "Type : %s", + parttype); + snprintf(statbuffer, sizeof statbuffer, "Type: %s", + parttype); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + + snprintf(buffer, sizeof buffer, "Bootable : %s", + (ptab->active_flag == 0x80) ? "Yes" : "No"); + snprintf(statbuffer, sizeof statbuffer, "Bootable: %s", + (ptab->active_flag == 0x80) ? "Yes" : "No"); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + + snprintf(buffer, sizeof buffer, "Start : %d", + start); + snprintf(statbuffer, sizeof statbuffer, "Start: %d", + start); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + + snprintf(buffer, sizeof buffer, "End : %d", + end); + snprintf(statbuffer, sizeof statbuffer, "End: %d", + end); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + + snprintf(buffer, sizeof buffer, "Id : %X", + ptab->ostype); + snprintf(statbuffer, sizeof statbuffer, "Id: %X", + ptab->ostype); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + + + free(parttype); + + /* Extra info */ + if (ptab->ostype == 0x82 && swsusp_check(drive_info, ptab) != -1) { + snprintf(buffer, sizeof buffer, "%s","Swsusp sig : detected"); + snprintf(statbuffer, sizeof statbuffer, "%s","Swsusp sig : detected"); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + } +} /* Compute the disk submenu */ -int compute_disk_module(struct s_my_menu *menu, int nb_sub_disk_menu, - struct diskinfo *d, int disk_number) +static int compute_disk_module(struct s_my_menu *menu, int nb_sub_disk_menu, + struct driveinfo *d, int disk_number) { char buffer[MENULEN + 1]; char statbuffer[STATLEN + 1]; - /* No need to add no existing devices */ - if (strlen(d[disk_number].aid.model) <= 0) - return -1; - - snprintf(buffer, sizeof buffer, " Disk <%d> ", nb_sub_disk_menu); + snprintf(buffer, sizeof buffer, " Disk <0x%X> (EDD %X)", d[disk_number].disk, + d[disk_number].edd_version); menu[nb_sub_disk_menu].menu = add_menu(buffer, -1); menu[nb_sub_disk_menu].items_count = 0; - snprintf(buffer, sizeof buffer, "Model : %s", - d[disk_number].aid.model); - snprintf(statbuffer, sizeof statbuffer, "Model: %s", - d[disk_number].aid.model); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; + int previous_size, size; + char previous_unit[3], unit[3]; // GB + char size_iec[9]; // GiB + sectors_to_size_dec(previous_unit, &previous_size, unit, &size, d[disk_number].edd_params.sectors); + sectors_to_size(d[disk_number].edd_params.sectors, size_iec); - /* Compute device size */ - char previous_unit[3], unit[3]; //GB - int previous_size, size = d[disk_number].sectors / 2; // Converting to bytes - strlcpy(unit, "KB", 2); - strlcpy(previous_unit, unit, 2); - previous_size = size; - if (size > 1000) { - size = size / 1000; - strlcpy(unit, "MB", 2); - if (size > 1000) { - previous_size = size; - size = size / 1000; - strlcpy(previous_unit, unit, 2); - strlcpy(unit, "GB", 2); - if (size > 1000) { - previous_size = size; - size = size / 1000; - strlcpy(previous_unit, unit, 2); - strlcpy(unit, "TB", 2); - } - } - } - - snprintf(buffer, sizeof buffer, "Size : %d %s (%d %s)", size, + snprintf(buffer, sizeof buffer, "Size : %s/%d %s (%d %s)", remove_spaces(size_iec), + size, unit, previous_size, previous_unit); + snprintf(statbuffer, sizeof statbuffer, "Size: %s/%d %s (%d %s)", remove_spaces(size_iec), size, unit, previous_size, previous_unit); - snprintf(statbuffer, sizeof statbuffer, "Size: %d %s (%d %s)", size, - unit, previous_size, previous_unit); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; - - snprintf(buffer, sizeof buffer, "Firmware Rev.: %s", - d[disk_number].aid.fw_rev); - snprintf(statbuffer, sizeof statbuffer, "Firmware Revision: %s", - d[disk_number].aid.fw_rev); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; - - snprintf(buffer, sizeof buffer, "Serial Number: %s", - d[disk_number].aid.serial_no); - snprintf(statbuffer, sizeof statbuffer, "Serial Number: %s", - d[disk_number].aid.serial_no); add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); menu[nb_sub_disk_menu].items_count++; - snprintf(buffer, sizeof buffer, "Interface : %s", - d[disk_number].interface_type); - snprintf(statbuffer, sizeof statbuffer, "Interface: %s", - d[disk_number].interface_type); + snprintf(buffer, sizeof buffer, "Host Bus / Interface : %s / %s", + remove_spaces(d[disk_number].edd_params.host_bus_type), + d[disk_number].edd_params.interface_type); + snprintf(statbuffer, sizeof statbuffer, "Host Bus / Interface: %s / %s", + remove_spaces(d[disk_number].edd_params.host_bus_type), + d[disk_number].edd_params.interface_type); add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); menu[nb_sub_disk_menu].items_count++; - snprintf(buffer, sizeof buffer, "Host Bus : %s", - d[disk_number].host_bus_type); - snprintf(statbuffer, sizeof statbuffer, "Host Bus Type: %s", - d[disk_number].host_bus_type); + snprintf(buffer, sizeof buffer, "C / H / S : %d / %d / %d", + d[disk_number].legacy_max_cylinder + 1, + d[disk_number].legacy_max_head + 1, + (int) d[disk_number].edd_params.sectors); + snprintf(statbuffer, sizeof statbuffer, "Cylinders / Heads / Sectors: %d / %d / %d", + d[disk_number].legacy_max_cylinder + 1, + d[disk_number].legacy_max_head + 1, + (int) d[disk_number].edd_params.sectors); add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); menu[nb_sub_disk_menu].items_count++; - snprintf(buffer, sizeof buffer, "Sectors : %d", - d[disk_number].sectors); - snprintf(statbuffer, sizeof statbuffer, "Sectors: %d", - d[disk_number].sectors); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; - - snprintf(buffer, sizeof buffer, "Heads : %d", - d[disk_number].heads); - snprintf(statbuffer, sizeof statbuffer, "Heads: %d", - d[disk_number].heads); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; - - snprintf(buffer, sizeof buffer, "Cylinders : %d", - d[disk_number].cylinders); - snprintf(statbuffer, sizeof statbuffer, "Cylinders: %d", - d[disk_number].cylinders); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; - - snprintf(buffer, sizeof buffer, "Sectors/Track: %d", - d[disk_number].sectors_per_track); + snprintf(buffer, sizeof buffer, "Sectors/Track : %d", + d[disk_number].legacy_sectors_per_track); snprintf(statbuffer, sizeof statbuffer, "Sectors per Track: %d", - d[disk_number].sectors_per_track); + d[disk_number].legacy_sectors_per_track); add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); menu[nb_sub_disk_menu].items_count++; - snprintf(buffer, sizeof buffer, "Port : 0x%X", disk_number); - snprintf(statbuffer, sizeof statbuffer, "Port: 0x%X", disk_number); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; + dn=disk_number; - snprintf(buffer, sizeof buffer, "EDD Version : %s", - d[disk_number].edd_version); - snprintf(statbuffer, sizeof statbuffer, "EDD Version: %s", - d[disk_number].edd_version); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu[nb_sub_disk_menu].items_count++; + parse_partition_table(&d[disk_number], &show_partition_information); + if (!parse_partition_table(&d[disk_number], &compute_partition_information)) { + get_error("parse_partition_table"); + menu[nb_sub_disk_menu].items_count++; + } return 0; } /* Compute the Disks menu */ -void compute_disks(struct s_hdt_menu *menu, struct diskinfo *disk_info, struct s_hardware *hardware) +void compute_disks(struct s_hdt_menu *menu, struct driveinfo *disk_info, struct s_hardware *hardware) { char buffer[MENULEN + 1]; int nb_sub_disk_menu = 0; @@ -161,17 +228,19 @@ void compute_disks(struct s_hdt_menu *menu, struct diskinfo *disk_info, struct s menu->disk_menu.items_count = 0; if (hardware->disks_count == 0) return; - for (int i = 0; i < 0xff; i++) { - if (compute_disk_module + for (int i = 0; i < hardware->disks_count; i++) { + if (!hardware->disk_info[i].cbios) + continue; /* Invalid geometry */ + compute_disk_module ((struct s_my_menu*) &(menu->disk_sub_menu), nb_sub_disk_menu, disk_info, - i) == 0) - nb_sub_disk_menu++; + i); + nb_sub_disk_menu++; } menu->disk_menu.menu = add_menu(" Disks ", -1); for (int i = 0; i < nb_sub_disk_menu; i++) { - snprintf(buffer, sizeof buffer, " Disk <%d> ", i); + snprintf(buffer, sizeof buffer, " Disk <%d> ", i+1); add_item(buffer, "Disk", OPT_SUBMENU, NULL, menu->disk_sub_menu[i].menu); menu->disk_menu.items_count++; diff --git a/com32/hdt/hdt-menu-dmi.c b/com32/hdt/hdt-menu-dmi.c index a3a3a8e6..77ee90e5 100644 --- a/com32/hdt/hdt-menu-dmi.c +++ b/com32/hdt/hdt-menu-dmi.c @@ -245,147 +245,6 @@ void compute_motherboard(struct s_my_menu *menu, s_dmi * dmi) printf("MENU: Motherboard menu done (%d items)\n", menu->items_count); } -/* Compute the Memory submenu */ -static void compute_memory_module(struct s_my_menu *menu, s_dmi * dmi, - int slot_number) -{ - int i = slot_number; - char buffer[MENULEN + 1]; - char statbuffer[STATLEN + 1]; - - sprintf(buffer, " Bank <%d> ", i); - menu->items_count = 0; - menu->menu = add_menu(buffer, -1); - - snprintf(buffer, sizeof buffer, "Form Factor : %s", - dmi->memory[i].form_factor); - snprintf(statbuffer, sizeof statbuffer, "Form Factor: %s", - dmi->memory[i].form_factor); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Type : %s", - dmi->memory[i].type); - snprintf(statbuffer, sizeof statbuffer, "Type: %s", - dmi->memory[i].type); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Type Details : %s", - dmi->memory[i].type_detail); - snprintf(statbuffer, sizeof statbuffer, "Type Details: %s", - dmi->memory[i].type_detail); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Speed : %s", - dmi->memory[i].speed); - snprintf(statbuffer, sizeof statbuffer, "Speed (Mhz): %s", - dmi->memory[i].speed); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Size : %s", - dmi->memory[i].size); - snprintf(statbuffer, sizeof statbuffer, "Size: %s", - dmi->memory[i].size); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Device Set : %s", - dmi->memory[i].device_set); - snprintf(statbuffer, sizeof statbuffer, "Device Set: %s", - dmi->memory[i].device_set); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Device Loc. : %s", - dmi->memory[i].device_locator); - snprintf(statbuffer, sizeof statbuffer, "Device Location: %s", - dmi->memory[i].device_locator); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Bank Locator : %s", - dmi->memory[i].bank_locator); - snprintf(statbuffer, sizeof statbuffer, "Bank Locator: %s", - dmi->memory[i].bank_locator); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Total Width : %s", - dmi->memory[i].total_width); - snprintf(statbuffer, sizeof statbuffer, "Total bit Width: %s", - dmi->memory[i].total_width); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Data Width : %s", - dmi->memory[i].data_width); - snprintf(statbuffer, sizeof statbuffer, "Data bit Width: %s", - dmi->memory[i].data_width); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Error : %s", - dmi->memory[i].error); - snprintf(statbuffer, sizeof statbuffer, "Error: %s", - dmi->memory[i].error); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Vendor : %s", - dmi->memory[i].manufacturer); - snprintf(statbuffer, sizeof statbuffer, "Vendor: %s", - dmi->memory[i].manufacturer); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Serial : %s", - dmi->memory[i].serial); - snprintf(statbuffer, sizeof statbuffer, "Serial: %s", - dmi->memory[i].serial); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Asset Tag : %s", - dmi->memory[i].asset_tag); - snprintf(statbuffer, sizeof statbuffer, "Asset Tag: %s", - dmi->memory[i].asset_tag); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - - snprintf(buffer, sizeof buffer, "Part Number : %s", - dmi->memory[i].part_number); - snprintf(buffer, sizeof statbuffer, "Part Number: %s", - dmi->memory[i].part_number); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; - -} - -/* Compute the Memory menu */ -void compute_memory(struct s_hdt_menu *menu, s_dmi * dmi, struct s_hardware *hardware) -{ - char buffer[MENULEN + 1]; - for (int i = 0; i < dmi->memory_count; i++) { - compute_memory_module(&(menu->memory_sub_menu[i]), dmi, i); - } - - menu->memory_menu.menu = add_menu(" Memory Banks ", -1); - menu->memory_menu.items_count = 0; - - for (int i = 0; i < dmi->memory_count; i++) { - snprintf(buffer, sizeof buffer, " Bank <%d> ", i); - add_item(buffer, "Memory Bank", OPT_SUBMENU, NULL, - menu->memory_sub_menu[i].menu); - menu->memory_menu.items_count++; - } - printf("MENU: Memory menu done (%d items)\n", - menu->memory_menu.items_count); - add_item("Run Test", "Run Test", OPT_RUN, hardware->memtest_label, 0); -} - /* Compute Main IPMI menu */ void compute_ipmi(struct s_my_menu *menu, s_dmi * dmi) { diff --git a/com32/hdt/hdt-menu-kernel.c b/com32/hdt/hdt-menu-kernel.c index b94d1fed..7e2d6cab 100644 --- a/com32/hdt/hdt-menu-kernel.c +++ b/com32/hdt/hdt-menu-kernel.c @@ -41,13 +41,14 @@ void compute_kernel(struct s_my_menu *menu, struct s_hardware *hardware) menu->items_count = 0; set_menu_pos(SUBMENU_Y, SUBMENU_X); - if (hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) { - add_item("The modules.pcimap file is missing", - "Missing modules.pcimap file", OPT_INACTIVE, NULL, 0); + if ((hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) && + (hardware->modules_alias_return_code == -ENOMODULESALIAS)) { + add_item("The modules.{pcimap|alias} file is missing", + "Missing modules.{pcimap|alias} file", OPT_INACTIVE, NULL, 0); add_item("Kernel modules can't be computed.", - "Missing modules.pcimap file", OPT_INACTIVE, NULL, 0); - add_item("Please put one in same dir as hdt", - "Missing modules.pcimap file", OPT_INACTIVE, NULL, 0); + "Missing modules.{pcimap|alias} file", OPT_INACTIVE, NULL, 0); + add_item("Please put one of them in same dir as hdt", + "Missing modules.{pcimap|alias} file", OPT_INACTIVE, NULL, 0); add_item("", "", OPT_SEP, "", 0); } else { /* diff --git a/com32/hdt/hdt-menu-memory.c b/com32/hdt/hdt-menu-memory.c new file mode 100644 index 00000000..ddc26fef --- /dev/null +++ b/com32/hdt/hdt-menu-memory.c @@ -0,0 +1,277 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <memory.h> +#include "hdt-menu.h" +#define E820MAX 128 + +/* Compute the e820 submenu */ +static void compute_e820(struct s_my_menu *menu) +{ + char buffer[MENULEN + 1]; + char statbuffer[STATLEN + 1]; + + sprintf(buffer, " e820 Physical RAM map "); + menu->items_count = 0; + menu->menu = add_menu(buffer, -1); + + struct e820entry map[E820MAX]; + int count = 0; + char type[14]; + + detect_memory_e820(map, E820MAX, &count); + for (int j = 0; j < count; j++) { + get_type(map[j].type, type, 14); + snprintf(buffer, sizeof buffer, + "%016llx - %016llx (%s)", + map[j].addr, map[j].size, + remove_spaces(type)); + snprintf(statbuffer, sizeof statbuffer, + "%016llx - %016llx (%s)", + map[j].addr, map[j].size, + remove_spaces(type)); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } +} + +/* Compute the e801 submenu */ +static void compute_e801(struct s_my_menu *menu) +{ + char buffer[MENULEN + 1]; + char statbuffer[STATLEN + 1]; + + sprintf(buffer, " e801 information "); + menu->items_count = 0; + menu->menu = add_menu(buffer, -1); + + int mem_low, mem_high = 0; + if (detect_memory_e801(&mem_low, &mem_high)) { + snprintf(buffer, sizeof buffer, "%s", "e801 output is bogus"); + snprintf(statbuffer, sizeof statbuffer, "%s", "e801 output is bogus"); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } else { + snprintf(buffer, sizeof buffer, "%d Kb (%d MiB) - %d Kb (%d MiB)", + mem_low, mem_low >> 10, mem_high << 6, mem_high >> 4); + snprintf(statbuffer, sizeof statbuffer, "%d Kb (%d MiB) - %d Kb (%d MiB)", + mem_low, mem_low >> 10, mem_high << 6, mem_high >> 4); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + } + menu->items_count++; +} + +/* Compute the e88 submenu */ +static void compute_e88(struct s_my_menu *menu) +{ + char buffer[MENULEN + 1]; + char statbuffer[STATLEN + 1]; + + sprintf(buffer, " e88 information "); + menu->items_count = 0; + menu->menu = add_menu(buffer, -1); + + int mem_size = 0; + if (detect_memory_88(&mem_size)) { + snprintf(buffer, sizeof buffer, "%s", "e88 output is bogus"); + snprintf(statbuffer, sizeof statbuffer, "%s", "e88 output is bogus"); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } else { + snprintf(buffer, sizeof buffer, "%d Kb (%d MiB)", + mem_size, mem_size >> 10); + snprintf(statbuffer, sizeof statbuffer, "%d Kb (%d MiB)", + mem_size, mem_size >> 10); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + } + menu->items_count++; +} +/* Compute the Memory submenu */ +static void compute_memory_module(struct s_my_menu *menu, s_dmi * dmi, + int slot_number) +{ + int i = slot_number; + char buffer[MENULEN + 1]; + char statbuffer[STATLEN + 1]; + + sprintf(buffer, " Bank <%d> ", i); + menu->items_count = 0; + menu->menu = add_menu(buffer, -1); + + snprintf(buffer, sizeof buffer, "Form Factor : %s", + dmi->memory[i].form_factor); + snprintf(statbuffer, sizeof statbuffer, "Form Factor: %s", + dmi->memory[i].form_factor); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Type : %s", + dmi->memory[i].type); + snprintf(statbuffer, sizeof statbuffer, "Type: %s", + dmi->memory[i].type); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Type Details : %s", + dmi->memory[i].type_detail); + snprintf(statbuffer, sizeof statbuffer, "Type Details: %s", + dmi->memory[i].type_detail); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Speed : %s", + dmi->memory[i].speed); + snprintf(statbuffer, sizeof statbuffer, "Speed (Mhz): %s", + dmi->memory[i].speed); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Size : %s", + dmi->memory[i].size); + snprintf(statbuffer, sizeof statbuffer, "Size: %s", + dmi->memory[i].size); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Device Set : %s", + dmi->memory[i].device_set); + snprintf(statbuffer, sizeof statbuffer, "Device Set: %s", + dmi->memory[i].device_set); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Device Loc. : %s", + dmi->memory[i].device_locator); + snprintf(statbuffer, sizeof statbuffer, "Device Location: %s", + dmi->memory[i].device_locator); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Bank Locator : %s", + dmi->memory[i].bank_locator); + snprintf(statbuffer, sizeof statbuffer, "Bank Locator: %s", + dmi->memory[i].bank_locator); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Total Width : %s", + dmi->memory[i].total_width); + snprintf(statbuffer, sizeof statbuffer, "Total bit Width: %s", + dmi->memory[i].total_width); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Data Width : %s", + dmi->memory[i].data_width); + snprintf(statbuffer, sizeof statbuffer, "Data bit Width: %s", + dmi->memory[i].data_width); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Error : %s", + dmi->memory[i].error); + snprintf(statbuffer, sizeof statbuffer, "Error: %s", + dmi->memory[i].error); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Vendor : %s", + dmi->memory[i].manufacturer); + snprintf(statbuffer, sizeof statbuffer, "Vendor: %s", + dmi->memory[i].manufacturer); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Serial : %s", + dmi->memory[i].serial); + snprintf(statbuffer, sizeof statbuffer, "Serial: %s", + dmi->memory[i].serial); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Asset Tag : %s", + dmi->memory[i].asset_tag); + snprintf(statbuffer, sizeof statbuffer, "Asset Tag: %s", + dmi->memory[i].asset_tag); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + + snprintf(buffer, sizeof buffer, "Part Number : %s", + dmi->memory[i].part_number); + snprintf(buffer, sizeof statbuffer, "Part Number: %s", + dmi->memory[i].part_number); + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + +} + +/* Compute the Memory menu */ +void compute_memory(struct s_hdt_menu *menu, s_dmi * dmi, struct s_hardware *hardware) +{ + char buffer[MENULEN + 1]; + int i=0; + for (i = 0; i < dmi->memory_count; i++) { + compute_memory_module(&(menu->memory_sub_menu[i]), dmi, i); + } + + compute_e820(&(menu->memory_sub_menu[++i])); + compute_e801(&(menu->memory_sub_menu[++i])); + compute_e88(&(menu->memory_sub_menu[++i])); + + menu->memory_menu.menu = add_menu(" Memory Banks ", -1); + menu->memory_menu.items_count = 0; + + for (i = 0; i < dmi->memory_count; i++) { + snprintf(buffer, sizeof buffer, " Bank <%d> ", i); + add_item(buffer, "Memory Bank", OPT_SUBMENU, NULL, + menu->memory_sub_menu[i].menu); + menu->memory_menu.items_count++; + } + + add_item("", "", OPT_SEP, "", 0); + + snprintf(buffer, sizeof buffer, " e820 "); + add_item(buffer, "e820 mapping", OPT_SUBMENU, NULL, + menu->memory_sub_menu[++i].menu); + menu->memory_menu.items_count++; + + snprintf(buffer, sizeof buffer, " e801 "); + add_item(buffer, "e801 information", OPT_SUBMENU, NULL, + menu->memory_sub_menu[++i].menu); + menu->memory_menu.items_count++; + + snprintf(buffer, sizeof buffer, " e88 "); + add_item(buffer, "e88 information", OPT_SUBMENU, NULL, + menu->memory_sub_menu[++i].menu); + menu->memory_menu.items_count++; + + add_item("", "", OPT_SEP, "", 0); + printf("MENU: Memory menu done (%d items)\n", + menu->memory_menu.items_count); + add_item("Run Test", "Run Test", OPT_RUN, hardware->memtest_label, 0); +} diff --git a/com32/hdt/hdt-menu-pci.c b/com32/hdt/hdt-menu-pci.c index 74c07107..4e0d5887 100644 --- a/com32/hdt/hdt-menu-pci.c +++ b/com32/hdt/hdt-menu-pci.c @@ -94,6 +94,8 @@ static void compute_pci_device(struct s_my_menu *menu, add_item(buffer,statbuffer,OPT_INACTIVE,NULL,0); menu->items_count++; + memset(kernel_modules,0,sizeof(kernel_modules)); + if (pci_device->dev_info->linux_kernel_module_count > 1) { for (int i = 0; i < pci_device->dev_info->linux_kernel_module_count; i++) { @@ -117,14 +119,15 @@ static void compute_pci_device(struct s_my_menu *menu, menu->items_count++; if (hardware->is_pxe_valid == true) { - snprintf(buffer,sizeof buffer,"MAC Addr. : %s",hardware->pxe.mac_addr); - snprintf(statbuffer,sizeof statbuffer,"MAC Address : %s",hardware->pxe.mac_addr); - add_item(buffer,statbuffer,OPT_INACTIVE,NULL,0); - menu->items_count++; - if ((hardware->pxe.pci_device != NULL) && (hardware->pxe.pci_device == pci_device)) { - snprintf(buffer,sizeof buffer,"PXE : %s","Current Boot device"); + + snprintf(buffer,sizeof buffer,"MAC Addr: %s",hardware->pxe.mac_addr); + snprintf(statbuffer,sizeof statbuffer,"MAC Address : %s",hardware->pxe.mac_addr); + add_item(buffer,statbuffer,OPT_INACTIVE,NULL,0); + menu->items_count++; + + snprintf(buffer,sizeof buffer,"PXE : %s","Current Boot device"); snprintf(statbuffer,sizeof statbuffer,"PXE : %s","Current Boot device"); add_item(buffer,statbuffer,OPT_INACTIVE,NULL,0); menu->items_count++; diff --git a/com32/hdt/hdt-menu-vpd.c b/com32/hdt/hdt-menu-vpd.c index 817c1079..49caf8ea 100644 --- a/com32/hdt/hdt-menu-vpd.c +++ b/com32/hdt/hdt-menu-vpd.c @@ -47,54 +47,68 @@ void compute_vpd(struct s_my_menu *menu, struct s_hardware *hardware) add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); menu->items_count++; - snprintf(buffer, sizeof buffer, "Bios Build ID : %s", + if (strlen(hardware->vpd.bios_build_id) > 0) { + snprintf(buffer, sizeof buffer, "Bios Build ID : %s", hardware->vpd.bios_build_id); - snprintf(statbuffer, sizeof statbuffer, "Bios Build ID: %s", + snprintf(statbuffer, sizeof statbuffer, "Bios Build ID: %s", hardware->vpd.bios_build_id); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } - snprintf(buffer, sizeof buffer, "Bios Release Date : %s", + if (strlen(hardware->vpd.bios_release_date) > 0) { + snprintf(buffer, sizeof buffer, "Bios Release Date : %s", hardware->vpd.bios_release_date); - snprintf(statbuffer, sizeof statbuffer, "Bios Release Date: %s", + snprintf(statbuffer, sizeof statbuffer, "Bios Release Date: %s", hardware->vpd.bios_release_date); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } - snprintf(buffer, sizeof buffer, "Bios Version : %s", + if (strlen(hardware->vpd.bios_version) > 0) { + snprintf(buffer, sizeof buffer, "Bios Version : %s", hardware->vpd.bios_version); - snprintf(statbuffer, sizeof statbuffer, "Bios Version: %s", + snprintf(statbuffer, sizeof statbuffer, "Bios Version: %s", hardware->vpd.bios_version); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } - snprintf(buffer, sizeof buffer, "Default Flash Filename : %s", + if (strlen(hardware->vpd.default_flash_filename) > 0) { + snprintf(buffer, sizeof buffer, "Default Flash Filename : %s", hardware->vpd.default_flash_filename); - snprintf(statbuffer, sizeof statbuffer, "Default Flash Filename: %s", + snprintf(statbuffer, sizeof statbuffer, "Default Flash Filename: %s", hardware->vpd.default_flash_filename); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } - snprintf(buffer, sizeof buffer, "Box Serial Number : %s", + if (strlen(hardware->vpd.box_serial_number) > 0) { + snprintf(buffer, sizeof buffer, "Box Serial Number : %s", hardware->vpd.box_serial_number); - snprintf(statbuffer, sizeof statbuffer, "Box Serial Number: %s", + snprintf(statbuffer, sizeof statbuffer, "Box Serial Number: %s", hardware->vpd.box_serial_number); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } - snprintf(buffer, sizeof buffer, "Motherboard Serial Number: %s", + if (strlen(hardware->vpd.motherboard_serial_number) > 0) { + snprintf(buffer, sizeof buffer, "Motherboard Serial Number: %s", hardware->vpd.motherboard_serial_number); - snprintf(statbuffer, sizeof statbuffer, "Motherboard Serial Number: %s", + snprintf(statbuffer, sizeof statbuffer, "Motherboard Serial Number: %s", hardware->vpd.motherboard_serial_number); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } - snprintf(buffer, sizeof buffer, "Machine Type/Model : %s", + if (strlen(hardware->vpd.machine_type_model) > 0) { + snprintf(buffer, sizeof buffer, "Machine Type/Model : %s", hardware->vpd.machine_type_model); - snprintf(statbuffer, sizeof statbuffer, "Machine Type/Model: %s", + snprintf(statbuffer, sizeof statbuffer, "Machine Type/Model: %s", hardware->vpd.machine_type_model); - add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); - menu->items_count++; + add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); + menu->items_count++; + } printf("MENU: VPD menu done (%d items)\n", menu->items_count); } diff --git a/com32/hdt/hdt-menu.c b/com32/hdt/hdt-menu.c index 18158ae3..c37fd41b 100644 --- a/com32/hdt/hdt-menu.c +++ b/com32/hdt/hdt-menu.c @@ -195,8 +195,7 @@ void compute_main_menu(struct s_hdt_menu *hdt_menu, struct s_hardware *hardware) } if (hdt_menu->memory_menu.items_count > 0) { - snprintf(menu_item, sizeof(menu_item), "<M>emory (%2d)\n", - hdt_menu->memory_menu.items_count); + snprintf(menu_item, sizeof(menu_item), "<M>emory\n"); add_item(menu_item, "Memory Menu", OPT_SUBMENU, NULL, hdt_menu->memory_menu.menu); hdt_menu->main_menu.items_count++; @@ -244,7 +243,7 @@ void compute_main_menu(struct s_hdt_menu *hdt_menu, struct s_hardware *hardware) } if (hardware->is_vpd_valid == true) { - add_item("VPD","VPD Information Menu", OPT_SUBMENU, NULL, + add_item("<V>PD","VPD Information Menu", OPT_SUBMENU, NULL, hdt_menu->vpd_menu.menu); hdt_menu->main_menu.items_count++; } @@ -263,7 +262,8 @@ void compute_main_menu(struct s_hdt_menu *hdt_menu, struct s_hardware *hardware) add_item("", "", OPT_SEP, "", 0); #ifdef WITH_PCI - if (hardware->modules_pcimap_return_code != -ENOMODULESPCIMAP) { + if ((hardware->modules_pcimap_return_code != -ENOMODULESPCIMAP) || + (hardware->modules_alias_return_code != -ENOMODULESALIAS)) { add_item("<K>ernel Modules", "Kernel Modules Menu", OPT_SUBMENU, NULL, hdt_menu->kernel_menu.menu); hdt_menu->main_menu.items_count++; diff --git a/com32/hdt/hdt-menu.h b/com32/hdt/hdt-menu.h index 70fdb385..1cd2c129 100644 --- a/com32/hdt/hdt-menu.h +++ b/com32/hdt/hdt-menu.h @@ -91,9 +91,7 @@ int compute_PCI(struct s_hdt_menu *hdt_menu, struct s_hardware *hardware); void compute_kernel(struct s_my_menu *menu, struct s_hardware *hardware); // Disk Stuff -int compute_disk_module(struct s_my_menu *menu, int nb_sub_disk_menu, - struct diskinfo *d, int disk_number); -void compute_disks(struct s_hdt_menu *menu, struct diskinfo *disk_info, struct s_hardware *hardware); +void compute_disks(struct s_hdt_menu *menu, struct driveinfo *disk_info, struct s_hardware *hardware); // DMI Stuff void compute_motherboard(struct s_my_menu *menu, s_dmi * dmi); diff --git a/com32/hdt/hdt-util.c b/com32/hdt/hdt-util.c new file mode 100644 index 00000000..5bc566af --- /dev/null +++ b/com32/hdt/hdt-util.c @@ -0,0 +1,71 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <string.h> + +void sectors_to_size(int sectors, char *buffer) +{ + int b = (sectors / 2); + int mib = b >> 10; + int gib = mib >> 10; + int tib = gib >> 10; + + if (tib > 0) + sprintf(buffer, "%3d TiB", tib); + else if (gib > 0) + sprintf(buffer, "%3d GiB", gib); + else if (mib > 0) + sprintf(buffer, "%3d MiB", mib); + else + sprintf(buffer, "%d b", b); +} + +void sectors_to_size_dec(char *previous_unit, int *previous_size, char *unit, int *size, int sectors) +{ + *size = sectors / 2; // Converting to bytes + strlcpy(unit, "KB", 2); + strlcpy(previous_unit, unit, 2); + *previous_size = *size; + if (*size > 1000) { + *size = *size / 1000; + strlcpy(unit, "MB", 2); + if (*size > 1000) { + *previous_size = *size; + *size = *size / 1000; + strlcpy(previous_unit, unit, 2); + strlcpy(unit, "GB", 2); + if (*size > 1000) { + *previous_size = *size; + *size = *size / 1000; + strlcpy(previous_unit, unit, 2); + strlcpy(unit, "TB", 2); + } + } + } +} diff --git a/com32/hdt/hdt-util.h b/com32/hdt/hdt-util.h new file mode 100644 index 00000000..8c1d6de5 --- /dev/null +++ b/com32/hdt/hdt-util.h @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#ifndef DEFINE_HDT_UTIL_H +#define DEFINE_HDT_UTIL_H +void sectors_to_size(int, char *); +void sectors_to_size_dec(char *, int *, char *, int *, int); +#endif diff --git a/com32/hdt/hdt.c b/com32/hdt/hdt.c index a2b9b538..93c4aae2 100644 --- a/com32/hdt/hdt.c +++ b/com32/hdt/hdt.c @@ -51,6 +51,7 @@ int main(const int argc, const char *argv[]) snprintf(version_string, sizeof version_string, "%s %s by %s", PRODUCT_NAME,VERSION,AUTHOR); + /* Opening the Syslinux console */ console_ansi_raw(); /* Cleaning structures */ @@ -62,8 +63,6 @@ int main(const int argc, const char *argv[]) /* Detecting parameters */ detect_parameters(argc, argv, &hardware); - /* Opening the Syslinux console */ -// openconsole(&dev_stdcon_r, &dev_ansicon_w); clear_screen(); printf("%s\n", version_string); diff --git a/com32/hdt/hdt.h b/com32/hdt/hdt.h index dfcb4368..04c0e664 100644 --- a/com32/hdt/hdt.h +++ b/com32/hdt/hdt.h @@ -32,7 +32,7 @@ #define PRODUCT_NAME "Hardware Detection Tool" #define AUTHOR "Erwan Velu" #define CONTACT "hdt@zytor.com" -#define VERSION "0.3.1" +#define VERSION "0.3.4" #define NB_CONTRIBUTORS 2 #define CONTRIBUTORS {"Pierre-Alexandre Meyer", "Sebastien Gonzalve"} diff --git a/com32/hdt/lib-ansi.c b/com32/hdt/lib-ansi.c index 12e5ecc7..411dba80 100644 --- a/com32/hdt/lib-ansi.c +++ b/com32/hdt/lib-ansi.c @@ -61,6 +61,13 @@ void move_cursor_right(int count) { fputs(buffer, stdout); } +void set_cursor_blink(bool status) { + if (status == true) + fputs("\033[05m",stdout); + else + fputs("\033[0m",stdout); +} + void clear_line() { fputs("\033[2K", stdout); } diff --git a/com32/hdt/lib-ansi.h b/com32/hdt/lib-ansi.h index 2a17766f..0b0d0d18 100644 --- a/com32/hdt/lib-ansi.h +++ b/com32/hdt/lib-ansi.h @@ -40,4 +40,5 @@ void disable_utf8(); void set_g1_special_char(); void set_us_g0_charset(); void clear_entire_screen(); +void set_cursor_blink(bool status); #endif diff --git a/com32/include/dirent.h b/com32/include/dirent.h index d99b21fb..c4aca4f0 100644 --- a/com32/include/dirent.h +++ b/com32/include/dirent.h @@ -10,23 +10,7 @@ #include <stddef.h> #include <sys/types.h> -#ifndef NAME_MAX -#define NAME_MAX 255 -#endif - -struct dirent { - long d_ino; /* Inode/File number */ - off_t d_size; /* Size of file */ - mode_t d_mode; /* Type of file */ - char d_name[NAME_MAX + 1]; -}; - -typedef struct { - short dd_stat; /* status return from last lookup */ - uint16_t dd_fd; - size_t dd_sect; - char dd_name[NAME_MAX + 1]; /* directory */ -} DIR; +#include <sys/dirent.h> __extern DIR *opendir(const char *); __extern struct dirent *readdir(DIR *); diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h index 582632c9..ccf04750 100644 --- a/com32/include/netinet/in.h +++ b/com32/include/netinet/in.h @@ -4,37 +4,47 @@ /* COM32 will be running on an i386 platform */ #include <stdint.h> +#include <klibc/compiler.h> -static inline uint16_t __htons(uint16_t v) +#define __htons_macro(v) ((uint16_t) \ + (((uint16_t)(v) << 8) | \ + ((uint16_t)(v) >> 8))) + +static inline __constfunc uint16_t __htons(uint16_t v) { - return ((v) << 8) | ((v) >> 8); + return __htons_macro(v); } -#define htons(x) __htons(x) -#define ntohs(x) __htons(x) +#define htons(x) (__builtin_constant_p(x) ? __htons_macro(x) : __htons(x)) +#define ntohs(x) htons(x) + +#define __htonl_macro(v) ((uint32_t) \ + ((((uint32_t)(v) & 0x000000ff) << 24) | \ + (((uint32_t)(v) & 0x0000ff00) << 8) | \ + (((uint32_t)(v) & 0x00ff0000) >> 8) | \ + (((uint32_t)(v) & 0xff000000) >> 24))) -static inline uint32_t __htonl(uint32_t v) +static inline __constfunc uint32_t __htonl(uint32_t v) { - if (__builtin_constant_p(v)) { - return (((v) & 0x000000ff) << 24) | - (((v) & 0x0000ff00) << 8) | - (((v) & 0x00ff0000) >> 8) | (((v) & 0xff000000) >> 24); - } else { -asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0":"+q"(v)); - return v; - } + asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0" + : "+q" (v)); + return v; } -#define htonl(x) __htonl(x) -#define ntohl(x) __htonl(x) +#define htonl(x) (__builtin_constant_p(x) ? __htonl_macro(x) : __htonl(x)) +#define ntohl(x) htonl(x) + +#define __htonq_macro(v) ((uint64_t) \ + (((uint64_t)__htonl_macro((uint32_t)(v)) << 32) | \ + (__htonl_macro((uint32_t)((uint64_t)(v) >> 32))))) -static inline uint64_t __htonq(uint64_t v) +static inline __constfunc uint64_t __htonq(uint64_t v) { - return ((uint64_t) __htonl(v) << 32) | __htonl(v >> 32); + return ((uint64_t)__htonl(v) << 32) | __htonl(v >> 32); } -#define htonq(x) __htonq(x) -#define ntohq(x) __htonq(x) +#define htonq(x) (__builtin_constant_p(x) ? __htonq_macro(x) : __htonq(x)) +#define ntohq(x) htonq(x) typedef uint32_t in_addr_t; typedef uint16_t in_port_t; diff --git a/com32/include/png.h b/com32/include/png.h index d9e73c9c..800b912e 100644 --- a/com32/include/png.h +++ b/com32/include/png.h @@ -338,12 +338,12 @@ #define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7 /* Release-Specific Flags */ -#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with - PNG_LIBPNG_BUILD_STABLE only */ -#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with - PNG_LIBPNG_BUILD_SPECIAL */ -#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with - PNG_LIBPNG_BUILD_PRIVATE */ +#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with + PNG_LIBPNG_BUILD_STABLE only */ +#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_SPECIAL */ +#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_PRIVATE */ #define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE @@ -352,7 +352,7 @@ * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only * version 1.0.0 was mis-numbered 100 instead of 10000). From * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ -#define PNG_LIBPNG_VER 10208 /* 1.2.8 */ +#define PNG_LIBPNG_VER 10208 /* 1.2.8 */ #ifndef PNG_VERSION_INFO_ONLY /* include the compression library's header */ @@ -392,7 +392,7 @@ /* Inhibit C++ name-mangling for libpng functions but not for system calls. */ #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif /* __cplusplus */ /* This file is arranged in several sections. The first section contains * structure and type definitions. The second section contains the external @@ -440,8 +440,8 @@ extern "C" { * the version above. */ #ifdef PNG_USE_GLOBAL_ARRAYS - PNG_EXPORT_VAR(const char) png_libpng_ver[18]; - /* need room for 99.99.99beta99z */ +PNG_EXPORT_VAR (const char) png_libpng_ver[18]; + /* need room for 99.99.99beta99z */ #else #define png_libpng_ver png_get_header_ver(NULL) #endif @@ -449,81 +449,86 @@ extern "C" { #ifdef PNG_USE_GLOBAL_ARRAYS /* This was removed in version 1.0.5c */ /* Structures to facilitate easy interlacing. See png.c for more details */ - PNG_EXPORT_VAR(const int FARDATA) png_pass_start[7]; - PNG_EXPORT_VAR(const int FARDATA) png_pass_inc[7]; - PNG_EXPORT_VAR(const int FARDATA) png_pass_ystart[7]; - PNG_EXPORT_VAR(const int FARDATA) png_pass_yinc[7]; - PNG_EXPORT_VAR(const int FARDATA) png_pass_mask[7]; - PNG_EXPORT_VAR(const int FARDATA) png_pass_dsp_mask[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_start[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_inc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_ystart[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_yinc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_mask[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_dsp_mask[7]; #ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW - PNG_EXPORT_VAR(const int FARDATA) png_pass_width[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_width[7]; #endif /* This isn't currently used. If you need it, see png.c for more details. PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; */ #endif -#endif /* PNG_NO_EXTERN */ +#endif /* PNG_NO_EXTERN */ /* Three color definitions. The order of the red, green, and blue, (and the * exact size) is not important, although the size of the fields need to * be png_byte or png_uint_16 (as defined below). */ - typedef struct png_color_struct { - png_byte red; - png_byte green; - png_byte blue; - } png_color; - typedef png_color FAR *png_colorp; - typedef png_color FAR *FAR * png_colorpp; - - typedef struct png_color_16_struct { - png_byte index; /* used for palette files */ - png_uint_16 red; /* for use in red green blue files */ - png_uint_16 green; - png_uint_16 blue; - png_uint_16 gray; /* for use in grayscale files */ - } png_color_16; - typedef png_color_16 FAR *png_color_16p; - typedef png_color_16 FAR *FAR * png_color_16pp; - - typedef struct png_color_8_struct { - png_byte red; /* for use in red green blue files */ - png_byte green; - png_byte blue; - png_byte gray; /* for use in grayscale files */ - png_byte alpha; /* for alpha channel files */ - } png_color_8; - typedef png_color_8 FAR *png_color_8p; - typedef png_color_8 FAR *FAR * png_color_8pp; +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color FAR * png_colorp; +typedef png_color FAR * FAR * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 FAR * png_color_16p; +typedef png_color_16 FAR * FAR * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 FAR * png_color_8p; +typedef png_color_8 FAR * FAR * png_color_8pp; /* * The following two structures are used for the in-core representation * of sPLT chunks. */ - typedef struct png_sPLT_entry_struct { - png_uint_16 red; - png_uint_16 green; - png_uint_16 blue; - png_uint_16 alpha; - png_uint_16 frequency; - } png_sPLT_entry; - typedef png_sPLT_entry FAR *png_sPLT_entryp; - typedef png_sPLT_entry FAR *FAR * png_sPLT_entrypp; +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry FAR * png_sPLT_entryp; +typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp; /* When the depth of the sPLT palette is 8 bits, the color and alpha samples * occupy the LSB of their respective members, and the MSB of each member * is zero-filled. The frequency member always occupies the full 16 bits. */ - typedef struct png_sPLT_struct { - png_charp name; /* palette name */ - png_byte depth; /* depth of palette samples */ - png_sPLT_entryp entries; /* palette entries */ - png_int_32 nentries; /* number of palette entries */ - } png_sPLT_t; - typedef png_sPLT_t FAR *png_sPLT_tp; - typedef png_sPLT_t FAR *FAR * png_sPLT_tpp; +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t FAR * png_sPLT_tp; +typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; #ifdef PNG_TEXT_SUPPORTED /* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, @@ -534,26 +539,27 @@ PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; * regular zero-terminated C strings (possibly empty), never NULL pointers, * so they can be safely used in printf() and other string-handling functions. */ - typedef struct png_text_struct { - int compression; /* compression value: - -1: tEXt, none - 0: zTXt, deflate - 1: iTXt, none - 2: iTXt, deflate */ - png_charp key; /* keyword, 1-79 character description of "text" */ - png_charp text; /* comment, may be an empty string (ie "") - or a NULL pointer */ - png_size_t text_length; /* length of the text string */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + png_size_t text_length; /* length of the text string */ #ifdef PNG_iTXt_SUPPORTED - png_size_t itxt_length; /* length of the itxt string */ - png_charp lang; /* language code, 0-79 characters - or a NULL pointer */ - png_charp lang_key; /* keyword translated UTF-8 string, 0 or more - chars or a NULL pointer */ + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ #endif - } png_text; - typedef png_text FAR *png_textp; - typedef png_text FAR *FAR * png_textpp; +} png_text; +typedef png_text FAR * png_textp; +typedef png_text FAR * FAR * png_textpp; #endif /* Supported compression types for text in PNG files (tEXt, and zTXt). @@ -564,7 +570,7 @@ PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; #define PNG_TEXT_COMPRESSION_zTXt 0 #define PNG_ITXT_COMPRESSION_NONE 1 #define PNG_ITXT_COMPRESSION_zTXt 2 -#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ /* png_time is a way to hold the time in an machine independent way. * Two conversions are provided, both from time_t and struct tm. There @@ -572,16 +578,17 @@ PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; * as I know. If you know of a portable way, send it to me. As a side * note - PNG has always been Year 2000 compliant! */ - typedef struct png_time_struct { - png_uint_16 year; /* full year, as in, 1995 */ - png_byte month; /* month of year, 1 - 12 */ - png_byte day; /* day of month, 1 - 31 */ - png_byte hour; /* hour of day, 0 - 23 */ - png_byte minute; /* minute of hour, 0 - 59 */ - png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ - } png_time; - typedef png_time FAR *png_timep; - typedef png_time FAR *FAR * png_timepp; +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time FAR * png_timep; +typedef png_time FAR * FAR * png_timepp; #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) /* png_unknown_chunk is a structure to hold queued chunks for which there is @@ -589,16 +596,18 @@ PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; * up private chunks for output even though the library doesn't actually * know about their semantics. */ - typedef struct png_unknown_chunk_t { - png_byte name[5]; - png_byte *data; - png_size_t size; - - /* libpng-using applications should NOT directly modify this byte. */ - png_byte location; /* mode of operation at read time */ - } png_unknown_chunk; - typedef png_unknown_chunk FAR *png_unknown_chunkp; - typedef png_unknown_chunk FAR *FAR * png_unknown_chunkpp; +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* libpng-using applications should NOT directly modify this byte. */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; +typedef png_unknown_chunk FAR * png_unknown_chunkp; +typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; #endif /* png_info is a structure that holds the information in a PNG file so @@ -640,245 +649,246 @@ PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns * functions do not make their own copies. */ - typedef struct png_info_struct { - /* the following are necessary for every PNG file */ - png_uint_32 width; /* width of image in pixels (from IHDR) */ - png_uint_32 height; /* height of image in pixels (from IHDR) */ - png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ - png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */ - png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ - png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ - png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ - png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ - png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ - /* The following three should have been named *_method not *_type */ - png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ - png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ - png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ - - /* The following is informational only on read, and not used on writes. */ - png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ - png_byte pixel_depth; /* number of bits per pixel */ - png_byte spare_byte; /* to align the data, and for future use */ - png_byte signature[8]; /* magic bytes read by libpng from start of file */ - - /* The rest of the data is optional. If you are reading, check the - * valid field to see if the information in these are valid. If you - * are writing, set the valid field to those chunks you want written, - * and initialize the appropriate fields below. - */ +typedef struct png_info_struct +{ + /* the following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following is informational only on read, and not used on writes. */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ #if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) - /* The gAMA chunk describes the gamma characteristics of the system - * on which the image was created, normally in the range [1.0, 2.5]. - * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. - */ - float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ + /* The gAMA chunk describes the gamma characteristics of the system + * on which the image was created, normally in the range [1.0, 2.5]. + * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. + */ + float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ #endif #if defined(PNG_sRGB_SUPPORTED) - /* GR-P, 0.96a */ - /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ - png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */ + /* GR-P, 0.96a */ + /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ + png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */ #endif #if defined(PNG_TEXT_SUPPORTED) - /* The tEXt, and zTXt chunks contain human-readable textual data in - * uncompressed, compressed, and optionally compressed forms, respectively. - * The data in "text" is an array of pointers to uncompressed, - * null-terminated C strings. Each chunk has a keyword that describes the - * textual data contained in that chunk. Keywords are not required to be - * unique, and the text string may be empty. Any number of text chunks may - * be in an image. - */ - int num_text; /* number of comments read/to write */ - int max_text; /* current size of text array */ - png_textp text; /* array of comments read/to write */ -#endif /* PNG_TEXT_SUPPORTED */ + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read/to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read/to write */ +#endif /* PNG_TEXT_SUPPORTED */ #if defined(PNG_tIME_SUPPORTED) - /* The tIME chunk holds the last time the displayed image data was - * modified. See the png_time struct for the contents of this struct. - */ - png_time mod_time; + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; #endif #if defined(PNG_sBIT_SUPPORTED) - /* The sBIT chunk specifies the number of significant high-order bits - * in the pixel data. Values are in the range [1, bit_depth], and are - * only specified for the channels in the pixel data. The contents of - * the low-order bits is not specified. Data is valid if - * (valid & PNG_INFO_sBIT) is non-zero. - */ - png_color_8 sig_bit; /* significant bits in color channels */ + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ #endif #if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ defined(PNG_READ_BACKGROUND_SUPPORTED) - /* The tRNS chunk supplies transparency data for paletted images and - * other image types that don't need a full alpha channel. There are - * "num_trans" transparency values for a paletted image, stored in the - * same order as the palette colors, starting from index 0. Values - * for the data are in the range [0, 255], ranging from fully transparent - * to fully opaque, respectively. For non-paletted images, there is a - * single color specified that should be treated as fully transparent. - * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. - */ - png_bytep trans; /* transparent values for paletted image */ - png_color_16 trans_values; /* transparent color for non-palette image */ + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans; /* transparent values for paletted image */ + png_color_16 trans_values; /* transparent color for non-palette image */ #endif #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - /* The bKGD chunk gives the suggested image background color if the - * display program does not have its own background color and the image - * is needs to composited onto a background before display. The colors - * in "background" are normally in the same color space/depth as the - * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. - */ - png_color_16 background; + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; #endif #if defined(PNG_oFFs_SUPPORTED) - /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards - * and downwards from the top-left corner of the display, page, or other - * application-specific co-ordinate space. See the PNG_OFFSET_ defines - * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. - */ - png_int_32 x_offset; /* x offset on page */ - png_int_32 y_offset; /* y offset on page */ - png_byte offset_unit_type; /* offset units type */ + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ #endif #if defined(PNG_pHYs_SUPPORTED) - /* The pHYs chunk gives the physical pixel density of the image for - * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ - * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. - */ - png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ - png_uint_32 y_pixels_per_unit; /* vertical pixel density */ - png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ #endif #if defined(PNG_hIST_SUPPORTED) - /* The hIST chunk contains the relative frequency or importance of the - * various palette entries, so that a viewer can intelligently select a - * reduced-color palette, if required. Data is an array of "num_palette" - * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) - * is non-zero. - */ - png_uint_16p hist; + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; #endif #ifdef PNG_cHRM_SUPPORTED - /* The cHRM chunk describes the CIE color characteristics of the monitor - * on which the PNG was created. This data allows the viewer to do gamut - * mapping of the input image to ensure that the viewer sees the same - * colors in the image as the creator. Values are in the range - * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. - */ + /* The cHRM chunk describes the CIE color characteristics of the monitor + * on which the PNG was created. This data allows the viewer to do gamut + * mapping of the input image to ensure that the viewer sees the same + * colors in the image as the creator. Values are in the range + * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. + */ #ifdef PNG_FLOATING_POINT_SUPPORTED - float x_white; - float y_white; - float x_red; - float y_red; - float x_green; - float y_green; - float x_blue; - float y_blue; + float x_white; + float y_white; + float x_red; + float y_red; + float x_green; + float y_green; + float x_blue; + float y_blue; #endif #endif #if defined(PNG_pCAL_SUPPORTED) - /* The pCAL chunk describes a transformation between the stored pixel - * values and original physical data values used to create the image. - * The integer range [0, 2^bit_depth - 1] maps to the floating-point - * range given by [pcal_X0, pcal_X1], and are further transformed by a - * (possibly non-linear) transformation function given by "pcal_type" - * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ - * defines below, and the PNG-Group's PNG extensions document for a - * complete description of the transformations and how they should be - * implemented, and for a description of the ASCII parameter strings. - * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. - */ - png_charp pcal_purpose; /* pCAL chunk description string */ - png_int_32 pcal_X0; /* minimum value */ - png_int_32 pcal_X1; /* maximum value */ - png_charp pcal_units; /* Latin-1 string giving physical units */ - png_charpp pcal_params; /* ASCII strings containing parameter values */ - png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ - png_byte pcal_nparams; /* number of parameters given in pcal_params */ + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ #endif /* New members added in libpng-1.0.6 */ #ifdef PNG_FREE_ME_SUPPORTED - png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ #endif #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - /* storage for unknown chunks that the library doesn't recognize. */ - png_unknown_chunkp unknown_chunks; - png_size_t unknown_chunks_num; + /* storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + png_size_t unknown_chunks_num; #endif #if defined(PNG_iCCP_SUPPORTED) - /* iCCP chunk data. */ - png_charp iccp_name; /* profile name */ - png_charp iccp_profile; /* International Color Consortium profile data */ - /* Note to maintainer: should be png_bytep */ - png_uint_32 iccp_proflen; /* ICC profile data length */ - png_byte iccp_compression; /* Always zero */ + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_charp iccp_profile; /* International Color Consortium profile data */ + /* Note to maintainer: should be png_bytep */ + png_uint_32 iccp_proflen; /* ICC profile data length */ + png_byte iccp_compression; /* Always zero */ #endif #if defined(PNG_sPLT_SUPPORTED) - /* data on sPLT chunks (there may be more than one). */ - png_sPLT_tp splt_palettes; - png_uint_32 splt_palettes_num; + /* data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + png_uint_32 splt_palettes_num; #endif #if defined(PNG_sCAL_SUPPORTED) - /* The sCAL chunk describes the actual physical dimensions of the - * subject matter of the graphic. The chunk contains a unit specification - * a byte value, and two ASCII strings representing floating-point - * values. The values are width and height corresponsing to one pixel - * in the image. This external representation is converted to double - * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero. - */ - png_byte scal_unit; /* unit of physical scale */ + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. This external representation is converted to double + * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ #ifdef PNG_FLOATING_POINT_SUPPORTED - double scal_pixel_width; /* width of one pixel */ - double scal_pixel_height; /* height of one pixel */ + double scal_pixel_width; /* width of one pixel */ + double scal_pixel_height; /* height of one pixel */ #endif #ifdef PNG_FIXED_POINT_SUPPORTED - png_charp scal_s_width; /* string containing height */ - png_charp scal_s_height; /* string containing width */ + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ #endif #endif #if defined(PNG_INFO_IMAGE_SUPPORTED) - /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */ - /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ - png_bytepp row_pointers; /* the image bits */ + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ #endif #if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED) - png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */ + png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */ #endif #if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED) - png_fixed_point int_x_white; - png_fixed_point int_y_white; - png_fixed_point int_x_red; - png_fixed_point int_y_red; - png_fixed_point int_x_green; - png_fixed_point int_y_green; - png_fixed_point int_x_blue; - png_fixed_point int_y_blue; + png_fixed_point int_x_white; + png_fixed_point int_y_white; + png_fixed_point int_x_red; + png_fixed_point int_y_red; + png_fixed_point int_x_green; + png_fixed_point int_y_green; + png_fixed_point int_x_blue; + png_fixed_point int_y_blue; #endif - } png_info; +} png_info; - typedef png_info FAR *png_infop; - typedef png_info FAR *FAR * png_infopp; +typedef png_info FAR * png_infop; +typedef png_info FAR * FAR * png_infopp; /* Maximum positive integer used in PNG is (2^31)-1 */ #define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) @@ -904,48 +914,48 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA /* This is for compression type. PNG 1.0-1.2 only define the single type. */ -#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ #define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE /* This is for filter type. PNG 1.0-1.2 only define the single type. */ -#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ -#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ #define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE /* These are for the interlacing type. These values should NOT be changed. */ -#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ -#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ -#define PNG_INTERLACE_LAST 2 /* Not a valid value */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ /* These are for the oFFs chunk. These values should NOT be changed. */ -#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ -#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ -#define PNG_OFFSET_LAST 2 /* Not a valid value */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ /* These are for the pCAL chunk. These values should NOT be changed. */ -#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ -#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ -#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ -#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ -#define PNG_EQUATION_LAST 4 /* Not a valid value */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ /* These are for the sCAL chunk. These values should NOT be changed. */ -#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ -#define PNG_SCALE_METER 1 /* meters per pixel */ -#define PNG_SCALE_RADIAN 2 /* radians per pixel */ -#define PNG_SCALE_LAST 3 /* Not a valid value */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ /* These are for the pHYs chunk. These values should NOT be changed. */ -#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ -#define PNG_RESOLUTION_METER 1 /* pixels/meter */ -#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ /* These are for the sRGB chunk. These values should NOT be changed. */ #define PNG_sRGB_INTENT_PERCEPTUAL 0 #define PNG_sRGB_INTENT_RELATIVE 1 #define PNG_sRGB_INTENT_SATURATION 2 #define PNG_sRGB_INTENT_ABSOLUTE 3 -#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ /* This is for text chunks */ #define PNG_KEYWORD_MAX_LENGTH 79 @@ -969,27 +979,28 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #define PNG_INFO_oFFs 0x0100 #define PNG_INFO_tIME 0x0200 #define PNG_INFO_pCAL 0x0400 -#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ -#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ -#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ -#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ -#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using * the routines for other purposes. */ - typedef struct png_row_info_struct { - png_uint_32 width; /* width of row */ - png_uint_32 rowbytes; /* number of bytes in row */ - png_byte color_type; /* color type of row */ - png_byte bit_depth; /* bit depth of row */ - png_byte channels; /* number of channels (1, 2, 3, or 4) */ - png_byte pixel_depth; /* bits per pixel (depth * channels) */ - } png_row_info; - - typedef png_row_info FAR *png_row_infop; - typedef png_row_info FAR *FAR * png_row_infopp; +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_uint_32 rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; /* These are the function types for the I/O functions and for the functions * that allow the user to override the default I/O functions with his or her @@ -997,67 +1008,60 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * and error functions, while the png_rw_ptr type should match that of the * user read/write data functions. */ - typedef struct png_struct_def png_struct; - typedef png_struct FAR *png_structp; - - typedef void (PNGAPI * - png_error_ptr) PNGARG((png_structp, png_const_charp)); - typedef void (PNGAPI * - png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); - typedef void (PNGAPI * png_flush_ptr) PNGARG((png_structp)); - typedef void (PNGAPI * - png_read_status_ptr) PNGARG((png_structp, png_uint_32, int)); - typedef void (PNGAPI * - png_write_status_ptr) PNGARG((png_structp, png_uint_32, int)); +typedef struct png_struct_def png_struct; +typedef png_struct FAR * png_structp; + +typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); +typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, + int)); +typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, + int)); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED - typedef void (PNGAPI * - png_progressive_info_ptr) PNGARG((png_structp, png_infop)); - typedef void (PNGAPI * - png_progressive_end_ptr) PNGARG((png_structp, png_infop)); - typedef void (PNGAPI * - png_progressive_row_ptr) PNGARG((png_structp, png_bytep, - png_uint_32, int)); +typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, + png_uint_32, int)); #endif #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_LEGACY_SUPPORTED) - typedef void (PNGAPI * png_user_transform_ptr) PNGARG((png_structp, - png_row_infop, - png_bytep)); +typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, + png_row_infop, png_bytep)); #endif #if defined(PNG_USER_CHUNKS_SUPPORTED) - typedef int (PNGAPI * - png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); +typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); #endif #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - typedef void (PNGAPI * png_unknown_chunk_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); #endif /* Transform masks for the high-level interface */ -#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ -#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ -#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ -#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ -#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ -#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ -#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ -#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ -#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ -#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ -#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ -#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ -#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */ /* Flags for MNG supported features */ #define PNG_FLAG_MNG_EMPTY_PLTE 0x01 #define PNG_FLAG_MNG_FILTER_64 0x04 #define PNG_ALL_MNG_FEATURES 0x05 - typedef png_voidp(*png_malloc_ptr) PNGARG((png_structp, png_size_t)); - typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); +typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); +typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); /* The structure that holds the information to read and write PNG files. * The only people who need to care about what is inside of this are the @@ -1066,222 +1070,223 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * the jmp_buf. */ - struct png_struct_def { +struct png_struct_def +{ #ifdef PNG_SETJMP_SUPPORTED - jmp_buf jmpbuf; /* used in png_error */ + jmp_buf jmpbuf; /* used in png_error */ #endif - png_error_ptr error_fn; /* function for printing errors and aborting */ - png_error_ptr warning_fn; /* function for printing warnings */ - png_voidp error_ptr; /* user supplied struct for error functions */ - png_rw_ptr write_data_fn; /* function for writing output data */ - png_rw_ptr read_data_fn; /* function for reading input data */ - png_voidp io_ptr; /* ptr to application struct for I/O functions */ + png_error_ptr error_fn; /* function for printing errors and aborting */ + png_error_ptr warning_fn; /* function for printing warnings */ + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - png_user_transform_ptr read_user_transform_fn; /* user read transform */ + png_user_transform_ptr read_user_transform_fn; /* user read transform */ #endif #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - png_user_transform_ptr write_user_transform_fn; /* user write transform */ + png_user_transform_ptr write_user_transform_fn; /* user write transform */ #endif /* These were added in libpng-1.0.2 */ #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - png_voidp user_transform_ptr; /* user supplied struct for user transform */ - png_byte user_transform_depth; /* bit depth of user transformed pixels */ - png_byte user_transform_channels; /* channels in user transformed pixels */ -#endif -#endif - - png_uint_32 mode; /* tells us where we are in the PNG file */ - png_uint_32 flags; /* flags indicating various things to libpng */ - png_uint_32 transformations; /* which transformations to perform */ - - z_stream zstream; /* pointer to decompression structure (below) */ - png_bytep zbuf; /* buffer for zlib */ - png_size_t zbuf_size; /* size of zbuf */ - int zlib_level; /* holds zlib compression level */ - int zlib_method; /* holds zlib compression method */ - int zlib_window_bits; /* holds zlib compression window bits */ - int zlib_mem_level; /* holds zlib compression memory level */ - int zlib_strategy; /* holds zlib compression strategy */ - - png_uint_32 width; /* width of image in pixels */ - png_uint_32 height; /* height of image in pixels */ - png_uint_32 num_rows; /* number of rows in current pass */ - png_uint_32 usr_width; /* width of row at start of write */ - png_uint_32 rowbytes; /* size of row in bytes */ - png_uint_32 irowbytes; /* size of current interlaced row in bytes */ - png_uint_32 iwidth; /* width of current interlaced row in pixels */ - png_uint_32 row_number; /* current row in interlace pass */ - png_bytep prev_row; /* buffer to save previous (unfiltered) row */ - png_bytep row_buf; /* buffer to save current (unfiltered) row */ - png_bytep sub_row; /* buffer to save "sub" row when filtering */ - png_bytep up_row; /* buffer to save "up" row when filtering */ - png_bytep avg_row; /* buffer to save "avg" row when filtering */ - png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ - png_row_info row_info; /* used for transformation routines */ - - png_uint_32 idat_size; /* current IDAT size for read */ - png_uint_32 crc; /* current chunk CRC value */ - png_colorp palette; /* palette from the input file */ - png_uint_16 num_palette; /* number of color entries in palette */ - png_uint_16 num_trans; /* number of transparency values */ - png_byte chunk_name[5]; /* null-terminated name of current chunk */ - png_byte compression; /* file compression type (always 0) */ - png_byte filter; /* file filter type (always 0) */ - png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ - png_byte pass; /* current interlace pass (0 - 6) */ - png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ - png_byte color_type; /* color type of file */ - png_byte bit_depth; /* bit depth of file */ - png_byte usr_bit_depth; /* bit depth of users row */ - png_byte pixel_depth; /* number of bits per pixel */ - png_byte channels; /* number of channels in file */ - png_byte usr_channels; /* channels at start of write */ - png_byte sig_bytes; /* magic bytes read/written from start of file */ + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + z_stream zstream; /* pointer to decompression structure (below) */ + png_bytep zbuf; /* buffer for zlib */ + png_size_t zbuf_size; /* size of zbuf */ + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_uint_32 rowbytes; /* size of row in bytes */ + png_uint_32 irowbytes; /* size of current interlaced row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row */ + png_bytep row_buf; /* buffer to save current (unfiltered) row */ + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ + png_row_info row_info; /* used for transformation routines */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + png_uint_16 num_trans; /* number of transparency values */ + png_byte chunk_name[5]; /* null-terminated name of current chunk */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ + png_byte usr_channels; /* channels at start of write */ + png_byte sig_bytes; /* magic bytes read/written from start of file */ #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) #ifdef PNG_LEGACY_SUPPORTED - png_byte filler; /* filler byte for pixel expansion */ + png_byte filler; /* filler byte for pixel expansion */ #else - png_uint_16 filler; /* filler bytes for pixel expansion */ + png_uint_16 filler; /* filler bytes for pixel expansion */ #endif #endif #if defined(PNG_bKGD_SUPPORTED) - png_byte background_gamma_type; + png_byte background_gamma_type; # ifdef PNG_FLOATING_POINT_SUPPORTED - float background_gamma; + float background_gamma; # endif - png_color_16 background; /* background color in screen gamma space */ + png_color_16 background; /* background color in screen gamma space */ #if defined(PNG_READ_GAMMA_SUPPORTED) - png_color_16 background_1; /* background normalized to gamma 1.0 */ + png_color_16 background_1; /* background normalized to gamma 1.0 */ #endif -#endif /* PNG_bKGD_SUPPORTED */ +#endif /* PNG_bKGD_SUPPORTED */ #if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_flush_ptr output_flush_fn; /* Function for flushing output */ - png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ - png_uint_32 flush_rows; /* number of rows written since last flush */ + png_flush_ptr output_flush_fn;/* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ #endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ + int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ #ifdef PNG_FLOATING_POINT_SUPPORTED - float gamma; /* file gamma value */ - float screen_gamma; /* screen gamma value (display_exponent) */ + float gamma; /* file gamma value */ + float screen_gamma; /* screen gamma value (display_exponent) */ #endif #endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep gamma_table; /* gamma table for 8-bit depth files */ - png_bytep gamma_from_1; /* converts from 1.0 to screen */ - png_bytep gamma_to_1; /* converts from file to 1.0 */ - png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ - png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ - png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ #endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) - png_color_8 sig_bit; /* significant bits in each available channel */ + png_color_8 sig_bit; /* significant bits in each available channel */ #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) - png_color_8 shift; /* shift for significant bit tranformation */ + png_color_8 shift; /* shift for significant bit tranformation */ #endif #if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep trans; /* transparency values for paletted files */ - png_color_16 trans_values; /* transparency values for non-paletted files */ + png_bytep trans; /* transparency values for paletted files */ + png_color_16 trans_values; /* transparency values for non-paletted files */ #endif - png_read_status_ptr read_row_fn; /* called after each row is decoded */ - png_write_status_ptr write_row_fn; /* called after each row is encoded */ + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_progressive_info_ptr info_fn; /* called after header data fully read */ - png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */ - png_progressive_end_ptr end_fn; /* called after image is complete */ - png_bytep save_buffer_ptr; /* current location in save_buffer */ - png_bytep save_buffer; /* buffer for previously read data */ - png_bytep current_buffer_ptr; /* current location in current_buffer */ - png_bytep current_buffer; /* buffer for recently used data */ - png_uint_32 push_length; /* size of current input chunk */ - png_uint_32 skip_length; /* bytes to skip in input data */ - png_size_t save_buffer_size; /* amount of data now in save_buffer */ - png_size_t save_buffer_max; /* total size of save_buffer */ - png_size_t buffer_size; /* total amount of available input data */ - png_size_t current_buffer_size; /* amount of data now in current_buffer */ - int process_mode; /* what push library is currently doing */ - int cur_palette; /* current push library palette index */ + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ # if defined(PNG_TEXT_SUPPORTED) - png_size_t current_text_size; /* current size of text input data */ - png_size_t current_text_left; /* how much text left to read in input */ - png_charp current_text; /* current text chunk buffer */ - png_charp current_text_ptr; /* current location in current_text */ -# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ + png_size_t current_text_size; /* current size of text input data */ + png_size_t current_text_left; /* how much text left to read in input */ + png_charp current_text; /* current text chunk buffer */ + png_charp current_text_ptr; /* current location in current_text */ +# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ #if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) /* for the Borland special 64K segment handler */ - png_bytepp offset_table_ptr; - png_bytep offset_table; - png_uint_16 offset_table_number; - png_uint_16 offset_table_count; - png_uint_16 offset_table_count_free; + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; #endif #if defined(PNG_READ_DITHER_SUPPORTED) - png_bytep palette_lookup; /* lookup table for dithering */ - png_bytep dither_index; /* index translation for palette files */ + png_bytep palette_lookup; /* lookup table for dithering */ + png_bytep dither_index; /* index translation for palette files */ #endif #if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) - png_uint_16p hist; /* histogram */ + png_uint_16p hist; /* histogram */ #endif #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) - png_byte heuristic_method; /* heuristic for row filter selection */ - png_byte num_prev_filters; /* number of weights for previous rows */ - png_bytep prev_filters; /* filter type(s) of previous row(s) */ - png_uint_16p filter_weights; /* weight(s) for previous line(s) */ - png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ - png_uint_16p filter_costs; /* relative filter calculation cost */ - png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ #endif #if defined(PNG_TIME_RFC1123_SUPPORTED) - png_charp time_buffer; /* String to hold RFC 1123 time text */ + png_charp time_buffer; /* String to hold RFC 1123 time text */ #endif /* New members added in libpng-1.0.6 */ #ifdef PNG_FREE_ME_SUPPORTED - png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ #endif #if defined(PNG_USER_CHUNKS_SUPPORTED) - png_voidp user_chunk_ptr; - png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ + png_voidp user_chunk_ptr; + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ #endif #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - int num_chunk_list; - png_bytep chunk_list; + int num_chunk_list; + png_bytep chunk_list; #endif /* New members added in libpng-1.0.3 */ #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - png_byte rgb_to_gray_status; - /* These were changed from png_byte in libpng-1.0.6 */ - png_uint_16 rgb_to_gray_red_coeff; - png_uint_16 rgb_to_gray_green_coeff; - png_uint_16 rgb_to_gray_blue_coeff; + png_byte rgb_to_gray_status; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + png_uint_16 rgb_to_gray_blue_coeff; #endif /* New member added in libpng-1.0.4 (renamed in 1.0.9) */ @@ -1290,69 +1295,70 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) /* changed from png_byte to png_uint_32 at version 1.2.0 */ #ifdef PNG_1_0_X - png_byte mng_features_permitted; + png_byte mng_features_permitted; #else - png_uint_32 mng_features_permitted; -#endif /* PNG_1_0_X */ + png_uint_32 mng_features_permitted; +#endif /* PNG_1_0_X */ #endif /* New member added in libpng-1.0.7 */ #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_fixed_point int_gamma; + png_fixed_point int_gamma; #endif /* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ #if defined(PNG_MNG_FEATURES_SUPPORTED) - png_byte filter_type; + png_byte filter_type; #endif #if defined(PNG_1_0_X) || (defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)) /* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ - png_uint_32 row_buf_size; + png_uint_32 row_buf_size; #endif /* New members added in libpng-1.2.0 */ #if !defined(PNG_1_0_X) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) - png_byte mmx_bitdepth_threshold; - png_uint_32 mmx_rowbytes_threshold; - png_uint_32 asm_flags; + png_byte mmx_bitdepth_threshold; + png_uint_32 mmx_rowbytes_threshold; + png_uint_32 asm_flags; #endif /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ #ifdef PNG_USER_MEM_SUPPORTED - png_voidp mem_ptr; /* user supplied struct for mem functions */ - png_malloc_ptr malloc_fn; /* function for allocating memory */ - png_free_ptr free_fn; /* function for freeing memory */ + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ #endif /* New member added in libpng-1.0.13 and 1.2.0 */ - png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ #if defined(PNG_READ_DITHER_SUPPORTED) /* The following three members were added at version 1.0.14 and 1.2.4 */ - png_bytep dither_sort; /* working sort array */ - png_bytep index_to_palette; /* where the original index currently is */ - /* in the palette */ - png_bytep palette_to_index; /* which original index points to this */ - /* palette color */ + png_bytep dither_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is */ + /* in the palette */ + png_bytep palette_to_index; /* which original index points to this */ + /* palette color */ #endif /* New members added in libpng-1.0.16 and 1.2.6 */ - png_byte compression_type; + png_byte compression_type; #ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_uint_32 user_width_max; - png_uint_32 user_height_max; + png_uint_32 user_width_max; + png_uint_32 user_height_max; #endif - }; +}; + /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ - typedef png_structp version_1_2_8; +typedef png_structp version_1_2_8; - typedef png_struct FAR *FAR * png_structpp; +typedef png_struct FAR * FAR * png_structpp; /* Here are the function definitions most commonly used. This is not * the place to find out how to use libpng. See libpng.txt for the @@ -1361,244 +1367,218 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) */ /* Returns the version number of the library */ - extern PNG_EXPORT(png_uint_32, png_access_version_number) PNGARG((void)); +extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); /* Tell lib we have already handled the first <num_bytes> magic bytes. * Handling more than 8 bytes from the beginning of the file is an error. */ - extern PNG_EXPORT(void, png_set_sig_bytes) PNGARG((png_structp png_ptr, - int num_bytes)); +extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, + int num_bytes)); /* Check sig[start] through sig[start + num_to_check - 1] to see if it's a * PNG file. Returns zero if the supplied bytes match the 8-byte PNG * signature, and non-zero otherwise. Having num_to_check == 0 or * start > 7 will always fail (ie return non-zero). */ - extern PNG_EXPORT(int, png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, - png_size_t num_to_check)); +extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, + png_size_t num_to_check)); /* Simple signature checking function. This is the same as calling * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). */ - extern PNG_EXPORT(int, png_check_sig) PNGARG((png_bytep sig, int num)); +extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)); /* Allocate and initialize png_ptr struct for reading, and any other memory. */ - extern PNG_EXPORT(png_structp, png_create_read_struct) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn)); +extern PNG_EXPORT(png_structp,png_create_read_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); /* Allocate and initialize png_ptr struct for writing, and any other memory */ - extern PNG_EXPORT(png_structp, png_create_write_struct) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn)); +extern PNG_EXPORT(png_structp,png_create_write_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); #ifdef PNG_WRITE_SUPPORTED - extern PNG_EXPORT(png_uint_32, png_get_compression_buffer_size) - PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) + PNGARG((png_structp png_ptr)); #endif #ifdef PNG_WRITE_SUPPORTED - extern PNG_EXPORT(void, png_set_compression_buffer_size) - PNGARG((png_structp png_ptr, png_uint_32 size)); +extern PNG_EXPORT(void,png_set_compression_buffer_size) + PNGARG((png_structp png_ptr, png_uint_32 size)); #endif /* Reset the compression stream */ - extern PNG_EXPORT(int, png_reset_zstream) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); /* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ #ifdef PNG_USER_MEM_SUPPORTED - extern PNG_EXPORT(png_structp, png_create_read_struct_2) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn)); - extern PNG_EXPORT(png_structp, png_create_write_struct_2) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +extern PNG_EXPORT(png_structp,png_create_read_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +extern PNG_EXPORT(png_structp,png_create_write_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); #endif /* Write a PNG chunk - size, type, (optional) data, CRC. */ - extern PNG_EXPORT(void, png_write_chunk) PNGARG((png_structp png_ptr, - png_bytep chunk_name, - png_bytep data, - png_size_t length)); +extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_bytep data, png_size_t length)); /* Write the start of a PNG chunk - length and chunk name. */ - extern PNG_EXPORT(void, png_write_chunk_start) PNGARG((png_structp png_ptr, - png_bytep chunk_name, - png_uint_32 length)); +extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_uint_32 length)); /* Write the data of a PNG chunk started with png_write_chunk_start(). */ - extern PNG_EXPORT(void, png_write_chunk_data) PNGARG((png_structp png_ptr, - png_bytep data, - png_size_t length)); +extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); /* Finish a chunk started with png_write_chunk_start() (includes CRC). */ - extern PNG_EXPORT(void, png_write_chunk_end) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); /* Allocate and initialize the info structure */ - extern PNG_EXPORT(png_infop, png_create_info_struct) - PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_infop,png_create_info_struct) + PNGARG((png_structp png_ptr)); /* Initialize the info structure (old interface - DEPRECATED) */ - extern PNG_EXPORT(void, png_info_init) PNGARG((png_infop info_ptr)); +extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)); #undef png_info_init #define png_info_init(info_ptr) png_info_init_3(&info_ptr,\ png_sizeof(png_info)); - extern PNG_EXPORT(void, png_info_init_3) PNGARG((png_infopp info_ptr, - png_size_t - png_info_struct_size)); +extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, + png_size_t png_info_struct_size)); /* Writes all the PNG information before the image. */ - extern PNG_EXPORT(void, - png_write_info_before_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - extern PNG_EXPORT(void, - png_write_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); #ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* read the information before the actual image data. */ - extern PNG_EXPORT(void, png_read_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); #endif #if defined(PNG_TIME_RFC1123_SUPPORTED) - extern PNG_EXPORT(png_charp, png_convert_to_rfc1123) - PNGARG((png_structp png_ptr, png_timep ptime)); +extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) + PNGARG((png_structp png_ptr, png_timep ptime)); #endif #if !defined(_WIN32_WCE) /* "time.h" functions are not supported on WindowsCE */ #if defined(PNG_WRITE_tIME_SUPPORTED) /* convert from a struct tm to png_time */ - extern PNG_EXPORT(void, png_convert_from_struct_tm) PNGARG((png_timep ptime, - struct tm FAR * - ttime)); +extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, + struct tm FAR * ttime)); /* convert from time_t to png_time. Uses gmtime() */ - extern PNG_EXPORT(void, png_convert_from_time_t) PNGARG((png_timep ptime, - time_t ttime)); -#endif /* PNG_WRITE_tIME_SUPPORTED */ -#endif /* _WIN32_WCE */ +extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, + time_t ttime)); +#endif /* PNG_WRITE_tIME_SUPPORTED */ +#endif /* _WIN32_WCE */ #if defined(PNG_READ_EXPAND_SUPPORTED) /* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ - extern PNG_EXPORT(void, png_set_expand) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(void, - png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(void, - png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(void, - png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Use blue, green, red order for pixels. */ - extern PNG_EXPORT(void, png_set_bgr) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) /* Expand the grayscale to 24-bit RGB if necessary. */ - extern PNG_EXPORT(void, png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) /* Reduce RGB to grayscale. */ #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_rgb_to_gray) PNGARG((png_structp png_ptr, - int error_action, - double red, - double green)); +extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, + int error_action, double red, double green )); #endif - extern PNG_EXPORT(void, - png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, - int error_action, - png_fixed_point red, - png_fixed_point - green)); - extern PNG_EXPORT(png_byte, - png_get_rgb_to_gray_status) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green )); +extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp + png_ptr)); #endif - extern PNG_EXPORT(void, png_build_grayscale_palette) PNGARG((int bit_depth, - png_colorp - palette)); +extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, + png_colorp palette)); #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - extern PNG_EXPORT(void, png_set_strip_alpha) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) - extern PNG_EXPORT(void, png_set_swap_alpha) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) - extern PNG_EXPORT(void, png_set_invert_alpha) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) /* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ - extern PNG_EXPORT(void, png_set_filler) PNGARG((png_structp png_ptr, - png_uint_32 filler, - int flags)); +extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); /* The values of the PNG_FILLER_ defines should NOT be changed */ #define PNG_FILLER_BEFORE 0 #define PNG_FILLER_AFTER 1 /* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ #if !defined(PNG_1_0_X) - extern PNG_EXPORT(void, png_set_add_alpha) PNGARG((png_structp png_ptr, - png_uint_32 filler, - int flags)); +extern PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); #endif -#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Swap bytes in 16-bit depth files. */ - extern PNG_EXPORT(void, png_set_swap) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) /* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ - extern PNG_EXPORT(void, png_set_packing) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Swap packing order of pixels in bytes. */ - extern PNG_EXPORT(void, png_set_packswap) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) /* Converts files to legal bit depths. */ - extern PNG_EXPORT(void, png_set_shift) PNGARG((png_structp png_ptr, - png_color_8p true_bits)); +extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, + png_color_8p true_bits)); #endif #if defined(PNG_READ_INTERLACING_SUPPORTED) || \ defined(PNG_WRITE_INTERLACING_SUPPORTED) /* Have the code handle the interlacing. Returns the number of passes. */ - extern PNG_EXPORT(int, - png_set_interlace_handling) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) /* Invert monochrome files */ - extern PNG_EXPORT(void, png_set_invert_mono) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) /* Handle alpha and tRNS by replacing with a background color. */ #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_background) PNGARG((png_structp png_ptr, - png_color_16p - background_color, - int - background_gamma_code, - int need_expand, - double - background_gamma)); +extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); #endif #define PNG_BACKGROUND_GAMMA_UNKNOWN 0 #define PNG_BACKGROUND_GAMMA_SCREEN 1 @@ -1608,25 +1588,21 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #if defined(PNG_READ_16_TO_8_SUPPORTED) /* strip the second byte of information from a 16-bit depth file. */ - extern PNG_EXPORT(void, png_set_strip_16) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_DITHER_SUPPORTED) /* Turn on dithering, and reduce the palette to the number of colors available. */ - extern PNG_EXPORT(void, png_set_dither) PNGARG((png_structp png_ptr, - png_colorp palette, - int num_palette, - int maximum_colors, - png_uint_16p histogram, - int full_dither)); +extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_uint_16p histogram, int full_dither)); #endif #if defined(PNG_READ_GAMMA_SUPPORTED) /* Handle gamma correction. Screen_gamma=(display_exponent) */ #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_gamma) PNGARG((png_structp png_ptr, - double screen_gamma, - double default_file_gamma)); +extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, + double screen_gamma, double default_file_gamma)); #endif #endif @@ -1634,100 +1610,87 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) /* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ /* Deprecated and will be removed. Use png_permit_mng_features() instead. */ - extern PNG_EXPORT(void, png_permit_empty_plte) PNGARG((png_structp png_ptr, - int - empty_plte_permitted)); +extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, + int empty_plte_permitted)); #endif #if defined(PNG_WRITE_FLUSH_SUPPORTED) /* Set how many lines between output flushes - 0 for no flushing */ - extern PNG_EXPORT(void, - png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); /* Flush the current PNG output buffer */ - extern PNG_EXPORT(void, png_write_flush) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); #endif /* optional update palette with requested transformations */ - extern PNG_EXPORT(void, png_start_read_image) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); /* optional call to update the users info structure */ - extern PNG_EXPORT(void, png_read_update_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); #ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* read one or more rows of image data. */ - extern PNG_EXPORT(void, png_read_rows) PNGARG((png_structp png_ptr, - png_bytepp row, - png_bytepp display_row, - png_uint_32 num_rows)); +extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); #endif #ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* read a row of data. */ - extern PNG_EXPORT(void, png_read_row) PNGARG((png_structp png_ptr, - png_bytep row, - png_bytep display_row)); +extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, + png_bytep row, + png_bytep display_row)); #endif #ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* read the whole image into memory at once. */ - extern PNG_EXPORT(void, png_read_image) PNGARG((png_structp png_ptr, - png_bytepp image)); +extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, + png_bytepp image)); #endif /* write a row of image data */ - extern PNG_EXPORT(void, png_write_row) PNGARG((png_structp png_ptr, - png_bytep row)); +extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, + png_bytep row)); /* write a few rows of image data */ - extern PNG_EXPORT(void, png_write_rows) PNGARG((png_structp png_ptr, - png_bytepp row, - png_uint_32 num_rows)); +extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_uint_32 num_rows)); /* write the image data */ - extern PNG_EXPORT(void, png_write_image) PNGARG((png_structp png_ptr, - png_bytepp image)); +extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, + png_bytepp image)); /* writes the end of the PNG file. */ - extern PNG_EXPORT(void, png_write_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); #ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* read the end of the PNG file. */ - extern PNG_EXPORT(void, png_read_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); #endif /* free any memory associated with the png_info_struct */ - extern PNG_EXPORT(void, - png_destroy_info_struct) PNGARG((png_structp png_ptr, - png_infopp - info_ptr_ptr)); +extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, + png_infopp info_ptr_ptr)); /* free any memory associated with the png_struct and the png_info_structs */ - extern PNG_EXPORT(void, png_destroy_read_struct) PNGARG((png_structpp - png_ptr_ptr, - png_infopp - info_ptr_ptr, - png_infopp - end_info_ptr_ptr)); +extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp + png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); /* free all memory used by the read (old method - NOT DLL EXPORTED) */ - extern void png_read_destroy - PNGARG((png_structp png_ptr, png_infop info_ptr, - png_infop end_info_ptr)); +extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr)); /* free any memory associated with the png_struct and the png_info_structs */ - extern PNG_EXPORT(void, png_destroy_write_struct) - PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); +extern PNG_EXPORT(void,png_destroy_write_struct) + PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); /* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ - extern void png_write_destroy PNGARG((png_structp png_ptr)); +extern void png_write_destroy PNGARG((png_structp png_ptr)); /* set the libpng method of handling chunk CRC errors */ - extern PNG_EXPORT(void, png_set_crc_action) PNGARG((png_structp png_ptr, - int crit_action, - int ancil_action)); +extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, + int crit_action, int ancil_action)); /* Values for png_set_crc_action() to say how to handle CRC errors in * ancillary and critical chunks, and whether to use the data contained @@ -1738,12 +1701,12 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * * value action:critical action:ancillary */ -#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ -#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ -#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ -#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ -#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ -#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ /* These functions give the user control over the scan-line filtering in * libpng and the compression methods used by zlib. These functions are @@ -1756,9 +1719,8 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) /* set the filtering method(s) used by libpng. Currently, the only valid * value for "method" is 0. */ - extern PNG_EXPORT(void, - png_set_filter) PNGARG((png_structp png_ptr, int method, - int filters)); +extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, + int filters)); /* Flags for png_set_filter() to say which filters to use. The flags * are chosen so that they don't conflict with real filter types @@ -1784,7 +1746,7 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #define PNG_FILTER_VALUE_PAETH 4 #define PNG_FILTER_VALUE_LAST 5 -#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ /* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ * defines, either the default (minimum-sum-of-absolute-differences), or * the experimental method (weighted-minimum-sum-of-absolute-differences). @@ -1814,24 +1776,19 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * to the UNWEIGHTED method, but with added encoding time/computation. */ #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(void, - png_set_filter_heuristics) PNGARG((png_structp png_ptr, - int heuristic_method, - int num_weights, - png_doublep - filter_weights, - png_doublep - filter_costs)); +extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, + int heuristic_method, int num_weights, png_doublep filter_weights, + png_doublep filter_costs)); #endif -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ /* Heuristic used for row filter selection. These defines should NOT be * changed. */ -#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ -#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ -#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ -#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ /* Set the library compression level. Currently, valid values range from * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 @@ -1840,22 +1797,20 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * for PNG images, and do considerably fewer caclulations. In the future, * these values may not correspond directly to the zlib compression levels. */ - extern PNG_EXPORT(void, - png_set_compression_level) PNGARG((png_structp png_ptr, - int level)); +extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, + int level)); - extern PNG_EXPORT(void, png_set_compression_mem_level) - PNGARG((png_structp png_ptr, int mem_level)); +extern PNG_EXPORT(void,png_set_compression_mem_level) + PNGARG((png_structp png_ptr, int mem_level)); - extern PNG_EXPORT(void, png_set_compression_strategy) - PNGARG((png_structp png_ptr, int strategy)); +extern PNG_EXPORT(void,png_set_compression_strategy) + PNGARG((png_structp png_ptr, int strategy)); - extern PNG_EXPORT(void, png_set_compression_window_bits) - PNGARG((png_structp png_ptr, int window_bits)); +extern PNG_EXPORT(void,png_set_compression_window_bits) + PNGARG((png_structp png_ptr, int window_bits)); - extern PNG_EXPORT(void, - png_set_compression_method) PNGARG((png_structp png_ptr, - int method)); +extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, + int method)); /* These next functions are called for input/output, memory, and error * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, @@ -1868,8 +1823,7 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #if !defined(PNG_NO_STDIO) /* Initialize the input/output for the PNG file to the default functions. */ - extern PNG_EXPORT(void, - png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); +extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); #endif /* Replace the (error and abort), and warning functions with user @@ -1880,167 +1834,126 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * default function will be used. */ - extern PNG_EXPORT(void, png_set_error_fn) PNGARG((png_structp png_ptr, - png_voidp error_ptr, - png_error_ptr error_fn, - png_error_ptr - warning_fn)); +extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); /* Return the user pointer associated with the error functions */ - extern PNG_EXPORT(png_voidp, - png_get_error_ptr) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); /* Replace the default data output functions with a user supplied one(s). * If buffered output is not used, then output_flush_fn can be set to NULL. * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time * output_flush_fn will be ignored (and thus can be NULL). */ - extern PNG_EXPORT(void, png_set_write_fn) PNGARG((png_structp png_ptr, - png_voidp io_ptr, - png_rw_ptr write_data_fn, - png_flush_ptr - output_flush_fn)); +extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); /* Replace the default data input function with a user supplied one. */ - extern PNG_EXPORT(void, png_set_read_fn) PNGARG((png_structp png_ptr, - png_voidp io_ptr, - png_rw_ptr read_data_fn)); +extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr read_data_fn)); /* Return the user pointer associated with the I/O functions */ - extern PNG_EXPORT(png_voidp, png_get_io_ptr) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(void, png_set_read_status_fn) PNGARG((png_structp png_ptr, - png_read_status_ptr - read_row_fn)); +extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, + png_read_status_ptr read_row_fn)); - extern PNG_EXPORT(void, - png_set_write_status_fn) PNGARG((png_structp png_ptr, - png_write_status_ptr - write_row_fn)); +extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, + png_write_status_ptr write_row_fn)); #ifdef PNG_USER_MEM_SUPPORTED /* Replace the default memory allocation functions with user supplied one(s). */ - extern PNG_EXPORT(void, png_set_mem_fn) PNGARG((png_structp png_ptr, - png_voidp mem_ptr, - png_malloc_ptr malloc_fn, - png_free_ptr free_fn)); +extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); /* Return the user pointer associated with the memory functions */ - extern PNG_EXPORT(png_voidp, png_get_mem_ptr) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); #endif #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_LEGACY_SUPPORTED) - extern PNG_EXPORT(void, png_set_read_user_transform_fn) PNGARG((png_structp - png_ptr, - png_user_transform_ptr - read_user_transform_fn)); +extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr read_user_transform_fn)); #endif #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_LEGACY_SUPPORTED) - extern PNG_EXPORT(void, png_set_write_user_transform_fn) PNGARG((png_structp - png_ptr, - png_user_transform_ptr - write_user_transform_fn)); +extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr write_user_transform_fn)); #endif #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_LEGACY_SUPPORTED) - extern PNG_EXPORT(void, png_set_user_transform_info) PNGARG((png_structp - png_ptr, - png_voidp - user_transform_ptr, - int - user_transform_depth, - int - user_transform_channels)); +extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp + png_ptr, png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); /* Return the user pointer associated with the user transform functions */ - extern PNG_EXPORT(png_voidp, png_get_user_transform_ptr) - PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) + PNGARG((png_structp png_ptr)); #endif #ifdef PNG_USER_CHUNKS_SUPPORTED - extern PNG_EXPORT(void, - png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, - png_voidp - user_chunk_ptr, - png_user_chunk_ptr - read_user_chunk_fn)); - extern PNG_EXPORT(png_voidp, - png_get_user_chunk_ptr) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp + png_ptr)); #endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED /* Sets the function callbacks for the push reader, and a pointer to a * user-defined structure available to the callback functions. */ - extern PNG_EXPORT(void, - png_set_progressive_read_fn) PNGARG((png_structp png_ptr, - png_voidp - progressive_ptr, - png_progressive_info_ptr - info_fn, - png_progressive_row_ptr - row_fn, - png_progressive_end_ptr - end_fn)); +extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, + png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn)); /* returns the user pointer associated with the push read functions */ - extern PNG_EXPORT(png_voidp, png_get_progressive_ptr) - PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) + PNGARG((png_structp png_ptr)); /* function to be called when data becomes available */ - extern PNG_EXPORT(void, png_process_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_bytep buffer, - png_size_t buffer_size)); +extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); /* function that combines rows. Not very much different than the * png_combine_row() call. Is this even used????? */ - extern PNG_EXPORT(void, - png_progressive_combine_row) PNGARG((png_structp png_ptr, - png_bytep old_row, - png_bytep new_row)); -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, + png_bytep old_row, png_bytep new_row)); +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - extern PNG_EXPORT(png_voidp, png_malloc) PNGARG((png_structp png_ptr, - png_uint_32 size)); +extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, + png_uint_32 size)); #if defined(PNG_1_0_X) # define png_malloc_warn png_malloc #else /* Added at libpng version 1.2.4 */ - extern PNG_EXPORT(png_voidp, png_malloc_warn) PNGARG((png_structp png_ptr, - png_uint_32 size)); +extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, + png_uint_32 size)); #endif /* frees a pointer allocated by png_malloc() */ - extern PNG_EXPORT(void, - png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); +extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); #if defined(PNG_1_0_X) /* Function to allocate memory for zlib. */ - extern PNG_EXPORT(voidpf, png_zalloc) PNGARG((voidpf png_ptr, uInt items, - uInt size)); +extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items, + uInt size)); /* Function to free memory for zlib */ - extern PNG_EXPORT(void, png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); +extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); #endif /* Free data that was allocated internally */ - extern PNG_EXPORT(void, png_free_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 free_me, - int num)); +extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 free_me, int num)); #ifdef PNG_FREE_ME_SUPPORTED /* Reassign responsibility for freeing existing data, whether allocated * by libpng or by the application */ - extern PNG_EXPORT(void, png_data_freer) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int freer, - png_uint_32 mask)); +extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, + png_infop info_ptr, int freer, png_uint_32 mask)); #endif /* assignments for png_data_freer */ #define PNG_DESTROY_WILL_FREE_DATA 1 @@ -2059,50 +1972,41 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #define PNG_FREE_TRNS 0x2000 #define PNG_FREE_TEXT 0x4000 #define PNG_FREE_ALL 0x7fff -#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ #ifdef PNG_USER_MEM_SUPPORTED - extern PNG_EXPORT(png_voidp, - png_malloc_default) PNGARG((png_structp png_ptr, - png_uint_32 size)); - extern PNG_EXPORT(void, - png_free_default) PNGARG((png_structp png_ptr, - png_voidp ptr)); +extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, + png_uint_32 size)); +extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, + png_voidp ptr)); #endif - extern PNG_EXPORT(png_voidp, png_memcpy_check) PNGARG((png_structp png_ptr, - png_voidp s1, - png_voidp s2, - png_uint_32 size)); +extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, + png_voidp s1, png_voidp s2, png_uint_32 size)); - extern PNG_EXPORT(png_voidp, png_memset_check) PNGARG((png_structp png_ptr, - png_voidp s1, - int value, - png_uint_32 size)); +extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, + png_voidp s1, int value, png_uint_32 size)); -#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ - extern void *png_far_to_near PNGARG((png_structp png_ptr, png_voidp ptr, - int check)); -#endif /* USE_FAR_KEYWORD */ +#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ +extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, + int check)); +#endif /* USE_FAR_KEYWORD */ /* Fatal error in PNG image of libpng - can't continue */ - extern PNG_EXPORT(void, png_error) PNGARG((png_structp png_ptr, - png_const_charp error_message)); +extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); /* The same, but the chunk name is prepended to the error string. */ - extern PNG_EXPORT(void, png_chunk_error) PNGARG((png_structp png_ptr, - png_const_charp - error_message)); +extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); /* Non-fatal error in libpng. Can continue, but may have a problem. */ - extern PNG_EXPORT(void, png_warning) PNGARG((png_structp png_ptr, - png_const_charp - warning_message)); +extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); /* Non-fatal error in libpng, chunk name is prepended to message. */ - extern PNG_EXPORT(void, png_chunk_warning) PNGARG((png_structp png_ptr, - png_const_charp - warning_message)); +extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); /* The png_set_<chunk> functions are for storing values in the png_info_struct. * Similarly, the png_get_<chunk> calls are used to read values from the @@ -2117,379 +2021,256 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * png_info_struct. */ /* Returns "flag" if chunk data is valid in info_ptr. */ - extern PNG_EXPORT(png_uint_32, png_get_valid) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 flag)); +extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 flag)); /* Returns number of bytes needed to hold a transformed row. */ - extern PNG_EXPORT(png_uint_32, - png_get_rowbytes) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, +png_infop info_ptr)); #if defined(PNG_INFO_IMAGE_SUPPORTED) /* Returns row_pointers, which is an array of pointers to scanlines that was returned from png_read_png(). */ - extern PNG_EXPORT(png_bytepp, png_get_rows) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, +png_infop info_ptr)); /* Set row_pointers, which is an array of pointers to scanlines for use by png_write_png(). */ - extern PNG_EXPORT(void, png_set_rows) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_bytepp row_pointers)); +extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); #endif /* Returns number of color channels in image. */ - extern PNG_EXPORT(png_byte, png_get_channels) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, +png_infop info_ptr)); #ifdef PNG_EASY_ACCESS_SUPPORTED /* Returns image width in pixels. */ - extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns image height in pixels. */ - extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns image bit_depth. */ - extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp - png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns image color_type. */ - extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns image filter_type. */ - extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns image interlace_type. */ - extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns image compression_type. */ - extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns image resolution in pixels per meter, from pHYs chunk data. */ - extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); - extern PNG_EXPORT(png_uint_32, - png_get_x_pixels_per_meter) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - extern PNG_EXPORT(png_uint_32, - png_get_y_pixels_per_meter) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); /* Returns pixel aspect ratio, computed from pHYs chunk data. */ #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp +png_ptr, png_infop info_ptr)); #endif /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ - extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp - png_ptr, - png_infop - info_ptr)); - extern PNG_EXPORT(png_int_32, - png_get_y_offset_pixels) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - extern PNG_EXPORT(png_int_32, - png_get_x_offset_microns) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - extern PNG_EXPORT(png_int_32, - png_get_y_offset_microns) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#endif /* PNG_EASY_ACCESS_SUPPORTED */ +extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ /* Returns pointer to signature string read from PNG header */ - extern PNG_EXPORT(png_bytep, png_get_signature) PNGARG((png_structp png_ptr, - png_infop - info_ptr)); +extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, +png_infop info_ptr)); #if defined(PNG_bKGD_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_color_16p * - background)); +extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p *background)); #endif #if defined(PNG_bKGD_SUPPORTED) - extern PNG_EXPORT(void, png_set_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_color_16p background)); +extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p background)); #endif #if defined(PNG_cHRM_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(png_uint_32, png_get_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, - double *white_x, - double *white_y, - double *red_x, - double *red_y, - double *green_x, - double *green_y, - double *blue_x, - double *blue_y)); +extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); #endif #ifdef PNG_FIXED_POINT_SUPPORTED - extern PNG_EXPORT(png_uint_32, - png_get_cHRM_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_fixed_point * int_white_x, - png_fixed_point * int_white_y, - png_fixed_point * int_red_x, - png_fixed_point * int_red_y, - png_fixed_point * int_green_x, - png_fixed_point * int_green_y, - png_fixed_point * int_blue_x, - png_fixed_point * - int_blue_y)); +extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); #endif #endif #if defined(PNG_cHRM_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, - double white_x, - double white_y, double red_x, - double red_y, double green_x, - double green_y, double blue_x, - double blue_y)); +extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double white_x, double white_y, double red_x, + double red_y, double green_x, double green_y, double blue_x, double blue_y)); #endif #ifdef PNG_FIXED_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_cHRM_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_fixed_point - int_white_x, - png_fixed_point - int_white_y, - png_fixed_point - int_red_x, - png_fixed_point - int_red_y, - png_fixed_point - int_green_x, - png_fixed_point - int_green_y, - png_fixed_point - int_blue_x, - png_fixed_point - int_blue_y)); +extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); #endif #endif #if defined(PNG_gAMA_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(png_uint_32, png_get_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, - double *file_gamma)); +extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *file_gamma)); #endif - extern PNG_EXPORT(png_uint_32, - png_get_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_fixed_point * - int_file_gamma)); +extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); #endif #if defined(PNG_gAMA_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, - double file_gamma)); +extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double file_gamma)); #endif - extern PNG_EXPORT(void, png_set_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_fixed_point - int_file_gamma)); +extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); #endif #if defined(PNG_hIST_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_16p * hist)); +extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p *hist)); #endif #if defined(PNG_hIST_SUPPORTED) - extern PNG_EXPORT(void, png_set_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_16p hist)); -#endif - - extern PNG_EXPORT(png_uint_32, png_get_IHDR) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 * width, - png_uint_32 * height, - int *bit_depth, - int *color_type, - int *interlace_method, - int - *compression_method, - int *filter_method)); - - extern PNG_EXPORT(void, png_set_IHDR) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 width, - png_uint_32 height, - int bit_depth, int color_type, - int interlace_method, - int compression_method, - int filter_method)); +extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p hist)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); #if defined(PNG_oFFs_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_oFFs) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_int_32 * offset_x, - png_int_32 * offset_y, - int *unit_type)); +extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); #endif #if defined(PNG_oFFs_SUPPORTED) - extern PNG_EXPORT(void, png_set_oFFs) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_int_32 offset_x, - png_int_32 offset_y, - int unit_type)); +extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); #endif #if defined(PNG_pCAL_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_pCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_charp * purpose, - png_int_32 * X0, - png_int_32 * X1, - int *type, - int *nparams, - png_charp * units, - png_charpp * params)); +extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, + int *type, int *nparams, png_charp *units, png_charpp *params)); #endif #if defined(PNG_pCAL_SUPPORTED) - extern PNG_EXPORT(void, png_set_pCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_charp purpose, - png_int_32 X0, png_int_32 X1, - int type, int nparams, - png_charp units, - png_charpp params)); +extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_charp units, png_charpp params)); #endif #if defined(PNG_pHYs_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_pHYs) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 * res_x, - png_uint_32 * res_y, - int *unit_type)); +extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); #endif #if defined(PNG_pHYs_SUPPORTED) - extern PNG_EXPORT(void, png_set_pHYs) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 res_x, - png_uint_32 res_y, - int unit_type)); +extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); #endif - extern PNG_EXPORT(png_uint_32, png_get_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_colorp * palette, - int *num_palette)); +extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp *palette, int *num_palette)); - extern PNG_EXPORT(void, png_set_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_colorp palette, - int num_palette)); +extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp palette, int num_palette)); #if defined(PNG_sBIT_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_color_8p * - sig_bit)); +extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p *sig_bit)); #endif #if defined(PNG_sBIT_SUPPORTED) - extern PNG_EXPORT(void, png_set_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_color_8p sig_bit)); +extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p sig_bit)); #endif #if defined(PNG_sRGB_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int *intent)); +extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *intent)); #endif #if defined(PNG_sRGB_SUPPORTED) - extern PNG_EXPORT(void, png_set_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int intent)); - extern PNG_EXPORT(void, - png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int intent)); +extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); #endif #if defined(PNG_iCCP_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_iCCP) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_charpp name, - int *compression_type, - png_charpp profile, - png_uint_32 * - proflen)); - /* Note to maintainer: profile should be png_bytepp */ +extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen)); + /* Note to maintainer: profile should be png_bytepp */ #endif #if defined(PNG_iCCP_SUPPORTED) - extern PNG_EXPORT(void, png_set_iCCP) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_charp name, - int compression_type, - png_charp profile, - png_uint_32 proflen)); - /* Note to maintainer: profile should be png_bytep */ +extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen)); + /* Note to maintainer: profile should be png_bytep */ #endif #if defined(PNG_sPLT_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_sPLT_tpp entries)); +extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tpp entries)); #endif #if defined(PNG_sPLT_SUPPORTED) - extern PNG_EXPORT(void, png_set_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_sPLT_tp entries, - int nentries)); +extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries)); #endif #if defined(PNG_TEXT_SUPPORTED) /* png_get_text also returns the number of text chunks in *num_text */ - extern PNG_EXPORT(png_uint_32, png_get_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_textp * text_ptr, - int *num_text)); +extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); #endif /* @@ -2501,39 +2282,30 @@ by png_write_png(). */ */ #if defined(PNG_TEXT_SUPPORTED) - extern PNG_EXPORT(void, png_set_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_textp text_ptr, - int num_text)); +extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); #endif #if defined(PNG_tIME_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_timep * mod_time)); +extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep *mod_time)); #endif #if defined(PNG_tIME_SUPPORTED) - extern PNG_EXPORT(void, png_set_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_timep mod_time)); +extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep mod_time)); #endif #if defined(PNG_tRNS_SUPPORTED) - extern PNG_EXPORT(png_uint_32, png_get_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_bytep * trans, - int *num_trans, - png_color_16p * - trans_values)); +extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep *trans, int *num_trans, + png_color_16p *trans_values)); #endif #if defined(PNG_tRNS_SUPPORTED) - extern PNG_EXPORT(void, png_set_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_bytep trans, - int num_trans, - png_color_16p trans_values)); +extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep trans, int num_trans, + png_color_16p trans_values)); #endif #if defined(PNG_tRNS_SUPPORTED) @@ -2541,35 +2313,26 @@ by png_write_png(). */ #if defined(PNG_sCAL_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(png_uint_32, png_get_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int *unit, - double *width, - double *height)); +extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, double *width, double *height)); #else #ifdef PNG_FIXED_POINT_SUPPORTED - extern PNG_EXPORT(png_uint_32, png_get_sCAL_s) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int *unit, - png_charpp swidth, - png_charpp sheight)); +extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); #endif #endif -#endif /* PNG_sCAL_SUPPORTED */ +#endif /* PNG_sCAL_SUPPORTED */ #if defined(PNG_sCAL_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, int unit, - double width, double height)); +extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, double width, double height)); #endif #ifdef PNG_FIXED_POINT_SUPPORTED - extern PNG_EXPORT(void, png_set_sCAL_s) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int unit, png_charp swidth, - png_charp sheight)); +extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); #endif -#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ +#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) /* provide a list of chunks and how they are to be handled, if the built-in @@ -2581,51 +2344,36 @@ by png_write_png(). */ = 2: keep only if safe-to-copy = 3: keep even if unsafe-to-copy */ - extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp - png_ptr, - int keep, - png_bytep - chunk_list, - int - num_chunks)); - extern PNG_EXPORT(void, - png_set_unknown_chunks) PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_unknown_chunkp - unknowns, - int num_unknowns)); - extern PNG_EXPORT(void, png_set_unknown_chunk_location) - PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); - extern PNG_EXPORT(png_uint_32, png_get_unknown_chunks) PNGARG((png_structp - png_ptr, - png_infop - info_ptr, - png_unknown_chunkpp - entries)); +extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +extern PNG_EXPORT(void, png_set_unknown_chunk_location) + PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp + png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); #endif #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - PNG_EXPORT(int, - png_handle_as_unknown) PNGARG((png_structp png_ptr, - png_bytep chunk_name)); +PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep + chunk_name)); #endif /* Png_free_data() will turn off the "valid" flag for anything it frees. If you need to turn it off for a chunk that your application has freed, you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ - extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int mask)); +extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, + png_infop info_ptr, int mask)); #if defined(PNG_INFO_IMAGE_SUPPORTED) /* The "params" pointer is currently not used and is for future expansion. */ - extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); - extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); +extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); #endif /* Define PNG_DEBUG at compile time for debugging information. Higher @@ -2642,10 +2390,10 @@ by png_write_png(). */ #define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1) #define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2) #endif -#else /* PNG_DEBUG_FILE || !_MSC_VER */ +#else /* PNG_DEBUG_FILE || !_MSC_VER */ #ifndef PNG_DEBUG_FILE #define PNG_DEBUG_FILE stderr -#endif /* PNG_DEBUG_FILE */ +#endif /* PNG_DEBUG_FILE */ #if (PNG_DEBUG > 1) #define png_debug(l,m) \ { \ @@ -2665,10 +2413,10 @@ by png_write_png(). */ fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ } -#endif /* (PNG_DEBUG > 1) */ -#endif /* _MSC_VER */ -#endif /* (PNG_DEBUG > 0) */ -#endif /* PNG_DEBUG */ +#endif /* (PNG_DEBUG > 1) */ +#endif /* _MSC_VER */ +#endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ #ifndef png_debug #define png_debug(l, m) #endif @@ -2679,22 +2427,16 @@ by png_write_png(). */ #define png_debug2(l, m, p1, p2) #endif - extern PNG_EXPORT(png_bytep, png_sig_bytes) PNGARG((void)); +extern PNG_EXPORT(png_bytep,png_sig_bytes) PNGARG((void)); - extern PNG_EXPORT(png_charp, - png_get_copyright) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(png_charp, - png_get_header_ver) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(png_charp, - png_get_header_version) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(png_charp, - png_get_libpng_ver) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); #ifdef PNG_MNG_FEATURES_SUPPORTED - extern PNG_EXPORT(png_uint_32, png_permit_mng_features) PNGARG((png_structp - png_ptr, - png_uint_32 - mng_features_permitted)); +extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp + png_ptr, png_uint_32 mng_features_permitted)); #endif /* For use in png_set_keep_unknown, added to version 1.2.6 */ @@ -2705,15 +2447,15 @@ by png_write_png(). */ /* Added to version 1.2.0 */ #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) -#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ -#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ #define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04 #define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08 #define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10 #define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20 #define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40 #define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80 -#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ +#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ #define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ | PNG_ASM_FLAG_MMX_READ_INTERLACE \ @@ -2733,64 +2475,58 @@ by png_write_png(). */ #if !defined(PNG_1_0_X) /* pngget.c */ - extern PNG_EXPORT(png_uint_32, png_get_mmx_flagmask) - PNGARG((int flag_select, int *compilerID)); +extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask) + PNGARG((int flag_select, int *compilerID)); /* pngget.c */ - extern PNG_EXPORT(png_uint_32, png_get_asm_flagmask) - PNGARG((int flag_select)); +extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask) + PNGARG((int flag_select)); /* pngget.c */ - extern PNG_EXPORT(png_uint_32, png_get_asm_flags) - PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_uint_32,png_get_asm_flags) + PNGARG((png_structp png_ptr)); /* pngget.c */ - extern PNG_EXPORT(png_byte, png_get_mmx_bitdepth_threshold) - PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold) + PNGARG((png_structp png_ptr)); /* pngget.c */ - extern PNG_EXPORT(png_uint_32, png_get_mmx_rowbytes_threshold) - PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold) + PNGARG((png_structp png_ptr)); /* pngset.c */ - extern PNG_EXPORT(void, png_set_asm_flags) - PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); +extern PNG_EXPORT(void,png_set_asm_flags) + PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); /* pngset.c */ - extern PNG_EXPORT(void, png_set_mmx_thresholds) - PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, - png_uint_32 mmx_rowbytes_threshold)); +extern PNG_EXPORT(void,png_set_mmx_thresholds) + PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, + png_uint_32 mmx_rowbytes_threshold)); -#endif /* PNG_1_0_X */ -#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ +#endif /* PNG_1_0_X */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ #if !defined(PNG_1_0_X) /* png.c, pnggccrd.c, or pngvcrd.c */ - extern PNG_EXPORT(int, png_mmx_support) PNGARG((void)); +extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); /* Strip the prepended error numbers ("#nnn ") from error and warning * messages before passing them to the error or warning handler. */ #ifdef PNG_ERROR_NUMBERS_SUPPORTED - extern PNG_EXPORT(void, png_set_strip_error_numbers) PNGARG((png_structp - png_ptr, - png_uint_32 - strip_mode)); +extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp + png_ptr, png_uint_32 strip_mode)); #endif -#endif /* PNG_1_0_X */ +#endif /* PNG_1_0_X */ /* Added at libpng-1.2.6 */ #ifdef PNG_SET_USER_LIMITS_SUPPORTED - extern PNG_EXPORT(void, png_set_user_limits) PNGARG((png_structp - png_ptr, - png_uint_32 - user_width_max, - png_uint_32 - user_height_max)); - extern PNG_EXPORT(png_uint_32, - png_get_user_width_max) PNGARG((png_structp png_ptr)); - extern PNG_EXPORT(png_uint_32, - png_get_user_height_max) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp + png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); +extern PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp + png_ptr)); +extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp + png_ptr)); #endif /* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */ @@ -2808,7 +2544,7 @@ by png_write_png(). */ * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] */ - /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ # define png_composite(composite, fg, alpha, bg) \ { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ @@ -2822,7 +2558,7 @@ by png_write_png(). */ (png_uint_32)(alpha)) + (png_uint_32)32768L); \ (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } -#else /* standard method using integer division */ +#else /* standard method using integer division */ # define png_composite(composite, fg, alpha, bg) \ (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ @@ -2834,7 +2570,7 @@ by png_write_png(). */ (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ (png_uint_32)32767) / (png_uint_32)65535L) -#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ /* These next functions are used internally in the code. They generally * shouldn't be used unless you are writing code to add or replace some @@ -2871,7 +2607,7 @@ by png_write_png(). */ #define PNG_DITHER 0x0040 #define PNG_BACKGROUND 0x0080 #define PNG_BACKGROUND_EXPAND 0x0100 - /* 0x0200 unused */ + /* 0x0200 unused */ #define PNG_16_TO_8 0x0400 #define PNG_RGBA 0x0800 #define PNG_EXPAND 0x1000 @@ -2885,15 +2621,15 @@ by png_write_png(). */ #define PNG_USER_TRANSFORM 0x100000L #define PNG_RGB_TO_GRAY_ERR 0x200000L #define PNG_RGB_TO_GRAY_WARN 0x400000L -#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ - /* 0x800000L Unused */ -#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ - /* 0x2000000L unused */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ +#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ + /* 0x800000L Unused */ +#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ + /* 0x2000000L unused */ + /* 0x4000000L unused */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ /* flags for png_create_struct */ #define PNG_STRUCT_PNG 0x0001 @@ -2927,16 +2663,16 @@ by png_write_png(). */ #define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L #define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L #define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L -#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ -#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ - /* 0x800000L unused */ - /* 0x1000000L unused */ - /* 0x2000000L unused */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ +#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ +#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ + /* 0x800000L unused */ + /* 0x1000000L unused */ + /* 0x2000000L unused */ + /* 0x4000000L unused */ + /* 0x8000000L unused */ + /* 0x10000000L unused */ + /* 0x20000000L unused */ + /* 0x40000000L unused */ #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ PNG_FLAG_CRC_ANCILLARY_NOWARN) @@ -2970,11 +2706,11 @@ by png_write_png(). */ #if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) /* place to hold the signature string for a PNG file. */ #ifdef PNG_USE_GLOBAL_ARRAYS - PNG_EXPORT_VAR(const png_byte FARDATA) png_sig[8]; + PNG_EXPORT_VAR (const png_byte FARDATA) png_sig[8]; #else #define png_sig png_sig_bytes(NULL) #endif -#endif /* PNG_NO_EXTERN */ +#endif /* PNG_NO_EXTERN */ /* Constant strings for known chunk types. If you need to add a chunk, * define the name here, and add an invocation of the macro in png.c and @@ -3003,28 +2739,29 @@ by png_write_png(). */ #define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} #ifdef PNG_USE_GLOBAL_ARRAYS - PNG_EXPORT_VAR(const png_byte FARDATA) png_IHDR[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_IDAT[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_IEND[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_PLTE[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_bKGD[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_cHRM[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_gAMA[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_hIST[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_iCCP[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_iTXt[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_oFFs[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_pCAL[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_sCAL[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_pHYs[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_sBIT[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_sPLT[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_sRGB[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_tEXt[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_tIME[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_tRNS[5]; - PNG_EXPORT_VAR(const png_byte FARDATA) png_zTXt[5]; -#endif /* PNG_USE_GLOBAL_ARRAYS */ +PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IDAT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IEND[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_PLTE[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_bKGD[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_cHRM[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_gAMA[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_hIST[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iCCP[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iTXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_oFFs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pHYs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sBIT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sPLT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sRGB[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5]; +#endif /* PNG_USE_GLOBAL_ARRAYS */ + /* Inline macros to do direct reads of bytes from the input buffer. These * require that you are using an architecture that uses PNG byte ordering @@ -3042,345 +2779,308 @@ by png_write_png(). */ # define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) #else # if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) - PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf)); +PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf)); # endif - PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf)); - PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); -#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ - PNG_EXTERN png_uint_32 png_get_uint_31 PNGARG((png_structp png_ptr, - png_bytep buf)); +PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf)); +PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); +#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ +PNG_EXTERN png_uint_32 png_get_uint_31 PNGARG((png_structp png_ptr, + png_bytep buf)); /* Initialize png_ptr struct for reading, and allocate any other memory. * (old interface - DEPRECATED - use png_create_read_struct instead). */ - extern PNG_EXPORT(void, png_read_init) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)); #undef png_read_init #define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); - extern PNG_EXPORT(void, png_read_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp - user_png_ver, - png_size_t - png_struct_size)); - extern PNG_EXPORT(void, - png_read_init_2) PNGARG((png_structp png_ptr, - png_const_charp user_png_ver, - png_size_t png_struct_size, - png_size_t png_info_size)); +extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); /* Initialize png_ptr struct for writing, and allocate any other memory. * (old interface - DEPRECATED - use png_create_write_struct instead). */ - extern PNG_EXPORT(void, png_write_init) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)); #undef png_write_init #define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); - extern PNG_EXPORT(void, png_write_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp - user_png_ver, - png_size_t - png_struct_size)); - extern PNG_EXPORT(void, - png_write_init_2) PNGARG((png_structp png_ptr, - png_const_charp user_png_ver, - png_size_t png_struct_size, - png_size_t png_info_size)); +extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); /* Allocate memory for an internal libpng struct */ - PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); +PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); /* Free memory from internal libpng struct */ - PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); +PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); - PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr - malloc_fn, - png_voidp mem_ptr)); - PNG_EXTERN void png_destroy_struct_2 - PNGARG((png_voidp struct_ptr, png_free_ptr free_fn, png_voidp mem_ptr)); +PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr + malloc_fn, png_voidp mem_ptr)); +PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, + png_free_ptr free_fn, png_voidp mem_ptr)); /* Free any memory that info_ptr points to and reset struct. */ - PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, + png_infop info_ptr)); #ifndef PNG_1_0_X /* Function to allocate memory for zlib. */ - PNG_EXTERN voidpf png_zalloc - PNGARG((voidpf png_ptr, uInt items, uInt size)); +PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); /* Function to free memory for zlib */ - PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); +PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); #ifdef PNG_SIZE_T /* Function to convert a sizeof an item to png_sizeof item */ - PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); #endif /* Next four functions are used internally as callbacks. PNGAPI is required * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ - PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, - png_bytep data, - png_size_t length)); +PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED - PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, - png_size_t length)); +PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); #endif - PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, - png_bytep data, - png_size_t length)); +PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); #if defined(PNG_WRITE_FLUSH_SUPPORTED) #if !defined(PNG_NO_STDIO) - PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); +PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); #endif #endif -#else /* PNG_1_0_X */ +#else /* PNG_1_0_X */ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED - PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, - png_size_t length)); +PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); #endif -#endif /* PNG_1_0_X */ +#endif /* PNG_1_0_X */ /* Reset the CRC variable */ - PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); /* Write the "data" buffer to whatever output you are using. */ - PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); +PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); /* Read data from whatever input you are using into the "data" buffer */ - PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); +PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); /* Read bytes into buf, and update png_ptr->crc */ - PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, - png_size_t length)); +PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, + png_size_t length)); /* Decompress data in a chunk that uses compression */ #if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) - PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr, - int comp_type, - png_charp chunkdata, - png_size_t chunklength, - png_size_t prefix_length, - png_size_t * - data_length)); +PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr, + int comp_type, png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_length, png_size_t *data_length)); #endif /* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ - PNG_EXTERN int png_crc_finish - PNGARG((png_structp png_ptr, png_uint_32 skip)); +PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); /* Read the CRC from the file and compare it to the libpng calculated CRC */ - PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); +PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); /* Calculate the CRC over a section of data. Note that we are only * passing a maximum of 64K on systems that have this as a memory limit, * since this is the maximum buffer size we can specify. */ - PNG_EXTERN void png_calculate_crc - PNGARG((png_structp png_ptr, png_bytep ptr, png_size_t length)); +PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, + png_size_t length)); #if defined(PNG_WRITE_FLUSH_SUPPORTED) - PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); #endif + /* Place a 32-bit number into a buffer in PNG byte order (big-endian). * The only currently known PNG chunks that use signed numbers are * the ancillary extension chunks, oFFs and pCAL. */ - PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i)); +PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i)); #if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) - PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i)); +PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i)); #endif /* Place a 16-bit number into a buffer in PNG byte order. * The parameter is declared unsigned int, not png_uint_16, * just to avoid potential problems on pre-ANSI C compilers. */ - PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i)); +PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i)); /* simple function to write the signature */ - PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)); /* write various chunks */ /* Write the IHDR chunk, and update the png_struct with the necessary * information. */ - PNG_EXTERN void png_write_IHDR - PNGARG((png_structp png_ptr, png_uint_32 width, png_uint_32 height, - int bit_depth, int color_type, int compression_method, - int filter_method, int interlace_method)); +PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, + png_uint_32 height, + int bit_depth, int color_type, int compression_method, int filter_method, + int interlace_method)); - PNG_EXTERN void png_write_PLTE - PNGARG((png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)); +PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, + png_uint_32 num_pal)); - PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); +PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); - PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); #if defined(PNG_WRITE_gAMA_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - PNG_EXTERN void png_write_gAMA - PNGARG((png_structp png_ptr, double file_gamma)); +PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); #endif #ifdef PNG_FIXED_POINT_SUPPORTED - PNG_EXTERN void png_write_gAMA_fixed - PNGARG((png_structp png_ptr, png_fixed_point file_gamma)); +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point + file_gamma)); #endif #endif #if defined(PNG_WRITE_sBIT_SUPPORTED) - PNG_EXTERN void png_write_sBIT - PNGARG((png_structp png_ptr, png_color_8p sbit, int color_type)); +PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, + int color_type)); #endif #if defined(PNG_WRITE_cHRM_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, - double white_x, double white_y, - double red_x, double red_y, - double green_x, double green_y, - double blue_x, double blue_y)); +PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, + double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y)); #endif #ifdef PNG_FIXED_POINT_SUPPORTED - PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, - png_fixed_point int_white_y, - png_fixed_point int_red_x, - png_fixed_point int_red_y, - png_fixed_point int_green_x, - png_fixed_point int_green_y, - png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); #endif #endif #if defined(PNG_WRITE_sRGB_SUPPORTED) - PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, int intent)); +PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, + int intent)); #endif #if defined(PNG_WRITE_iCCP_SUPPORTED) - PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, - png_charp name, int compression_type, - png_charp profile, int proflen)); - /* Note to maintainer: profile should be png_bytep */ +PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, + png_charp name, int compression_type, + png_charp profile, int proflen)); + /* Note to maintainer: profile should be png_bytep */ #endif #if defined(PNG_WRITE_sPLT_SUPPORTED) - PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, - png_sPLT_tp palette)); +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_sPLT_tp palette)); #endif #if defined(PNG_WRITE_tRNS_SUPPORTED) - PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, - png_color_16p values, int number, - int color_type)); +PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, + png_color_16p values, int number, int color_type)); #endif #if defined(PNG_WRITE_bKGD_SUPPORTED) - PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, - png_color_16p values, - int color_type)); +PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, + png_color_16p values, int color_type)); #endif #if defined(PNG_WRITE_hIST_SUPPORTED) - PNG_EXTERN void png_write_hIST - PNGARG((png_structp png_ptr, png_uint_16p hist, int num_hist)); +PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, + int num_hist)); #endif #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) - PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, - png_charp key, - png_charpp new_key)); +PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, + png_charp key, png_charpp new_key)); #endif #if defined(PNG_WRITE_tEXt_SUPPORTED) - PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, - png_size_t text_len)); +PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len)); #endif #if defined(PNG_WRITE_zTXt_SUPPORTED) - PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, png_size_t text_len, - int compression)); +PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len, int compression)); #endif #if defined(PNG_WRITE_iTXt_SUPPORTED) - PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, - int compression, png_charp key, - png_charp lang, png_charp lang_key, - png_charp text)); +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)); #endif -#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */ - PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_textp text_ptr, int num_text)); +#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */ +PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); #endif #if defined(PNG_WRITE_oFFs_SUPPORTED) - PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, - png_int_32 x_offset, - png_int_32 y_offset, int unit_type)); +PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type)); #endif #if defined(PNG_WRITE_pCAL_SUPPORTED) - PNG_EXTERN void png_write_pCAL - PNGARG((png_structp png_ptr, png_charp purpose, png_int_32 X0, - png_int_32 X1, int type, int nparams, png_charp units, - png_charpp params)); +PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, + png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params)); #endif #if defined(PNG_WRITE_pHYs_SUPPORTED) - PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, - png_uint_32 x_pixels_per_unit, - png_uint_32 y_pixels_per_unit, - int unit_type)); +PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type)); #endif #if defined(PNG_WRITE_tIME_SUPPORTED) - PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, - png_timep mod_time)); +PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, + png_timep mod_time)); #endif #if defined(PNG_WRITE_sCAL_SUPPORTED) #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) - PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, - int unit, double width, - double height)); +PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, + int unit, double width, double height)); #else #ifdef PNG_FIXED_POINT_SUPPORTED - PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, - int unit, png_charp width, - png_charp height)); +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)); #endif #endif #endif /* Called when finished processing a row of data */ - PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); /* Internal use only. Called before first row of data */ - PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); #if defined(PNG_READ_GAMMA_SUPPORTED) - PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); #endif /* combine a row of data, dealing with alpha, etc. if requested */ - PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, - int mask)); +PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, + int mask)); #if defined(PNG_READ_INTERLACING_SUPPORTED) /* expand an interlaced row */ @@ -3388,172 +3088,153 @@ by png_write_png(). */ PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, png_bytep row, int pass, png_uint_32 transformations)); */ - PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); #endif /* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ #if defined(PNG_WRITE_INTERLACING_SUPPORTED) /* grab pixels out of a row for an interlaced pass */ - PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass)); +PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass)); #endif /* unfilter a row */ - PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, - png_row_infop row_info, - png_bytep row, - png_bytep prev_row, - int filter)); +PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); /* Choose the best filter to use and filter the row data */ - PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, - png_row_infop row_info)); +PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)); /* Write out the filtered row. */ - PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, - png_bytep filtered_row)); +PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)); /* finish a row while reading, dealing with interlacing passes, etc. */ - PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); /* initialize the row buffers, etc. */ - PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); /* optional call to update the users info structure */ - PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); /* these are the functions that do the transformations */ #if defined(PNG_READ_FILLER_SUPPORTED) - PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, - png_bytep row, - png_uint_32 filler, - png_uint_32 flags)); +PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags)); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) - PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); #endif #if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) - PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); #endif #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) - PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); #endif #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) - PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); #endif #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, - png_bytep row, - png_uint_32 flags)); +PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 flags)); #endif #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) - PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); +PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) - PNG_EXTERN void png_do_packswap - PNGARG((png_row_infop row_info, png_bytep row)); +PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); #endif #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop - row_info, png_bytep row)); +PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop + row_info, png_bytep row)); #endif #if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) - PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, + png_bytep row)); #endif #if defined(PNG_READ_PACK_SUPPORTED) - PNG_EXTERN void png_do_unpack - PNGARG((png_row_infop row_info, png_bytep row)); +PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) - PNG_EXTERN void png_do_unshift - PNGARG((png_row_infop row_info, png_bytep row, png_color_8p sig_bits)); +PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p sig_bits)); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) - PNG_EXTERN void png_do_invert - PNGARG((png_row_infop row_info, png_bytep row)); +PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); #endif #if defined(PNG_READ_16_TO_8_SUPPORTED) - PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); +PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); #endif #if defined(PNG_READ_DITHER_SUPPORTED) - PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, - png_bytep row, - png_bytep palette_lookup, - png_bytep dither_lookup)); +PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, + png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); # if defined(PNG_CORRECT_PALETTE_SUPPORTED) - PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, - png_colorp palette, - int num_palette)); +PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)); # endif #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) - PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); +PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); #endif #if defined(PNG_WRITE_PACK_SUPPORTED) - PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 bit_depth)); +PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth)); #endif #if defined(PNG_WRITE_SHIFT_SUPPORTED) - PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p bit_depth)); +PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p bit_depth)); #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) #if defined(PNG_READ_GAMMA_SUPPORTED) - PNG_EXTERN void png_do_background - PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background, - png_color_16p background_1, png_bytep gamma_table, - png_bytep gamma_from_1, png_bytep gamma_to_1, - png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, - png_uint_16pp gamma_16_to_1, int gamma_shift)); +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift)); #else - PNG_EXTERN void png_do_background - PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background)); +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background)); #endif #endif #if defined(PNG_READ_GAMMA_SUPPORTED) - PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, - png_bytep gamma_table, - png_uint_16pp gamma_16_table, - int gamma_shift)); +PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift)); #endif #if defined(PNG_READ_EXPAND_SUPPORTED) - PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, - png_bytep row, - png_colorp palette, - png_bytep trans, - int num_trans)); - PNG_EXTERN void png_do_expand - PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_value)); +PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, + png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); +PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, + png_bytep row, png_color_16p trans_value)); #endif /* The following decodes the appropriate chunks, and does error correction, @@ -3561,185 +3242,178 @@ PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, */ /* decode the IHDR chunk */ - PNG_EXTERN void png_handle_IHDR - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); - PNG_EXTERN void png_handle_PLTE - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); - PNG_EXTERN void png_handle_IEND - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #if defined(PNG_READ_bKGD_SUPPORTED) - PNG_EXTERN void png_handle_bKGD - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_cHRM_SUPPORTED) - PNG_EXTERN void png_handle_cHRM - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_gAMA_SUPPORTED) - PNG_EXTERN void png_handle_gAMA - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_hIST_SUPPORTED) - PNG_EXTERN void png_handle_hIST - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_iCCP_SUPPORTED) - extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_iCCP_SUPPORTED */ +extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_iCCP_SUPPORTED */ #if defined(PNG_READ_iTXt_SUPPORTED) - PNG_EXTERN void png_handle_iTXt - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_oFFs_SUPPORTED) - PNG_EXTERN void png_handle_oFFs - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_pCAL_SUPPORTED) - PNG_EXTERN void png_handle_pCAL - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_pHYs_SUPPORTED) - PNG_EXTERN void png_handle_pHYs - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_sBIT_SUPPORTED) - PNG_EXTERN void png_handle_sBIT - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_sCAL_SUPPORTED) - PNG_EXTERN void png_handle_sCAL - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_sPLT_SUPPORTED) - extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_sPLT_SUPPORTED */ +extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_sPLT_SUPPORTED */ #if defined(PNG_READ_sRGB_SUPPORTED) - PNG_EXTERN void png_handle_sRGB - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_tEXt_SUPPORTED) - PNG_EXTERN void png_handle_tEXt - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_tIME_SUPPORTED) - PNG_EXTERN void png_handle_tIME - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_tRNS_SUPPORTED) - PNG_EXTERN void png_handle_tRNS - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif #if defined(PNG_READ_zTXt_SUPPORTED) - PNG_EXTERN void png_handle_zTXt - PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); #endif - PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 length)); +PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); - PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, - png_bytep chunk_name)); +PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, + png_bytep chunk_name)); /* handle the transformations for reading and writing */ - PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); - PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); - PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED - PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, - png_infop info_ptr)); - PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, - png_infop info_ptr)); - PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); - PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, - png_uint_32 length)); - PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); - PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); - PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, - png_size_t buffer_length)); - PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); - PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, - png_bytep buffer, - png_size_t buffer_length)); - PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); - PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 length)); - PNG_EXTERN void png_push_have_info - PNGARG((png_structp png_ptr, png_infop info_ptr)); - PNG_EXTERN void png_push_have_end - PNGARG((png_structp png_ptr, png_infop info_ptr)); - PNG_EXTERN void png_push_have_row - PNGARG((png_structp png_ptr, png_bytep row)); - PNG_EXTERN void png_push_read_end - PNGARG((png_structp png_ptr, png_infop info_ptr)); - PNG_EXTERN void png_process_some_data - PNGARG((png_structp png_ptr, png_infop info_ptr)); - PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, + png_uint_32 length)); +PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); +PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); #if defined(PNG_READ_tEXt_SUPPORTED) - PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 length)); - PNG_EXTERN void png_push_read_tEXt - PNGARG((png_structp png_ptr, png_infop info_ptr)); +PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); #endif #if defined(PNG_READ_zTXt_SUPPORTED) - PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 length)); - PNG_EXTERN void png_push_read_zTXt - PNGARG((png_structp png_ptr, png_infop info_ptr)); +PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); #endif #if defined(PNG_READ_iTXt_SUPPORTED) - PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, - png_uint_32 length)); - PNG_EXTERN void png_push_read_iTXt - PNGARG((png_structp png_ptr, png_infop info_ptr)); +PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); #endif -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ #ifdef PNG_MNG_FEATURES_SUPPORTED - PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); - PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); #endif #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) - /* png.c *//* PRIVATE */ - PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)); +/* png.c */ /* PRIVATE */ +PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)); #endif /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ -#endif /* PNG_INTERNAL */ +#endif /* PNG_INTERNAL */ #ifdef __cplusplus } #endif -#endif /* PNG_VERSION_INFO_ONLY */ + +#endif /* PNG_VERSION_INFO_ONLY */ /* do not put anything past this line */ -#endif /* PNG_H */ +#endif /* PNG_H */ diff --git a/com32/include/pngconf.h b/com32/include/pngconf.h index bc28b9ed..3ac628c4 100644 --- a/com32/include/pngconf.h +++ b/com32/include/pngconf.h @@ -253,7 +253,7 @@ */ #ifndef PNGARG -#ifdef OF /* zlib prototype munger */ +#ifdef OF /* zlib prototype munger */ # define PNGARG(arglist) OF(arglist) #else @@ -304,8 +304,8 @@ /* If you encounter a compiler error here, see the explanation * near the end of INSTALL. */ -__png.h__ already includes setjmp.h; -__dont__ include it again.; + __png.h__ already includes setjmp.h; + __dont__ include it again.; # endif # endif /* __linux__ */ @@ -572,16 +572,16 @@ __dont__ include it again.; #endif /* PNG_READ_TRANSFORMS_SUPPORTED */ #if !defined(PNG_NO_PROGRESSIVE_READ) && \ - !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ -# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ -#endif /* about interlacing capability! You'll */ - /* still have interlacing unless you change the following line: */ + !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ +# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ +#endif /* about interlacing capability! You'll */ + /* still have interlacing unless you change the following line: */ -#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ +#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ #ifndef PNG_NO_READ_COMPOSITE_NODIV -# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ -# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ +# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ +# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ # endif #endif @@ -620,7 +620,7 @@ __dont__ include it again.; # define PNG_WRITE_INVERT_SUPPORTED # endif # ifndef PNG_NO_WRITE_FILLER -# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ +# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ # endif # ifndef PNG_NO_WRITE_SWAP_ALPHA # define PNG_WRITE_SWAP_ALPHA_SUPPORTED @@ -633,9 +633,9 @@ __dont__ include it again.; # endif #endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ -#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant - encoders, but can cause trouble - if left undefined */ +#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant + encoders, but can cause trouble + if left undefined */ #if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ defined(PNG_FLOATING_POINT_SUPPORTED) @@ -880,8 +880,8 @@ __dont__ include it again.; # endif #endif #ifndef PNG_NO_READ_OPT_PLTE -# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ -#endif /* optional PLTE chunk in RGB and RGBA images */ +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ #if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ defined(PNG_READ_zTXt_SUPPORTED) # define PNG_READ_TEXT_SUPPORTED @@ -1056,10 +1056,10 @@ typedef unsigned char png_byte; /* This is usually size_t. It is typedef'ed just in case you need it to change (I'm not sure if you will or not, so I thought I'd be safe) */ #ifdef PNG_SIZE_T -typedef PNG_SIZE_T png_size_t; + typedef PNG_SIZE_T png_size_t; # define png_sizeof(x) png_convert_size(sizeof (x)) #else -typedef size_t png_size_t; + typedef size_t png_size_t; # define png_sizeof(x) sizeof (x) #endif @@ -1088,14 +1088,15 @@ typedef size_t png_size_t; # define FAR __far # endif # define USE_FAR_KEYWORD -# endif /* LDATA != 1 */ +# endif /* LDATA != 1 */ /* Possibly useful for moving data out of default segment. * Uncomment it if you want. Could also define FARDATA as * const if your compiler supports it. (SJT) - # define FARDATA FAR +# define FARDATA FAR */ -# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ -#endif /* __BORLANDC__ */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + /* Suggest testing for specific compiler first before testing for * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, @@ -1126,43 +1127,43 @@ typedef size_t png_size_t; typedef png_int_32 png_fixed_point; /* Add typedefs for pointers */ -typedef void FAR *png_voidp; -typedef png_byte FAR *png_bytep; -typedef png_uint_32 FAR *png_uint_32p; -typedef png_int_32 FAR *png_int_32p; -typedef png_uint_16 FAR *png_uint_16p; -typedef png_int_16 FAR *png_int_16p; -typedef PNG_CONST char FAR *png_const_charp; -typedef char FAR *png_charp; -typedef png_fixed_point FAR *png_fixed_point_p; +typedef void FAR * png_voidp; +typedef png_byte FAR * png_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST char FAR * png_const_charp; +typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; #ifndef PNG_NO_STDIO #if defined(_WIN32_WCE) -typedef HANDLE png_FILE_p; +typedef HANDLE png_FILE_p; #else -typedef FILE *png_FILE_p; +typedef FILE * png_FILE_p; #endif #endif #ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR *png_doublep; +typedef double FAR * png_doublep; #endif /* Pointers to pointers; i.e. arrays */ -typedef png_byte FAR *FAR * png_bytepp; -typedef png_uint_32 FAR *FAR * png_uint_32pp; -typedef png_int_32 FAR *FAR * png_int_32pp; -typedef png_uint_16 FAR *FAR * png_uint_16pp; -typedef png_int_16 FAR *FAR * png_int_16pp; -typedef PNG_CONST char FAR *FAR * png_const_charpp; -typedef char FAR *FAR * png_charpp; -typedef png_fixed_point FAR *FAR * png_fixed_point_pp; +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; #ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR *FAR * png_doublepp; +typedef double FAR * FAR * png_doublepp; #endif /* Pointers to pointers to pointers; i.e., pointer to array */ -typedef char FAR *FAR * FAR * png_charppp; +typedef char FAR * FAR * FAR * png_charppp; #if defined(PNG_1_0_X) || defined(PNG_1_2_X) /* SPC - Is this stuff deprecated? */ @@ -1171,9 +1172,9 @@ typedef char FAR *FAR * FAR * png_charppp; * or another compression library is used, then change these. * Eliminates need to change all the source files. */ -typedef charf *png_zcharp; -typedef charf *FAR * png_zcharpp; -typedef z_stream FAR *png_zstreamp; +typedef charf * png_zcharp; +typedef charf * FAR * png_zcharpp; +typedef z_stream FAR * png_zstreamp; #endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */ /* @@ -1288,10 +1289,10 @@ typedef z_stream FAR *png_zstreamp; # if defined(PNG_BUILD_DLL) # define PNG_IMPEXP __export # else -# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in - VC++ */ -# endif /* Exists in Borland C++ for - C++ classes (== huge) */ +# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in + VC++ */ +# endif /* Exists in Borland C++ for + C++ classes (== huge) */ # endif # endif @@ -1302,14 +1303,14 @@ typedef z_stream FAR *png_zstreamp; # define PNG_IMPEXP __declspec(dllimport) # endif # endif -# endif /* PNG_IMPEXP */ +# endif /* PNG_IMPEXP */ #else /* !(DLL || non-cygwin WINDOWS) */ # if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) # ifndef PNGAPI # define PNGAPI _System # endif # else -# if 0 /* ... other platforms, with other meanings */ +# if 0 /* ... other platforms, with other meanings */ # endif # endif #endif @@ -1357,25 +1358,25 @@ typedef z_stream FAR *png_zstreamp; (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) #endif -#if defined(USE_FAR_KEYWORD) /* memory model independent fns */ +#if defined(USE_FAR_KEYWORD) /* memory model independent fns */ /* use this to make far-to-near assignments */ # define CHECK 1 # define NOCHECK 0 # define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) # define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) # define png_strcpy _fstrcpy -# define png_strncpy _fstrncpy /* Added to v 1.2.6 */ +# define png_strncpy _fstrncpy /* Added to v 1.2.6 */ # define png_strlen _fstrlen -# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcmp _fmemcmp /* SJT: added */ # define png_memcpy _fmemcpy # define png_memset _fmemset #else /* use the usual functions */ # define CVT_PTR(ptr) (ptr) # define CVT_PTR_NOCHECK(ptr) (ptr) # define png_strcpy strcpy -# define png_strncpy strncpy /* Added to v 1.2.6 */ +# define png_strncpy strncpy /* Added to v 1.2.6 */ # define png_strlen strlen -# define png_memcmp memcmp /* SJT: added */ +# define png_memcmp memcmp /* SJT: added */ # define png_memcpy memcpy # define png_memset memset #endif @@ -1400,10 +1401,10 @@ typedef z_stream FAR *png_zstreamp; */ #ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT -# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */ +# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */ #endif #ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT -# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */ +# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */ #endif /* Set this in the makefile for VC++ on Pentium, not here. */ diff --git a/com32/include/string.h b/com32/include/string.h index c964ee3b..af9792b6 100644 --- a/com32/include/string.h +++ b/com32/include/string.h @@ -23,7 +23,6 @@ __extern char *strcat(char *, const char *); __extern char *strchr(const char *, int); __extern int strcmp(const char *, const char *); __extern char *strcpy(char *, const char *); -__extern char *strpcpy(char *, const char *); __extern size_t strcspn(const char *, const char *); __extern char *strdup(const char *); __extern char *strndup(const char *, size_t); diff --git a/com32/include/sys/dirent.h b/com32/include/sys/dirent.h new file mode 100644 index 00000000..cc2916e1 --- /dev/null +++ b/com32/include/sys/dirent.h @@ -0,0 +1,30 @@ +/* + * sys/dirent.h + */ + +#ifndef DIRENT_H +#define DIRENT_H + +#include <stdint.h> + +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +struct dirent { + uint32_t d_ino; + uint32_t d_off; + uint16_t d_reclen; + uint16_t d_type; + char d_name[NAME_MAX + 1]; +}; + +struct file; + +typedef struct { + struct file *dd_dir; +} DIR; + +#define DIR_REC_LEN(name) (12 + strlen(name) + 1 + 3) & ~3 + +#endif /* sys/dirent.h */ diff --git a/com32/include/sys/pci.h b/com32/include/sys/pci.h index 2c6b5158..aba1f965 100644 --- a/com32/include/sys/pci.h +++ b/com32/include/sys/pci.h @@ -17,8 +17,9 @@ typedef uint32_t pciaddr_t; enum { - ENOPCIIDS = 100, - ENOMODULESPCIMAP + ENOPCIIDS = 100, + ENOMODULESPCIMAP, + ENOMODULESALIAS }; /* a structure for extended pci information */ @@ -145,9 +146,8 @@ void free_pci_domain(struct pci_domain *domain); struct match *find_pci_device(const struct pci_domain *pci_domain, struct match *list); int get_name_from_pci_ids(struct pci_domain *pci_domain, char *pciids_path); -int get_module_name_from_pcimap(struct pci_domain *pci_domain, - char *modules_pcimap_path); -int get_class_name_from_pci_ids(struct pci_domain *pci_domain, - char *pciids_path); +int get_module_name_from_pcimap(struct pci_domain *pci_domain, char *modules_pcimap_path); +int get_module_name_from_alias(struct pci_domain *pci_domain, char *modules_alias_path); +int get_class_name_from_pci_ids(struct pci_domain *pci_domain, char *pciids_path); void gather_additional_pci_config(struct pci_domain *domain); #endif /* _SYS_PCI_H */ diff --git a/com32/include/syslinux/pxe.h b/com32/include/syslinux/pxe.h index 037642bc..041e0ae1 100644 --- a/com32/include/syslinux/pxe.h +++ b/com32/include/syslinux/pxe.h @@ -34,493 +34,10 @@ #ifndef _SYSLINUX_PXE_H #define _SYSLINUX_PXE_H -#include <stdint.h> -#include <netinet/in.h> -#include <klibc/compiler.h> - -/* PXE spec structures and definitions. These mostly follow the PXE - spec, except when the PXE spec is unnecessarily stupid. Of course, - that is most of the time. */ - -/* Basic types; use Unix-like _t convention instead of SCREAMING; also - re-use types we already have, like in_addr_t. */ - -typedef uint16_t pxenv_status_t; - -#define MAC_ADDR_LEN 16 -typedef uint8_t mac_addr_t[MAC_ADDR_LEN]; - -/* "Protected mode segment descriptor" according to PXE... */ -typedef struct { - uint16_t segaddr; - uint32_t physaddr; - uint16_t segsize; -} __packed pxe_segdesc_t; - -typedef struct { - uint16_t offs; - uint16_t seg; -} segoff16_t; - -typedef struct { - uint8_t opcode; -#define BOOTP_REQ 1 -#define BOOTP_REP 2 - uint8_t Hardware; - uint8_t Hardlen; - uint8_t Gatehops; - uint32_t ident; - uint16_t seconds; - uint16_t Flags; -#define BOOTP_BCAST 0x8000 - in_addr_t cip; /* Client IP address */ - in_addr_t yip; /* You IP address */ - in_addr_t sip; /* next server IP address */ - in_addr_t gip; /*relay agent IP address */ - mac_addr_t CAddr; - uint8_t Sname[64]; - uint8_t bootfile[128]; - union { -#define BOOTP_DHCPVEND 1024 - uint8_t d[BOOTP_DHCPVEND]; - struct { - uint8_t magic[4]; -#define VM_RFC1048 0x63825363L - uint32_t flags; - uint8_t pad[56]; - } v; - } vendor; -} __packed pxe_bootp_t; - -/* Function calling structures and constants */ - -typedef struct s_PXENV_GET_CACHED_INFO { - pxenv_status_t Status; - uint16_t PacketType; -#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 -#define PXENV_PACKET_TYPE_DHCP_ACK 2 -#define PXENV_PACKET_TYPE_CACHED_REPLY 3 - uint16_t BufferSize; - segoff16_t Buffer; - uint16_t BufferLimit; -} __packed t_PXENV_GET_CACHED_INFO; - -typedef struct s_PXENV_START_UNDI { - pxenv_status_t Status; - uint16_t AX; - uint16_t BX; - uint16_t DX; - uint16_t DI; - uint16_t ES; -} __packed t_PXENV_START_UNDI; - -typedef struct s_PXENV_STOP_UNDI { - pxenv_status_t Status; -} __packed t_PXENV_STOP_UNDI; - -typedef struct s_PXENV_START_BASE { - pxenv_status_t Status; -} __packed t_PXENV_START_BASE; - -typedef struct s_PXENV_STOP_BASE { - pxenv_status_t Status; -} __packed t_PXENV_STOP_BASE; - -typedef struct s_PXENV_TFTP_OPEN { - pxenv_status_t Status; - in_addr_t ServerIPAddress; - in_addr_t GatewayIPAddress; - uint8_t FileName[128]; - in_port_t TFTPPort; - uint16_t PacketSize; -} __packed t_PXENV_TFTP_OPEN; - -typedef struct s_PXENV_TFTP_CLOSE { - pxenv_status_t Status; -} __packed t_PXENV_TFTP_CLOSE; - -typedef struct s_PXENV_TFTP_READ { - pxenv_status_t Status; - uint16_t PacketNumber; - uint16_t BufferSize; - segoff16_t Buffer; -} __packed t_PXENV_TFTP_READ; - -typedef struct s_PXENV_TFTP_READ_FILE { - pxenv_status_t Status; - uint8_t FileName[128]; - uint32_t BufferSize; - void *Buffer; - in_addr_t ServerIPAddress; - in_addr_t GatewayIPAddress; - in_addr_t McastIPAddress; - in_port_t TFTPClntPort; - in_port_t TFTPSrvPort; - uint16_t TFTPOpenTimeOut; - uint16_t TFTPReopenDelay; -} __packed t_PXENV_TFTP_READ_FILE; - -typedef struct s_PXENV_TFTP_GET_FSIZE { - pxenv_status_t Status; - in_addr_t ServerIPAddress; - in_addr_t GatewayIPAddress; - uint8_t FileName[128]; - uint32_t FileSize; -} __packed t_PXENV_TFTP_GET_FSIZE; - -typedef struct s_PXENV_UDP_OPEN { - pxenv_status_t status; - in_addr_t src_ip; -} __packed t_PXENV_UDP_OPEN; - -typedef struct s_PXENV_UDP_CLOSE { - pxenv_status_t status; -} __packed t_PXENV_UDP_CLOSE; - -typedef struct s_PXENV_UDP_WRITE { - pxenv_status_t status; - in_addr_t ip; - in_addr_t gw; - in_port_t src_port; - in_port_t dst_port; - uint16_t buffer_size; - segoff16_t buffer; -} __packed t_PXENV_UDP_WRITE; - -typedef struct s_PXENV_UDP_READ { - pxenv_status_t status; - in_addr_t src_ip; - in_addr_t dest_ip; - in_port_t s_port; - in_port_t d_port; - uint16_t buffer_size; - segoff16_t buffer; -} __packed t_PXENV_UDP_READ; - -typedef struct s_PXENV_UNDI_STARTUP { - pxenv_status_t Status; -} __packed t_PXENV_UNDI_STARTUP; - -typedef struct s_PXENV_UNDI_CLEANUP { - pxenv_status_t Status; -} __packed t_PXENV_UNDI_CLEANUP; - -typedef struct s_PXENV_UNDI_INITIALIZE { - pxenv_status_t Status; - void *ProtocolIni; - uint8_t reserved[8]; -} __packed t_PXENV_UNDI_INITIALIZE; - -#define MAXNUM_MCADDR 8 -typedef struct s_PXENV_UNDI_MCAST_ADDRESS { - uint16_t MCastAddrCount; - mac_addr_t McastAddr[MAXNUM_MCADDR]; -} __packed t_PXENV_UNDI_MCAST_ADDRESS; - -typedef struct s_PXENV_UNDI_RESET { - pxenv_status_t Status; - t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} __packed t_PXENV_UNDI_RESET; - -typedef struct s_PXENV_UNDI_SHUTDOWN { - pxenv_status_t Status; -} __packed t_PXENV_UNDI_SHUTDOWN; - -typedef struct s_PXENV_UNDI_OPEN { - pxenv_status_t Status; - uint16_t OpenFlag; - uint16_t PktFilter; -#define FLTR_DIRECTED 0x0001 -#define FLTR_BRDCST 0x0002 -#define FLTR_PRMSCS 0x0004 -#define FLTR_SRC_RTG 0x0008 - t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} __packed t_PXENV_UNDI_OPEN; - -typedef struct s_PXENV_UNDI_CLOSE { - pxenv_status_t Status; -} __packed t_PXENV_UNDI_CLOSE; - -typedef struct s_PXENV_UNDI_TRANSMIT { - pxenv_status_t Status; - uint8_t Protocol; -#define P_UNKNOWN 0 -#define P_IP 1 -#define P_ARP 2 -#define P_RARP 3 - uint8_t XmitFlag; -#define XMT_DESTADDR 0x0000 -#define XMT_BROADCAST 0x0001 - segoff16_t DestAddr; - segoff16_t TBD; - uint32_t Reserved[2]; -} __packed t_PXENV_UNDI_TRANSMIT; -#define MAX_DATA_BLKS 8 -typedef struct s_PXENV_UNDI_TBD { - uint16_t ImmedLength; - segoff16_t Xmit; - uint16_t DataBlkCount; - struct DataBlk { - uint8_t TDPtrType; - uint8_t TDRsvdByte; - uint16_t TDDataLen; - segoff16_t TDDataPtr; - } DataBlock[MAX_DATA_BLKS]; -} __packed t_PXENV_UNDI_TBD; - -typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS { - pxenv_status_t Status; - t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} __packed t_PXENV_UNDI_SET_MCAST_ADDR; - -typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS { - pxenv_status_t Status; - mac_addr_t StationAddress; -} __packed t_PXENV_UNDI_SET_STATION_ADDR; - -typedef struct s_PXENV_UNDI_SET_PACKET_FILTER { - pxenv_status_t Status; - uint8_t filter; -} __packed t_PXENV_UNDI_SET_PACKET_FILTER; - -typedef struct s_PXENV_UNDI_GET_INFORMATION { - pxenv_status_t Status; - uint16_t BaseIo; - uint16_t IntNumber; - uint16_t MaxTranUnit; - uint16_t HwType; -#define ETHER_TYPE 1 -#define EXP_ETHER_TYPE 2 -#define IEEE_TYPE 6 -#define ARCNET_TYPE 7 - uint16_t HwAddrLen; - mac_addr_t CurrentNodeAddress; - mac_addr_t PermNodeAddress; - uint16_t ROMAddress; - uint16_t RxBufCt; - uint16_t TxBufCt; -} __packed t_PXENV_UNDI_GET_INFORMATION; - -typedef struct s_PXENV_UNDI_GET_STATISTICS { - pxenv_status_t Status; - uint32_t XmtGoodFrames; - uint32_t RcvGoodFrames; - uint32_t RcvCRCErrors; - uint32_t RcvResourceErrors; -} __packed t_PXENV_UNDI_GET_STATISTICS; - -typedef struct s_PXENV_UNDI_CLEAR_STATISTICS { - pxenv_status_t Status; -} __packed t_PXENV_UNDI_CLEAR_STATISTICS; - -typedef struct s_PXENV_UNDI_INITIATE_DIAGS { - pxenv_status_t Status; -} __packed t_PXENV_UNDI_INITIATE_DIAGS; - -typedef struct s_PXENV_UNDI_FORCE_INTERRUPT { - pxenv_status_t Status; -} __packed t_PXENV_UNDI_FORCE_INTERRUPT; - -typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS { - pxenv_status_t Status; - in_addr_t InetAddr; - mac_addr_t MediaAddr; -} __packed t_PXENV_UNDI_GET_MCAST_ADDR; - -typedef struct s_PXENV_UNDI_GET_NIC_TYPE { - pxenv_status_t Status; - uint8_t NicType; -#define PCI_NIC 2 -#define PnP_NIC 3 -#define CardBus_NIC 4 - union { - struct { - uint16_t Vendor_ID; - uint16_t Dev_ID; - uint8_t Base_Class; - uint8_t Sub_Class; - uint8_t Prog_Intf; - uint8_t Rev; - uint16_t BusDevFunc; - uint16_t SubVendor_ID; - uint16_t SubDevice_ID; - } pci, cardbus; - struct { - uint32_t EISA_Dev_ID; - uint8_t Base_Class; - uint8_t Sub_Class; - uint8_t Prog_Intf; - uint16_t CardSelNum; - } __packed pnp; - } __packed info; -} __packed t_PXENV_UNDI_GET_NIC_TYPE; - -typedef struct s_PXENV_UNDI_GET_IFACE_INFO { - pxenv_status_t Status; - uint8_t IfaceType[16]; - uint32_t LinkSpeed; - uint32_t ServiceFlags; - uint32_t Reserved[4]; -} __packed t_PXENV_UNDI_GET_NDIS_INFO; - -typedef struct s_PXENV_UNDI_GET_STATE { -#define PXE_UNDI_GET_STATE_STARTED 1 -#define PXE_UNDI_GET_STATE_INITIALIZED 2 -#define PXE_UNDI_GET_STATE_OPENED 3 - pxenv_status_t Status; - uint8_t UNDIstate; -} __packed t_PXENV_UNDI_GET_STATE; - -typedef struct s_PXENV_UNDI_ISR { - pxenv_status_t Status; - uint16_t FuncFlag; - uint16_t BufferLength; - uint16_t FrameLength; - uint16_t FrameHeaderLength; - segoff16_t Frame; - uint8_t ProtType; - uint8_t PktType; -} __packed t_PXENV_UNDI_ISR; -#define PXENV_UNDI_ISR_IN_START 1 -#define PXENV_UNDI_ISR_IN_PROCESS 2 -#define PXENV_UNDI_ISR_IN_GET_NEXT 3 -/* One of these will be returned for - PXENV_UNDI_ISR_IN_START */ -#define PXENV_UNDI_ISR_OUT_OURS 0 -#define PXENV_UNDI_USR_OUT_NOT_OURS 1 -/* One of these will be returned for - PXENV_UNDI_ISR_IN_PROCESS and - PXENV_UNDI_ISR_IN_GET_NEXT */ -#define PXENV_UNDI_ISR_OUT_DONE 0 -#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 -#define PXENV_UNDI_ISR_OUT_RECEIVE 3 -#define PXENV_UNDI_ISR_OUT_BUSY 4 - -/* Function numbers and error codes */ - -#define PXENV_TFTP_OPEN 0x0020 -#define PXENV_TFTP_CLOSE 0x0021 -#define PXENV_TFTP_READ 0x0022 -#define PXENV_TFTP_READ_FILE 0x0023 -#define PXENV_TFTP_READ_FILE_PMODE 0x0024 -#define PXENV_TFTP_GET_FSIZE 0x0025 - -#define PXENV_UDP_OPEN 0x0030 -#define PXENV_UDP_CLOSE 0x0031 -#define PXENV_UDP_READ 0x0032 -#define PXENV_UDP_WRITE 0x0033 - -#define PXENV_START_UNDI 0x0000 -#define PXENV_UNDI_STARTUP 0x0001 -#define PXENV_UNDI_CLEANUP 0x0002 -#define PXENV_UNDI_INITIALIZE 0x0003 -#define PXENV_UNDI_RESET_NIC 0x0004 -#define PXENV_UNDI_SHUTDOWN 0x0005 -#define PXENV_UNDI_OPEN 0x0006 -#define PXENV_UNDI_CLOSE 0x0007 -#define PXENV_UNDI_TRANSMIT 0x0008 -#define PXENV_UNDI_SET_MCAST_ADDR 0x0009 -#define PXENV_UNDI_SET_STATION_ADDR 0x000A -#define PXENV_UNDI_SET_PACKET_FILTER 0x000B -#define PXENV_UNDI_GET_INFORMATION 0x000C -#define PXENV_UNDI_GET_STATISTICS 0x000D -#define PXENV_UNDI_CLEAR_STATISTICS 0x000E -#define PXENV_UNDI_INITIATE_DIAGS 0x000F -#define PXENV_UNDI_FORCE_INTERRUPT 0x0010 -#define PXENV_UNDI_GET_MCAST_ADDR 0x0011 -#define PXENV_UNDI_GET_NIC_TYPE 0x0012 -#define PXENV_UNDI_GET_IFACE_INFO 0x0013 -#define PXENV_UNDI_ISR 0x0014 -#define PXENV_STOP_UNDI 0x0015 /* Overlap...? */ -#define PXENV_UNDI_GET_STATE 0x0015 /* Overlap...? */ - -#define PXENV_UNLOAD_STACK 0x0070 -#define PXENV_GET_CACHED_INFO 0x0071 -#define PXENV_RESTART_DHCP 0x0072 -#define PXENV_RESTART_TFTP 0x0073 -#define PXENV_MODE_SWITCH 0x0074 -#define PXENV_START_BASE 0x0075 -#define PXENV_STOP_BASE 0x0076 - -#define PXENV_EXIT_SUCCESS 0x0000 -#define PXENV_EXIT_FAILURE 0x0001 - -#define PXENV_STATUS_SUCCESS 0x00 -#define PXENV_STATUS_FAILURE 0x01 -#define PXENV_STATUS_BAD_FUNC 0x02 -#define PXENV_STATUS_UNSUPPORTED 0x03 -#define PXENV_STATUS_KEEP_UNDI 0x04 -#define PXENV_STATUS_KEEP_ALL 0x05 -#define PXENV_STATUS_OUT_OF_RESOURCES 0x06 -#define PXENV_STATUS_ARP_TIMEOUT 0x11 -#define PXENV_STATUS_UDP_CLOSED 0x18 -#define PXENV_STATUS_UDP_OPEN 0x19 -#define PXENV_STATUS_TFTP_CLOSED 0x1A -#define PXENV_STATUS_TFTP_OPEN 0x1B -#define PXENV_STATUS_MCOPY_PROBLEM 0x20 -#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21 -#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22 -#define PXENV_STATUS_BIS_INIT_FAILURE 0x23 -#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24 -#define PXENV_STATUS_BIS_GBOA_FAILURE 0x25 -#define PXENV_STATUS_BIS_FREE_FAILURE 0x26 -#define PXENV_STATUS_BIS_GSI_FAILURE 0x27 -#define PXENV_STATUS_BIS_BAD_CKSUM 0x28 -#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30 -#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32 - -#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33 -#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35 -#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36 -#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38 -#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39 -#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3A -#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3B -#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3C -#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3D -#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3E -#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3F -#define PXENV_STATUS_DHCP_TIMEOUT 0x51 -#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52 -#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53 -#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54 -#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60 -#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61 -#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62 -#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63 -#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64 -#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65 -#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66 -#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67 -#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68 -#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69 -#define PXENV_STATUS_UNDI_INVALID_STATE 0x6A -#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6B -#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6C -#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74 -#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76 -#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77 -#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78 -#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79 -#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xA0 -#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xA1 -#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xA2 -#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xA3 -#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xB0 -#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xC0 -#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xC1 -#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xC2 -#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xC3 -#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xC4 -#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xC5 -#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xC6 -#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xC8 -#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xC9 -#define PXENV_STATUS_LOADER_UNDI_START 0xCA -#define PXENV_STATUS_LOADER_BC_START 0xCB +#include <syslinux/pxe_api.h> /* SYSLINUX-defined PXE utility functions */ -int pxe_get_cached_info(int level, void **buf, size_t * len); +int pxe_get_cached_info(int level, void **buf, size_t *len); int pxe_get_nic_type(t_PXENV_UNDI_GET_NIC_TYPE * gnt); #endif /* _SYSLINUX_PXE_H */ diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h new file mode 100644 index 00000000..fcc4f873 --- /dev/null +++ b/com32/include/syslinux/pxe_api.h @@ -0,0 +1,566 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux/pxe_api.h + * + * PXE type and constant definitions for SYSLINUX + */ + +#ifndef _SYSLINUX_PXE_API_H +#define _SYSLINUX_PXE_API_H + +#include <stdint.h> +#include <netinet/in.h> +#include <klibc/compiler.h> +#include <com32.h> + +/* PXE spec structures and definitions. These mostly follow the PXE + spec, except when the PXE spec is unnecessarily stupid. Of course, + that is most of the time. */ + +/* Basic types; use Unix-like _t convention instead of SCREAMING; also + re-use types we already have, like in_addr_t. */ + +typedef uint16_t pxenv_status_t; + +#define MAC_ADDR_LEN 16 +typedef uint8_t mac_addr_t[MAC_ADDR_LEN]; + +/* "Protected mode segment descriptor" according to PXE... */ +typedef struct { + uint16_t sel; + uint32_t base; + uint16_t size; +} __packed pxe_segdesc_t; + +typedef far_ptr_t segoff16_t; + +typedef struct { + uint8_t opcode; +#define BOOTP_REQ 1 +#define BOOTP_REP 2 + uint8_t Hardware; + uint8_t Hardlen; + uint8_t Gatehops; + uint32_t ident; + uint16_t seconds; + uint16_t Flags; +#define BOOTP_BCAST 0x8000 + in_addr_t cip; /* Client IP address */ + in_addr_t yip; /* You IP address */ + in_addr_t sip; /* next server IP address */ + in_addr_t gip; /*relay agent IP address */ + mac_addr_t CAddr; + uint8_t Sname[64]; + uint8_t bootfile[128]; + union { +#define BOOTP_DHCPVEND 1024 + uint8_t d[BOOTP_DHCPVEND]; + struct { + uint8_t magic[4]; +#define VM_RFC1048 0x63825363L + uint32_t flags; + uint8_t pad[56]; + } v; + } vendor; +} __packed pxe_bootp_t; + +/* Function calling structures and constants */ + +typedef struct s_PXENV_GET_CACHED_INFO { + pxenv_status_t Status; + uint16_t PacketType; +#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 +#define PXENV_PACKET_TYPE_DHCP_ACK 2 +#define PXENV_PACKET_TYPE_CACHED_REPLY 3 + uint16_t BufferSize; + segoff16_t Buffer; + uint16_t BufferLimit; +} __packed t_PXENV_GET_CACHED_INFO; + +typedef struct s_PXENV_START_UNDI { + pxenv_status_t Status; + uint16_t AX; + uint16_t BX; + uint16_t DX; + uint16_t DI; + uint16_t ES; +} __packed t_PXENV_START_UNDI; + +typedef struct s_PXENV_STOP_UNDI { + pxenv_status_t Status; +} __packed t_PXENV_STOP_UNDI; + +typedef struct s_PXENV_START_BASE { + pxenv_status_t Status; +} __packed t_PXENV_START_BASE; + +typedef struct s_PXENV_STOP_BASE { + pxenv_status_t Status; +} __packed t_PXENV_STOP_BASE; + +typedef struct s_PXENV_TFTP_OPEN { + pxenv_status_t Status; + in_addr_t ServerIPAddress; + in_addr_t GatewayIPAddress; + uint8_t FileName[128]; + in_port_t TFTPPort; + uint16_t PacketSize; +} __packed t_PXENV_TFTP_OPEN; + +typedef struct s_PXENV_TFTP_CLOSE { + pxenv_status_t Status; +} __packed t_PXENV_TFTP_CLOSE; + +typedef struct s_PXENV_TFTP_READ { + pxenv_status_t Status; + uint16_t PacketNumber; + uint16_t BufferSize; + segoff16_t Buffer; +} __packed t_PXENV_TFTP_READ; + +typedef struct s_PXENV_TFTP_READ_FILE { + pxenv_status_t Status; + uint8_t FileName[128]; + uint32_t BufferSize; + void *Buffer; + in_addr_t ServerIPAddress; + in_addr_t GatewayIPAddress; + in_addr_t McastIPAddress; + in_port_t TFTPClntPort; + in_port_t TFTPSrvPort; + uint16_t TFTPOpenTimeOut; + uint16_t TFTPReopenDelay; +} __packed t_PXENV_TFTP_READ_FILE; + +typedef struct s_PXENV_TFTP_GET_FSIZE { + pxenv_status_t Status; + in_addr_t ServerIPAddress; + in_addr_t GatewayIPAddress; + uint8_t FileName[128]; + uint32_t FileSize; +} __packed t_PXENV_TFTP_GET_FSIZE; + +typedef struct s_PXENV_UDP_OPEN { + pxenv_status_t status; + in_addr_t src_ip; +} __packed t_PXENV_UDP_OPEN; + +typedef struct s_PXENV_UDP_CLOSE { + pxenv_status_t status; +} __packed t_PXENV_UDP_CLOSE; + +typedef struct s_PXENV_UDP_WRITE { + pxenv_status_t status; + in_addr_t ip; + in_addr_t gw; + in_port_t src_port; + in_port_t dst_port; + uint16_t buffer_size; + segoff16_t buffer; +} __packed t_PXENV_UDP_WRITE; + +typedef struct s_PXENV_UDP_READ { + pxenv_status_t status; + in_addr_t src_ip; + in_addr_t dest_ip; + in_port_t s_port; + in_port_t d_port; + uint16_t buffer_size; + segoff16_t buffer; +} __packed t_PXENV_UDP_READ; + +typedef struct s_PXENV_UNDI_STARTUP { + pxenv_status_t Status; +} __packed t_PXENV_UNDI_STARTUP; + +typedef struct s_PXENV_UNDI_CLEANUP { + pxenv_status_t Status; +} __packed t_PXENV_UNDI_CLEANUP; + +typedef struct s_PXENV_UNDI_INITIALIZE { + pxenv_status_t Status; + void *ProtocolIni; + uint8_t reserved[8]; +} __packed t_PXENV_UNDI_INITIALIZE; + +#define MAXNUM_MCADDR 8 +typedef struct s_PXENV_UNDI_MCAST_ADDRESS { + uint16_t MCastAddrCount; + mac_addr_t McastAddr[MAXNUM_MCADDR]; +} __packed t_PXENV_UNDI_MCAST_ADDRESS; + +typedef struct s_PXENV_UNDI_RESET { + pxenv_status_t Status; + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} __packed t_PXENV_UNDI_RESET; + +typedef struct s_PXENV_UNDI_SHUTDOWN { + pxenv_status_t Status; +} __packed t_PXENV_UNDI_SHUTDOWN; + +typedef struct s_PXENV_UNDI_OPEN { + pxenv_status_t Status; + uint16_t OpenFlag; + uint16_t PktFilter; +#define FLTR_DIRECTED 0x0001 +#define FLTR_BRDCST 0x0002 +#define FLTR_PRMSCS 0x0004 +#define FLTR_SRC_RTG 0x0008 + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} __packed t_PXENV_UNDI_OPEN; + +typedef struct s_PXENV_UNDI_CLOSE { + pxenv_status_t Status; +} __packed t_PXENV_UNDI_CLOSE; + +typedef struct s_PXENV_UNDI_TRANSMIT { + pxenv_status_t Status; + uint8_t Protocol; +#define P_UNKNOWN 0 +#define P_IP 1 +#define P_ARP 2 +#define P_RARP 3 + uint8_t XmitFlag; +#define XMT_DESTADDR 0x0000 +#define XMT_BROADCAST 0x0001 + segoff16_t DestAddr; + segoff16_t TBD; + uint32_t Reserved[2]; +} __packed t_PXENV_UNDI_TRANSMIT; +#define MAX_DATA_BLKS 8 +typedef struct s_PXENV_UNDI_TBD { + uint16_t ImmedLength; + segoff16_t Xmit; + uint16_t DataBlkCount; + struct DataBlk { + uint8_t TDPtrType; + uint8_t TDRsvdByte; + uint16_t TDDataLen; + segoff16_t TDDataPtr; + } DataBlock[MAX_DATA_BLKS]; +} __packed t_PXENV_UNDI_TBD; + +typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS { + pxenv_status_t Status; + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} __packed t_PXENV_UNDI_SET_MCAST_ADDR; + +typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS { + pxenv_status_t Status; + mac_addr_t StationAddress; +} __packed t_PXENV_UNDI_SET_STATION_ADDR; + +typedef struct s_PXENV_UNDI_SET_PACKET_FILTER { + pxenv_status_t Status; + uint8_t filter; +} __packed t_PXENV_UNDI_SET_PACKET_FILTER; + +typedef struct s_PXENV_UNDI_GET_INFORMATION { + pxenv_status_t Status; + uint16_t BaseIo; + uint16_t IntNumber; + uint16_t MaxTranUnit; + uint16_t HwType; +#define ETHER_TYPE 1 +#define EXP_ETHER_TYPE 2 +#define IEEE_TYPE 6 +#define ARCNET_TYPE 7 + uint16_t HwAddrLen; + mac_addr_t CurrentNodeAddress; + mac_addr_t PermNodeAddress; + uint16_t ROMAddress; + uint16_t RxBufCt; + uint16_t TxBufCt; +} __packed t_PXENV_UNDI_GET_INFORMATION; + +typedef struct s_PXENV_UNDI_GET_STATISTICS { + pxenv_status_t Status; + uint32_t XmtGoodFrames; + uint32_t RcvGoodFrames; + uint32_t RcvCRCErrors; + uint32_t RcvResourceErrors; +} __packed t_PXENV_UNDI_GET_STATISTICS; + +typedef struct s_PXENV_UNDI_CLEAR_STATISTICS { + pxenv_status_t Status; +} __packed t_PXENV_UNDI_CLEAR_STATISTICS; + +typedef struct s_PXENV_UNDI_INITIATE_DIAGS { + pxenv_status_t Status; +} __packed t_PXENV_UNDI_INITIATE_DIAGS; + +typedef struct s_PXENV_UNDI_FORCE_INTERRUPT { + pxenv_status_t Status; +} __packed t_PXENV_UNDI_FORCE_INTERRUPT; + +typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS { + pxenv_status_t Status; + in_addr_t InetAddr; + mac_addr_t MediaAddr; +} __packed t_PXENV_UNDI_GET_MCAST_ADDR; + +typedef struct s_PXENV_UNDI_GET_NIC_TYPE { + pxenv_status_t Status; + uint8_t NicType; +#define PCI_NIC 2 +#define PnP_NIC 3 +#define CardBus_NIC 4 + union { + struct { + uint16_t Vendor_ID; + uint16_t Dev_ID; + uint8_t Base_Class; + uint8_t Sub_Class; + uint8_t Prog_Intf; + uint8_t Rev; + uint16_t BusDevFunc; + uint16_t SubVendor_ID; + uint16_t SubDevice_ID; + } pci, cardbus; + struct { + uint32_t EISA_Dev_ID; + uint8_t Base_Class; + uint8_t Sub_Class; + uint8_t Prog_Intf; + uint16_t CardSelNum; + } __packed pnp; + } __packed info; +} __packed t_PXENV_UNDI_GET_NIC_TYPE; + +typedef struct s_PXENV_UNDI_GET_IFACE_INFO { + pxenv_status_t Status; + uint8_t IfaceType[16]; + uint32_t LinkSpeed; + uint32_t ServiceFlags; + uint32_t Reserved[4]; +} __packed t_PXENV_UNDI_GET_NDIS_INFO; + +typedef struct s_PXENV_UNDI_GET_STATE { +#define PXE_UNDI_GET_STATE_STARTED 1 +#define PXE_UNDI_GET_STATE_INITIALIZED 2 +#define PXE_UNDI_GET_STATE_OPENED 3 + pxenv_status_t Status; + uint8_t UNDIstate; +} __packed t_PXENV_UNDI_GET_STATE; + +typedef struct s_PXENV_UNDI_ISR { + pxenv_status_t Status; + uint16_t FuncFlag; + uint16_t BufferLength; + uint16_t FrameLength; + uint16_t FrameHeaderLength; + segoff16_t Frame; + uint8_t ProtType; + uint8_t PktType; +} __packed t_PXENV_UNDI_ISR; + +typedef struct s_PXENV_FILE_API_CHECK { + pxenv_status_t Status; + uint16_t Size; + uint32_t Magic; + uint32_t Provider; + uint32_t APIMask; + uint32_t Flags; +} __packed t_PXENV_FILE_API_CHECK; + +typedef struct s_PXENV_FILE_READ { + pxenv_status_t Status; + uint16_t FileHandle; + uint16_t BufferSize; + segoff16_t Buffer; +} __packed t_PXENV_FILE_READ; + +typedef struct s_PXENV_FILE_OPEN { + pxenv_status_t Status; + uint16_t FileHandle; + segoff16_t FileName; + uint32_t Reserved; +} __packed t_PXENV_FILE_OPEN; + +typedef struct s_PXENV_GET_FILE_SIZE { + pxenv_status_t Status; + uint16_t FileHandle; + uint32_t FileSize; +} __packed t_PXENV_GET_FILE_SIZE; + +typedef struct s_PXENV_UNLOAD_STACK { + pxenv_status_t Status; + uint8_t reserved[10]; +} __packed t_PXENV_UNLOAD_STACK; + +#define PXENV_UNDI_ISR_IN_START 1 +#define PXENV_UNDI_ISR_IN_PROCESS 2 +#define PXENV_UNDI_ISR_IN_GET_NEXT 3 +/* One of these will be returned for + PXENV_UNDI_ISR_IN_START */ +#define PXENV_UNDI_ISR_OUT_OURS 0 +#define PXENV_UNDI_USR_OUT_NOT_OURS 1 +/* One of these will be returned for + PXENV_UNDI_ISR_IN_PROCESS and + PXENV_UNDI_ISR_IN_GET_NEXT */ +#define PXENV_UNDI_ISR_OUT_DONE 0 +#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 +#define PXENV_UNDI_ISR_OUT_RECEIVE 3 +#define PXENV_UNDI_ISR_OUT_BUSY 4 + +/* Function numbers and error codes */ + +#define PXENV_TFTP_OPEN 0x0020 +#define PXENV_TFTP_CLOSE 0x0021 +#define PXENV_TFTP_READ 0x0022 +#define PXENV_TFTP_READ_FILE 0x0023 +#define PXENV_TFTP_READ_FILE_PMODE 0x0024 +#define PXENV_TFTP_GET_FSIZE 0x0025 + +#define PXENV_UDP_OPEN 0x0030 +#define PXENV_UDP_CLOSE 0x0031 +#define PXENV_UDP_READ 0x0032 +#define PXENV_UDP_WRITE 0x0033 + +#define PXENV_START_UNDI 0x0000 +#define PXENV_UNDI_STARTUP 0x0001 +#define PXENV_UNDI_CLEANUP 0x0002 +#define PXENV_UNDI_INITIALIZE 0x0003 +#define PXENV_UNDI_RESET_NIC 0x0004 +#define PXENV_UNDI_SHUTDOWN 0x0005 +#define PXENV_UNDI_OPEN 0x0006 +#define PXENV_UNDI_CLOSE 0x0007 +#define PXENV_UNDI_TRANSMIT 0x0008 +#define PXENV_UNDI_SET_MCAST_ADDR 0x0009 +#define PXENV_UNDI_SET_STATION_ADDR 0x000A +#define PXENV_UNDI_SET_PACKET_FILTER 0x000B +#define PXENV_UNDI_GET_INFORMATION 0x000C +#define PXENV_UNDI_GET_STATISTICS 0x000D +#define PXENV_UNDI_CLEAR_STATISTICS 0x000E +#define PXENV_UNDI_INITIATE_DIAGS 0x000F +#define PXENV_UNDI_FORCE_INTERRUPT 0x0010 +#define PXENV_UNDI_GET_MCAST_ADDR 0x0011 +#define PXENV_UNDI_GET_NIC_TYPE 0x0012 +#define PXENV_UNDI_GET_IFACE_INFO 0x0013 +#define PXENV_UNDI_ISR 0x0014 +#define PXENV_STOP_UNDI 0x0015 /* Overlap...? */ +#define PXENV_UNDI_GET_STATE 0x0015 /* Overlap...? */ + +#define PXENV_UNLOAD_STACK 0x0070 +#define PXENV_GET_CACHED_INFO 0x0071 +#define PXENV_RESTART_DHCP 0x0072 +#define PXENV_RESTART_TFTP 0x0073 +#define PXENV_MODE_SWITCH 0x0074 +#define PXENV_START_BASE 0x0075 +#define PXENV_STOP_BASE 0x0076 + +/* gPXE extensions... */ +#define PXENV_FILE_OPEN 0x00e0 +#define PXENV_FILE_CLOSE 0x00e1 +#define PXENV_FILE_SELECT 0x00e2 +#define PXENV_FILE_READ 0x00e3 +#define PXENV_GET_FILE_SIZE 0x00e4 +#define PXENV_FILE_EXEC 0x00e5 +#define PXENV_FILE_API_CHECK 0x00e6 + +/* Exit codes */ +#define PXENV_EXIT_SUCCESS 0x0000 +#define PXENV_EXIT_FAILURE 0x0001 + +/* Status codes */ +#define PXENV_STATUS_SUCCESS 0x00 +#define PXENV_STATUS_FAILURE 0x01 +#define PXENV_STATUS_BAD_FUNC 0x02 +#define PXENV_STATUS_UNSUPPORTED 0x03 +#define PXENV_STATUS_KEEP_UNDI 0x04 +#define PXENV_STATUS_KEEP_ALL 0x05 +#define PXENV_STATUS_OUT_OF_RESOURCES 0x06 +#define PXENV_STATUS_ARP_TIMEOUT 0x11 +#define PXENV_STATUS_UDP_CLOSED 0x18 +#define PXENV_STATUS_UDP_OPEN 0x19 +#define PXENV_STATUS_TFTP_CLOSED 0x1a +#define PXENV_STATUS_TFTP_OPEN 0x1b +#define PXENV_STATUS_MCOPY_PROBLEM 0x20 +#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21 +#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22 +#define PXENV_STATUS_BIS_INIT_FAILURE 0x23 +#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24 +#define PXENV_STATUS_BIS_GBOA_FAILURE 0x25 +#define PXENV_STATUS_BIS_FREE_FAILURE 0x26 +#define PXENV_STATUS_BIS_GSI_FAILURE 0x27 +#define PXENV_STATUS_BIS_BAD_CKSUM 0x28 +#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30 +#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32 + +#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33 +#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35 +#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36 +#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38 +#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39 +#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3a +#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3b +#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3c +#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3d +#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3e +#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3f +#define PXENV_STATUS_DHCP_TIMEOUT 0x51 +#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52 +#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53 +#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54 +#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60 +#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61 +#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62 +#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63 +#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64 +#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65 +#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66 +#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67 +#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68 +#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69 +#define PXENV_STATUS_UNDI_INVALID_STATE 0x6a +#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6b +#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6c +#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74 +#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76 +#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77 +#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78 +#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79 +#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xa0 +#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xa1 +#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xa2 +#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xa3 +#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xb0 +#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xc0 +#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xc1 +#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xc2 +#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xc3 +#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xc4 +#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xc5 +#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xc6 +#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xc8 +#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xc9 +#define PXENV_STATUS_LOADER_UNDI_START 0xca +#define PXENV_STATUS_LOADER_BC_START 0xcb + +#endif /* _SYSLINUX_PXE_API_H */ diff --git a/com32/lib/MCONFIG b/com32/lib/MCONFIG index 8e400776..ca8234b6 100644 --- a/com32/lib/MCONFIG +++ b/com32/lib/MCONFIG @@ -5,7 +5,12 @@ include $(topdir)/MCONFIG GCCOPT := $(call gcc_ok,-std=gnu99,) GCCOPT += $(call gcc_ok,-m32,) GCCOPT += $(call gcc_ok,-fno-stack-protector,) +GCCOPT += $(call gcc_ok,-fwrapv,) +GCCOPT += $(call gcc_ok,-freg-struct-return,) GCCOPT += $(call gcc_ok,-fPIE,-fPIC) +GCCOPT += $(call gcc_ok,-fno-exceptions,) +GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,) +GCCOPT += $(call gcc_ok,-fno-strict-aliasing,) GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0) GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0) GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0) diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 999b4869..2adb59bf 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -15,36 +15,36 @@ LIBPNG_OBJS = \ libpng/pngrio.o libpng/pngwio.o libpng/pngwrite.o \ libpng/pngrtran.o libpng/pngwtran.o libpng/pngmem.o \ libpng/pngerror.o libpng/pngpread.o - + # ZIP library object files LIBZLIB_OBJS = \ - zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/gzio.o \ + zlib/adler32.o zlib/compress.o zlib/crc32.o \ zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \ zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o\ \ sys/zfile.o sys/zfopen.o \ \ syslinux/zloadfile.o - + # JPG library object files LIBJPG_OBJS = \ jpeg/tinyjpeg.o jpeg/jidctflt.o jpeg/decode1.o jpeg/decode3.o \ jpeg/rgb24.o jpeg/bgr24.o jpeg/yuv420p.o jpeg/grey.o \ jpeg/rgba32.o jpeg/bgra32.o - + LIBVESA_OBJS = \ sys/vesacon_write.o sys/vesaserial_write.o \ sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \ sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o - + LIBPCI_OBJS = \ pci/cfgtype.o pci/scan.o \ pci/readb.o pci/readw.o pci/readl.o pci/readbios.o \ pci/writeb.o pci/writew.o pci/writel.o pci/writebios.o - + LIBSYSLINUX_OBJS = \ syslinux/reboot.o syslinux/keyboard.o \ - syslinux/features.o syslinux/config.o \ + syslinux/features.o syslinux/config.o \ syslinux/ipappend.o syslinux/dsinfo.o syslinux/version.o \ \ syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \ @@ -78,23 +78,23 @@ LIBENTRY_OBJS = \ sys/openmem.o sys/unread.o \ sys/isatty.o sys/fstat.o \ \ - syslinux/idle.o \ + syslinux/idle.o \ \ exit.o - + LIBMODULE_OBJS = \ sys/module/common.o sys/module/elf_module.o \ sys/module/shallow_module.o sys/module/elfutils.o \ sys/module/exec.o - - + + LIBGCC_OBJS = \ libgcc/__ashldi3.o libgcc/__udivdi3.o \ libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \ libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \ libgcc/__divdi3.o libgcc/__moddi3.o - + LIBCONSOLE_OBJS = \ \ sys/openconsole.o sys/line_input.o \ @@ -122,9 +122,9 @@ LIBOTHER_OBJS = \ perror.o printf.o puts.o qsort.o realloc.o seed48.o snprintf.o \ sprintf.o srand48.o sscanf.o strcasecmp.o strcat.o \ strchr.o strcmp.o strcpy.o strdup.o strerror.o strlen.o \ - strnlen.o strpcpy.o \ + strnlen.o \ strncasecmp.o strncat.o strncmp.o strncpy.o strndup.o \ - stpcpy.o stpncpy.o \ + stpcpy.o stpncpy.o \ strntoimax.o strntoumax.o strrchr.o strsep.o strspn.o strstr.o \ strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o \ strtoumax.o vfprintf.o vprintf.o vsnprintf.o vsprintf.o \ @@ -158,7 +158,7 @@ LIBOTHER_OBJS = \ sys/x86_init_fpu.o math/pow.o math/strtod.o \ \ syslinux/memscan.o - + MINLIBOBJS = \ $(LIBOTHER_OBJS) \ $(LIBENTRY_OBJS) \ @@ -167,7 +167,7 @@ MINLIBOBJS = \ $(LIBMODULE_OBJS) \ # $(LIBVESA_OBJS) - + DYNLIBOBJS = \ $(LIBZLIB_OBJS) \ $(LIBPNG_OBJS) \ @@ -176,8 +176,8 @@ DYNLIBOBJS = \ $(LIBVESA_OBJS) \ $(LIBSYSLINUX_OBJS) \ $(DYNENTRY_OBJS) - - + + LIBOBJS = \ $(MINLIBOBJS) \ $(DYNLIBOBJS) @@ -195,7 +195,7 @@ libcom32.a : $(LIBOBJS) rm -f $@ $(AR) cq $@ $^ $(RANLIB) $@ - + $(LIBMODULE_OBJS) : CFLAGS += -DELF_DEBUG libcom32min.a : $(MINLIBOBJS) rm -f $@ diff --git a/com32/lib/closedir.c b/com32/lib/closedir.c index f8bbbabd..b3f55642 100644 --- a/com32/lib/closedir.c +++ b/com32/lib/closedir.c @@ -13,17 +13,17 @@ int closedir(DIR * dir) { - int rv; - com32sys_t regs; - if (dir == NULL) { - rv = 0; - } else { - memset(®s, 0, sizeof regs); /* ?Needed? */ + int rv = -1; + + if (dir) { + com32sys_t regs; + memset(®s, 0, sizeof regs); regs.eax.w[0] = 0x0022; - regs.esi.w[0] = dir->dd_fd; + regs.esi.l = (uint32_t)dir; __com32.cs_intcall(0x22, ®s, ®s); - free(dir); /* garbage collection? */ + free(dir); rv = 0; } + return rv; } diff --git a/com32/lib/opendir.c b/com32/lib/opendir.c index 6fc0f14f..6f91032b 100644 --- a/com32/lib/opendir.c +++ b/com32/lib/opendir.c @@ -13,11 +13,9 @@ DIR *opendir(const char *pathname) { - DIR *newdir; + DIR *newdir = NULL; com32sys_t regs; - - newdir = NULL; - + strlcpy(__com32.cs_bounce, pathname, __com32.cs_bounce_size); regs.eax.w[0] = 0x0020; @@ -25,16 +23,13 @@ DIR *opendir(const char *pathname) regs.es = SEG(__com32.cs_bounce); __com32.cs_intcall(0x22, ®s, ®s); - + if (!(regs.eflags.l & EFLAGS_CF)) { - /* Initialization: malloc() then zero */ - newdir = calloc(1, sizeof(DIR)); - strcpy(newdir->dd_name, pathname); - newdir->dd_fd = regs.esi.w[0]; - newdir->dd_sect = regs.eax.l; - newdir->dd_stat = 0; + /* Initialization: malloc() then zero */ + newdir = calloc(1, sizeof(DIR)); + newdir->dd_dir = (struct file *)regs.eax.l; } - + /* We're done */ return newdir; } diff --git a/com32/lib/pci/scan.c b/com32/lib/pci/scan.c index f24a5cd8..82a7c844 100644 --- a/com32/lib/pci/scan.c +++ b/com32/lib/pci/scan.c @@ -78,100 +78,89 @@ static int hex_to_int(char *hexa) int get_module_name_from_pcimap(struct pci_domain *domain, char *modules_pcimap_path) { - char line[MAX_LINE]; - char module_name[21]; // the module name field is 21 char long - char delims[] = " "; // colums are separated by spaces - char vendor_id[16]; - char product_id[16]; - char sub_vendor_id[16]; - char sub_product_id[16]; - FILE *f; - struct pci_device *dev = NULL; - - /* Intializing the linux_kernel_module for each pci device to "unknown" */ - /* adding a dev_info member if needed */ - for_each_pci_func(dev, domain) { - /* initialize the dev_info structure if it doesn't exist yet. */ - if (!dev->dev_info) { - dev->dev_info = zalloc(sizeof *dev->dev_info); - if (!dev->dev_info) - return -1; - } - for (int i = 0; i < MAX_KERNEL_MODULES_PER_PCI_DEVICE; i++) { - strlcpy(dev->dev_info->linux_kernel_module[i], "unknown", 7); - } + char line[MAX_LINE]; + char module_name[21]; // the module name field is 21 char long + char delims[]=" "; // colums are separated by spaces + char vendor_id[16]; + char product_id[16]; + char sub_vendor_id[16]; + char sub_product_id[16]; + FILE *f; + struct pci_device *dev=NULL; + + /* Intializing the linux_kernel_module for each pci device to "unknown" */ + /* adding a dev_info member if needed */ + for_each_pci_func(dev, domain) { + /* initialize the dev_info structure if it doesn't exist yet. */ + if (! dev->dev_info) { + dev->dev_info = zalloc(sizeof *dev->dev_info); + if (!dev->dev_info) + return -1; } - - /* Opening the modules.pcimap (of a linux kernel) from the boot device */ - f = fopen(modules_pcimap_path, "r"); - if (!f) - return -ENOMODULESPCIMAP; - - strcpy(vendor_id, "0000"); - strcpy(product_id, "0000"); - strcpy(sub_product_id, "0000"); - strcpy(sub_vendor_id, "0000"); - dev->dev_info->linux_kernel_module_count = 0; - - /* for each line we found in the modules.pcimap */ - while (fgets(line, sizeof line, f)) { - /* skipping unecessary lines */ - if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10)) - continue; - - char *result = NULL; - int field = 0; - - /* looking for the next field */ - result = strtok(line, delims); - while (result != NULL) { - /* if the column is larger than 1 char */ - /* multiple spaces generates some empty fields */ - if (strlen(result) > 1) { - switch (field) { - case 0: - strcpy(module_name, result); - break; - case 1: - strcpy(vendor_id, result); - break; - case 2: - strcpy(product_id, result); - break; - case 3: - strcpy(sub_vendor_id, result); - break; - case 4: - strcpy(sub_product_id, result); - break; - } - field++; - } - /* Searching the next field */ - result = strtok(NULL, delims); - } - int int_vendor_id = hex_to_int(vendor_id); - int int_sub_vendor_id = hex_to_int(sub_vendor_id); - int int_product_id = hex_to_int(product_id); - int int_sub_product_id = hex_to_int(sub_product_id); - /* if a pci_device matches an entry, fill the linux_kernel_module with - the appropriate kernel module */ - for_each_pci_func(dev, domain) { - if (int_vendor_id == dev->vendor && - int_product_id == dev->product && - (int_sub_product_id & dev->sub_product) - == dev->sub_product && (int_sub_vendor_id & dev->sub_vendor) - == dev->sub_vendor) { - strcpy(dev->dev_info-> - linux_kernel_module[dev->dev_info-> - linux_kernel_module_count], - module_name); - dev->dev_info->linux_kernel_module_count++; - } - } + for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) { + if (strlen(dev->dev_info->linux_kernel_module[i])==0) + strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7); } - fclose(f); - return 0; + } + + /* Opening the modules.pcimap (of a linux kernel) from the boot device */ + f=fopen(modules_pcimap_path, "r"); + if (!f) + return -ENOMODULESPCIMAP; + + strcpy(vendor_id,"0000"); + strcpy(product_id,"0000"); + strcpy(sub_product_id,"0000"); + strcpy(sub_vendor_id,"0000"); + dev->dev_info->linux_kernel_module_count=0; + + /* for each line we found in the modules.pcimap */ + while ( fgets(line, sizeof line, f) ) { + /* skipping unecessary lines */ + if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 10)) + continue; + + char *result = NULL; + int field=0; + + /* looking for the next field */ + result = strtok(line, delims); + while( result != NULL ) { + /* if the column is larger than 1 char */ + /* multiple spaces generates some empty fields */ + if (strlen(result)>1) { + switch (field) { + case 0:strcpy(module_name,result); break; + case 1:strcpy(vendor_id,result); break; + case 2:strcpy(product_id,result); break; + case 3:strcpy(sub_vendor_id,result); break; + case 4:strcpy(sub_product_id,result); break; + } + field++; + } + /* Searching the next field */ + result = strtok( NULL, delims ); + } + int int_vendor_id=hex_to_int(vendor_id); + int int_sub_vendor_id=hex_to_int(sub_vendor_id); + int int_product_id=hex_to_int(product_id); + int int_sub_product_id=hex_to_int(sub_product_id); + /* if a pci_device matches an entry, fill the linux_kernel_module with + the appropriate kernel module */ + for_each_pci_func(dev, domain) { + if (int_vendor_id == dev->vendor && + int_product_id == dev->product && + (int_sub_product_id & dev->sub_product) + == dev->sub_product && + (int_sub_vendor_id & dev->sub_vendor) + == dev->sub_vendor) { + strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name); + dev->dev_info->linux_kernel_module_count++; + } + } + } + fclose(f); + return 0; } /* Try to match any pci device to the appropriate class name */ @@ -595,3 +584,129 @@ void free_pci_domain(struct pci_domain *domain) } } } + +/* Try to match any pci device to the appropriate kernel module */ +/* it uses the modules.alias from the boot device */ +int get_module_name_from_alias(struct pci_domain *domain, char *modules_alias_path) +{ + char line[MAX_LINE]; + char module_name[21]; // the module name field is 21 char long + char delims[]="*"; // colums are separated by spaces + char vendor_id[16]; + char product_id[16]; + char sub_vendor_id[16]; + char sub_product_id[16]; + FILE *f; + struct pci_device *dev=NULL; + + /* Intializing the linux_kernel_module for each pci device to "unknown" */ + /* adding a dev_info member if needed */ + for_each_pci_func(dev, domain) { + /* initialize the dev_info structure if it doesn't exist yet. */ + if (! dev->dev_info) { + dev->dev_info = zalloc(sizeof *dev->dev_info); + if (!dev->dev_info) + return -1; + } + for (int i=0;i<MAX_KERNEL_MODULES_PER_PCI_DEVICE;i++) { + if (strlen(dev->dev_info->linux_kernel_module[i])==0) + strlcpy(dev->dev_info->linux_kernel_module[i], "unknown",7); + } + } + + /* Opening the modules.pcimap (of a linux kernel) from the boot device */ + f=fopen(modules_alias_path, "r"); + if (!f) + return -ENOMODULESALIAS; + + dev->dev_info->linux_kernel_module_count=0; + + /* for each line we found in the modules.pcimap */ + while ( fgets(line, sizeof line, f) ) { + /* skipping unecessary lines */ + if ((line[0] == '#') || (strstr(line,"alias pci:v")==NULL)) + continue; + + /* Resetting temp buffer*/ + memset(module_name,0,sizeof(module_name)); + memset(vendor_id,0,sizeof(vendor_id)); + memset(sub_vendor_id,0,sizeof(sub_vendor_id)); + memset(product_id,0,sizeof(product_id)); + memset(sub_product_id,0,sizeof(sub_product_id)); + strcpy(vendor_id,"0000"); + strcpy(product_id,"0000"); + /* ffff will be used to match any device as in modules.alias + * a missing subvendor/product have to be considered as 0xFFFF*/ + strcpy(sub_product_id,"ffff"); + strcpy(sub_vendor_id,"ffff"); + + char *result = NULL; + int field=0; + + /* looking for the next field */ + result = strtok(line+strlen("alias pci:v"), delims); + while( result != NULL ) { + if (field==0) { + + /* Searching for the vendor separator*/ + char *temp = strstr(result,"d"); + if (temp != NULL) { + strncpy(vendor_id,result,temp-result); + result+=strlen(vendor_id)+1; + } + + /* Searching for the product separator*/ + temp = strstr(result,"sv"); + if (temp != NULL) { + strncpy(product_id,result,temp-result); + result+=strlen(product_id)+1; + } + + /* Searching for the sub vendor separator*/ + temp = strstr(result,"sd"); + if (temp != NULL) { + strncpy(sub_vendor_id,result,temp-result); + result+=strlen(sub_vendor_id)+1; + } + + /* Searching for the sub product separator*/ + temp = strstr(result,"bc"); + if (temp != NULL) { + strncpy(sub_product_id,result,temp-result); + result+=strlen(sub_product_id)+1; + } + /* That's the module name */ + } else if ((strlen(result)>2) && + (result[0]==0x20)) + strcpy(module_name,result+1); + /* We have to replace \n by \0*/ + module_name[strlen(module_name)-1]='\0'; + field++; + + /* Searching the next field */ + result = strtok( NULL, delims ); + } + + /* Now we have extracted informations from the modules.alias + * Let's compare it with the devices we know*/ + int int_vendor_id=hex_to_int(vendor_id); + int int_sub_vendor_id=hex_to_int(sub_vendor_id); + int int_product_id=hex_to_int(product_id); + int int_sub_product_id=hex_to_int(sub_product_id); + /* if a pci_device matches an entry, fill the linux_kernel_module with + the appropriate kernel module */ + for_each_pci_func(dev, domain) { + if (int_vendor_id == dev->vendor && + int_product_id == dev->product && + (int_sub_product_id & dev->sub_product) + == dev->sub_product && + (int_sub_vendor_id & dev->sub_vendor) + == dev->sub_vendor) { + strcpy(dev->dev_info->linux_kernel_module[dev->dev_info->linux_kernel_module_count], module_name); + dev->dev_info->linux_kernel_module_count++; + } + } + } + fclose(f); + return 0; +} diff --git a/com32/lib/readdir.c b/com32/lib/readdir.c index 2ec7c7b3..07ca3955 100644 --- a/com32/lib/readdir.c +++ b/com32/lib/readdir.c @@ -15,40 +15,12 @@ struct dirent *readdir(DIR * dir) { struct dirent *newde; com32sys_t regs; - - newde = NULL; - if ((dir != NULL) && (dir->dd_fd != 0) && (dir->dd_stat >= 0)) { - memset(__com32.cs_bounce, 0, 32); - memset(®s, 0, sizeof(regs)); - - regs.eax.w[0] = 0x0021; - regs.esi.w[0] = dir->dd_fd; - regs.edi.w[0] = OFFS(__com32.cs_bounce); - regs.es = SEG(__com32.cs_bounce); - - __com32.cs_intcall(0x22, ®s, ®s); - - /* Don't do this as we won't be able to rewind. - dir->dd_fd = regs.esi.w[0]; /* Shouldn't be needed? */ - if ((!(regs.eflags.l & EFLAGS_CF)) && (regs.esi.w[0] != 0)) { - newde = calloc(1, sizeof(newde)); - if (newde != NULL) { - strcpy(newde->d_name, __com32.cs_bounce); - newde->d_mode = regs.edx.b[0]; - newde->d_size = regs.eax.l; - newde->d_ino = regs.ebx.l; - dir->dd_stat = 1; - } else { - dir->dd_stat = -2; - errno = ENOMEM; - } - } else { - dir->dd_stat = -1; - errno = EIO; /* Is this the right nmber? */ - } - } else { - errno = EBADF; - } - + + memset(®s, 0, sizeof(regs)); + regs.eax.w[0] = 0x0021; + regs.esi.l = (uint32_t)dir; + __com32.cs_intcall(0x22, ®s, ®s); + newde = (struct dirent *)(regs.eax.l); + return newde; } diff --git a/com32/lib/strpcpy.c b/com32/lib/strpcpy.c deleted file mode 100644 index a4fd2a06..00000000 --- a/com32/lib/strpcpy.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * strpcpy.c - * - * strpcpy() - strcpy() which returns a pointer to the final null - */ - -#include <string.h> - -char *strpcpy(char *dst, const char *src) -{ - char *q = dst; - const char *p = src; - char ch; - - do { - *q++ = ch = *p++; - } while (ch); - - return q - 1; -} diff --git a/com32/lib/zlib/example.c b/com32/lib/zlib/example.c deleted file mode 100644 index 14614b74..00000000 --- a/com32/lib/zlib/example.c +++ /dev/null @@ -1,566 +0,0 @@ -/* example.c -- usage example of the zlib compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - - -#include <stdio.h> -#include "zlib.h" - -#ifdef STDC -# include <string.h> -# include <stdlib.h> -#else - extern void exit OF((int)); -#endif - -#if defined(VMS) || defined(RISCOS) -# define TESTFILE "foo-gz" -#else -# define TESTFILE "foo.gz" -#endif - -#define CHECK_ERR(err, msg) { \ - if (err != Z_OK) { \ - fprintf(stderr, "%s error: %d\n", msg, err); \ - exit(1); \ - } \ -} - -const char hello[] = "hello, hello!"; -/* "hello world" would be more standard, but the repeated "hello" - * stresses the compression code better, sorry... - */ - -const char dictionary[] = "hello"; -uLong dictId; /* Adler32 value of the dictionary */ - -void test_compress OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_gzio OF((const char *fname, - Byte *uncompr, uLong uncomprLen)); -void test_deflate OF((Byte *compr, uLong comprLen)); -void test_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_deflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_flush OF((Byte *compr, uLong *comprLen)); -void test_sync OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_dict_deflate OF((Byte *compr, uLong comprLen)); -void test_dict_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -int main OF((int argc, char *argv[])); - -/* =========================================================================== - * Test compress() and uncompress() - */ -void test_compress(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - uLong len = (uLong)strlen(hello)+1; - - err = compress(compr, &comprLen, (const Bytef*)hello, len); - CHECK_ERR(err, "compress"); - - strcpy((char*)uncompr, "garbage"); - - err = uncompress(uncompr, &uncomprLen, compr, comprLen); - CHECK_ERR(err, "uncompress"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad uncompress\n"); - exit(1); - } else { - printf("uncompress(): %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Test read/write of .gz files - */ -void test_gzio(fname, uncompr, uncomprLen) - const char *fname; /* compressed file name */ - Byte *uncompr; - uLong uncomprLen; -{ -#ifdef NO_GZCOMPRESS - fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); -#else - int err; - int len = (int)strlen(hello)+1; - gzFile file; - z_off_t pos; - - file = gzopen(fname, "wb"); - if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); - } - gzputc(file, 'h'); - if (gzputs(file, "ello") != 4) { - fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); - exit(1); - } - if (gzprintf(file, ", %s!", "hello") != 8) { - fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); - exit(1); - } - gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ - gzclose(file); - - file = gzopen(fname, "rb"); - if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); - } - strcpy((char*)uncompr, "garbage"); - - if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { - fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); - exit(1); - } - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); - exit(1); - } else { - printf("gzread(): %s\n", (char*)uncompr); - } - - pos = gzseek(file, -8L, SEEK_CUR); - if (pos != 6 || gztell(file) != pos) { - fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", - (long)pos, (long)gztell(file)); - exit(1); - } - - if (gzgetc(file) != ' ') { - fprintf(stderr, "gzgetc error\n"); - exit(1); - } - - if (gzungetc(' ', file) != ' ') { - fprintf(stderr, "gzungetc error\n"); - exit(1); - } - - gzgets(file, (char*)uncompr, (int)uncomprLen); - if (strlen((char*)uncompr) != 7) { /* " hello!" */ - fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); - exit(1); - } - if (strcmp((char*)uncompr, hello + 6)) { - fprintf(stderr, "bad gzgets after gzseek\n"); - exit(1); - } else { - printf("gzgets() after gzseek: %s\n", (char*)uncompr); - } - - gzclose(file); -#endif -} - -/* =========================================================================== - * Test deflate() with small buffers - */ -void test_deflate(compr, comprLen) - Byte *compr; - uLong comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - uLong len = (uLong)strlen(hello)+1; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_in = (Bytef*)hello; - c_stream.next_out = compr; - - while (c_stream.total_in != len && c_stream.total_out < comprLen) { - c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - } - /* Finish the stream, still forcing small buffers: */ - for (;;) { - c_stream.avail_out = 1; - err = deflate(&c_stream, Z_FINISH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "deflate"); - } - - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with small buffers - */ -void test_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = 0; - d_stream.next_out = uncompr; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { - d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "inflate"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate\n"); - exit(1); - } else { - printf("inflate(): %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Test deflate() with large buffers and dynamic change of compression level - */ -void test_large_deflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_BEST_SPEED); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_out = compr; - c_stream.avail_out = (uInt)comprLen; - - /* At this point, uncompr is still mostly zeroes, so it should compress - * very well: - */ - c_stream.next_in = uncompr; - c_stream.avail_in = (uInt)uncomprLen; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - if (c_stream.avail_in != 0) { - fprintf(stderr, "deflate not greedy\n"); - exit(1); - } - - /* Feed in already compressed data and switch to no compression: */ - deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); - c_stream.next_in = compr; - c_stream.avail_in = (uInt)comprLen/2; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - - /* Switch back to compressing mode: */ - deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); - c_stream.next_in = uncompr; - c_stream.avail_in = (uInt)uncomprLen; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with large buffers - */ -void test_large_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = (uInt)comprLen; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - for (;;) { - d_stream.next_out = uncompr; /* discard the output */ - d_stream.avail_out = (uInt)uncomprLen; - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "large inflate"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (d_stream.total_out != 2*uncomprLen + comprLen/2) { - fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); - exit(1); - } else { - printf("large_inflate(): OK\n"); - } -} - -/* =========================================================================== - * Test deflate() with full flush - */ -void test_flush(compr, comprLen) - Byte *compr; - uLong *comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - uInt len = (uInt)strlen(hello)+1; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_in = (Bytef*)hello; - c_stream.next_out = compr; - c_stream.avail_in = 3; - c_stream.avail_out = (uInt)*comprLen; - err = deflate(&c_stream, Z_FULL_FLUSH); - CHECK_ERR(err, "deflate"); - - compr[3]++; /* force an error in first compressed block */ - c_stream.avail_in = len - 3; - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - CHECK_ERR(err, "deflate"); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); - - *comprLen = c_stream.total_out; -} - -/* =========================================================================== - * Test inflateSync() - */ -void test_sync(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = 2; /* just read the zlib header */ - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - d_stream.next_out = uncompr; - d_stream.avail_out = (uInt)uncomprLen; - - inflate(&d_stream, Z_NO_FLUSH); - CHECK_ERR(err, "inflate"); - - d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ - err = inflateSync(&d_stream); /* but skip the damaged part */ - CHECK_ERR(err, "inflateSync"); - - err = inflate(&d_stream, Z_FINISH); - if (err != Z_DATA_ERROR) { - fprintf(stderr, "inflate should report DATA_ERROR\n"); - /* Because of incorrect adler32 */ - exit(1); - } - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - printf("after inflateSync(): hel%s\n", (char *)uncompr); -} - -/* =========================================================================== - * Test deflate() with preset dictionary - */ -void test_dict_deflate(compr, comprLen) - Byte *compr; - uLong comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_BEST_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - err = deflateSetDictionary(&c_stream, - (const Bytef*)dictionary, sizeof(dictionary)); - CHECK_ERR(err, "deflateSetDictionary"); - - dictId = c_stream.adler; - c_stream.next_out = compr; - c_stream.avail_out = (uInt)comprLen; - - c_stream.next_in = (Bytef*)hello; - c_stream.avail_in = (uInt)strlen(hello)+1; - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with a preset dictionary - */ -void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = (uInt)comprLen; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - d_stream.next_out = uncompr; - d_stream.avail_out = (uInt)uncomprLen; - - for (;;) { - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - if (err == Z_NEED_DICT) { - if (d_stream.adler != dictId) { - fprintf(stderr, "unexpected dictionary"); - exit(1); - } - err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, - sizeof(dictionary)); - } - CHECK_ERR(err, "inflate with dict"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate with dict\n"); - exit(1); - } else { - printf("inflate with dictionary: %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Usage: example [output.gz [input.gz]] - */ - -int main(argc, argv) - int argc; - char *argv[]; -{ - Byte *compr, *uncompr; - uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ - uLong uncomprLen = comprLen; - static const char* myVersion = ZLIB_VERSION; - - if (zlibVersion()[0] != myVersion[0]) { - fprintf(stderr, "incompatible zlib version\n"); - exit(1); - - } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { - fprintf(stderr, "warning: different zlib version\n"); - } - - printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", - ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); - - compr = (Byte*)calloc((uInt)comprLen, 1); - uncompr = (Byte*)calloc((uInt)uncomprLen, 1); - /* compr and uncompr are cleared to avoid reading uninitialized - * data and to ensure that uncompr compresses well. - */ - if (compr == Z_NULL || uncompr == Z_NULL) { - printf("out of memory\n"); - exit(1); - } - test_compress(compr, comprLen, uncompr, uncomprLen); - - test_gzio((argc > 1 ? argv[1] : TESTFILE), - uncompr, uncomprLen); - - test_deflate(compr, comprLen); - test_inflate(compr, comprLen, uncompr, uncomprLen); - - test_large_deflate(compr, comprLen, uncompr, uncomprLen); - test_large_inflate(compr, comprLen, uncompr, uncomprLen); - - test_flush(compr, &comprLen); - test_sync(compr, comprLen, uncompr, uncomprLen); - comprLen = uncomprLen; - - test_dict_deflate(compr, comprLen); - test_dict_inflate(compr, comprLen, uncompr, uncomprLen); - - free(compr); - free(uncompr); - - return 0; -} diff --git a/com32/lib/zlib/gzio.c b/com32/lib/zlib/gzio.c deleted file mode 100644 index 9bc8d34e..00000000 --- a/com32/lib/zlib/gzio.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. - */ - - -#include <stdio.h> - -#include "zutil.h" - -#ifdef NO_DEFLATE /* for compatiblity with old definition */ -# define NO_GZCOMPRESS -#endif - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#ifdef __MVS__ -# pragma map (fdopen , "\174\174FDOPEN") - FILE *fdopen(int, const char *); -#endif - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern void free OF((voidpf ptr)); -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_DEFAULT_COMPRESSION; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else if (*p == 'R') { - strategy = Z_RLE; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->start = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * start anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->start = ftell(s->file) - s->stream.avail_in; - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[20]; - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "<fd:%d>", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - /* klibc hack */ - if (errno) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Assure two bytes in the buffer so we can peek ahead -- handle case - where first byte of header is at the end of the buffer after the last - gzip segment */ - len = s->stream.avail_in; - if (len < 2) { - if (len) s->inbuf[0] = s->stream.next_in[0]; - errno = 0; - len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); - /* klibc hack */ - if (len == 0 && errno) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - s->transparent = s->stream.avail_in; - return; - } - } - - /* Peek ahead to check the gzip magic header */ - if (s->stream.next_in[0] != gz_magic[0] || - s->stream.next_in[1] != gz_magic[1]) { - s->transparent = 1; - return; - } - s->stream.avail_in -= 2; - s->stream.next_in += 2; - - /* Check the rest of the gzip header */ - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - if (s->stream.avail_out && s->back != EOF) { - *next_out++ = s->back; - s->stream.next_out++; - s->stream.avail_out--; - s->back = EOF; - s->out++; - if (s->last) { - s->z_err = Z_STREAM_END; - return 1; - } - } - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, - s->file); - } - len -= s->stream.avail_out; - s->in += len; - s->out += len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (errno) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may be - * different from s->out in case of concatenated .gz files. - * Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - inflateReset(&(s->stream)); - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Push one byte back onto the stream. -*/ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; - s->back = c; - s->out--; - s->last = (s->z_err == Z_STREAM_END); - if (s->last) s->z_err = Z_OK; - s->z_eof = 0; - return c; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_GZCOMPRESS -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include <stdarg.h> - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - buf[sizeof(buf) - 1] = 0; - va_start(va, format); -#ifdef NO_vsnprintf -# ifdef HAS_vsprintf_void - (void)vsprintf(buf, format, va); - va_end(va); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = vsprintf(buf, format, va); - va_end(va); -# endif -#else -# ifdef HAS_vsnprintf_void - (void)vsnprintf(buf, sizeof(buf), format, va); - va_end(va); - len = strlen(buf); -# else - len = vsnprintf(buf, sizeof(buf), format, va); - va_end(va); -# endif -#endif - if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - - buf[sizeof(buf) - 1] = 0; -#ifdef NO_snprintf -# ifdef HAS_sprintf_void - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#else -# ifdef HAS_snprintf_void - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(buf); -# else - len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#endif - if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), flush); - s->out -= s->stream.avail_out; - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_GZCOMPRESS */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -#if 0 /* COM32: seek not supported */ - -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - if (s->inbuf == Z_NULL) return -1L; - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return s->in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->in = s->out = offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if (offset >= s->out) { - offset -= s->out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - if (s->outbuf == Z_NULL) return -1L; - } - if (offset && s->back != EOF) { - s->back = EOF; - s->out++; - offset--; - if (s->last) s->z_err = Z_STREAM_END; - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return s->out; -} - -#endif - -/* =========================================================================== - Rewinds input file. -*/ -#if 0 /* COM32: seek not supported */ - -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - if (!s->transparent) (void)inflateReset(&s->stream); - s->in = 0; - s->out = 0; - return fseek(s->file, s->start, SEEK_SET); -} -#endif - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -#if 0 /* COM32: seek not supported */ - -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} -#endif - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - /* With concatenated compressed files that can have embedded - * crc trailers, z_eof is no longer the only/best indicator of EOF - * on a gz_stream. Handle end-of-stream error explicitly here. - */ - if (s == NULL || s->mode != 'r') return 0; - if (s->z_eof) return 1; - return s->z_err == Z_STREAM_END; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - int err; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return Z_STREAM_ERROR; -#else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, (uLong)(s->in & 0xffffffff)); -#endif - } - return destroy((gz_stream*)file); -} - -/* =========================================================================== - Returns the error message for the last error which occured on the - given compressed file. errnum is set to zlib error number. If an - error occured in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char * ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} - -/* =========================================================================== - Clear the error and end-of-file flags, and do the same for the real file. -*/ -void ZEXPORT gzclearerr (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return; - if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; - s->z_eof = 0; - /* klibc hack */ - /* clearerr(s->file); */ -} diff --git a/com32/lib/zlib/minigzip.c b/com32/lib/zlib/minigzip.c deleted file mode 100644 index 077e2e12..00000000 --- a/com32/lib/zlib/minigzip.c +++ /dev/null @@ -1,322 +0,0 @@ -/* minigzip.c -- simulate gzip using the zlib compression library - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * minigzip is a minimal implementation of the gzip utility. This is - * only an example of using zlib and isn't meant to replace the - * full-featured gzip. No attempt is made to deal with file systems - * limiting names to 14 or 8+3 characters, etc... Error checking is - * very limited. So use minigzip only for testing; use gzip for the - * real thing. On MSDOS, use only on file names without extension - * or in pipe mode. - */ - - -#include <stdio.h> -#include "zlib.h" - -#ifdef STDC -# include <string.h> -# include <stdlib.h> -#else - extern void exit OF((int)); -#endif - -#ifdef USE_MMAP -# include <sys/types.h> -# include <sys/mman.h> -# include <sys/stat.h> -#endif - -#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) -# include <fcntl.h> -# include <io.h> -# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) -#else -# define SET_BINARY_MODE(file) -#endif - -#ifdef VMS -# define unlink delete -# define GZ_SUFFIX "-gz" -#endif -#ifdef RISCOS -# define unlink remove -# define GZ_SUFFIX "-gz" -# define fileno(file) file->__file -#endif -#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include <unix.h> /* for fileno */ -#endif - -#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ - extern int unlink OF((const char *)); -#endif - -#ifndef GZ_SUFFIX -# define GZ_SUFFIX ".gz" -#endif -#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) - -#define BUFLEN 16384 -#define MAX_NAME_LEN 1024 - -#ifdef MAXSEG_64K -# define local static - /* Needed for systems with limitation on stack size. */ -#else -# define local -#endif - -char *prog; - -void error OF((const char *msg)); -void gz_compress OF((FILE *in, gzFile out)); -#ifdef USE_MMAP -int gz_compress_mmap OF((FILE *in, gzFile out)); -#endif -void gz_uncompress OF((gzFile in, FILE *out)); -void file_compress OF((char *file, char *mode)); -void file_uncompress OF((char *file)); -int main OF((int argc, char *argv[])); - -/* =========================================================================== - * Display error message and exit - */ -void error(msg) - const char *msg; -{ - fprintf(stderr, "%s: %s\n", prog, msg); - exit(1); -} - -/* =========================================================================== - * Compress input to output then close both files. - */ - -void gz_compress(in, out) - FILE *in; - gzFile out; -{ - local char buf[BUFLEN]; - int len; - int err; - -#ifdef USE_MMAP - /* Try first compressing with mmap. If mmap fails (minigzip used in a - * pipe), use the normal fread loop. - */ - if (gz_compress_mmap(in, out) == Z_OK) return; -#endif - for (;;) { - errno = 0; - len = (int)fread(buf, 1, sizeof(buf), in); - if (!len && errno) { - perror("fread"); - exit(1); - } - if (len == 0) break; - - if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); - } - fclose(in); - if (gzclose(out) != Z_OK) error("failed gzclose"); -} - -#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ - -/* Try compressing the input file at once using mmap. Return Z_OK if - * if success, Z_ERRNO otherwise. - */ -int gz_compress_mmap(in, out) - FILE *in; - gzFile out; -{ - int len; - int err; - int ifd = fileno(in); - caddr_t buf; /* mmap'ed buffer for the entire input file */ - off_t buf_len; /* length of the input file */ - struct stat sb; - - /* Determine the size of the file, needed for mmap: */ - if (fstat(ifd, &sb) < 0) return Z_ERRNO; - buf_len = sb.st_size; - if (buf_len <= 0) return Z_ERRNO; - - /* Now do the actual mmap: */ - buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); - if (buf == (caddr_t)(-1)) return Z_ERRNO; - - /* Compress the whole file at once: */ - len = gzwrite(out, (char *)buf, (unsigned)buf_len); - - if (len != (int)buf_len) error(gzerror(out, &err)); - - munmap(buf, buf_len); - fclose(in); - if (gzclose(out) != Z_OK) error("failed gzclose"); - return Z_OK; -} -#endif /* USE_MMAP */ - -/* =========================================================================== - * Uncompress input to output then close both files. - */ -void gz_uncompress(in, out) - gzFile in; - FILE *out; -{ - local char buf[BUFLEN]; - int len; - int err; - - for (;;) { - len = gzread(in, buf, sizeof(buf)); - if (len < 0) error (gzerror(in, &err)); - if (len == 0) break; - - if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { - error("failed fwrite"); - } - } - if (fclose(out)) error("failed fclose"); - - if (gzclose(in) != Z_OK) error("failed gzclose"); -} - - -/* =========================================================================== - * Compress the given file: create a corresponding .gz file and remove the - * original. - */ -void file_compress(file, mode) - char *file; - char *mode; -{ - local char outfile[MAX_NAME_LEN]; - FILE *in; - gzFile out; - - strcpy(outfile, file); - strcat(outfile, GZ_SUFFIX); - - in = fopen(file, "rb"); - if (in == NULL) { - perror(file); - exit(1); - } - out = gzopen(outfile, mode); - if (out == NULL) { - fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); - exit(1); - } - gz_compress(in, out); - - unlink(file); -} - - -/* =========================================================================== - * Uncompress the given file and remove the original. - */ -void file_uncompress(file) - char *file; -{ - local char buf[MAX_NAME_LEN]; - char *infile, *outfile; - FILE *out; - gzFile in; - uInt len = (uInt)strlen(file); - - strcpy(buf, file); - - if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { - infile = file; - outfile = buf; - outfile[len-3] = '\0'; - } else { - outfile = file; - infile = buf; - strcat(infile, GZ_SUFFIX); - } - in = gzopen(infile, "rb"); - if (in == NULL) { - fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); - exit(1); - } - out = fopen(outfile, "wb"); - if (out == NULL) { - perror(file); - exit(1); - } - - gz_uncompress(in, out); - - unlink(infile); -} - - -/* =========================================================================== - * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...] - * -d : decompress - * -f : compress with Z_FILTERED - * -h : compress with Z_HUFFMAN_ONLY - * -r : compress with Z_RLE - * -1 to -9 : compression level - */ - -int main(argc, argv) - int argc; - char *argv[]; -{ - int uncompr = 0; - gzFile file; - char outmode[20]; - - strcpy(outmode, "wb6 "); - - prog = argv[0]; - argc--, argv++; - - while (argc > 0) { - if (strcmp(*argv, "-d") == 0) - uncompr = 1; - else if (strcmp(*argv, "-f") == 0) - outmode[3] = 'f'; - else if (strcmp(*argv, "-h") == 0) - outmode[3] = 'h'; - else if (strcmp(*argv, "-r") == 0) - outmode[3] = 'R'; - else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && - (*argv)[2] == 0) - outmode[2] = (*argv)[1]; - else - break; - argc--, argv++; - } - if (argc == 0) { - SET_BINARY_MODE(stdin); - SET_BINARY_MODE(stdout); - if (uncompr) { - file = gzdopen(fileno(stdin), "rb"); - if (file == NULL) error("can't gzdopen stdin"); - gz_uncompress(file, stdout); - } else { - file = gzdopen(fileno(stdout), outmode); - if (file == NULL) error("can't gzdopen stdout"); - gz_compress(stdin, file); - } - } else { - do { - if (uncompr) { - file_uncompress(*argv); - } else { - file_compress(*argv, outmode); - } - } while (argv++, --argc); - } - return 0; -} diff --git a/com32/mboot/mboot.c b/com32/mboot/mboot.c index e7bb8dbb..62ebf523 100644 --- a/com32/mboot/mboot.c +++ b/com32/mboot/mboot.c @@ -135,7 +135,7 @@ static int get_modules(char **argv, struct module_data **mdp) char *p; mp->cmdline = p = malloc(arglen); for (; *argp && strcmp(*argp, module_separator); argp++) { - p = strpcpy(p, *argp); + p = stpcpy(p, *argp); *p++ = ' '; } *--p = '\0'; diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c index 3af630f8..b2d81017 100644 --- a/com32/menu/menumain.c +++ b/com32/menu/menumain.c @@ -1101,12 +1101,13 @@ int menu_main(int argc, char *argv[]) m->mparm[i] = max(m->mparm[i] + rows, 0); } + cm = start_menu; + if (!cm->nentries) { fputs("Initial menu has no LABEL entries!\n", stdout); return 1; /* Error! */ } - cm = start_menu; for (;;) { cmdline = run_menu(); diff --git a/com32/modules/Makefile b/com32/modules/Makefile index e3155bd5..68e50571 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -18,10 +18,10 @@ topdir = ../.. include ../MCONFIG -MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ +MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 disk.c32 \ pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 meminfo.c32 \ sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 kbdmap.c32 cmd.c32 \ - vpdtest.c32 + vpdtest.c32 host.c32 dir.c32 TESTFILES = diff --git a/com32/modules/dir.c b/com32/modules/dir.c new file mode 100644 index 00000000..913c2ca7 --- /dev/null +++ b/com32/modules/dir.c @@ -0,0 +1,35 @@ +/* + * A dir test module + */ +#include <stdio.h> +#include <console.h> +#include <string.h> +#include <com32.h> +#include <dirent.h> + +int main(int argc, char *argv[]) +{ + DIR *dir; + struct dirent *de; + + openconsole(&dev_null_r, &dev_stdcon_w); + + if (argc != 2) { + printf("Usage: dir direcotry\n"); + return 0; + } + + dir = opendir(argv[1]); + if (dir == NULL) { + printf("Unable to read dir: %s\n", argv[1]); + return 0; + } + + while ((de = readdir(dir)) != NULL) + printf("%s\n", de->d_name); + + closedir(dir); + + return 0; +} + diff --git a/com32/modules/disk.c b/com32/modules/disk.c new file mode 100644 index 00000000..e94a36bf --- /dev/null +++ b/com32/modules/disk.c @@ -0,0 +1,63 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <stdio.h> +#include <console.h> +#include <stdlib.h> +#include <string.h> +#include <disk/geom.h> +#include <disk/util.h> + +int main(int argc __attribute__ (( unused )), + char *argv[] __attribute__ (( unused ))) +{ + char* error_buffer; + int err; + struct driveinfo drive; + struct driveinfo *d = &drive; + + openconsole(&dev_null_r, &dev_stdcon_w); + + for (int disk = 0x80; disk < 0xff; disk++) { + memset(d, 0, sizeof(struct driveinfo)); + d->disk = disk; + err = get_drive_parameters(d); + + /* Do not print output when drive does not exists */ + if (err == -1) + continue; + + if (err) { + get_error(err, &error_buffer); + printf("Error 0x%Xh while reading disk 0x%X:\n %s\n", + err, d->disk, error_buffer); + free(error_buffer); + continue; + } + + printf("DISK 0x%X:\n", d->disk); + printf(" C/H/S: %d heads, %d cylinders\n", + d->legacy_max_head + 1, d->legacy_max_cylinder + 1); + printf(" %d sectors/track, %d drives\n", + d->legacy_sectors_per_track, d->legacy_max_drive); + printf(" EDD: ebios=%d, EDD version: %X\n", + d->ebios, d->edd_version); + printf(" %d heads, %d cylinders\n", + (int) d->edd_params.heads, (int) d->edd_params.cylinders); + printf(" %d sectors, %d bytes/sector, %d sectors/track\n", + (int) d->edd_params.sectors, (int) d->edd_params.bytes_per_sector, + (int) d->edd_params.sectors_per_track); + printf(" Host bus: %s, Interface type: %s\n\n", + d->edd_params.host_bus_type, d->edd_params.interface_type); + } + return 0; +} diff --git a/com32/modules/host.c b/com32/modules/host.c new file mode 100644 index 00000000..94ca876d --- /dev/null +++ b/com32/modules/host.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <console.h> +#include <string.h> +#include <netinet/in.h> +#include <com32.h> + +static struct in_addr dnsresolve(const char *hostname) +{ + com32sys_t regs; + struct in_addr addr; + + strcpy(__com32.cs_bounce, hostname); + + regs.eax.w[0] = 0x0010; + regs.es = SEG(__com32.cs_bounce); + regs.ebx.w[0] = OFFS(__com32.cs_bounce); + __intcall(0x22, ®s, ®s); + + addr.s_addr = regs.eax.l; + return addr; +} + +int main(int argc, char *argv[]) +{ + int i; + struct in_addr addr; + + openconsole(&dev_null_r, &dev_stdcon_w); + + for (i = 1; i < argc; i++) { + addr = dnsresolve(argv[i]); + + printf("%-39s %08X %d.%d.%d.%d\n", + argv[i], ntohl(addr.s_addr), + ((uint8_t *)&addr.s_addr)[0], + ((uint8_t *)&addr.s_addr)[1], + ((uint8_t *)&addr.s_addr)[2], + ((uint8_t *)&addr.s_addr)[3]); + } + + return 0; +} diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c index 9a4edae2..2221bb0a 100644 --- a/com32/rosh/rosh.c +++ b/com32/rosh/rosh.c @@ -389,12 +389,12 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr) ROSH_DEBUG("--'%s'\n", filestr); } fd = open(filestr, O_RDONLY); - if (fd != -1) { + if (fd == -1) { status = fstat(fd, &fdstat); - if (S_ISDIR(fdstat.st_mode)) { + if (S_ISDIR(fdstat.st_mode)) { ROSH_DEBUG("PATH '%s' is a directory\n", ifilstr); d = fdopendir(fd); - de = readdir(d); + de = readdir(d); while (de != NULL) { #ifdef DO_DEBUG filestr2[0] = 0; @@ -423,19 +423,18 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr) } } else { #ifdef __COM32__ - if (filestr[strlen(filestr) - 1] == SEP) { + if (filestr[strlen(filestr) - 1] == SEP) { /* Directory */ filepos = 0; - d = opendir(filestr); + d = opendir(filestr); if (d != NULL) { - printf("DIR:'%s' %8d %8d\n", d->dd_name, d->dd_fd, - d->dd_sect); + //printf("DIR:'%s' %08x %8d\n", d->dd_name, (int)d->dd_sect, d->dd_offset); de = readdir(d); while (de != NULL) { filepos++; #ifdef DO_DEBUG // if (strlen(de->d_name) > 25) de->d_name[25] = 0; - switch (de->d_mode) { + switch (de->d_type) { case 16: ty = 'D'; break; @@ -445,8 +444,6 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr) default: ty = '*'; } - printf("@%8d:%8d:%4d ", (int)de->d_ino, (int)de->d_size, - de->d_mode); #endif /* DO_DEBUG */ // printf("%s\n", de->d_name); printf("'%s'\n", de->d_name); @@ -458,7 +455,6 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr) de = readdir(d); // if(filepos>15){ de = NULL; printf("Force Break\n");} } - printf("Dir.dd_fd: '%8d'\n", d->dd_fd); closedir(d); } else { rosh_error(0, "dir:NULL", filestr); diff --git a/com32/rosh/rosh.h b/com32/rosh/rosh.h index 64b0564c..0c41bac9 100644 --- a/com32/rosh/rosh.h +++ b/com32/rosh/rosh.h @@ -47,6 +47,8 @@ #error SYSLINUX (I believe) requires __GNUC__ #endif /* __GNUC__ */ +#define DO_DEBUG 1 + #ifdef DO_DEBUG #define ROSH_DEBUG(f, ...) printf (f, ## __VA_ARGS__) #ifdef DO_DEBUG2 diff --git a/core/Makefile b/core/Makefile index 17dac944..b9963657 100644 --- a/core/Makefile +++ b/core/Makefile @@ -33,24 +33,28 @@ CODEPAGE = cp865 # The targets to build in this directory... BTARGET = kwdhash.gen \ + extlinux.bin extlinux.bss extlinux.sys \ ldlinux.bss ldlinux.sys ldlinux.bin \ - pxelinux.0 isolinux.bin isolinux-debug.bin \ - extlinux.bin extlinux.bss extlinux.sys + isolinux.bin isolinux-debug.bin pxelinux.0 # All primary source files for the main syslinux files NASMSRC := $(wildcard *.asm) NASMHDR := $(wildcard *.inc) -CSRC := $(wildcard *.c */*.c) -SSRC := $(wildcard *.S lzo/*.S) -CHDR := $(wildcard *.h */*.h) +CSRC := $(wildcard *.c */*.c */*/*.c) +SSRC := $(wildcard *.S */*.S */*/*.S) +CHDR := $(wildcard *.h */*.h */*/*.h) OTHERSRC := keywords ALLSRC = $(NASMSRC) $(NASMHDR) $(CSRC) $(SSRC) $(CHDR) $(OTHERSRC) COBJ := $(patsubst %.c,%.o,$(CSRC)) SOBJ := $(patsubst %.S,%.o,$(SSRC)) +# +# Note: libcore.a should *NOT* be --whole-archive, since it contains all +# the filesystems... +# LIB = libcore.a -LIBS = --whole-archive $(LIB) $(com32)/lib/libcom32min.a +LIBS = $(LIB) --whole-archive $(com32)/lib/libcom32min.a # --no-whole-archive $(LIBGCC) LIBDEP = $(filter-out -% %start%,$(LIBS)) LIBOBJS = $(COBJ) $(SOBJ) @@ -131,8 +135,9 @@ netinstall: installer tidy dist: rm -f codepage.cp *.o *.elf *.a stupid.* patch.offset .depend .*.d - rm -f *.sym *.lsr *.lst *.map *.sec *.raw - rm -f */*.o */*.lst */.*.d + rm -f *.elf.tmp *.sym + rm -f *.lsr *.lst *.map *.sec *.raw + rm -f */*.o */*/*.o */*.lst */*/*.lst */.*.d */*/.*.d rm -f $(OBSOLETE) clean: tidy diff --git a/core/bios.inc b/core/bios.inc index 987a2166..4c6c5b59 100644 --- a/core/bios.inc +++ b/core/bios.inc @@ -18,6 +18,7 @@ %ifndef _BIOS_INC %define _BIOS_INC + global BIOS_fbm, BIOS_timer absolute 4*1Eh ; In the interrupt table fdctab equ $ diff --git a/core/bootsect.inc b/core/bootsect.inc index 4d70998c..23b4fdb4 100644 --- a/core/bootsect.inc +++ b/core/bootsect.inc @@ -80,7 +80,7 @@ load_bootsec: xor bx,bx %elif IS_PXELINUX mov byte [KeepPXE],03h ; Chainloading + keep PXE - call reset_pxe + pm_call reset_pxe lfs si,[InitStack] ; Put restore DS, EDX and ESI to the true initial values mov bx,[fs:si+6] diff --git a/core/cache.c b/core/cache.c new file mode 100644 index 00000000..c55f1603 --- /dev/null +++ b/core/cache.c @@ -0,0 +1,155 @@ +#include "core.h" +#include "cache.h" +#include <stdio.h> +#include <string.h> + + +/** + * Each CachePtr contains: + * - Block pointer + * - LRU previous pointer + * - LRU next pointer + * - Block data buffer address + * + * The cache buffer are pointed to by a cache_head structure. + */ + +/** + * cache_init: + * + * Initialize the cache data structres. + * regs->eax.l stores the block size(in bits not bytes) + * + */ +void cache_init(struct device *dev, int block_size_shift) +{ + struct cache_struct *prev, *cur; + char *data = dev->cache_data; + static __lowmem struct cache_struct cache_head, cache[MAX_CACHE_ENTRIES]; + int i; + + dev->cache_head = &cache_head; + dev->cache_block_size = 1 << block_size_shift; + dev->cache_entries = dev->cache_size >> block_size_shift; + if (dev->cache_entries > MAX_CACHE_ENTRIES) + dev->cache_entries = MAX_CACHE_ENTRIES; + + cache_head.prev = &cache[dev->cache_entries-1]; + cache_head.prev->next = &cache_head; + prev = &cache_head; + + for (i = 0; i < dev->cache_entries; i++) { + cur = &cache[i]; + cur->block = 0; + cur->prev = prev; + prev->next = cur; + cur->data = data; + data += dev->cache_block_size; + prev = cur++; + } +} + + +/** + * get_cache_block: + * + * Check for a particular BLOCK in the block cache, + * and if it is already there, just do nothing and return; + * otherwise load it and updata the relative cache + * structre with data pointer. + * + * it's a test version for my start of merging extlinux into core. + * and after I have figured out how to handle the relations between + * rm and pm, c and asm, we call call it from C file, so no need + * com32sys_t *regs any more. + * + * I just found that I was tring to do a stupid thing! + * I haven't change the fs code to c, so for now the cache is based + * on SECTOR SIZE but not block size. While we can fix it easily by + * make the block size be the sector size. + * + * @return: the data stores at gs:si + * + */ +struct cache_struct* get_cache_block(struct device *dev, block_t block) +{ + struct cache_struct *head = (struct cache_struct *)dev->cache_head; + struct cache_struct *last = head->prev; + /* let's find it from the end, 'cause the endest is the freshest */ + struct cache_struct *cs = head->prev; + int i; + static int total_read; + static int missed; + +#if 0 + printf("we are looking for cache of %d\n", block); +#endif + + if (!block) { + printf("ERROR: we got a ZERO block number that's not we want!\n"); + return NULL; + } + + /* it's aleardy the freshest, so nothing we need do , just return it */ + if (cs->block == block) + goto out; + + for (i = 0; i < dev->cache_entries; i ++) { + if (cs->block == block) + break; + else + cs = cs->prev; + } + + /* missed, so we need to load it */ + if (i == dev->cache_entries) { + /* store it at the head of real cache */ + cs = head->next; + cs->block = block; + getoneblk(dev->disk, cs->data, block, dev->cache_block_size); + + missed ++; + } + + /* remove cs from current position in list */ + cs->prev->next = cs->next; + cs->next->prev = cs->prev; + + /* add to just before head node */ + last->next = cs; + cs->prev = last; + head->prev = cs; + cs->next = head; + + out: + total_read ++; +#if 0 /* testing how efficiency the cache is */ + if (total_read % 5 == 0) + printf("total_read %d\tmissed %d\n", total_read, missed); +#endif + + /* in fact, that would never be happened */ + if ((char *)(cs->data) > (char*)0x100000) + printf("the buffer addres higher than 1M limit\n"); + + return cs; +} + + +/** + * Just print the sector, and according the LRU algorithm, + * Left most value is the most least secotr, and Right most + * value is the most Recent sector. I see it's a Left Right Used + * (LRU) algorithm; Just kidding:) + */ +void print_cache(struct device *dev) +{ + int i = 0; + struct cache_struct *cs = dev->cache_head; + for (; i < dev->cache_entries; i++) { + cs = cs->next; + printf("%d(%p) ", cs->block, cs->data); + } + + printf("\n"); +} diff --git a/core/call16.c b/core/call16.c index 1e369e29..86d70461 100644 --- a/core/call16.c +++ b/core/call16.c @@ -19,6 +19,8 @@ #include <stddef.h> #include "core.h" +const com32sys_t zero_regs; /* Common all-zero register set */ + void call16(void (*func)(void), const com32sys_t *ireg, com32sys_t *oreg) { core_farcall((size_t)func, ireg, oreg); diff --git a/core/comboot.inc b/core/comboot.inc index 079b4761..f01ff646 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -63,7 +63,7 @@ ; Looks like a COMBOOT image but too large comboot_too_large: - call close_file + pm_call close_file mov si,err_comlarge call writestr jmp enter_command @@ -126,7 +126,7 @@ is_comboot_image: mov bx,100h ; Load at <seg>:0100h mov cx,10000h >> SECTOR_SHIFT ; Absolute maximum # of sectors - call getfssec + pm_call getfssec cmp ecx,65536-256-2 ; Maximum size ja comboot_too_large @@ -517,9 +517,9 @@ comapi_open: mov ds,P_ES mov si,P_SI mov di,InitRD - call mangle_name + pm_call mangle_name pop ds - call searchdir + pm_call searchdir jz comapi_err mov P_EAX,eax mov P_CX,SECTOR_SIZE @@ -535,7 +535,7 @@ comapi_read: mov bx,P_BX mov si,P_SI mov cx,P_CX - call getfssec + pm_call getfssec jnc .noteof xor si,si ; SI <- 0 on EOF, CF <- 0 .noteof: mov P_SI,si @@ -547,7 +547,7 @@ comapi_read: ; comapi_close: mov si,P_SI - call close_file + pm_call close_file clc ret @@ -635,7 +635,7 @@ comapi_cleanup: test dl,3 setnz [KeepPXE] sub bp,sp ; unload_pxe may move the stack around - call unload_pxe + pm_call unload_pxe add bp,sp ; restore frame pointer... %elif IS_SYSLINUX || IS_EXTLINUX ; Restore original FDC table @@ -686,10 +686,11 @@ comapi_ipappend: ; INT 22h AX=0010h Resolve hostname ; %if IS_PXELINUX + extern pxe_dns_resolv comapi_dnsresolv: mov ds,P_ES mov si,P_BX - call dns_resolv + pm_call pxe_dns_resolv mov P_EAX,eax clc ret @@ -748,9 +749,9 @@ comapi_runkernel: mov ds,P_DS mov si,P_SI mov di,KernelName - call mangle_name + pm_call mangle_name pop ds - call searchdir + pm_call searchdir jz comapi_err ; The kernel image was found, so we can load it... @@ -900,21 +901,14 @@ comapi_getcwd: ; %if IS_SYSLINUX comapi_opendir: - push ds - mov ds,P_ES + mov es,P_ES mov si,P_SI mov di,InitRD - call mangle_name - pop ds - call searchdir - jnz comapi_err ; Didn't find a directory + pm_call vfs_opendir + jz comapi_err ; Didn't find a directory cmp eax,0 jz comapi_err ; Found nothing - ;ZF is unset - call alloc_fill_dir - mov P_EAX,eax - mov P_CX,SECTOR_SIZE - mov P_SI,si + mov P_EAX,eax clc ret %else @@ -926,14 +920,9 @@ comapi_opendir equ comapi_err ; %if IS_SYSLINUX comapi_readdir: - mov es,P_ES - mov di,P_DI - mov si,P_SI - call readdir - mov P_EAX,eax - mov P_DL,dl - mov P_EBX,ebx - mov P_SI,si + mov esi,P_ESI ; The address of DIR structure + pm_call vfs_readdir + mov P_EAX,eax ; The address of newly read dirent structure ret %else comapi_readdir equ comapi_err @@ -942,15 +931,10 @@ comapi_readdir equ comapi_err ; ; INT 22h AX=0022h Close directory ; -%if IS_SYSLINUX comapi_closedir: - mov si,P_SI - call close_dir - clc + mov esi,P_ESI ; The address of DIR structure + pm_call vfs_closedir ret -%else -comapi_closedir equ comapi_err -%endif ; ; INT 22h AX=0023h Query shuffler size @@ -1051,5 +1035,7 @@ err_comlarge db 'COMBOOT image too large.', CR, LF, 0 section .bss16 alignb 4 DOSErrTramp resd 33 ; Error trampolines + + global ConfigName, CurrentDirName ConfigName resb FILENAME_MAX CurrentDirName resb FILENAME_MAX diff --git a/core/config.inc b/core/config.inc index 5a3d1c5a..269e13ec 100644 --- a/core/config.inc +++ b/core/config.inc @@ -32,6 +32,12 @@ MAX_FKEYS equ 12 ; Number of F-key help files %assign HAS_LOCALBOOT 1 ; +; log2(Max filename size Including final null) +; +FILENAME_MAX_LG2 equ 8 +FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size + +; ; Version number definitinons ; %include "../version.gen" diff --git a/core/conio.inc b/core/conio.inc index 5209af1c..835359fb 100644 --- a/core/conio.inc +++ b/core/conio.inc @@ -207,8 +207,8 @@ msg_viewimage: mov byte [si],0 ; Zero-terminate filename mov si,VGAFileBuf mov di,VGAFileMBuf - call mangle_name - call open + pm_call mangle_name + call core_open jz msg_putcharnext ; Not there call vgadisplayfile ; Fall through diff --git a/core/dir.c b/core/dir.c new file mode 100644 index 00000000..d745a32f --- /dev/null +++ b/core/dir.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <string.h> +#include <sys/dirent.h> +#include <fs.h> +#include <core.h> + +extern struct fs_info *this_fs; + +/* + * open dir, return the file structure pointer in _eax_, or NULL if failed + */ +void vfs_opendir(com32sys_t *regs) +{ + this_fs->fs_ops->opendir(regs); + regs->eax.l = (uint32_t)handle_to_file(regs->esi.w[0]); +} + +/* + * Read one dirent at one time. + * + * @input: _esi_ register stores the address of DIR structure + * @output: _eax_ register stores the address of newly read dirent structure + */ +void vfs_readdir(com32sys_t *regs) +{ + DIR *dir = (DIR *)regs->esi.l; + struct dirent *de = NULL; + + if (dir->dd_dir) + de = this_fs->fs_ops->readdir(dir->dd_dir); + else + de = NULL; + + /* Return the newly read de in _eax_ register */ + regs->eax.l = (uint32_t)de; +} + +void vfs_closedir(com32sys_t *regs) +{ + DIR *dir = (DIR *)regs->esi.l; + _close_file(dir->dd_dir); +} + + diff --git a/core/diskfs.inc b/core/diskfs.inc new file mode 100644 index 00000000..b8d03762 --- /dev/null +++ b/core/diskfs.inc @@ -0,0 +1,182 @@ +; -*- fundamental -*- (asm-mode sucks) +; ----------------------------------------------------------------------- +; +; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved +; Copyright 2009 Intel Corporation; author: H. Peter Anvin +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +; Boston MA 02110-1301, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; ----------------------------------------------------------------------- + +; +; diskfs.inc +; +; Common code for conventional disk-based filesystems +; + +; +; Some semi-configurable constants... change on your own risk. +; +NULLFILE equ 0 ; Null character == empty filename +NULLOFFSET equ 0 ; Position in which to look +retry_count equ 16 ; How patient are we with the disk? +%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top +LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with + +SECTOR_SHIFT equ 9 +SECTOR_SIZE equ (1 << SECTOR_SHIFT) + +; +; The following structure is used for "virtual kernels"; i.e. LILO-style +; option labels. The options we permit here are `kernel' and `append +; Since there is no room in the bottom 64K for all of these, we +; stick them in high memory and copy them down before we need them. +; + struc vkernel +vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** +vk_rname: resb FILENAME_MAX ; Real name +vk_appendlen: resw 1 +vk_type: resb 1 ; Type of file + alignb 4 +vk_append: resb max_cmd_len+1 ; Command line + alignb 4 +vk_end: equ $ ; Should be <= vk_size + endstruc + + + +; --------------------------------------------------------------------------- +; BEGIN CODE +; --------------------------------------------------------------------------- + +; +; Memory below this point is reserved for the BIOS and the MBR +; + section .earlybss + global trackbuf +trackbufsize equ 8192 +trackbuf resb trackbufsize ; Track buffer goes here + ; ends at 2800h + +; +; Common bootstrap code for disk-based derivatives +; +%include "diskstart.inc" + + +; +; Now, everything is "up and running"... patch kaboom for more +; verbosity and using the full screen system +; + ; E9 = JMP NEAR + mov di,kaboom.patch + mov al,0e9h + stosb + mov ax,kaboom2-2 + sub ax,di + stosw + +; +; Now we're all set to start with our *real* business. First load the +; configuration file (if any) and parse it. +; +; In previous versions I avoided using 32-bit registers because of a +; rumour some BIOSes clobbered the upper half of 32-bit registers at +; random. I figure, though, that if there are any of those still left +; they probably won't be trying to install Linux on them... +; +; The code is still ripe with 16-bitisms, though. Not worth the hassle +; to take'm out. In fact, we may want to put them back if we're going +; to boot ELKS at some point. +; + +; +; Load configuration file +; + pm_call load_config + jz no_config_file + +; +; Now we have the config file open. Parse the config file and +; run the user interface. +; +%include "ui.inc" + +; +; +; kaboom2: once everything is loaded, replace the part of kaboom +; starting with "kaboom.patch" with this part + +kaboom2: + mov si,err_bootfailed + call writestr + cmp byte [kaboom.again+1],18h ; INT 18h version? + je .int18 + call getchar + call vgaclearmode + int 19h ; And try once more to boot... +.norge: jmp short .norge ; If int 19h returned; this is the end +.int18: + call vgaclearmode + int 18h +.noreg: jmp short .noreg ; Nynorsk + +; ----------------------------------------------------------------------------- +; Common modules +; ----------------------------------------------------------------------------- + +%include "common.inc" ; Universal modules +%include "plaincon.inc" ; writechr +%include "writestr.inc" ; String output +%include "writehex.inc" ; Hexadecimal output +%include "localboot.inc" ; Disk-based local boot + +; ----------------------------------------------------------------------------- +; Begin data section +; ----------------------------------------------------------------------------- + + section .data16 +copyright_str db ' Copyright (C) 1994-' + asciidec YEAR + db ' H. Peter Anvin et al', CR, LF, 0 +err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' + db 'a key to continue.', CR, LF, 0 + +; +; Config file keyword table +; +%include "keywords.inc" + +; +; Extensions to search for (in *forward* order). +; + alignz 4 +exten_table: db '.cbt' ; COMBOOT (specific) +%if IS_SYSLINUX + db '.bss' ; Boot sector (add superblock) +%endif + db '.bs', 0 ; Boot sector + db '.com' ; COMBOOT (same as DOS) + db '.c32' ; COM32 +exten_table_end: + dd 0, 0 ; Need 8 null bytes here + +; +; Misc initialized (data) variables +; +%ifdef debug ; This code for debugging only +debug_magic dw 0D00Dh ; Debug code sentinel +%endif + + alignz 4 +BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf +BufSafeBytes dw trackbufsize ; = how many bytes? +%ifndef DEPEND +%if ( trackbufsize % SECTOR_SIZE ) != 0 +%error trackbufsize must be a multiple of SECTOR_SIZE +%endif +%endif diff --git a/core/diskio.c b/core/diskio.c new file mode 100644 index 00000000..c51f7225 --- /dev/null +++ b/core/diskio.c @@ -0,0 +1,352 @@ +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <klibc/compiler.h> +#include "core.h" +#include "fs.h" +#include "disk.h" + +#define RETRY_COUNT 6 + +static uint16_t MaxTransfer = 1 << (16 - 9); + +static int chs_rdwr_sectors(struct disk *disk, void *buf, + sector_t lba, size_t count, bool is_write) +{ + char *ptr = buf; + char *tptr; + size_t chunk, freeseg; + int sector_shift = disk->sector_shift; + uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */ + uint32_t t; + uint16_t c, h, s; + com32sys_t ireg, oreg; + size_t done = 0; + size_t bytes; + int retry; + + memset(&ireg, 0, sizeof ireg); + + ireg.eax.b[1] = 0x02 + is_write; + ireg.edx.b[0] = disk->disk_number; + + while (count) { + chunk = count; + if (chunk > MaxTransfer) + chunk = MaxTransfer; + + freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; + + if ((size_t)buf <= 0xf0000 && freeseg) { + /* Can do a direct load */ + tptr = ptr; + } else { + /* Either accessing high memory or we're crossing a 64K line */ + tptr = core_xfer_buf; + freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift; + } + if (chunk > freeseg) + chunk = freeseg; + + bytes = chunk << sector_shift; + + if (tptr != ptr && is_write) + memcpy(tptr, ptr, bytes); + + s = xlba % disk->s; + t = xlba / disk->s; + h = t % disk->h; + c = t / disk->h; + + ireg.eax.b[0] = chunk; + ireg.ecx.b[1] = c; + ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); + ireg.edx.b[1] = h; + ireg.ebx.w[0] = OFFS(tptr); + ireg.es = SEG(tptr); + + retry = RETRY_COUNT; + + for (;;) { + __intcall(0x13, &ireg, &oreg); + if (!(oreg.eflags.l & EFLAGS_CF)) + break; + if (retry--) + continue; + + /* if we are reading ONE sector and go here, just make it _faile_ */ + chunk = chunk == 1 ? 0 : ((chunk+1) >> 1); + if (chunk) { + MaxTransfer = chunk; + retry = RETRY_COUNT; + ireg.eax.b[0] = chunk; + continue; + } + return done; /* Failure */ + } + + bytes = chunk << sector_shift; + + if (tptr != ptr && !is_write) + memcpy(ptr, tptr, bytes); + + ptr += bytes; + xlba += chunk; + count -= chunk; + done += chunk; + } + + return done; +} + +struct edd_rdwr_packet { + uint16_t size; + uint16_t blocks; + far_ptr_t buf; + uint64_t lba; +}; + +static int edd_rdwr_sectors(struct disk *disk, void *buf, + sector_t lba, size_t count, bool is_write) +{ + static __lowmem struct edd_rdwr_packet pkt; + char *ptr = buf; + char *tptr; + size_t chunk, freeseg; + int sector_shift = disk->sector_shift; + com32sys_t ireg, oreg; + size_t done = 0; + size_t bytes; + int retry; + + memset(&ireg, 0, sizeof ireg); + + ireg.eax.b[1] = 0x42 + is_write; + ireg.edx.b[0] = disk->disk_number; + ireg.ds = SEG(&pkt); + ireg.esi.w[0] = OFFS(&pkt); + + lba += disk->part_start; + while (count) { + chunk = count; + if (chunk > MaxTransfer) + chunk = MaxTransfer; + + freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; + + if ((size_t)buf <= 0xf0000 && freeseg) { + /* Can do a direct load */ + tptr = ptr; + } else { + /* Either accessing high memory or we're crossing a 64K line */ + tptr = core_xfer_buf; + freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift; + } + if (chunk > freeseg) + chunk = freeseg; + + bytes = chunk << sector_shift; + + if (tptr != ptr && is_write) + memcpy(tptr, ptr, bytes); + + pkt.size = sizeof pkt; + pkt.blocks = chunk; + pkt.buf = FAR_PTR(tptr); + pkt.lba = lba; + + retry = RETRY_COUNT; + + for (;;) { + __intcall(0x13, &ireg, &oreg); + if (!(oreg.eflags.l & EFLAGS_CF)) + break; + if (retry--) + continue; + chunk = chunk == 1 ? 0 : ((chunk+1) >> 1); + if (chunk) { + MaxTransfer = chunk; + retry = RETRY_COUNT; + pkt.blocks = chunk; + continue; + } + /*** XXX: Consider falling back to CHS here?! ***/ + printf("reading sectors error(EDD)\n"); + return done; /* Failure */ + } + + bytes = chunk << sector_shift; + + if (tptr != ptr && !is_write) + memcpy(ptr, tptr, bytes); + + ptr += bytes; + lba += chunk; + count -= chunk; + done += chunk; + } + return done; +} +struct edd_disk_params { + uint16_t len; + uint16_t flags; + uint32_t phys_c; + uint32_t phys_h; + uint32_t phys_s; + uint64_t sectors; + uint16_t sector_size; + far_ptr_t dpte; + uint16_t devpath_key; + uint8_t devpath_len; + uint8_t _pad1[3]; + char bus_type[4]; + char if_type[8]; + uint8_t if_path[8]; + uint8_t dev_path[8]; + uint8_t _pad2; + uint8_t devpath_csum; +} __attribute__((packed)); + +static inline bool is_power_of_2(uint32_t x) +{ + return !(x & (x-1)); +} + +static int ilog2(uint32_t num) +{ + int i = 0; + + if (!is_power_of_2(num)) { + printf("ERROR: the num must be power of 2 when conveting to log2\n"); + return 0; + } + while (num >>= 1) + i++; + return i; +} + +void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) +{ + int sec_per_block = block_size >> SECTOR_SHIFT; + + disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0); +} + +static void dump_disk(struct disk *disk) +{ + printf("drive number: 0x%x\n", disk->disk_number); + printf("disk type: %s(%d)\n", disk->type ? "EDD" : "CHS", disk->type); + printf("sector size: %d(%d)\n", disk->sector_size, disk->sector_shift); + printf("h: %d\ts: %d\n", disk->h, disk->s); + printf("offset: %d\n", disk->part_start); + printf("%s\n", disk->rdwr_sectors == edd_rdwr_sectors ? "EDD_RDWR_SECTORS" : + "CHS_RDWR_SECTORS"); + printf("--------------------------------\n"); + printf("disk->rdwr_sectors@: %p\n", disk->rdwr_sectors); + printf("edd_rdwr_sectors @: %p\n", edd_rdwr_sectors); + printf("chs_rdwr_sectors @: %p\n", chs_rdwr_sectors); +} + +struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, + uint16_t bsHeads, uint16_t bsSecPerTrack) +{ + static struct disk disk; + static __lowmem struct edd_disk_params edd_params; + com32sys_t ireg, oreg; + bool ebios = cdrom; + int sector_size = cdrom ? 2048 : 512; + + memset(&ireg, 0, sizeof ireg); + + /* Get EBIOS support */ + ireg.eax.b[1] = 0x41; + ireg.ebx.w[0] = 0x55aa; + ireg.edx.b[0] = devno; + ireg.eflags.b[0] = 0x3; /* CF set */ + + __intcall(0x13, &ireg, &oreg); + + if (cdrom || (!(oreg.eflags.l & EFLAGS_CF) && + oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1))) { + /* Query EBIOS parameters */ + ireg.eax.b[1] = 0x48; + ireg.ds = SEG(&edd_params); + ireg.esi.w[0] = OFFS(&edd_params); + __intcall(0x13, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) { + ebios = true; + if (edd_params.sector_size >= 512 && + is_power_of_2(edd_params.sector_size)) + sector_size = edd_params.sector_size; + } + } + + /* CBIOS parameters */ + disk.h = bsHeads; + disk.s = bsSecPerTrack; + + if ((int8_t)devno < 0) { + /* Get hard disk geometry from BIOS */ + + ireg.eax.b[1] = 0x08; + __intcall(0x13, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF)) { + disk.h = oreg.edx.b[1] + 1; + disk.s = oreg.ecx.b[0] & 63; + } + } + + disk.disk_number = devno; + disk.type = ebios; + disk.sector_size = sector_size; + disk.sector_shift = ilog2(sector_size); + disk.part_start = part_start; + disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; + +#if 0 + dump_disk(&disk); +#endif + return &disk; +} + + +/* + * initialize the device structure + */ +struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start, + uint16_t bsHeads, uint16_t bsSecPerTrack) +{ + static struct device dev; + + dev.disk = disk_init(devno, cdrom, part_start, bsHeads, bsSecPerTrack); + + /* for now, isolinux doesn't use cache */ + if (!cdrom) { + /* + * FIX!! I can't use __lowmem here, 'cause it will cause the error: + * "auxseg/lowmem region collides with xfer_buf_seg". + * + * static __lowmem char cache_buf[65536]; + */ + dev.cache_data = core_cache_buf; + dev.cache_size = sizeof core_cache_buf; + } else + dev.cache_data = NULL; + + return &dev; +} + + +/* debug function */ +static void dump_dev(struct device *dev) +{ + printf("device type:%s\n", dev->disk->type ? "EDD" : "CHS"); + printf("drive number: 0x%x\n", dev->disk->disk_number); + printf("cache_data: %p\n", dev->cache_data); + printf("cache_head: %p\n", dev->cache_head); + printf("cache_block_size: %d\n", dev->cache_block_size); + printf("cache_entries: %d\n", dev->cache_entries); + printf("cache_size: %d\n", dev->cache_size); +} diff --git a/core/diskstart.inc b/core/diskstart.inc index d7279028..36d513ed 100644 --- a/core/diskstart.inc +++ b/core/diskstart.inc @@ -96,6 +96,7 @@ superblock_len_fat32 equ $-superblock+54 zb 54 ; Maximum needed size superblock_max equ $-superblock + global SecPerClust SecPerClust equ bxSecPerClust ; ; Note we don't check the constraints above now; we did that at install @@ -252,6 +253,7 @@ getonesec: ; that is dead from that point; this saves space. However, please keep ; the order to dst,src to keep things sane. ; + global getlinsec getlinsec: add eax,[bsHidden] ; Add partition offset xor edx,edx ; Zero-extend LBA (eventually allow 64 bits) @@ -453,6 +455,7 @@ bailmsg: db 'Boot error', 0Dh, 0Ah, 0 zb 1F8h-($-$$) FirstSector dd 0xDEADBEEF ; Location of sector 1 + global MaxTransfer MaxTransfer dw 0x007F ; Max transfer size ; This field will be filled in 0xAA55 by the installer, but we abuse it @@ -487,6 +490,7 @@ ADVSectors dw 0 ; Additional sectors for ADVs LDLDwords dd 0 ; Total dwords starting at ldlinux_sys, CheckSum dd 0 ; Checksum starting at ldlinux_sys ; value = LDLINUX_MAGIC - [sum of dwords] + global CurrentDir CurrentDir dd 2 ; "Current" directory inode number (EXTLINUX) SecPtrOffset dw SectorPtrs - ldlinux_sys SecPtrCnt dw (SectorPtrsEnd - SectorPtrs) >> 2 @@ -709,6 +713,21 @@ expand_super: stosd ; Store expanded byte loop .loop + ; -; Fall through to the mainline code... +; Common initialization code ; +%include "init.inc" +%include "cpuinit.inc" + + + pushad + mov eax,ROOT_FS_OPS + movzx dx,byte [DriveNumber] + ; DH = 0: we are boot from disk not CDROM + mov ecx,[bsHidden] + mov ebx,[bsHidden+4] + mov si,[bsHeads] + mov di,[bsSecPerTrack] + pm_call fs_init + popad diff --git a/core/dnsresolv.inc b/core/dnsresolv.inc deleted file mode 100644 index 7b632378..00000000 --- a/core/dnsresolv.inc +++ /dev/null @@ -1,389 +0,0 @@ -; -*- fundamental -*- -; ----------------------------------------------------------------------- -; -; Copyright 2004-2008 H. Peter Anvin - All Rights Reserved -; -; This program is free software; you can redistribute it and/or modify -; it under the terms of the GNU General Public License as published by -; the Free Software Foundation, Inc., 53 Temple Place Ste 330, -; Bostom MA 02111-1307, USA; either version 2 of the License, or -; (at your option) any later version; incorporated herein by reference. -; -; ----------------------------------------------------------------------- - -; -; dnsresolv.inc -; -; Very simple DNS resolver (assumes recursion-enabled DNS server; -; this should be the normal thing for client-serving DNS servers.) -; - -DNS_PORT equ htons(53) ; Default DNS port -DNS_MAX_PACKET equ 512 ; Defined by protocol -; TFTP uses the range 49152-57343 -DNS_LOCAL_PORT equ htons(60053) ; All local DNS queries come from this port # -DNS_MAX_SERVERS equ 4 ; Max no of DNS servers - - section .text16 - -; -; Turn a string in DS:SI into a DNS "label set" in ES:DI. -; On return, DI points to the first byte after the label set, -; and SI to the terminating byte. -; -; On return, DX contains the number of dots encountered. -; -dns_mangle: - push ax - push bx - xor dx,dx -.isdot: - inc dx - xor al,al - mov bx,di - stosb -.getbyte: - lodsb - and al,al - jz .endstring - cmp al,':' - jz .endstring - cmp al,'.' - je .isdot - inc byte [es:bx] - stosb - jmp .getbyte -.endstring: - dec si - dec dx ; We always counted one high - cmp byte [es:bx],0 - jz .done - xor al,al - stosb -.done: - pop bx - pop ax - ret - -; -; Compare two sets of DNS labels, in DS:SI and ES:DI; the one in SI -; is allowed pointers relative to a packet in DNSRecvBuf. -; -; Assumes DS == ES. ZF = 1 if same; no registers changed. -; (Note: change reference to [di] to [es:di] to remove DS == ES assumption) -; -dns_compare: - pusha -%if 0 - -.label: - lodsb - cmp al,0C0h - jb .noptr - and al,03Fh ; Get pointer value - mov ah,al ; ... in network byte order! - lodsb - mov si,DNSRecvBuf - add si,ax - jmp .label -.noptr: - cmp al,[di] - jne .done ; Mismatch - inc di - movzx cx,al ; End label? - and cx,cx ; ZF = 1 if match - jz .done - - ; We have a string of bytes that need to match now - repe cmpsb - je .label - -.done: -%else - xor ax,ax -%endif - popa - ret - -; -; Skip past a DNS label set in DS:SI. -; -dns_skiplabel: - push ax - xor ax,ax ; AH == 0 -.loop: - lodsb - cmp al,0C0h ; Pointer? - jae .ptr - and al,al - jz .done - add si,ax - jmp .loop -.ptr: - inc si ; Pointer is two bytes -.done: - pop ax - ret - - ; DNS header format - struc dnshdr -.id: resw 1 -.flags: resw 1 -.qdcount: resw 1 -.ancount: resw 1 -.nscount: resw 1 -.arcount: resw 1 - endstruc - - ; DNS query - struc dnsquery -.qtype: resw 1 -.qclass: resw 1 - endstruc - - ; DNS RR - struc dnsrr -.type: resw 1 -.class: resw 1 -.ttl: resd 1 -.rdlength: resw 1 -.rdata: equ $ - endstruc - - section .bss16 - alignb 2 -DNSSendBuf resb DNS_MAX_PACKET -DNSRecvBuf resb DNS_MAX_PACKET -LocalDomain resb 256 ; Max possible length -DNSServers resd DNS_MAX_SERVERS - - section .data16 -pxe_udp_write_pkt_dns: -.status: dw 0 ; Status -.sip: dd 0 ; Server IP -.gip: dd 0 ; Gateway IP -.lport: dw DNS_LOCAL_PORT ; Local port -.rport: dw DNS_PORT ; Remote port -.buffersize: dw 0 ; Size of packet -.buffer: dw DNSSendBuf, 0 ; off, seg of buffer - -pxe_udp_read_pkt_dns: -.status: dw 0 ; Status -.sip: dd 0 ; Source IP -.dip: dd 0 ; Destination (our) IP -.rport: dw DNS_PORT ; Remote port -.lport: dw DNS_LOCAL_PORT ; Local port -.buffersize: dw DNS_MAX_PACKET ; Max packet size -.buffer: dw DNSRecvBuf, 0 ; off, seg of buffer - -LastDNSServer dw DNSServers - -; Actual resolver function -; Points to a null-terminated or :-terminated string in DS:SI -; and returns the name in EAX if it exists and can be found. -; If EAX = 0 on exit, the lookup failed. -; -; No segment assumptions permitted. -; - section .text16 -dns_resolv: - push ds - push es - push di - push bx - push cx - push dx - - push cs - pop es ; ES <- CS - - ; First, build query packet - mov di,DNSSendBuf+dnshdr.flags - inc word [es:di-2] ; New query ID - mov ax,htons(0100h) ; Recursion requested - stosw - mov ax,htons(1) ; One question - stosw - xor ax,ax ; No answers, NS or ARs - stosw - stosw - stosw - - call dns_mangle ; Convert name to DNS labels - - push cs ; DS <- CS - pop ds - - push si ; Save pointer to after DNS string - - ; Initialize... - mov eax,[MyIP] - mov [pxe_udp_read_pkt_dns.dip],eax - - and dx,dx - jnz .fqdn ; If we have dots, assume it's FQDN - dec di ; Remove final null - mov si,LocalDomain - call strcpy ; Uncompressed DNS label set so it ends in null -.fqdn: - - mov ax,htons(1) - stosw ; QTYPE = 1 = A - stosw ; QCLASS = 1 = IN - - sub di,DNSSendBuf - mov [pxe_udp_write_pkt_dns.buffersize],di - - ; Now, send it to the nameserver(s) - ; Outer loop: exponential backoff - ; Inner loop: scan the various DNS servers - - mov bx,TimeoutTable -.backoff: - movzx dx,byte [bx] - mov si,DNSServers -.servers: - cmp si,[LastDNSServer] - jb .moreservers - -.nomoreservers: - inc bx - cmp bx,TimeoutTableEnd - jb .backoff - - xor eax,eax ; Nothing... -.done: - pop si - pop dx - pop cx - pop bx - pop di - pop es - pop ds - ret - -.moreservers: - lodsd ; EAX <- next server - push si - push bx - push cx - push dx - - mov word [pxe_udp_write_pkt_dns.status],0 - - mov [pxe_udp_write_pkt_dns.sip],eax - mov [pxe_udp_read_pkt_dns.sip],eax - xor eax,[MyIP] - and eax,[Netmask] - jz .nogw - mov eax,[Gateway] -.nogw: - mov [pxe_udp_write_pkt_dns.gip],eax - - mov di,pxe_udp_write_pkt_dns - mov bx,PXENV_UDP_WRITE - call pxenv - jc .timeout ; Treat failed transmit as timeout - cmp word [pxe_udp_write_pkt_dns.status],0 - jne .timeout - - mov cx,[BIOS_timer] -.waitrecv: - mov ax,[BIOS_timer] - sub ax,cx - cmp ax,dx - jae .timeout - - mov word [pxe_udp_read_pkt_dns.status],0 - mov word [pxe_udp_read_pkt_dns.buffersize],DNS_MAX_PACKET - mov di,pxe_udp_read_pkt_dns - mov bx,PXENV_UDP_READ - call pxenv - and ax,ax - jnz .waitrecv - cmp [pxe_udp_read_pkt_dns.status],ax - jnz .waitrecv - - ; Got a packet, deal with it... - mov si,DNSRecvBuf - lodsw - cmp ax,[DNSSendBuf] ; ID - jne .waitrecv ; Not ours - - lodsw ; flags - xor al,80h ; Query#/Answer bit - test ax,htons(0F80Fh) - jnz .badness - - lodsw - xchg ah,al ; ntohs - mov cx,ax ; Questions echoed - lodsw - xchg ah,al ; ntohs - push ax ; Replies - lodsw ; NS records - lodsw ; Authority records - - jcxz .qskipped -.skipq: - call dns_skiplabel ; Skip name - add si,4 ; Skip question trailer - loop .skipq - -.qskipped: - pop cx ; Number of replies - jcxz .badness - -.parseanswer: - mov di,DNSSendBuf+dnshdr_size - call dns_compare - pushf - call dns_skiplabel - mov ax,[si+8] ; RDLENGTH - xchg ah,al ; ntohs - popf - jnz .notsame - cmp dword [si],htons(1)*0x10001 ; TYPE = A, CLASS = IN? - jne .notsame - cmp ax,4 ; RDLENGTH = 4? - jne .notsame - ; - ; We hit paydirt here... - ; - mov eax,[si+10] -.gotresult: - add sp,8 ; Drop timeout information - jmp .done - -.notsame: - add si,10 - add si,ax - loop .parseanswer - -.badness: - ; We got back no data from this server. - ; Unfortunately, for a recursive, non-authoritative - ; query there is no such thing as an NXDOMAIN reply, - ; which technically means we can't draw any - ; conclusions. However, in practice that means the - ; domain doesn't exist. If this turns out to be a - ; problem, we may want to add code to go through all - ; the servers before giving up. - - ; If the DNS server wasn't capable of recursion, and - ; isn't capable of giving us an authoritative reply - ; (i.e. neither AA or RA set), then at least try a - ; different setver... - - test word [DNSRecvBuf+dnshdr.flags],htons(0480h) - jz .timeout - - xor eax,eax - jmp .gotresult - -.timeout: - pop dx - pop cx - pop bx - pop si - jmp .servers diff --git a/core/ext2_fs.inc b/core/ext2_fs.inc deleted file mode 100644 index e84efb14..00000000 --- a/core/ext2_fs.inc +++ /dev/null @@ -1,183 +0,0 @@ -; ----------------------------------------------------------------------- -; -; Copyright 1998-2008 H. Peter Anvin - All Rights Reserved -; -; This program is free software; you can redistribute it and/or modify -; it under the terms of the GNU General Public License as published by -; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, -; USA; either version 2 of the License, or (at your option) any later -; version; incorporated herein by reference. -; -; ----------------------------------------------------------------------- - -; -; ext2_fs.inc -; -; NASM include file for ext2fs data structures -; - -%define EXT2_SUPER_MAGIC 0xEF53 - -%define EXT2_GOOD_OLD_REV 0 ; The good old (original) format -%define EXT2_DYNAMIC_REV 1 ; V2 format w/ dynamic inode sizes -%define EXT2_GOOD_OLD_INODE_SIZE 128 - -; Special inode numbers -%define EXT2_BAD_INO 1 ; Bad blocks inode -%define EXT2_ROOT_INO 2 ; Root inode -%define EXT2_BOOT_LOADER_INO 5 ; Boot loader inode -%define EXT2_UNDEL_DIR_INO 6 ; Undelete directory inode -%define EXT3_RESIZE_INO 7 ; Reserved group descriptors inode -%define EXT3_JOURNAL_INO 8 ; Journal inode - -; We're readonly, so we only care about incompat features. -%define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 -%define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 -%define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 -%define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 -%define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 -%define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff - -%define EXT2_NDIR_BLOCKS 12 -%define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS -%define EXT2_DIND_BLOCK (EXT2_IND_BLOCK+1) -%define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK+1) -%define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1) - -; -; File types and file modes -; -%define S_IFDIR 0040000o ; Directory -%define S_IFCHR 0020000o ; Character device -%define S_IFBLK 0060000o ; Block device -%define S_IFREG 0100000o ; Regular file -%define S_IFIFO 0010000o ; FIFO -%define S_IFLNK 0120000o ; Symbolic link -%define S_IFSOCK 0140000o ; Socket - -%define S_IFSHIFT 12 - -%define T_IFDIR (S_IFDIR >> S_IFSHIFT) -%define T_IFCHR (S_IFCHR >> S_IFSHIFT) -%define T_IFBLK (S_IFBLK >> S_IFSHIFT) -%define T_IFREG (S_IFREG >> S_IFSHIFT) -%define T_IFIFO (S_IFIFO >> S_IFSHIFT) -%define T_IFLNK (S_IFLNK >> S_IFSHIFT) -%define T_IFSOCK (S_IFSOCK >> S_IFSHIFT) - -; -; Structure definition for the ext2 superblock -; - struc ext2_super_block -s_inodes_count resd 1 ; Inodes count -s_blocks_count resd 1 ; Blocks count -s_r_blocks_count resd 1 ; Reserved blocks count -s_free_blocks_count resd 1 ; Free blocks count -s_free_inodes_count resd 1 ; Free inodes count -s_first_data_block resd 1 ; First Data Block -s_log_block_size resd 1 ; Block size -s_log_frag_size resd 1 ; Fragment size -s_blocks_per_group resd 1 ; # Blocks per group -s_frags_per_group resd 1 ; # Fragments per group -s_inodes_per_group resd 1 ; # Inodes per group -s_mtime resd 1 ; Mount time -s_wtime resd 1 ; Write time -s_mnt_count resw 1 ; Mount count -s_max_mnt_count resw 1 ; Maximal mount count -s_magic resw 1 ; Magic signature -s_state resw 1 ; File system state -s_errors resw 1 ; Behaviour when detecting errors -s_minor_rev_level resw 1 ; minor revision level -s_lastcheck resd 1 ; time of last check -s_checkinterval resd 1 ; max. time between checks -s_creator_os resd 1 ; OS -s_rev_level resd 1 ; Revision level -s_def_resuid resw 1 ; Default uid for reserved blocks -s_def_resgid resw 1 ; Default gid for reserved blocks -s_first_ino resd 1 ; First non-reserved inode -s_inode_size resw 1 ; size of inode structure -s_block_group_nr resw 1 ; block group # of this superblock -s_feature_compat resd 1 ; compatible feature set -s_feature_incompat resd 1 ; incompatible feature set -s_feature_ro_compat resd 1 ; readonly-compatible feature set -s_uuid resb 16 ; 128-bit uuid for volume -s_volume_name resb 16 ; volume name -s_last_mounted resb 64 ; directory where last mounted -s_algorithm_usage_bitmap resd 1 ; For compression -s_prealloc_blocks resb 1 ; Nr of blocks to try to preallocate -s_prealloc_dir_blocks resb 1 ; Nr to preallocate for dirs -s_padding1 resw 1 -s_reserved resd 204 ; Padding to the end of the block - endstruc - -%ifndef DEPEND -%if ext2_super_block_size != 1024 -%error "ext2_super_block definition bogus" -%endif -%endif - -; -; Structure definition for the ext2 inode -; - struc ext2_inode -i_mode resw 1 ; File mode -i_uid resw 1 ; Owner Uid -i_size resd 1 ; Size in bytes -i_atime resd 1 ; Access time -i_ctime resd 1 ; Creation time -i_mtime resd 1 ; Modification time -i_dtime resd 1 ; Deletion Time -i_gid resw 1 ; Group Id -i_links_count resw 1 ; Links count -i_blocks resd 1 ; Blocks count -i_flags resd 1 ; File flags -l_i_reserved1 resd 1 -i_block resd EXT2_N_BLOCKS ; Pointer to blocks -i_version resd 1 ; File version (for NFS) -i_file_acl resd 1 ; File ACL -i_dir_acl resd 1 ; Directory ACL -i_faddr resd 1 ; Fragment address -l_i_frag resb 1 ; Fragment number -l_i_fsize resb 1 ; Fragment size -i_pad1 resw 1 -l_i_reserved2 resd 2 - endstruc - -%ifndef DEPEND -%if ext2_inode_size != 128 -%error "ext2_inode definition bogus" -%endif -%endif - -; -; Structure definition for ext2 block group descriptor -; - struc ext2_group_desc -bg_block_bitmap resd 1 ; Block bitmap block -bg_inode_bitmap resd 1 ; Inode bitmap block -bg_inode_table resd 1 ; Inode table block -bg_free_blocks_count resw 1 ; Free blocks count -bg_free_inodes_count resw 1 ; Free inodes count -bg_used_dirs_count resw 1 ; Used inodes count -bg_pad resw 1 -bg_reserved resd 3 - endstruc - -%ifndef DEPEND -%if ext2_group_desc_size != 32 -%error "ext2_group_desc definition bogus" -%endif -%endif - -%define ext2_group_desc_lg2size 5 - -; -; Structure definition for ext2 directory entry -; - struc ext2_dir_entry -d_inode resd 1 ; Inode number -d_rec_len resw 1 ; Directory entry length -d_name_len resb 1 ; Name length -d_file_type resb 1 ; File type -d_name equ $ - endstruc diff --git a/core/extern.inc b/core/extern.inc index bc3ffef5..0c127805 100644 --- a/core/extern.inc +++ b/core/extern.inc @@ -15,4 +15,15 @@ ; elflink/load_env32.c extern load_env32 + ; fs.c + extern fs_init, searchdir, getfssec, mangle_name, load_config + extern unmangle_name, close_file + + ; dir.c + extern vfs_opendir, vfs_readdir, vfs_closedir +%if IS_PXELINUX + ; pxe.c + extern unload_pxe, reset_pxe +%endif + %endif ; EXTERN_INC diff --git a/core/extlinux.asm b/core/extlinux.asm index 503bbf7e..1f5423b2 100644 --- a/core/extlinux.asm +++ b/core/extlinux.asm @@ -18,909 +18,13 @@ %define IS_EXTLINUX 1 %include "head.inc" -%include "ext2_fs.inc" ; ; Some semi-configurable constants... change on your own risk. ; my_id equ extlinux_id -; NASM 0.98.38 croaks if these are equ's rather than macros... -FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null) -FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size -NULLFILE equ 0 ; Null character == empty filename -NULLOFFSET equ 0 ; Position in which to look -retry_count equ 16 ; How patient are we with the disk? -%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top -LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with -MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) -MAX_OPEN equ (1 << MAX_OPEN_LG2) + extern ext2_fs_ops +ROOT_FS_OPS equ ext2_fs_ops -SECTOR_SHIFT equ 9 -SECTOR_SIZE equ (1 << SECTOR_SHIFT) - -MAX_SYMLINKS equ 64 ; Maximum number of symlinks per lookup -SYMLINK_SECTORS equ 2 ; Max number of sectors in a symlink - ; (should be >= FILENAME_MAX) - -ROOT_DIR_WORD equ 0x002F -CUR_DIR_DWORD equ 0x00002F2E - -; -; The following structure is used for "virtual kernels"; i.e. LILO-style -; option labels. The options we permit here are `kernel' and `append -; Since there is no room in the bottom 64K for all of these, we -; stick them in high memory and copy them down before we need them. -; - struc vkernel -vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** -vk_rname: resb FILENAME_MAX ; Real name -vk_appendlen: resw 1 -vk_type: resb 1 ; Type of file - alignb 4 -vk_append: resb max_cmd_len+1 ; Command line - alignb 4 -vk_end: equ $ ; Should be <= vk_size - endstruc - -; -; File structure. This holds the information for each currently open file. -; - struc open_file_t -file_bytesleft resd 1 ; Number of bytes left (0 = free) -file_sector resd 1 ; Next linear sector to read -file_in_sec resd 1 ; Sector where inode lives -file_in_off resw 1 -file_mode resw 1 - endstruc - -%ifndef DEPEND -%if (open_file_t_size & (open_file_t_size-1)) -%error "open_file_t is not a power of 2" -%endif -%endif - -; --------------------------------------------------------------------------- -; BEGIN CODE -; --------------------------------------------------------------------------- - -; -; Memory below this point is reserved for the BIOS and the MBR -; - section .earlybss -trackbufsize equ 8192 -trackbuf resb trackbufsize ; Track buffer goes here - ; ends at 2800h - - section .bss16 -SuperBlock resb 1024 ; ext2 superblock -ClustSize resd 1 ; Bytes/cluster ("block") -ClustMask resd 1 ; Sectors/cluster - 1 -PtrsPerBlock1 resd 1 ; Pointers/cluster -PtrsPerBlock2 resd 1 ; (Pointers/cluster)^2 -ClustShift resb 1 ; Shift count for sectors/cluster -ClustByteShift resb 1 ; Shift count for bytes/cluster - - alignb open_file_t_size -Files resb MAX_OPEN*open_file_t_size - -; -; Common bootstrap code for disk-based derivatives -; -%include "diskstart.inc" - -; -; Common initialization code -; -%include "init.inc" -%include "cpuinit.inc" - -; -; Load the real (ext2) superblock; 1024 bytes long at offset 1024 -; - mov bx,SuperBlock - mov eax,1024 >> SECTOR_SHIFT - mov bp,ax - call getlinsecsr - -; -; Compute some values... -; - xor edx,edx - inc edx - - ; s_log_block_size = log2(blocksize) - 10 - mov cl,[SuperBlock+s_log_block_size] - add cl,10 - mov [ClustByteShift],cl - mov eax,edx - shl eax,cl - mov [ClustSize],eax - - sub cl,SECTOR_SHIFT - mov [ClustShift],cl - shr eax,SECTOR_SHIFT - mov [SecPerClust],eax - dec eax - mov [ClustMask],eax - - add cl,SECTOR_SHIFT-2 ; 4 bytes/pointer - shl edx,cl - mov [PtrsPerBlock1],edx - shl edx,cl - mov [PtrsPerBlock2],edx - -; -; Initialize the metadata cache -; - call initcache - -; -; Now, everything is "up and running"... patch kaboom for more -; verbosity and using the full screen system -; - ; E9 = JMP NEAR - mov di,kaboom.patch - mov al,0e9h - stosb - mov ax,kaboom2-2 - sub ax,di - stosw - -; -; Now we're all set to start with our *real* business. First load the -; configuration file (if any) and parse it. -; -; In previous versions I avoided using 32-bit registers because of a -; rumour some BIOSes clobbered the upper half of 32-bit registers at -; random. I figure, though, that if there are any of those still left -; they probably won't be trying to install Linux on them... -; -; The code is still ripe with 16-bitisms, though. Not worth the hassle -; to take'm out. In fact, we may want to put them back if we're going -; to boot ELKS at some point. -; - -; -; Load configuration file -; -load_config: - - mov si,config_name ; Save config file name - mov di,ConfigName - call strcpy - mov dword [CurrentDirName],CUR_DIR_DWORD ; Write './',0,0 to the CurrentDirName - call build_curdir_str - - mov di,ConfigName - pm_call load_env32 - - call open - jz no_config_file - -; -; Now we have the config file open. Parse the config file and -; run the user interface. -; -%include "ui.inc" - -; -; getlinsec_ext: same as getlinsec, except load any sector from the zero -; block as all zeros; use to load any data derived -; from an ext2 block pointer, i.e. anything *except the -; superblock.* -; -getonesec_ext: - mov bp,1 - -getlinsec_ext: - cmp eax,[SecPerClust] - jae getlinsecsr ; Nothing fancy - - ; If we get here, at least part of what we want is in the - ; zero block. Zero one sector at a time and loop. - push eax - push cx - xchg di,bx - xor eax,eax - mov cx,SECTOR_SIZE >> 2 - rep stosd - xchg di,bx - pop cx - pop eax - inc eax - dec bp - jnz getlinsec_ext - ret - -; -; allocate_file: Allocate a file structure -; -; If successful: -; ZF set -; BX = file pointer -; In unsuccessful: -; ZF clear -; -allocate_file: - TRACER 'a' - push cx - mov bx,Files - mov cx,MAX_OPEN -.check: cmp dword [bx], byte 0 - je .found - add bx,open_file_t_size ; ZF = 0 - loop .check - ; ZF = 0 if we fell out of the loop -.found: pop cx - ret -; -; open_inode: -; Open a file indicated by an inode number in EAX -; -; NOTE: This file considers finding a zero-length file an -; error. This is so we don't have to deal with that special -; case elsewhere in the program (most loops have the test -; at the end). -; -; If successful: -; ZF clear -; SI = file pointer -; EAX = file length in bytes -; ThisInode = the first 128 bytes of the inode -; If unsuccessful -; ZF set -; -; Assumes CS == DS == ES. -; -open_inode.allocate_failure: - xor eax,eax - pop bx - pop di - ret - -open_inode: - push di - push bx - call allocate_file - jnz .allocate_failure - - push cx - push gs - ; First, get the appropriate inode group and index - dec eax ; There is no inode 0 - xor edx,edx - mov [bx+file_sector],edx - div dword [SuperBlock+s_inodes_per_group] - ; EAX = inode group; EDX = inode within group - push edx - - ; Now, we need the block group descriptor. - ; To get that, we first need the relevant descriptor block. - - shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table - xor edx,edx - div dword [ClustSize] - ; eax = block #, edx = offset in block - add eax,dword [SuperBlock+s_first_data_block] - inc eax ; s_first_data_block+1 - mov cl,[ClustShift] - shl eax,cl - push edx - shr edx,SECTOR_SHIFT - add eax,edx - pop edx - and dx,SECTOR_SIZE-1 - call getcachesector ; Get the group descriptor - add si,dx - mov esi,[gs:si+bg_inode_table] ; Get inode table block # - pop eax ; Get inode within group - movzx edx, word [SuperBlock+s_inode_size] - mul edx - ; edx:eax = byte offset in inode table - div dword [ClustSize] - ; eax = block # versus inode table, edx = offset in block - add eax,esi - shl eax,cl ; Turn into sector - push dx - shr edx,SECTOR_SHIFT - add eax,edx - mov [bx+file_in_sec],eax - pop dx - and dx,SECTOR_SIZE-1 - mov [bx+file_in_off],dx - - call getcachesector - add si,dx - mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2 - mov di,ThisInode - gs rep movsd - - mov ax,[ThisInode+i_mode] - mov [bx+file_mode],ax - mov eax,[ThisInode+i_size] - mov [bx+file_bytesleft],eax - mov si,bx - and eax,eax ; ZF clear unless zero-length file - pop gs - pop cx - pop bx - pop di - ret - - section .bss16 - alignb 4 -ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode - - section .text16 -; -; close_file: -; Deallocates a file structure (pointer in SI) -; Assumes CS == DS. -; -close_file: - and si,si - jz .closed - mov dword [si],0 ; First dword == file_bytesleft - xor si,si -.closed: ret - -; -; searchdir: -; Search the root directory for a pre-mangled filename in DS:DI. -; -; NOTE: This file considers finding a zero-length file an -; error. This is so we don't have to deal with that special -; case elsewhere in the program (most loops have the test -; at the end). -; -; If successful: -; ZF clear -; SI = file pointer -; DX:AX = EAX = file length in bytes -; If unsuccessful -; ZF set -; -; Assumes CS == DS == ES; *** IS THIS CORRECT ***? -; -searchdir: - push bx - push cx - push bp - mov byte [SymlinkCtr],MAX_SYMLINKS - - mov eax,[CurrentDir] -.begin_path: -.leadingslash: - cmp byte [di],'/' ; Absolute filename? - jne .gotdir - mov eax,EXT2_ROOT_INO - inc di ; Skip slash - jmp .leadingslash -.gotdir: - - ; At this point, EAX contains the directory inode, - ; and DS:DI contains a pathname tail. -.open: - push eax ; Save directory inode - - call open_inode - jz .missing ; If error, done - - mov cx,[si+file_mode] - shr cx,S_IFSHIFT ; Get file type - - cmp cx,T_IFDIR - je .directory - - add sp,4 ; Drop directory inode - - cmp cx,T_IFREG - je .file - cmp cx,T_IFLNK - je .symlink - - ; Otherwise, something bad... -.err: - call close_file -.err_noclose: - xor eax,eax - xor si,si - cwd ; DX <- 0 - -.done: - and eax,eax ; Set/clear ZF - pop bp - pop cx - pop bx - ret - -.missing: - add sp,4 ; Drop directory inode - jmp .done - - ; - ; It's a file. - ; -.file: - cmp byte [di],0 ; End of path? - je .done ; If so, done - jmp .err ; Otherwise, error - - ; - ; It's a directory. - ; -.directory: - pop dword [ThisDir] ; Remember what directory we're searching - - cmp byte [di],0 ; More path? - je .err ; If not, bad - -.skipslash: ; Skip redundant slashes - cmp byte [di],'/' - jne .readdir - inc di - jmp .skipslash - -.readdir: - mov cx,[SecPerClust] - push cx - shl cx,SECTOR_SHIFT - mov bx,trackbuf - add cx,bx - mov [EndBlock],cx - pop cx - push bx - call getfssec - pop bx - pushf ; Save EOF flag - push si ; Save filesystem pointer -.getent: - cmp bx,[EndBlock] - jae .endblock - - push di - cmp dword [bx+d_inode],0 ; Zero inode = void entry - je .nope - - movzx cx,byte [bx+d_name_len] - lea si,[bx+d_name] - repe cmpsb - je .maybe -.nope: - pop di - add bx,[bx+d_rec_len] - jmp .getent - -.endblock: - pop si - popf - jnc .readdir ; There is more - jmp .err ; Otherwise badness... - -.maybe: - mov eax,[bx+d_inode] - - ; Does this match the end of the requested filename? - cmp byte [di],0 - je .finish - cmp byte [di],'/' - jne .nope - - ; We found something; now we need to open the file -.finish: - pop bx ; Adjust stack (di) - pop si - call close_file ; Close directory - pop bx ; Adjust stack (flags) - jmp .open - - ; - ; It's a symlink. We have to determine if it's a fast symlink - ; (data stored in the inode) or not (data stored as a regular - ; file.) Either which way, we start from the directory - ; which we just visited if relative, or from the root directory - ; if absolute, and append any remaining part of the path. - ; -.symlink: - dec byte [SymlinkCtr] - jz .err ; Too many symlink references - - cmp eax,SYMLINK_SECTORS*SECTOR_SIZE - jae .err ; Symlink too long - - ; Computation for fast symlink, as defined by ext2/3 spec - xor ecx,ecx - cmp [ThisInode+i_file_acl],ecx - setne cl ; ECX <- i_file_acl ? 1 : 0 - cmp [ThisInode+i_blocks],ecx - jne .slow_symlink - - ; It's a fast symlink -.fast_symlink: - call close_file ; We've got all we need - mov si,ThisInode+i_block - - push di - mov di,SymlinkTmpBuf - mov ecx,eax - rep movsb - pop si - -.symlink_finish: - cmp byte [si],0 - je .no_slash - mov al,'/' - stosb -.no_slash: - mov bp,SymlinkTmpBufEnd - call strecpy - jc .err_noclose ; Buffer overflow - - ; Now copy it to the "real" buffer; we need to have - ; two buffers so we avoid overwriting the tail on the - ; next copy - mov si,SymlinkTmpBuf - mov di,SymlinkBuf - push di - call strcpy - pop di - mov eax,[ThisDir] ; Resume searching previous directory - jmp .begin_path - -.slow_symlink: - mov bx,SymlinkTmpBuf - mov cx,SYMLINK_SECTORS - call getfssec - ; The EOF closed the file - - mov si,di ; SI = filename tail - mov di,SymlinkTmpBuf - add di,ax ; AX = file length - jmp .symlink_finish - - - section .bss16 - alignb 4 -SymlinkBuf resb SYMLINK_SECTORS*SECTOR_SIZE+64 -SymlinkTmpBuf equ trackbuf -SymlinkTmpBufEnd equ trackbuf+SYMLINK_SECTORS*SECTOR_SIZE+64 -ThisDir resd 1 -EndBlock resw 1 -SymlinkCtr resb 1 - - section .text16 -; -; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed -; to by ES:DI; ends on encountering any whitespace. -; DI is preserved. -; -; This verifies that a filename is < FILENAME_MAX characters, -; doesn't contain whitespace, zero-pads the output buffer, -; and removes redundant slashes, -; so "repe cmpsb" can do a compare, and the -; path-searching routine gets a bit of an easier job. -; -; FIX: we may want to support \-escapes here (and this would -; be the place.) -; -mangle_name: - push di - push bx - xor ax,ax - mov cx,FILENAME_MAX-1 - mov bx,di - -.mn_loop: - lodsb - cmp al,' ' ; If control or space, end - jna .mn_end - cmp al,ah ; Repeated slash? - je .mn_skip - xor ah,ah - cmp al,'/' - jne .mn_ok - mov ah,al -.mn_ok stosb -.mn_skip: loop .mn_loop -.mn_end: - cmp bx,di ; At the beginning of the buffer? - jbe .mn_zero - cmp byte [di-1],'/' ; Terminal slash? - jne .mn_zero -.mn_kill: dec di ; If so, remove it - inc cx - jmp short .mn_end -.mn_zero: - inc cx ; At least one null byte - xor ax,ax ; Zero-fill name - rep stosb - pop bx - pop di - ret ; Done - -; -; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled -; filename to the conventional representation. This is needed -; for the BOOT_IMAGE= parameter for the kernel. -; -; DS:SI -> input mangled file name -; ES:DI -> output buffer -; -; On return, DI points to the first byte after the output name, -; which is set to a null byte. -; -unmangle_name: call strcpy - dec di ; Point to final null byte - ret - -; -; -; kaboom2: once everything is loaded, replace the part of kaboom -; starting with "kaboom.patch" with this part - -kaboom2: - mov si,err_bootfailed - call writestr - cmp byte [kaboom.again+1],18h ; INT 18h version? - je .int18 - call getchar - call vgaclearmode - int 19h ; And try once more to boot... -.norge: jmp short .norge ; If int 19h returned; this is the end -.int18: - call vgaclearmode - int 18h -.noreg: jmp short .noreg ; Nynorsk - - -; -; linsector: Convert a linear sector index in a file to a linear sector number -; EAX -> linear sector number -; DS:SI -> open_file_t -; -; Returns next sector number in EAX; CF on EOF (not an error!) -; -linsector: - push gs - push ebx - push esi - push edi - push ecx - push edx - push ebp - - push eax ; Save sector index - mov cl,[ClustShift] - shr eax,cl ; Convert to block number - push eax - mov eax,[si+file_in_sec] - mov bx,si - call getcachesector ; Get inode - add si,[bx+file_in_off] ; Get *our* inode - pop eax - lea ebx,[i_block+4*eax] - cmp eax,EXT2_NDIR_BLOCKS - jb .direct - mov ebx,i_block+4*EXT2_IND_BLOCK - sub eax,EXT2_NDIR_BLOCKS - mov ebp,[PtrsPerBlock1] - cmp eax,ebp - jb .ind1 - mov ebx,i_block+4*EXT2_DIND_BLOCK - sub eax,ebp - mov ebp,[PtrsPerBlock2] - cmp eax,ebp - jb .ind2 - mov ebx,i_block+4*EXT2_TIND_BLOCK - sub eax,ebp - -.ind3: - ; Triple indirect; eax contains the block no - ; with respect to the start of the tind area; - ; ebx contains the pointer to the tind block. - xor edx,edx - div dword [PtrsPerBlock2] - ; EAX = which dind block, EDX = pointer within dind block - push ax - shr eax,SECTOR_SHIFT-2 - mov ebp,[gs:si+bx] - shl ebp,cl - add eax,ebp - call getcachesector - pop bx - and bx,(SECTOR_SIZE >> 2)-1 - shl bx,2 - mov eax,edx ; The ind2 code wants the remainder... - -.ind2: - ; Double indirect; eax contains the block no - ; with respect to the start of the dind area; - ; ebx contains the pointer to the dind block. - xor edx,edx - div dword [PtrsPerBlock1] - ; EAX = which ind block, EDX = pointer within ind block - push ax - shr eax,SECTOR_SHIFT-2 - mov ebp,[gs:si+bx] - shl ebp,cl - add eax,ebp - call getcachesector - pop bx - and bx,(SECTOR_SIZE >> 2)-1 - shl bx,2 - mov eax,edx ; The int1 code wants the remainder... - -.ind1: - ; Single indirect; eax contains the block no - ; with respect to the start of the ind area; - ; ebx contains the pointer to the ind block. - push ax - shr eax,SECTOR_SHIFT-2 - mov ebp,[gs:si+bx] - shl ebp,cl - add eax,ebp - call getcachesector - pop bx - and bx,(SECTOR_SIZE >> 2)-1 - shl bx,2 - -.direct: - mov ebx,[gs:bx+si] ; Get the pointer - - pop eax ; Get the sector index again - shl ebx,cl ; Convert block number to sector - and eax,[ClustMask] ; Add offset within block - add eax,ebx - - pop ebp - pop edx - pop ecx - pop edi - pop esi - pop ebx - pop gs - ret - -; -; getfssec: Get multiple sectors from a file -; -; Same as above, except SI is a pointer to a open_file_t -; -; ES:BX -> Buffer -; DS:SI -> Pointer to open_file_t -; CX -> Sector count (0FFFFh = until end of file) -; Must not exceed the ES segment -; Returns CF=1 on EOF (not necessarily error) -; On return ECX = number of bytes read -; All arguments are advanced to reflect data read. -; -getfssec: - push ebp - push eax - push edx - push edi - - movzx ecx,cx - push ecx ; Sectors requested read - mov eax,[si+file_bytesleft] - add eax,SECTOR_SIZE-1 - shr eax,SECTOR_SHIFT - cmp ecx,eax ; Number of sectors left - jbe .lenok - mov cx,ax -.lenok: -.getfragment: - mov eax,[si+file_sector] ; Current start index - mov edi,eax - call linsector - push eax ; Fragment start sector - mov edx,eax - xor ebp,ebp ; Fragment sector count -.getseccnt: - inc bp - dec cx - jz .do_read - xor eax,eax - mov ax,es - shl ax,4 - add ax,bx ; Now DI = how far into 64K block we are - not ax ; Bytes left in 64K block - inc eax - shr eax,SECTOR_SHIFT ; Sectors left in 64K block - cmp bp,ax - jnb .do_read ; Unless there is at least 1 more sector room... - inc edi ; Sector index - inc edx ; Linearly next sector - mov eax,edi - call linsector - ; jc .do_read - cmp edx,eax - je .getseccnt -.do_read: - pop eax ; Linear start sector - pushad - call getlinsec_ext - popad - push bp - shl bp,9 - add bx,bp ; Adjust buffer pointer - pop bp - add [si+file_sector],ebp ; Next sector index - jcxz .done - jnz .getfragment - ; Fall through -.done: - pop ecx ; Sectors requested read - shl ecx,SECTOR_SHIFT - sub [si+file_bytesleft],ecx - jnbe .noteof ; CF=0 in this case - add ecx,[si+file_bytesleft] ; Actual number of bytes read - call close_file - stc ; We hit EOF -.noteof: - pop edi - pop edx - pop eax - pop ebp - ret - -build_curdir_str: - ret - -; ----------------------------------------------------------------------------- -; Common modules -; ----------------------------------------------------------------------------- - -%include "common.inc" ; Universal modules -%include "plaincon.inc" ; writechr -%include "writestr.inc" ; String output -%include "writehex.inc" ; Hexadecimal output -%include "strecpy.inc" ; strcpy with end pointer check -%include "cache.inc" ; Metadata disk cache -%include "localboot.inc" ; Disk-based local boot - -; ----------------------------------------------------------------------------- -; Begin data section -; ----------------------------------------------------------------------------- - - section .data16 -copyright_str db ' Copyright (C) 1994-' - asciidec YEAR - db ' H. Peter Anvin et al', CR, LF, 0 -err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' - db 'a key to continue.', CR, LF, 0 -config_name db 'extlinux.conf',0 ; Unmangled form - -; -; Config file keyword table -; -%include "keywords.inc" - -; -; Extensions to search for (in *forward* order). -; - alignz 4 -exten_table: db '.cbt' ; COMBOOT (specific) - db '.img' ; Disk image - db '.bs', 0 ; Boot sector - db '.com' ; COMBOOT (same as DOS) - db '.c32' ; COM32 -exten_table_end: - dd 0, 0 ; Need 8 null bytes here - -; -; Misc initialized (data) variables -; -%ifdef debug ; This code for debugging only -debug_magic dw 0D00Dh ; Debug code sentinel -%endif - - alignz 4 -BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf -BufSafeBytes dw trackbufsize ; = how many bytes? -%ifndef DEPEND -%if ( trackbufsize % SECTOR_SIZE ) != 0 -%error trackbufsize must be a multiple of SECTOR_SIZE -%endif -%endif +%include "diskfs.inc" diff --git a/core/fs.c b/core/fs.c new file mode 100644 index 00000000..a3407cfe --- /dev/null +++ b/core/fs.c @@ -0,0 +1,190 @@ +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include "fs.h" +#include "cache.h" + +/* The currently mounted filesystem */ +struct fs_info *this_fs = NULL; +struct fs_info fs; + +/* Actual file structures (we don't have malloc yet...) */ +struct file files[MAX_OPEN]; + +/* + * Get an empty file structure + */ +static struct file *alloc_file(void) +{ + int i; + struct file *file = files; + + for (i = 0; i < MAX_OPEN; i++) { + if (!file->open_file) + return file; + file++; + } + + return NULL; +} + +/* + * Close and free a file structure + */ +static inline void free_file(struct file *file) +{ + memset(file, 0, sizeof *file); +} + +void _close_file(struct file *file) +{ + if (file->open_file) + file->fs->fs_ops->close_file(file); + free_file(file); +} + +/* + * Convert between a 16-bit file handle and a file structure + */ +inline uint16_t file_to_handle(struct file *file) +{ + return file ? (file - files)+1 : 0; +} +inline struct file *handle_to_file(uint16_t handle) +{ + return handle ? &files[handle-1] : NULL; +} + +void load_config(void) +{ + int err; + err = this_fs->fs_ops->load_config(); + +#if 0 + printf("Loading config file %s\n", err ? "failed" : "successed"); +#endif +} + +void mangle_name(com32sys_t *regs) +{ + const char *src = MK_PTR(regs->ds, regs->esi.w[0]); + char *dst = MK_PTR(regs->es, regs->edi.w[0]); + + this_fs->fs_ops->mangle_name(dst, src); +} + + +void unmangle_name(com32sys_t *regs) +{ + const char *src = MK_PTR(regs->ds, regs->esi.w[0]); + char *dst = MK_PTR(regs->es, regs->edi.w[0]); + + dst = this_fs->fs_ops->unmangle_name(dst, src); + + /* Update the di register to point to the last null char */ + regs->edi.w[0] = OFFS_WRT(dst, regs->es); +} + + +void getfssec(com32sys_t *regs) +{ + int sectors; + bool have_more; + uint32_t bytes_read; + char *buf; + struct file *file; + uint16_t handle; + + sectors = regs->ecx.w[0]; + + handle = regs->esi.w[0]; + file = handle_to_file(handle); + + buf = MK_PTR(regs->es, regs->ebx.w[0]); + bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more); + + /* + * If we reach EOF, the filesystem driver will have already closed + * the underlying file... this really should be cleaner. + */ + if (!have_more) { + _close_file(file); + regs->esi.w[0] = 0; + } + + regs->ecx.l = bytes_read; +} + + +void searchdir(com32sys_t *regs) +{ + char *filename = (char *)MK_PTR(regs->ds, regs->edi.w[0]);; + struct file *file; + +#if 0 + printf("filename: %s\n", filename); +#endif + + file = alloc_file(); + + if (file) { + file->fs = this_fs; + file->fs->fs_ops->searchdir(filename, file); + + if (file->open_file) { + regs->esi.w[0] = file_to_handle(file); + regs->eax.l = file->file_len; + regs->eflags.l &= ~EFLAGS_ZF; + return; + } + } + + /* failure... */ + regs->esi.w[0] = 0; + regs->eax.l = 0; + regs->eflags.l |= EFLAGS_ZF; +} + +void close_file(com32sys_t *regs) +{ + uint16_t handle = regs->esi.w[0]; + struct file *file; + + if (handle) { + file = handle_to_file(handle); + _close_file(file); + } +} + +/* + * it will do: + * set up the vfs fs structure; + * initialize the device structure; + * invoke the fs-specific init function; + * finally, initialize the cache + * + */ +void fs_init(com32sys_t *regs) +{ + int blk_shift; + const struct fs_ops *ops = (const struct fs_ops *)regs->eax.l; + + /* set up the fs stucture */ + fs.fs_ops = ops; + + /* this is a total hack... */ + if (ops->fs_flags & FS_NODEV) + fs.fs_dev = NULL; /* Non-device filesystem */ + else + fs.fs_dev = device_init(regs->edx.b[0], regs->edx.b[1], regs->ecx.l, + regs->esi.w[0], regs->edi.w[0]); + + this_fs = &fs; + + /* invoke the fs-specific init code */ + blk_shift = fs.fs_ops->fs_init(&fs); + + /* initialize the cache */ + if (fs.fs_dev && fs.fs_dev->cache_data) + cache_init(fs.fs_dev, blk_shift); +} diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c new file mode 100644 index 00000000..8c44b3ae --- /dev/null +++ b/core/fs/ext2/ext2.c @@ -0,0 +1,736 @@ +#include <stdio.h> +#include <string.h> +#include <cache.h> +#include <core.h> +#include <disk.h> +#include <fs.h> +#include "ext2_fs.h" + +#define MAX_SYMLINKS 64 +#define SYMLINK_SECTORS 2 +static char SymlinkBuf[SYMLINK_SECTORS * SECTOR_SIZE + 64]; + +/* + * File structure, This holds the information for each currently open file + */ +struct open_file_t { + uint32_t file_bytesleft; /* Number of bytes left (0 = free) */ + uint32_t file_sector; /* Next linear sector to read */ + sector_t file_in_sec; /* Sector where inode lives */ + uint16_t file_in_off; + uint16_t file_mode; + uint32_t pad[3]; /* pad to 2^5 == 0x20 bytes */ +}; +static struct open_file_t Files[MAX_OPEN]; + +static struct ext2_inode this_inode; +static struct ext2_super_block sb; + +static uint16_t ClustByteShift, ClustShift; +static uint32_t SecPerClust, ClustSize, ClustMask; +static uint32_t PtrsPerBlock1, PtrsPerBlock2, PtrsPerBlock3; +static int DescPerBlock, InodePerBlock; + +/* + * just like the function strcpy(), except it returns non-zero if overflow. + * + */ +static int strecpy(char *dst, char *src, char *end) +{ + while (*src != '\0') + *dst++ = *src++; + *dst = '\0'; + + if (dst > end) + return 1; + else + return 0; +} + + +/* + * Allocate a file structure, if successful return the file pointer, or NULL. + * + */ +static struct open_file_t *allocate_file(void) +{ + struct open_file_t *file = Files; + int i; + + for (i = 0; i < MAX_OPEN; i++) { + if (file->file_bytesleft == 0) /* found it */ + return file; + file++; + } + + return NULL; /* not found */ +} + + +/** + * ext2_close_file: + * + * Deallocates a file structure point by FILE + * + * @param: file, the file structure we want deallocate + * + */ +static inline void close_pvt(struct open_file_t *of) +{ + of->file_bytesleft = 0; +} + +static void ext2_close_file(struct file *file) +{ + close_pvt(file->open_file); +} + +/** + * get the group's descriptor of group_num + * + * @param: group_num, the group number; + * + * @return: the pointer of the group's descriptor + * + */ +static struct ext2_group_desc * +get_group_desc(struct fs_info *fs, uint32_t group_num) +{ + block_t block_num; + uint32_t offset; + struct ext2_group_desc *desc; + struct cache_struct *cs; + + block_num = group_num / DescPerBlock; + offset = group_num % DescPerBlock; + + block_num += sb.s_first_data_block + 1; + cs = get_cache_block(fs->fs_dev, block_num); + desc = (struct ext2_group_desc *)cs->data + offset; + + return desc; +} + + +/** + * read the right inode structure to _dst_. + * + * @param: inode_offset, the inode offset within a group; + * @prarm: dst, wher we will store the inode structure; + * @param: desc, the pointer to the group's descriptor + * @param: block, a pointer used for retruning the blk number for file structure + * @param: offset, same as block + * + */ +static void read_inode(struct fs_info *fs, uint32_t inode_offset, + struct ext2_inode *dst, struct ext2_group_desc *desc, + block_t *block, uint32_t *offset) +{ + struct cache_struct *cs; + struct ext2_inode *inode; + + *block = inode_offset / InodePerBlock + desc->bg_inode_table; + *offset = inode_offset % InodePerBlock; + + cs = get_cache_block(fs->fs_dev, *block); + + /* well, in EXT4, the inode structure usually be 256 */ + inode = (struct ext2_inode *)(cs->data + (*offset * (sb.s_inode_size))); + memcpy(dst, inode, EXT2_GOOD_OLD_INODE_SIZE); + + /* for file structure */ + *offset = (inode_offset * sb.s_inode_size) % ClustSize; +} + + +/** + * open a file indicated by an inode number in INR + * + * @param : inr, the inode number + * @return: a open_file_t structure pointer + * file length in bytes + * the first 128 bytes of the inode, stores in ThisInode + * + */ +static struct open_file_t * +open_inode(struct fs_info *fs, uint32_t inr, uint32_t *file_len) +{ + struct open_file_t *file; + struct ext2_group_desc *desc; + + uint32_t inode_group, inode_offset; + block_t block_num; + uint32_t block_off; + + file = allocate_file(); + if (!file) + return NULL; + + file->file_sector = 0; + + inr --; + inode_group = inr / sb.s_inodes_per_group; + + /* get the group desc */ + desc = get_group_desc(fs, inode_group); + + inode_offset = inr % sb.s_inodes_per_group; + read_inode(fs, inode_offset, &this_inode, desc, &block_num, &block_off); + + /* Finally, we need to convet it to sector for now */ + file->file_in_sec = (block_num<<ClustShift) + (block_off>>SECTOR_SHIFT); + file->file_in_off = block_off & (SECTOR_SIZE - 1); + file->file_mode = this_inode.i_mode; + *file_len = file->file_bytesleft = this_inode.i_size; + + if (*file_len == 0) + return NULL; + + return file; +} + + + +static struct ext4_extent_header * +ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block) +{ + struct ext4_extent_idx *index; + struct cache_struct *cs; + block_t blk; + int i; + + while (1) { + if (eh->eh_magic != EXT4_EXT_MAGIC) + return NULL; + + /* got it */ + if (eh->eh_depth == 0) + return eh; + + index = EXT4_FIRST_INDEX(eh); + for (i = 0; i < eh->eh_entries; i++) { + if (block < index[i].ei_block) + break; + } + if (--i < 0) + return NULL; + + blk = index[i].ei_leaf_hi; + blk = (blk << 32) + index[i].ei_leaf_lo; + + /* read the blk to memeory */ + cs = get_cache_block(fs->fs_dev, blk); + eh = (struct ext4_extent_header *)(cs->data); + } +} + +/* handle the ext4 extents to get the phsical block number */ +static block_t linsector_extent(struct fs_info *fs, block_t block, + struct ext2_inode *inode) +{ + struct ext4_extent_header *leaf; + struct ext4_extent *ext; + int i; + block_t start; + + leaf = ext4_find_leaf(fs, (struct ext4_extent_header*)inode->i_block, block); + if (!leaf) { + printf("ERROR, extent leaf not found\n"); + return 0; + } + + ext = EXT4_FIRST_EXTENT(leaf); + for (i = 0; i < leaf->eh_entries; i++) { + if (block < ext[i].ee_block) + break; + } + if (--i < 0) { + printf("ERROR, not find the right block\n"); + return 0; + } + + /* got it */ + block -= ext[i].ee_block; + if (block >= ext[i].ee_len) + return 0; + + start = ext[i].ee_start_hi; + start = (start << 32) + ext[i].ee_start_lo; + + return start + block; +} + + +/** + * linsector_direct: + * + * @param: block, the block index + * @param: inode, the inode structure + * + * @return: the physic block number + */ +static block_t linsector_direct(struct fs_info *fs, uint32_t block, struct ext2_inode *inode) +{ + struct cache_struct *cs; + + /* direct blocks */ + if (block < EXT2_NDIR_BLOCKS) + return inode->i_block[block]; + + + /* indirect blocks */ + block -= EXT2_NDIR_BLOCKS; + if (block < PtrsPerBlock1) { + block_t ind_block = inode->i_block[EXT2_IND_BLOCK]; + cs = get_cache_block(fs->fs_dev, ind_block); + + return ((uint32_t *)cs->data)[block]; + } + + /* double indirect blocks */ + block -= PtrsPerBlock1; + if (block < PtrsPerBlock2) { + block_t dou_block = inode->i_block[EXT2_DIND_BLOCK]; + cs = get_cache_block(fs->fs_dev, dou_block); + + dou_block = ((uint32_t *)cs->data)[block / PtrsPerBlock1]; + cs = get_cache_block(fs->fs_dev, dou_block); + + return ((uint32_t*)cs->data)[block % PtrsPerBlock1]; + } + + /* triple indirect block */ + block -= PtrsPerBlock2; + if (block < PtrsPerBlock3) { + block_t tri_block = inode->i_block[EXT2_TIND_BLOCK]; + cs = get_cache_block(fs->fs_dev, tri_block); + + tri_block = ((uint32_t *)cs->data)[block / PtrsPerBlock2]; + cs = get_cache_block(fs->fs_dev, tri_block); + + tri_block = ((uint32_t *)cs->data)[block % PtrsPerBlock2]; + cs = get_cache_block(fs->fs_dev, tri_block); + + return ((uint32_t*)cs->data)[block % PtrsPerBlock1]; + } + + /* File too big, can not handle */ + printf("ERROR, file too big\n"); + return 0; +} + + +/** + * linsector: + * + * Convert a linear sector index in a file to linear sector number + * + * well, alought this function converts a linear sector number to + * physic sector number, it uses block cache in the implemention. + * + * @param: lin_sector, the lineral sector index + * + * @return: physic sector number + */ +static sector_t linsector(struct fs_info *fs, uint32_t lin_sector) +{ + uint32_t block = lin_sector >> ClustShift; + block_t ret; + struct ext2_inode *inode; + + /* well, this is what I think the variable this_inode used for */ + inode = &this_inode; + + if (inode->i_flags & EXT4_EXTENTS_FLAG) + ret = linsector_extent(fs, block, inode); + else + ret = linsector_direct(fs, block, inode); + + if (!ret) { + printf("ERROR: something error happend at linsector..\n"); + return 0; + } + + /* finally convert it to sector */ + return ((ret << ClustShift) + (lin_sector & ClustMask)); +} + + +/* + * NOTE! unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure. + * + * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller. + */ +static inline int ext2_match_entry (const char * const name, + struct ext2_dir_entry * de) +{ + if (!de->d_inode) + return 0; + return !strncmp(name, de->d_name, de->d_name_len); +} + + +/* + * p is at least 6 bytes before the end of page + */ +static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p) +{ + return (struct ext2_dir_entry *)((char*)p + p->d_rec_len); +} + +/** + * getlinsec_ext: + * + * same as getlinsec, except load any sector from the zero + * block as all zeros; use to load any data derived from + * n ext2 block pointer, i.e. anything *except the superblock + * + */ +static void getlinsec_ext(struct fs_info *fs, char *buf, + sector_t sector, int sector_cnt) +{ + int ext_cnt = 0; + struct disk *disk = fs->fs_dev->disk; + + if (sector < SecPerClust) { + ext_cnt = SecPerClust - sector; + memset(buf, 0, ext_cnt << SECTOR_SHIFT); + buf += ext_cnt << SECTOR_SHIFT; + } + + sector += ext_cnt; + sector_cnt -= ext_cnt; + disk->rdwr_sectors(disk, buf, sector, sector_cnt, 0); +} + +/** + * getfssec: + * + * Get multiple sectors from a file + * + * Alought we have made the buffer data based on block size, + * we use sector for implemention; because reading multiple + * sectors (then can be multiple blocks) is what the function + * do. So, let it be based on sectors. + * + * This function can be called from C function, and either from + * ASM function. + * + * @param: ES:BX(of regs), the buffer to store data + * @param: DS:SI(of regs), the pointer to open_file_t + * @param: CX(of regs), number of sectors to read + * + * @return: ECX(of regs), number of bytes read + * + */ +static uint32_t ext2_getfssec(struct file *gfile, char *buf, + int sectors, bool *have_more) +{ + int sector_left, next_sector, sector_idx; + int frag_start, con_sec_cnt; + int bytes_read = sectors << SECTOR_SHIFT; + struct open_file_t *file = gfile->open_file; + struct fs_info *fs = gfile->fs; + + sector_left = (file->file_bytesleft + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + if (sectors > sector_left) + sectors = sector_left; + + while (sectors) { + /* + * get the frament + */ + sector_idx = file->file_sector; + next_sector = frag_start = linsector(fs, sector_idx); + con_sec_cnt = 0; + + /* get the consective sectors count */ + do { + con_sec_cnt ++; + sectors --; + if (sectors <= 0) + break; + + /* if sectors >= the sectors left in the 64K block, break and read */ + if (sectors >= (((~(uint32_t)buf&0xffff)|((uint32_t)buf&0xffff0000)) + 1)) + break; + + sector_idx ++; + next_sector ++; + } while (next_sector == linsector(fs, sector_idx)); + +#if 0 + printf("You are reading data stored at sector --0x%x--0x%x\n", + frag_start, frag_start + con_sec_cnt -1); +#endif + getlinsec_ext(fs, buf, frag_start, con_sec_cnt); + buf += con_sec_cnt << 9; + file->file_sector += con_sec_cnt; /* next sector index */ + } while(sectors); + + if (bytes_read >= file->file_bytesleft) { + bytes_read = file->file_bytesleft; + *have_more = 0; + } else { + *have_more = 1; + } + file->file_bytesleft -= bytes_read; + + return bytes_read; +} + + + +/** + * find_dir_entry: + * + * find a dir entry, if find return it or return NULL + * + */ +static struct ext2_dir_entry* +find_dir_entry(struct fs_info *fs, struct open_file_t *file, char *filename) +{ + bool have_more; + char *EndBlock = trackbuf + (SecPerClust << SECTOR_SHIFT);; + struct ext2_dir_entry *de; + struct file xfile; + + /* Fake out a VFS file structure */ + xfile.fs = fs; + xfile.open_file = file; + + /* read a clust at a time */ + ext2_getfssec(&xfile, trackbuf, SecPerClust, &have_more); + de = (struct ext2_dir_entry *)trackbuf; + + while (1) { + if ((char *)de >= (char *)EndBlock) { + if (!have_more) + return NULL; + ext2_getfssec(&xfile, trackbuf, SecPerClust, &have_more); + de = (struct ext2_dir_entry *)trackbuf; + } + + /* Zero inode == void entry */ + if (de->d_inode == 0) { + de = ext2_next_entry(de); + continue; + } + + if (ext2_match_entry (filename, de)) { + filename += de->d_name_len; + if ((*filename == 0) || (*filename == '/')) + return de; /* got it */ + + /* not match, restore the filename then try next */ + filename -= de->d_name_len; + } + + de = ext2_next_entry(de); + } +} + + +static char *do_symlink(struct fs_info *fs, struct open_file_t *file, + uint32_t file_len, char *filename) +{ + int flag; + bool have_more; + + char *SymlinkTmpBuf = trackbuf; + char *lnk_end; + char *SymlinkTmpBufEnd = trackbuf + SYMLINK_SECTORS * SECTOR_SIZE+64; + struct file xfile; + xfile.fs = fs; + xfile.open_file = file; + + flag = this_inode.i_file_acl ? SecPerClust : 0; + if (this_inode.i_blocks == flag) { + /* fast symlink */ + close_pvt(file); /* we've got all we need */ + memcpy(SymlinkTmpBuf, this_inode.i_block, file_len); + lnk_end = SymlinkTmpBuf + file_len; + + } else { + /* slow symlink */ + ext2_getfssec(&xfile, SymlinkTmpBuf, SYMLINK_SECTORS, &have_more); + lnk_end = SymlinkTmpBuf + file_len; + } + + if (*filename != 0) + *lnk_end++ = '/'; + + if (strecpy(lnk_end, filename, SymlinkTmpBufEnd)) + return NULL; /* buffer overflow */ + + /* + * now copy it to the "real" buffer; we need to have + * two buffers so we avoid overwriting the tail on + * the next copy. + */ + strcpy(SymlinkBuf, SymlinkTmpBuf); + + /* return the new path */ + return SymlinkBuf; +} + + + + +/** + * Search the root directory for a pre-mangle filename in FILENAME. + * + * @param: filename, the filename we want to search. + * + * @out : a open_file_t structure pointer, stores in file->open_file + * @out : file lenght in bytes, stores in file->file_len + * + */ +static void ext2_searchdir(char *filename, struct file *file) +{ + extern int CurrentDir; + + struct open_file_t *open_file; + struct ext2_dir_entry *de; + uint8_t file_mode; + uint8_t SymlinkCtr = MAX_SYMLINKS; + uint32_t inr = CurrentDir; + uint32_t ThisDir = CurrentDir; + uint32_t file_len; + + begin_path: + while (*filename == '/') { /* Absolute filename */ + inr = EXT2_ROOT_INO; + filename ++; + } + open: + if ((open_file = open_inode(file->fs, inr, &file_len)) == NULL) + goto err_noclose; + + file_mode = open_file->file_mode >> S_IFSHIFT; + + /* It's a file */ + if (file_mode == T_IFREG) { + if (*filename == '\0') + goto done; + else + goto err; + } + + + /* It's a directory */ + if (file_mode == T_IFDIR) { + ThisDir = inr; + + if (*filename == 0) + goto err; + while (*filename == '/') + filename ++; + + de = find_dir_entry(file->fs, open_file, filename); + if (!de) + goto err; + + inr = de->d_inode; + filename += de->d_name_len; + close_pvt(open_file); + goto open; + } + + + /* + * It's a symlink. We have to determine if it's a fast symlink + * (data stored in the inode) or not (data stored as a regular + * file.) Either which way, we start from the directory + * which we just visited if relative, or from the root directory + * if absolute, and append any remaining part of the path. + */ + if (file_mode == T_IFLNK) { + if (--SymlinkCtr==0 || file_len>=SYMLINK_SECTORS*SECTOR_SIZE) + goto err; /* too many links or symlink too long */ + + filename = do_symlink(file->fs, open_file, file_len, filename); + if (!filename) + goto err_noclose;/* buffer overflow */ + + inr = ThisDir; + goto begin_path; /* we got a new path, so search it again */ + } + + /* Otherwise, something bad ... */ + err: + close_pvt(open_file); + err_noclose: + file_len = 0; + open_file = NULL; + done: + + file->file_len = file_len; + file->open_file = (void*)open_file; + +#if 0 + if (open_file) { + printf("file bytesleft: %d\n", open_file->file_bytesleft); + printf("file sector : %d\n", open_file->file_sector); + printf("file in sector: %d\n", open_file->file_in_sec); + printf("file offsector: %d\n", open_file->file_in_off); + } +#endif + +} + +/* Load the config file, return 1 if failed, or 0 */ +static int ext2_load_config(void) +{ + char *config_name = "extlinux.conf"; + com32sys_t regs; + + strcpy(ConfigName, config_name); + *(uint32_t *)CurrentDirName = 0x00002f2e; + + memset(®s, 0, sizeof regs); + regs.edi.w[0] = OFFS_WRT(ConfigName, 0); + call16(core_open, ®s, ®s); + + return !!(regs.eflags.l & EFLAGS_ZF); +} + + +/* + * init. the fs meta data, return the block size bits. + */ +static int ext2_fs_init(struct fs_info *fs) +{ + struct disk *disk = fs->fs_dev->disk; + + /* read the super block */ + disk->rdwr_sectors(disk, &sb, 2, 2, 0); + + ClustByteShift = sb.s_log_block_size + 10; + ClustSize = 1 << ClustByteShift; + ClustShift = ClustByteShift - SECTOR_SHIFT; + + DescPerBlock = ClustSize >> ext2_group_desc_lg2size; + InodePerBlock = ClustSize / sb.s_inode_size; + + SecPerClust = ClustSize >> SECTOR_SHIFT; + ClustMask = SecPerClust - 1; + + PtrsPerBlock1 = 1 << (ClustByteShift - 2); + PtrsPerBlock2 = 1 << ((ClustByteShift - 2) * 2); + PtrsPerBlock3 = 1 << ((ClustByteShift - 2) * 3); + + return ClustByteShift; +} + +const struct fs_ops ext2_fs_ops = { + .fs_name = "ext2", + .fs_flags = 0, + .fs_init = ext2_fs_init, + .searchdir = ext2_searchdir, + .getfssec = ext2_getfssec, + .close_file = ext2_close_file, + .mangle_name = generic_mangle_name, + .unmangle_name = generic_unmangle_name, + .load_config = ext2_load_config +}; diff --git a/core/fs/ext2/ext2_fs.h b/core/fs/ext2/ext2_fs.h new file mode 100644 index 00000000..d579eade --- /dev/null +++ b/core/fs/ext2/ext2_fs.h @@ -0,0 +1,252 @@ +#ifndef __EXT2_FS_H +#define __EXT2_FS_H + +#include <stdint.h> + +#define EXT2_SUPER_MAGIC 0xEF53 + +#define EXT2_GOOD_OLD_REV 0 // The good old (original) format +#define EXT2_DYNAMIC_REV 1 // V2 format w/ dynamic inode sizes +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +// Special inode numbers +#define EXT2_BAD_INO 1 // Bad blocks inode +#define EXT2_ROOT_INO 2 // Root inode +#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode +#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode +#define EXT3_RESIZE_INO 7 // Reserved group descriptors inode +#define EXT3_JOURNAL_INO 8 // Journal inode + +// We're readonly, so we only care about incompat features. +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff + +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK+1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK+1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1) + + +/* for EXT4 extent */ +#define EXT4_EXT_MAGIC 0xf30a +#define EXT4_EXTENTS_FLAG 0x00080000 + +/* + * File types and file modes + */ +#define S_IFDIR 0040000 // Directory +#define S_IFCHR 0020000 // Character device +#define S_IFBLK 0060000 // Block device +#define S_IFREG 0100000 // Regular file +#define S_IFIFO 0010000 // FIFO +#define S_IFLNK 0120000 // Symbolic link +#define S_IFSOCK 0140000 // Socket + +#define S_IFSHIFT 12 + +#define T_IFDIR (S_IFDIR >> S_IFSHIFT) +#define T_IFCHR (S_IFCHR >> S_IFSHIFT) +#define T_IFBLK (S_IFBLK >> S_IFSHIFT) +#define T_IFREG (S_IFREG >> S_IFSHIFT) +#define T_IFIFO (S_IFIFO >> S_IFSHIFT) +#define T_IFLNK (S_IFLNK >> S_IFSHIFT) +#define T_IFSOCK (S_IFSOCK >> S_IFSHIFT) + + +#define ext2_group_desc_lg2size 5 + + + +/* + * super block structure: + * include/linux/ext2_fs.h + */ +struct ext2_super_block { + uint32_t s_inodes_count; /* Inodes count */ + uint32_t s_blocks_count; /* Blocks count */ + uint32_t s_r_blocks_count; /* Reserved blocks count */ + uint32_t s_free_blocks_count; /* Free blocks count */ + uint32_t s_free_inodes_count; /* Free inodes count */ + uint32_t s_first_data_block; /* First Data Block */ + uint32_t s_log_block_size; /* Block size */ + uint32_t s_log_frag_size; /* Fragment size */ + uint32_t s_blocks_per_group; /* # Blocks per group */ + uint32_t s_frags_per_group; /* # Fragments per group */ + uint32_t s_inodes_per_group; /* # Inodes per group */ + uint32_t s_mtime; /* Mount time */ + uint32_t s_wtime; /* Write time */ + uint16_t s_mnt_count; /* Mount count */ + int16_t s_max_mnt_count; /* Maximal mount count */ + uint16_t s_magic; /* Magic signature */ + uint16_t s_state; /* File system state */ + uint16_t s_errors; /* Behaviour when detecting errors */ + uint16_t s_minor_rev_level; + uint32_t s_lastcheck; /* time of last check */ + uint32_t s_checkinterval; /* max. time between checks */ + uint32_t s_creator_os; /* OS */ + uint32_t s_rev_level; /* Revision level */ + uint16_t s_def_resuid; /* Default uid for reserved blocks */ + uint16_t s_def_resgid; /* Default gid for reserved blocks */ + + uint32_t s_first_ino; /* First non-reserved inode */ + uint16_t s_inode_size; /* size of inode structure */ + uint16_t s_block_group_nr; /* block group # of this superblock */ + uint32_t s_feature_compat; /* compatible feature set */ + uint32_t s_feature_incompat; /* incompatible feature set */ + uint32_t s_feature_ro_compat; /* readonly-compatible feature set */ + uint8_t s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + uint32_t s_algorithm_usage_bitmap; /* For compression */ + uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + uint8_t s_prealloc_dir_blocks; + uint16_t s_padding1; + uint32_t s_reserved[204]; /* Padding to the end of the block */ +}; + +/******************************************************************************* +#ifndef DEPEND +#if ext2_super_block_size != 1024 +#error ext2_super_block definition bogus +#endif +#endif +*******************************************************************************/ + +/* + * ext2 group desc structure: + */ +struct ext2_group_desc { + uint32_t bg_block_bitmap; /* Blocks bitmap block */ + uint32_t bg_inode_bitmap; /* Inodes bitmap block */ + uint32_t bg_inode_table; /* Inodes table block */ + uint16_t bg_free_blocks_count; /* Free blocks count */ + uint16_t bg_free_inodes_count; /* Free inodes count */ + uint16_t bg_used_dirs_count; /* Directories count */ + uint16_t bg_pad; + uint32_t bg_reserved[3]; +}; + +/******************************************************************************* +#ifndef DEPEND +#if ext2_group_desc_size != 32 +#error ext2_group_desc definition bogus +#endif +#endif +*******************************************************************************/ + + +/* + * ext2 inode structure: + */ +struct ext2_inode { + uint16_t i_mode; /* File mode */ + uint16_t i_uid; /* Owner Uid */ + uint32_t i_size; /* 4: Size in bytes */ + uint32_t i_atime; /* Access time */ + uint32_t i_ctime; /* 12: Creation time */ + uint32_t i_mtime; /* Modification time */ + uint32_t i_dtime; /* 20: Deletion Time */ + uint16_t i_gid; /* Group Id */ + uint16_t i_links_count; /* 24: Links count */ + uint32_t i_blocks; /* Blocks count */ + uint32_t i_flags; /* 32: File flags */ + uint32_t l_i_reserved1; + uint32_t i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ + uint32_t i_version; /* File version (for NFS) */ + uint32_t i_file_acl; /* File ACL */ + uint32_t i_dir_acl; /* Directory ACL */ + uint32_t i_faddr; /* Fragment address */ + uint8_t l_i_frag; /* Fragment number */ + uint8_t l_i_fsize; /* Fragment size */ + uint16_t i_pad1; + uint32_t l_i_reserved2[2]; +}; + +/******************************************************************************* +#ifndef DEPEND +#if ext2_inode_size != 128 +#error ext2_inode definition bogus +#endif +#endif +*******************************************************************************/ + + +#define EXT2_NAME_LEN 255 +struct ext2_dir_entry { + unsigned int d_inode; /* Inode number */ + unsigned short d_rec_len; /* Directory entry length */ + unsigned char d_name_len; /* Name length */ + unsigned char d_file_type; + char d_name[EXT2_NAME_LEN]; /* File name */ +}; + +/******************************************************************************* +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) +*******************************************************************************/ + + + + + + +/* + * This is the extent on-disk structure. + * It's used at the bottom of the tree. + */ +struct ext4_extent { + uint32_t ee_block; /* first logical block extent covers */ + uint16_t ee_len; /* number of blocks covered by extent */ + uint16_t ee_start_hi; /* high 16 bits of physical block */ + uint32_t ee_start_lo; /* low 32 bits of physical block */ +}; + +/* + * This is index on-disk structure. + * It's used at all the levels except the bottom. + */ +struct ext4_extent_idx { + uint32_t ei_block; /* index covers logical blocks from 'block' */ + uint32_t ei_leaf_lo; /* pointer to the physical block of the next * + * level. leaf or next index could be there */ + uint16_t ei_leaf_hi; /* high 16 bits of physical block */ + uint16_t ei_unused; +}; + +/* + * Each block (leaves and indexes), even inode-stored has header. + */ +struct ext4_extent_header { + uint16_t eh_magic; /* probably will support different formats */ + uint16_t eh_entries; /* number of valid entries */ + uint16_t eh_max; /* capacity of store in entries */ + uint16_t eh_depth; /* has tree real underlying blocks? */ + uint32_t eh_generation; /* generation of the tree */ +}; + + + +#define EXT4_FIRST_EXTENT(header) ( (struct ext4_extent *)(header + 1) ) +#define EXT4_FIRST_INDEX(header) ( (struct ext4_extent_idx *) (header + 1) ) + + + + + + + +/* function declartion */ +/******************************************************************************* +extern struct open_file_t * ext2_read(char *); +extern int ext2_read(struct open_file_t *, char *, int); +*******************************************************************************/ + + +#endif /* ext2_fs.h */ diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c new file mode 100644 index 00000000..e7931b0f --- /dev/null +++ b/core/fs/fat/fat.c @@ -0,0 +1,895 @@ +#include <stdio.h> +#include <string.h> +#include <sys/dirent.h> +#include <cache.h> +#include <core.h> +#include <disk.h> +#include <fs.h> +#include "fat_fs.h" + +#define ROOT_DIR_WORD 0x002f + +/* file structure. This holds the information for each currently open file */ +struct open_file_t { + sector_t file_sector; /* sector pointer (0 = structure free) */ + uint32_t file_bytesleft; /* number of bytes left */ + uint32_t file_left; /* number of sectors left */ +}; + +static struct open_file_t Files[MAX_OPEN]; + +extern uint8_t SecPerClust; + +/* the fat bpb data */ +static struct fat_bpb fat; +static int FATType = 0; + +/* generic information about FAT fs */ +static sector_t FAT; /* Location of (first) FAT */ +static sector_t RootDirArea; /* Location of root directory area */ +static sector_t RootDir; /* Location of root directory proper */ +static sector_t DataArea; /* Location of data area */ +static uint32_t TotalSectors; /* Total number of sectors */ +static uint32_t ClustSize; /* Bytes/cluster */ +static uint32_t ClustMask; /* Sector/cluster - 1 */ +static uint8_t ClustShift; /* Shift count for sectors/cluster */ +static uint8_t ClustByteShift; /* Shift count for bytes/cluster */ + +static int CurrentDir; +static int PrevDir; + +/* used for long name entry */ +static char MangleBuf[12]; +static char entry_name[14]; + +/* try with the biggest long name */ +static char long_name[0x40 * 13]; +static char *NameStart; +static int NameLen; + +/* + * Allocate a file structure, if successful return the file pointer, or NULL. + * + */ +static struct open_file_t *allocate_file(void) +{ + struct open_file_t *file = Files; + int i = 0; + + for (; i < MAX_OPEN; i ++) { + if (file->file_sector == 0) /* found it */ + return file; + file ++; + } + + return NULL; /* not found */ +} + + +/* + * Allocate then fill a file structure for a directory starting in + * sector SECTOR. if successful, return the pointer of filled file + * structure, or return NULL. + * + */ +static struct open_file_t *alloc_fill_dir(sector_t sector) +{ + struct open_file_t *file; + + file = allocate_file(); + if (!file) + return NULL; + + file->file_sector = sector; /* current sector */ + file->file_bytesleft = 0; /* current offset */ + file->file_left = sector; /* beginning sector */ + return file; +} + + +/* Deallocates a file structure */ +static inline void close_pvt(struct open_file_t *of) +{ + of->file_sector = 0; +} + +static void vfat_close_file(struct file *file) +{ + close_pvt(file->open_file); +} + + +/* + * check for a particular sector in the FAT cache. + * + */ +static struct cache_struct *getfatsector(struct fs_info *fs, sector_t sector) +{ + return get_cache_block(fs->fs_dev, FAT + sector); +} + + +/** + * Advance a cluster pointer in clust_num to the next cluster + * pointer at in the FAT tables. return the next cluster number + * if success, or return 0 if end of file. + * + */ +static uint32_t nextcluster(struct fs_info *fs, uint32_t clust_num) +{ + uint32_t next_cluster; + sector_t fat_sector; + uint32_t offset; + int lo, hi; + struct cache_struct *cs; + + switch(FATType) { + case FAT12: + fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT; + cs = getfatsector(fs, fat_sector); + offset = (clust_num * 3 / 2) & (SECTOR_SIZE -1); + if (offset == 0x1ff) { + /* + * we got the end of the one fat sector, + * but we don't got we have(just one byte, we need two), + * so store the low part, then read the next fat + * sector, read the high part, then combine it. + */ + lo = *(uint8_t *)(cs->data + offset); + cs = getfatsector(fs, fat_sector + 1); + hi = *(uint8_t *)cs->data; + next_cluster = (hi << 8) + lo; + } else + next_cluster = *(uint16_t *)(cs->data + offset); + + if (clust_num & 0x0001) + next_cluster >>= 4; /* cluster number is ODD */ + else + next_cluster &= 0x0fff; /* cluster number is EVEN */ + if (next_cluster > 0x0ff0) + goto fail; + break; + + case FAT16: + fat_sector = clust_num >> (SECTOR_SHIFT - 1); + offset = clust_num & ((1 << (SECTOR_SHIFT-1)) -1); + cs = getfatsector(fs, fat_sector); + next_cluster = ((uint16_t *)cs->data)[offset]; + if (next_cluster > 0xfff0) + goto fail; + break; + + case FAT32: + fat_sector = clust_num >> (SECTOR_SHIFT - 2); + offset = clust_num & ((1 << (SECTOR_SHIFT-2)) -1); + cs = getfatsector(fs, fat_sector); + next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff; + if (next_cluster > 0x0ffffff0) + goto fail; + break; + } + + return next_cluster; + + fail: + /* got an unexcepted cluster number, so return ZERO */ + return 0; +} + + + +/* + * given a sector on input, return the next sector of the + * same filesystem object, which may be the root directory or a + * cluster chain. Returns EOF. + * + */ +static sector_t nextsector(struct fs_info *fs, sector_t sector) +{ + sector_t data_sector; + uint32_t cluster; + + if (sector < DataArea) { + sector ++; + /* if we reached the end of root area */ + if (sector == DataArea) + sector = 0; /* return 0 */ + return sector; + } + + data_sector = sector - DataArea; + if ((data_sector+1) & ClustMask) /* in a cluster */ + return (++sector); + + /* got a new cluster */ + cluster = nextcluster(fs, (data_sector >> ClustShift) + 2); + if (!cluster ) + return 0; + + /* return the start of the new cluster */ + sector = ((cluster - 2) << ClustShift) + DataArea; + return sector; +} + + + + + +/** + * __getfssec: + * + * get multiple sectors from a file + * + * This routine makes sure the subransfers do not cross a 64K boundary + * and will correct the situation if it does, UNLESS *sectos* cross + * 64K boundaries. + * + * @param: buf + * @param: file structure + * @param: sectors + * + */ +static void __getfssec(struct fs_info *fs, char *buf, + struct open_file_t *file, uint32_t sectors) +{ + sector_t curr_sector = file->file_sector; + sector_t frag_start , next_sector; + uint32_t con_sec_cnt; + struct disk *disk = fs->fs_dev->disk; + + while (sectors) { + /* get fragment */ + con_sec_cnt = 0; + frag_start = curr_sector; + + do { + /* get consective sector count */ + con_sec_cnt ++; + sectors --; + if (sectors == 0) + break; + + next_sector = nextsector(fs, curr_sector); + if (!next_sector) + break; + }while(next_sector == (++curr_sector)); + +#if 0 + printf("You are reading data stored at sector --0x%x--0x%x\n", + frag_start, frag_start + con_sec_cnt -1); +#endif + + /* do read */ + disk->rdwr_sectors(disk, buf, frag_start, con_sec_cnt, 0); + buf += con_sec_cnt << 9;/* adjust buffer pointer */ + + if (!sectors) + break; + //curr_sector --; /* this is the last sector actually read */ + curr_sector = next_sector; + } + + /* update the file_sector filed for the next read */ + file->file_sector = nextsector(fs, curr_sector); +} + + + +/** + * get multiple sectors from a file + * + * @param: buf, the buffer to store the read data + * @param: gfile, the file structure pointer + * @param: sectors, number of sectors wanna read + * @param: have_more, set one if has more + * + * @return: number of bytes read + * + */ +static uint32_t vfat_getfssec(struct file *gfile, char *buf, int sectors, + bool *have_more) +{ + uint32_t bytes_read = sectors << SECTOR_SHIFT; + struct open_file_t *file = gfile->open_file; + struct fs_info *fs = gfile->fs; + + if (sectors > file->file_left) + sectors = file->file_left; + + __getfssec(fs, buf, file, sectors); + + if (bytes_read >= file->file_bytesleft) { + bytes_read = file->file_bytesleft; + *have_more = 0; + } else + *have_more = 1; + file->file_bytesleft -= bytes_read; + file->file_left -= sectors; + + return bytes_read; +} + +/* + * Mangle a filename pointed to by src into a buffer pointed to by dst; + * ends on encountering any whitespace. + * + */ +static void vfat_mangle_name(char *dst, const char *src) +{ + char *p = dst; + char c; + int i = FILENAME_MAX -1; + + /* + * Copy the filename, converting backslash to slash and + * collapsing duplicate separators. + */ + while (not_whitespace(c = *src)) { + if (c == '\\') + c = '/'; + + if (c == '/') { + if (src[1] == '/' || src[1] == '\\') { + src++; + i--; + continue; + } + } + i--; + *dst++ = *src++; + } + + /* Strip terminal slashes or whitespace */ + while (1) { + if (dst == p) + break; + if (*(dst-1) == '/' && dst-1 == p) /* it's the '/' case */ + break; + if ((*(dst-1) != '/') && (*(dst-1) != '.')) + break; + + dst--; + i++; + } + + i++; + for (; i > 0; i --) + *dst++ = '\0'; +} + +/* + * Mangle a dos filename component pointed to by FILENAME + * into MangleBuf; ends on encountering any whitespace or + * slash. + * + * WARNING: saves pointers into the buffer for longname matchs! + */ +/** + * for now, it can't handle this case: + * xyxzxyxjfdkfjdjf.txt as it will just output the first 11 chars + * but not care the dot char at the later, so I think we need do + * this, but it seems that the SYSLINUX doesn't do it, so I will + * make it stay as what it was orignal. + * + */ +static void mangle_dos_name(char *MangleBuf, char *filename) +{ + + char *dst = MangleBuf; + char *src = filename; + int i = 0; + unsigned char c; + + NameStart = filename; + + for (; i < 11; i ++) + MangleBuf[i] = ' '; + + for (i = 0; i < 11; i++) { + c = *src ++; + + if ((c <= ' ') || (c == '/')) + break; + + if (c == '.') { + dst = &MangleBuf[8]; + i = 7; + continue; + } + + if (c >= 'a' && c <= 'z') + c -= 32; + if ((c == 0xe5) && (i == 11)) + c = 0x05; + + *dst++ = c; + } + MangleBuf[12] = '\0'; + + while((*src != '/') && (*src > ' ')) + src ++; + + NameLen = src - filename; +} + +static void unicode_to_ascii(char *entry_name, uint16_t *unicode_buf) +{ + int i = 0; + + for (; i < 13; i++) { + if (unicode_buf[i] == 0xffff) { + entry_name[i] = '\0'; + return; + } + entry_name[i] = (char)unicode_buf[i]; + } +} + +/* + * get the long entry name + * + */ +static void long_entry_name(struct fat_long_name_entry *dir) +{ + uint16_t unicode_buf[13]; + + memcpy(unicode_buf, dir->name1, 5 * 2); + memcpy(unicode_buf + 5, dir->name2, 6 * 2); + memcpy(unicode_buf + 11,dir->name3, 2 * 2); + + unicode_to_ascii(entry_name, unicode_buf); + +} + + +static uint8_t get_checksum(char *dir_name) +{ + int i; + uint8_t sum=0; + + for (i=11; i; i--) + sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++; + return sum; +} + +/* compute the first sector number of one dir where the data stores */ +static inline sector_t first_sector(struct fat_dir_entry *dir) +{ + uint32_t first_clust, sector; + + first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low; + sector = ((first_clust - 2) << ClustShift) + DataArea; + + return sector; +} + + +/** + * search a specific directory for a pre-mangled filename in + * MangleBuf, in the directory starting in sector SECTOR + * + * NOTE: This file considers finding a zero-length file an + * error. This is so we don't have to deal with that special + * case elsewhere in the program (most loops have the test + * at the end). + * + * @param: MangleBuf + * @param: dir_sector, directory sector + * + * @out: file pointer + * @out: file length (MAY BE ZERO!) + * @out: file attribute + * + */ +static struct open_file_t* +search_dos_dir(struct fs_info *fs, char *MangleBuf, + uint32_t dir_sector, uint32_t *file_len, uint8_t *attr) +{ + struct open_file_t* file; + struct cache_struct* cs; + struct fat_dir_entry *dir; + struct fat_long_name_entry *long_dir; + + uint8_t VFATInit, VFATNext, VFATCsum; + uint8_t id; + uint32_t slots; + uint32_t entries; + int checksum; + + file = allocate_file(); + if (!file) + return NULL; + + /* + * Compute the value of a possible VFAT longname + * "last" entry (which, of coures, comes first ...) + */ + slots = (NameLen + 12) / 13; + slots |= 0x40; + VFATInit = slots; + VFATNext = slots; + + do { + cs = get_cache_block(fs->fs_dev, dir_sector); + dir = (struct fat_dir_entry *)cs->data; + entries = SECTOR_SIZE / 32; + + /* scan all the entries in a sector */ + do { + if (dir->name[0] == 0) + return NULL; /* Hit directory high water mark */ + + if (dir->attr == 0x0f) { + /* it's a long name entry */ + long_dir = (struct fat_long_name_entry *)dir; + id = long_dir->id; + if (id !=VFATNext) + goto not_match; + + if (id & 0x40) { + /*get the initial checksum value*/ + VFATCsum = long_dir->checksum; + } else { + if (long_dir->checksum != VFATCsum) + goto not_match; + } + + id &= 0x3f; + VFATNext = --id; + + /* got the long entry name */ + long_entry_name(long_dir); + memcpy(long_name + id * 13, entry_name, 13); + + /* + * if we got the last entry? + * if so, check it, or go on with the next entry + */ + if (id == 0) { + if (strcmp(long_name, NameStart)) + goto not_match; + } + + goto next_entry; + + } else { + /* it's a short entry */ + if (dir->attr & 0x08) /* ingore volume labels */ + goto not_match; + + + /* If we have a long name match, then VFATNext must be 0 */ + if (!VFATNext) { + /* + * we already have a VFAT long name match, however, + * the match is only valid if the checksum matchs. + */ + checksum = get_checksum(dir->name); + if (checksum == VFATCsum) + goto found; /* got a match on long name */ + + } else { + if (strncmp(MangleBuf, dir->name, 11) == 0) + goto found; + } + } + + not_match:/* find it again */ + VFATNext = VFATInit; + + next_entry: + dir ++; + + }while (--entries); + + dir_sector = nextsector(fs, dir_sector); + + }while (dir_sector); /* scan another secotr */ + + found: + *file_len = file->file_bytesleft = dir->file_size; + file->file_sector = first_sector(dir); + *attr = dir->attr; + + return file; +} + + + +/** + * open a file + * + * @param: filename, the file we wanna open + * @param: file_len, to return the file length + * + * @return: return the file structure on successful, or NULL. + * + */ +static void vfat_searchdir(char *filename, struct file *file) +{ + sector_t dir_sector; + uint32_t file_len = 0; + uint8_t attr = 0; + char *p; + struct open_file_t *open_file = NULL; + + dir_sector = CurrentDir; + if (*filename == '/') { + dir_sector = RootDir; + if (*(filename + 1) == 0) /* root dir is what we need */ + goto found_dir; + } + + while (*filename) { + if (*filename == '/') + filename++; /* skip '/' */ + p = filename; + if (*p == 0) + break; + PrevDir = dir_sector; + + /* try to find the end */ + while ((*p > ' ') && (*p != '/')) + p ++; + + if (filename == p) { + /* found a dir */ + dir_sector = PrevDir; + goto found_dir; + } + + mangle_dos_name(MangleBuf, filename); + /* close it before open a new dir file */ + if (open_file) + close_pvt(open_file); + open_file = search_dos_dir(file->fs, MangleBuf, dir_sector, &file_len, &attr); + if (!open_file) + goto fail; + + dir_sector = open_file->file_sector; + filename = p; + } + + if (attr & 0x10) { + found_dir: + open_file = alloc_fill_dir(dir_sector); + } else if ((attr & 0x18) || (file_len == 0)) { + fail: + file_len = 0; + open_file = NULL; + } else { + open_file->file_bytesleft = file_len; + open_file->file_left = (file_len + SECTOR_SIZE -1) >> SECTOR_SHIFT; + } + + file->file_len = file_len; + file->open_file = open_file; +} + +/* + * The open dir function, just call the searchdir function directly. + * I don't think we need call the mangle_name function first + */ +void vfat_opendir(com32sys_t *regs) +{ + char *src = MK_PTR(regs->es, regs->esi.w[0]); + char *dst = MK_PTR(regs->ds, regs->edi.w[0]); + strcpy(dst, src); + searchdir(regs); +} + +/* + * read one file from a directory; return the newly read de structure + */ +struct dirent* vfat_readdir(struct file *dir) +{ + uint32_t sector, sec_off; + /* make it to be 1 to check if we have met a long name entry before */ + uint8_t id = 1; + uint8_t init_id, next_id; + uint8_t checksum = 0; + uint8_t entries_left; + int i; + static struct dirent de; + char *de_name = de.d_name; + struct cache_struct *cs; + struct fat_dir_entry *fat_dir; + struct fat_long_name_entry *long_dir; + struct open_file_t *file = dir->open_file; + struct fs_info *fs = dir->fs; + + sector = file->file_sector; + sec_off = file->file_bytesleft; + if (!sector) + return NULL; + entries_left = (SECTOR_SIZE - sec_off) >> 5; + cs = get_cache_block(fs->fs_dev, sector); + fat_dir = (struct fat_dir_entry *)(cs->data + sec_off);/* resume last position in sector */ + + while (1) { + if (!entries_left) { + sector = nextsector(fs, sector); + if (!sector) + return NULL; + cs = get_cache_block(fs->fs_dev, sector); + fat_dir = (struct fat_dir_entry *)cs->data; + } + + if (fat_dir->name[0] == 0) + return NULL; + if (fat_dir->attr == FAT_ATTR_LONG_NAME) { + /* it's a long name */ + long_dir = (struct fat_long_name_entry *)fat_dir; + + if (long_dir->id & 0x40) { + checksum = long_dir->checksum; + init_id = id = long_dir->id & 0x3f; + id--; + } else { + next_id = (long_dir->id & 0x3f) - 1; + id--; + if (id != next_id || long_dir->checksum != checksum) + goto next_entry; + } + + long_entry_name(long_dir); + memcpy(de_name + id * 13, entry_name, 13); + + /* + * we need go on with the next entry + * and we will fall through to next entry + */ + + } else { + /* it's a short entry */ + + if (!id) { + /* Got a long name match */ + if (get_checksum(fat_dir->name) != checksum) + goto next_entry; + + break; + } + + if (fat_dir->attr & FAT_ATTR_VOLUME_ID || + get_checksum(fat_dir->name) != checksum ) + goto next_entry; + + for(i = 0; i < 8; i ++) { + if (fat_dir->name[i] == ' ') + break; + *de_name++ = fat_dir->name[i]; + } + *de_name++ = '.'; + for (i = 8; i < 11; i ++) { + if (fat_dir->name[i] == ' ') + break; + *de_name ++ = fat_dir->name[i]; + } + /* check if we have got an extention */ + if (*(de_name - 1) == '.') + *(de_name - 1) = '\0'; + else + *de_name = '\0'; + + break; + } + + next_entry: + entries_left --; + fat_dir ++; + } + + /* found what we want, fill the de structure */ + de.d_reclen = DIR_REC_LEN(de.d_name); + de.d_type = fat_dir->attr; + + /* update the DIR structure */ + entries_left--; + if (!entries_left) { + sector = nextsector(fs, sector); + file->file_bytesleft = 0; + } else { + file->file_bytesleft = SECTOR_SIZE - (entries_left << 5); + } + file->file_sector = sector; + + return &de; +} + +/* Load the config file, return 1 if failed, or 0 */ +static int vfat_load_config(void) +{ + static const char syslinux_cfg1[] = "/boot/syslinux/syslinux.cfg"; + static const char syslinux_cfg2[] = "/syslinux/syslinux.cfg"; + static const char syslinux_cfg3[] = "/syslinux.cfg"; + static const char config_name[] = "syslinux.cfg"; + const char * const syslinux_cfg[] = + { syslinux_cfg1, syslinux_cfg2, syslinux_cfg3 }; + com32sys_t regs; + int i = 0; + + *(uint16_t *)CurrentDirName = ROOT_DIR_WORD; + CurrentDir = RootDir; + + /* + * we use the ConfigName to pass the config path because + * it is under the address 0xffff + */ + memset(®s, 0, sizeof regs); + regs.edi.w[0] = OFFS_WRT(ConfigName, 0); + for (; i < 3; i++) { + strcpy(ConfigName, syslinux_cfg[i]); + call16(core_open, ®s, ®s); + + /* if zf flag set, then failed; try another */ + if (! (regs.eflags.l & EFLAGS_ZF)) + break; + } + if (i == 3) { + printf("no config file found\n"); + return 1; /* no config file */ + } + + strcpy(ConfigName, config_name); + strcpy(CurrentDirName, syslinux_cfg[i]); + CurrentDirName[strlen(syslinux_cfg[i])-strlen(config_name)] = '\0'; + CurrentDir = PrevDir; + return 0; +} + +static inline __constfunc uint32_t bsr(uint32_t num) +{ + asm("bsrl %1,%0" : "=r" (num) : "rm" (num)); + return num; +} + +/* init. the fs meta data, return the block size in bits */ +static int vfat_fs_init(struct fs_info *fs) +{ + int sectors_per_fat; + uint32_t clust_num; + int RootDirSize; + struct disk *disk = fs->fs_dev->disk; + + /* get the fat bpb information */ + disk->rdwr_sectors(disk, &fat, 0, 1, 0); + + TotalSectors = fat.bxSectors ? : fat.bsHugeSectors; + FAT = fat.bxResSectors; + + sectors_per_fat = fat.bxFATsecs ? : fat.u.fat32.bxFATsecs_32; + RootDir = RootDirArea = FAT + sectors_per_fat * fat.bxFATs; + RootDirSize = (fat.bxRootDirEnts+SECTOR_SIZE/32-1) >> (SECTOR_SHIFT-5); + DataArea = RootDirArea + RootDirSize; + + ClustShift = bsr(fat.bxSecPerClust); + ClustByteShift = ClustShift + SECTOR_SHIFT; + ClustMask = fat.bxSecPerClust - 1; + ClustSize = fat.bxSecPerClust << SECTOR_SHIFT; + + clust_num = (TotalSectors - DataArea) >> ClustShift; + if (clust_num < 4085) + FATType = FAT12; + else if (clust_num < 65525) + FATType = FAT16; + else + FATType = FAT32; + + /* for SYSLINUX, the cache is based on sector size */ + return SECTOR_SHIFT; +} + +const struct fs_ops vfat_fs_ops = { + .fs_name = "vfat", + .fs_flags = 0, + .fs_init = vfat_fs_init, + .searchdir = vfat_searchdir, + .getfssec = vfat_getfssec, + .close_file = vfat_close_file, + .mangle_name = vfat_mangle_name, + .unmangle_name = generic_unmangle_name, + .load_config = vfat_load_config, + .opendir = vfat_opendir, + .readdir = vfat_readdir +}; diff --git a/core/fs/fat/fat_fs.h b/core/fs/fat/fat_fs.h new file mode 100644 index 00000000..71c1d9a7 --- /dev/null +++ b/core/fs/fat/fat_fs.h @@ -0,0 +1,114 @@ +#ifndef FAT_FS_H +#define FAT_FS_H + +#include <stdint.h> + +#define FAT_DIR_ENTRY_SIZE 32 +#define DIRENT_SHIFT 5 + +#define FAT_ATTR_READ_ONLY 0x01 +#define FAT_ATTR_HIDDEN 0x02 +#define FAT_ATTR_SYSTEM 0x04 +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIRECTORY 0x10 +#define FAT_ATTR_ARCHIVE 0x20 + +#define FAT_MAXFILE 256 + +#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY \ + | FAT_ATTR_HIDDEN \ + | FAT_ATTR_SYSTEM \ + | FAT_ATTR_VOLUME_ID) + +#define FAT_ATTR_VALID (FAT_ATTR_READ_ONLY \ + | FAT_ATTR_HIDDEN \ + | FAT_ATTR_SYSTEM \ + | FAT_ATTR_DIRECTORY \ + | FAT_ATTR_ARCHIVE) + +enum fat_type{ FAT12, FAT16, FAT32 }; + +/* + * The fat file system structures + */ + +struct fat_bpb { + uint8_t jmp_boot[3]; + uint8_t oem_name[8]; + uint16_t sector_size; + uint8_t bxSecPerClust; + uint16_t bxResSectors; + uint8_t bxFATs; + uint16_t bxRootDirEnts; + uint16_t bxSectors; + uint8_t media; + uint16_t bxFATsecs; + uint16_t sectors_per_track; + uint16_t num_heads; + uint32_t num_hidden_sectors; + uint32_t bsHugeSectors; + + union { + struct { + uint8_t num_ph_drive; + uint8_t reserved; + uint8_t boot_sig; + uint32_t num_serial; + uint8_t label[11]; + uint8_t fstype[8]; + } __attribute__ ((packed)) fat12_16; + + struct { + uint32_t bxFATsecs_32; + uint16_t extended_flags; + uint16_t fs_version; + uint32_t root_cluster; + uint16_t fs_info; + uint16_t backup_boot_sector; + uint8_t reserved[12]; + uint8_t num_ph_drive; + uint8_t reserved1; + uint8_t boot_sig; + uint32_t num_serial; + uint8_t label[11]; + uint8_t fstype[8]; + } __attribute__ ((packed)) fat32; + + } __attribute__ ((packed)) u; + +} __attribute__ ((packed)); + + + +struct fat_dir_entry { + char name[11]; + uint8_t attr; + uint8_t nt_reserved; + uint8_t c_time_tenth; + uint16_t c_time; + uint16_t c_date; + uint16_t a_date; + uint16_t first_cluster_high; + uint16_t w_time; + uint16_t w_date; + uint16_t first_cluster_low; + uint32_t file_size; +} __attribute__ ((packed)); + + + +struct fat_long_name_entry { + uint8_t id; + uint16_t name1[5]; + uint8_t attr; + uint8_t reserved; + uint8_t checksum; + uint16_t name2[6]; + uint16_t first_cluster; + uint16_t name3[2]; +} __attribute__ ((packed)); + + + + +#endif /* fat_fs.h */ diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c new file mode 100644 index 00000000..e060b13d --- /dev/null +++ b/core/fs/iso9660/iso9660.c @@ -0,0 +1,536 @@ +#include <stdio.h> +#include <string.h> +#include <core.h> +#include <disk.h> +#include <fs.h> +#include "iso9660_fs.h" + +#define DEBUG 1 + +#define ISO_SECTOR_SHIFT 11 +#define ISO_SECTOR_SIZE (1 << ISO_SECTOR_SHIFT) +#define ROOT_DIR_WORD 0x002f +#define TRACKBUF_SIZE 8192 + +struct open_file_t { + sector_t file_sector; + uint32_t file_bytesleft; + uint32_t file_left; +}; +static struct open_file_t Files[MAX_OPEN]; + +struct dir_t { + uint32_t dir_lba; /* Directory start (LBA) */ + uint32_t dir_len; /* Length in bytes */ + uint32_t dir_clust; /* Length in clusters */ +}; +static struct dir_t RootDir; +static struct dir_t CurrentDir; + +static uint16_t BufSafe = TRACKBUF_SIZE >> ISO_SECTOR_SHIFT; + +static char ISOFileName[64]; /* ISO filename canonicalizatin buffer */ +static char *ISOFileNameEnd = &ISOFileName[64]; + +/* + * use to store the block shift, since we treat the hd-mode as 512 bytes + * sector size, 2048 bytes block size. we still treat the cdrom as 2048 + * bytes sector size and also the block size. + */ +static int block_shift; + +/* + * allocate a file structure + * + */ +static struct open_file_t *allocate_file(void) +{ + struct open_file_t *file = Files; + int i; + + for (i = 0; i < MAX_OPEN; i++) { + if ( file->file_sector == 0 ) /* found it */ + return file; + file++; + } + + return NULL; /* not found */ +} + + +/** + * close_file: + * + * Deallocates a file structure + * + */ +static inline void close_pvt(struct open_file_t *file) +{ + file->file_sector = 0; +} + +static void iso_close_file(struct file *file) +{ + close_pvt(file->open_file); +} + +/* + * Mangle a filename pointed to by src into a buffer pointed + * to by dst; ends on encountering any whitespace. + * dst is preserved. + * + * This verifies that a filename is < FilENAME_MAX characters, + * doesn't contain whitespace, zero-pads the output buffer, + * and removes trailing dots and redumndant slashes, so "repe + * cmpsb" can do a compare, and the path-searching routine gets + * a bit of an easier job. + * + */ +static void iso_mangle_name(char *dst, const char *src) +{ + char *p = dst; + int i = FILENAME_MAX - 1; + + while (not_whitespace(*src)) { + if ( *src == '/' ) { + if ( *(src+1) == '/' ) { + i--; + src++; + continue; + } + } + + *dst++ = *src ++; + i--; + } + + while ( 1 ) { + if ( dst == p ) + break; + + if ( (*(dst-1) != '.') && (*(dst-1) != '/') ) + break; + + dst --; + i ++; + } + + i ++; + for (; i > 0; i -- ) + *dst++ = '\0'; +} + +/** + * compare the names de_name and file_name and report if they are + * equal from an ISO 9600 perspective. + * + * @param: de_name, the name from the file system. + * @param: len, the length of de_name, and will return the real name of the de_name + * ';' and other terminates excluded. + * @param: file_name, the name we want to check, is expected to end with a null + * + * @return: 1 on match, or 0. + * + */ +static int iso_compare_names(char *de_name, int *len, char *file_name) +{ + char *p = ISOFileName; + char c1, c2; + + int i = 0; + + while ( (i < *len) && *de_name && (*de_name != ';') && (p < ISOFileNameEnd - 1) ) { + *p++ = *de_name++; + i++; + } + + /* Remove terminal dots */ + while ( *(p-1) == '.' ) { + if ( *len <= 2 ) + break; + + if ( p <= ISOFileName ) + break; + p --; + i--; + } + + if ( i <= 0 ) + return 0; + + *p = '\0'; + + /* return the 'real' length of de_name */ + *len = i; + + p = ISOFileName; + + /* i is the 'real' name length of file_name */ + while ( i ) { + c1 = *p++; + c2 = *file_name++; + + if ( (c1 == 0) && (c2 == 0) ) + return 1; /* success */ + + else if ( (c1 == 0) || ( c2 == 0 ) ) + return 0; + + c1 |= 0x20; + c2 |= 0x20; /* convert to lower case */ + if ( c1 != c2 ) + return 0; + i --; + } + + return 1; +} + +static inline int cdrom_read_sectors(struct disk *disk, void *buf, int block, int count) +{ + /* changed those to _sector_ */ + block <<= block_shift; + count <<= block_shift; + return disk->rdwr_sectors(disk, buf, block, count, 0); +} + +/** + * Get multiple clusters from a file, given the file pointer. + * + * @param: buf + * @param: file, the address of the open file structure + * @param: sectors, how many we want to read at once + * @param: have_more, to indicate if we have reach the end of the file + * + */ +static uint32_t iso_getfssec(struct file *gfile, char *buf, + int sectors, bool *have_more) +{ + uint32_t bytes_read = sectors << ISO_SECTOR_SHIFT; + struct open_file_t *file = gfile->open_file; + struct disk *disk = gfile->fs->fs_dev->disk; + + if ( sectors > file->file_left ) + sectors = file->file_left; + + cdrom_read_sectors(disk, buf, file->file_sector, sectors); + + file->file_sector += sectors; + file->file_left -= sectors; + + if ( bytes_read >= file->file_bytesleft ) { + bytes_read = file->file_bytesleft; + *have_more = 0; + } else + *have_more = 1; + file->file_bytesleft -= bytes_read; + + return bytes_read; +} + + + +/* + * find a file or directory with name within the _dir_ directory. + * + * the return value will tell us what we find, it's a file or dir? + * on 1 be dir, 2 be file, 0 be error. res will return the result. + * + */ +static int do_search_dir(struct fs_info *fs, struct dir_t *dir, + char *name, uint32_t *file_len, void **res) +{ + struct open_file_t *file; + struct iso_dir_entry *de; + struct iso_dir_entry tmpde; + struct file xfile; + + uint32_t offset = 0; /* let's start it with the start */ + uint32_t file_pos = 0; + char *de_name; + int de_len; + int de_name_len; + bool have_more; + + file = allocate_file(); + if ( !file ) + return 0; + + file->file_left = dir->dir_clust; + file->file_sector = dir->dir_lba; + + xfile.fs = fs; + xfile.open_file = file; + + iso_getfssec(&xfile, trackbuf, BufSafe, &have_more); + de = (struct iso_dir_entry *)trackbuf; + + while ( file_pos < dir->dir_len ) { + int found = 0; + + if ( (char *)de >= (char *)(trackbuf + TRACKBUF_SIZE) ) { + if ( !have_more ) + return 0; + + iso_getfssec(&xfile, trackbuf, BufSafe, &have_more); + offset = 0; + } + + de = (struct iso_dir_entry *) (trackbuf + offset); + + de_len = de->length; + + if ( de_len == 0) { + offset = file_pos = (file_pos+ISO_SECTOR_SIZE) & ~(ISO_SECTOR_SIZE-1); + continue; + } + + + offset += de_len; + + /* Make sure we have a full directory entry */ + if ( offset >= TRACKBUF_SIZE ) { + int slop = TRACKBUF_SIZE - offset + de_len; + memcpy(&tmpde, de, slop); + offset &= TRACKBUF_SIZE - 1; + file->file_sector++; + if ( offset ) { + if ( !have_more ) + return 0; + iso_getfssec(&xfile, trackbuf, BufSafe, &have_more); + memcpy((void*)&tmpde + slop, trackbuf, offset); + } + de = &tmpde; + } + + if ( de_len < 33 ) { + printf("Corrutped directory entry in sector %d\n", file->file_sector); + return 0; + } + + de_name_len = de->name_len; + de_name = (char *)((void *)de + 0x21); + + + if ( (de_name_len == 1) && (*de_name == 0) ) { + found = iso_compare_names(".", &de_name_len, name); + + } else if ( (de_name_len == 1) && (*de_name == 1) ) { + de_name_len = 2; + found = iso_compare_names("..", &de_name_len, name); + + } else + found = iso_compare_names(de_name, &de_name_len, name); + + if (found) + break; + + file_pos += de_len; + } + + if ( file_pos >= dir->dir_len ) + return 0; /* not found */ + + + if ( *(name+de_name_len) && (*(name+de_name_len) != '/' ) ) { + printf("Something wrong happened during searching file %s\n", name); + + *res = NULL; + return 0; + } + + if ( de->flags & 0x02 ) { + /* it's a directory */ + dir = &CurrentDir; + dir->dir_lba = *(uint32_t *)de->extent; + dir->dir_len = *(uint32_t *)de->size; + dir->dir_clust = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT; + + *file_len = dir->dir_len; + *res = dir; + + /* we can close it now */ + close_pvt(file); + + /* Mark we got a directory */ + return 1; + } else { + /* it's a file */ + file->file_sector = *(uint32_t *)de->extent; + file->file_bytesleft = *(uint32_t *)de->size; + file->file_left = (file->file_bytesleft + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT; + + *file_len = file->file_bytesleft; + *res = file; + + /* Mark we got a file */ + return 2; + } +} + + +/* + * open a file + * + * searchdir_iso is a special entry point for ISOLINUX only. In addition + * to the above, searchdir_iso passes a file flag mask in AL. This is + * useful for searching for directories. + * + * well, it's not like the searchidr function in EXT fs or FAT fs; it also + * can read a diretory.(Just thought of mine, liu) + * + */ +static void iso_searchdir(char *filename, struct file *file) +{ + struct open_file_t *open_file = NULL; + struct dir_t *dir; + uint32_t file_len = 0; + int ret; + void *res; + + dir = &CurrentDir; + if ( *filename == '/' ) { + dir = &RootDir; + filename ++; + } + + while ( *filename ) { + ret = do_search_dir(file->fs, dir, filename, &file_len, &res); + if ( ret == 1 ) + dir = (struct dir_t *)res; + else if ( ret == 2 ) + break; + else + goto err; + + /* find the end */ + while ( *filename && (*filename != '/') ) + filename ++; + + /* skip the slash */ + while ( *filename && (*filename == '/') ) + filename++; + } + + /* well , we need recheck it , becuase it can be a directory */ + if ( ret == 2 ) { + open_file = (struct open_file_t *)res; + goto found; + } else { + open_file = allocate_file(); + if ( !open_file ) + goto err; + + open_file->file_sector = dir->dir_lba; + open_file->file_bytesleft = dir->dir_len; + open_file->file_left = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT; + goto found; + } + err: + close_pvt(open_file); + file_len = 0; + open_file = NULL; + + found: + file->file_len = file_len; + file->open_file = (void*)open_file; + +#if 0 + if (open_file) { + printf("file bytesleft: %d\n", open_file->file_bytesleft); + printf("file sector : %d\n", open_file->file_sector); + printf("file in sector: %d\n", open_file->file_in_sec); + printf("file offsector: %d\n", open_file->file_in_off); + } +#endif +} + +/* Load the config file, return 1 if failed, or 0 */ +static int iso_load_config(void) +{ + char *config_name = "isolinux.cfg"; + com32sys_t regs; + + memset(®s, 0, sizeof regs); + strcpy(ConfigName, config_name); + regs.edi.w[0] = OFFS_WRT(ConfigName, 0); + call16(core_open, ®s, ®s); + + return !!(regs.eflags.l & EFLAGS_ZF); +} + + +static int iso_fs_init(struct fs_info *fs) +{ + char *iso_dir; + char *boot_dir = "/boot/isolinux"; + char *isolinux_dir = "/isolinux"; + int len; + int bi_pvd = 16; + struct file file; + struct open_file_t *open_file; + struct disk *disk = fs->fs_dev->disk; + + block_shift = ISO_SECTOR_SHIFT - disk->sector_shift; + cdrom_read_sectors(disk, trackbuf, bi_pvd, 1); + CurrentDir.dir_lba = RootDir.dir_lba = *(uint32_t *)(trackbuf + 156 + 2); + +#ifdef DEBUG + printf("Root directory at LBA = 0x%x\n", RootDir.dir_lba); +#endif + + CurrentDir.dir_len = RootDir.dir_len = *(uint32_t*)(trackbuf + 156 + 10); + CurrentDir.dir_clust = RootDir.dir_clust = (RootDir.dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT; + + /* + * Look for an isolinux directory, and if found, + * make it the current directory instead of the + * root directory. + * + * Also copy the name of the directory to CurrrentDirName + */ + *(uint16_t *)CurrentDirName = ROOT_DIR_WORD; + + iso_dir = boot_dir; + file.fs = fs; + iso_searchdir(boot_dir, &file); /* search for /boot/isolinux */ + if ( !file.file_len ) { + iso_dir = isolinux_dir; + iso_searchdir(isolinux_dir, &file); /* search for /isolinux */ + if ( !file.file_len ) { + printf("No isolinux directory found!\n"); + return 0; + } + } + + strcpy(CurrentDirName, iso_dir); + len = strlen(CurrentDirName); + CurrentDirName[len] = '/'; + CurrentDirName[len+1] = '\0'; + + open_file = (struct open_file_t *)file.open_file; + CurrentDir.dir_len = open_file->file_bytesleft; + CurrentDir.dir_clust = open_file->file_left; + CurrentDir.dir_lba = open_file->file_sector; + close_pvt(open_file); + +#ifdef DEBUG + printf("isolinux directory at LBA = 0x%x\n", CurrentDir.dir_lba); +#endif + + /* we do not use cache for now, so we can just return 0 */ + return 0; +} + + +const struct fs_ops iso_fs_ops = { + .fs_name = "iso", + .fs_flags = 0, + .fs_init = iso_fs_init, + .searchdir = iso_searchdir, + .getfssec = iso_getfssec, + .close_file = iso_close_file, + .mangle_name = iso_mangle_name, + .unmangle_name = generic_unmangle_name, + .load_config = iso_load_config +}; diff --git a/core/fs/iso9660/iso9660_fs.h b/core/fs/iso9660/iso9660_fs.h new file mode 100644 index 00000000..ca123b16 --- /dev/null +++ b/core/fs/iso9660/iso9660_fs.h @@ -0,0 +1,21 @@ +#ifndef ISO9660_FS_H +#define ISO9660_FS_H + +#include <stdint.h> + +struct iso_dir_entry { + uint8_t length; /* 00 */ + uint8_t ext_attr_length; /* 01 */ + uint8_t extent[8]; /* 02 */ + uint8_t size[8]; /* 0a */ + uint8_t date[7]; /* 12 */ + uint8_t flags; /* 19 */ + uint8_t file_unit_size; /* 1a */ + uint8_t interleave; /* 1b */ + uint8_t volume_sequence_number[4]; /* 1c */ + uint8_t name_len; /* 20 */ + //uint8_t name[]; /* 21 */ +}; + + +#endif /* iso9660_fs.h */ diff --git a/core/fs/lib/mangle.c b/core/fs/lib/mangle.c new file mode 100644 index 00000000..813099fb --- /dev/null +++ b/core/fs/lib/mangle.c @@ -0,0 +1,47 @@ +/** + * mangle_name: + * + * Mangle a filename pointed to by src into a buffer pointed + * to by dst; ends on encountering any whitespace. + * dst is preserved. + * + * This verifies that a filename is < FILENAME_MAX characters, + * doesn't contain whitespace, zero-pads the output buffer, + * and removes redundant slashes. + * + */ + +#include <string.h> +#include "fs.h" + +void generic_mangle_name(char *dst, const char *src) +{ + char *p = dst; + int i = FILENAME_MAX-1; + + while (not_whitespace(*src)) { + if (*src == '/') { + if (src[1] == '/') { + src++; + i--; + continue; + } + } + i--; + *dst++ = *src++; + } + + while (1) { + if (dst == p) + break; + if (dst[-1] != '/') + break; + + dst--; + i++; + } + + i++; + for (; i > 0; i --) + *dst++ = '\0'; +} diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c new file mode 100644 index 00000000..7935f8ba --- /dev/null +++ b/core/fs/pxe/dhcp_option.c @@ -0,0 +1,272 @@ +#include <stdio.h> +#include <string.h> +#include <core.h> +#include <sys/cpu.h> +#include "pxe.h" + +char LocalDomain[256]; + +int over_load; +uint8_t uuid_type; +char uuid[17]; + +void parse_dhcp_options(void *, int, int); + +static void subnet_mask(void *data, int opt_len) +{ + if (opt_len != 4) + return; + net_mask = *(uint32_t *)data; +} + +static void router(void *data, int opt_len) +{ + if (opt_len != 4) + return; + gate_way = *(uint32_t *)data; +} + +static void dns_servers(void *data, int opt_len) +{ + int num = opt_len >> 2; + int i; + + if (num > DNS_MAX_SERVERS) + num = DNS_MAX_SERVERS; + + for (i = 0; i < num; i++) { + dns_server[i] = *(uint32_t *)data; + data += 4; + } + +#if 0 + /* + * if you find you got no corret DNS server, you can add + * it here manually. BUT be carefull the DNS_MAX_SERVERS + */ + if (i < DNS_MAX_SERVERS ) { + dns_server[i++] = your_master_dns_server; + dns_server[i++] = your_second_dns_server; + } +#endif +} + +static void local_domain(void *data, int opt_len) +{ + char *p = (char *)data + opt_len; + char *ld = LocalDomain; + char end = *p; + + *p = '\0'; /* Zero-terminate option */ + dns_mangle(&ld, data); + *p = end; /* Restore ending byte */ +} + +static void vendor_encaps(void *data, int opt_len) +{ + /* Only recongnize PXELINUX options */ + parse_dhcp_options(data, opt_len, 208); +} + +static void option_overload(void *data, int opt_len) +{ + if (opt_len != 1) + return; + over_load = *(uint8_t *)data; +} + + +static void server(void *data, int opt_len) +{ + uint32_t ip; + + if (opt_len != 4) + return; + + if (server_ip) + return; + + ip = *(uint32_t *)data; + if (ip_ok(ip)) + server_ip = ip; +} + +static void client_identifier(void *data, int opt_len) +{ + if (opt_len > MAC_MAX || opt_len < 2 || + MAC_len != (opt_len >> 8) || + *(uint8_t *)data != MAC_type) + return; + + opt_len --; + MAC_len = opt_len & 0xff; + memcpy(MAC, data+1, opt_len); + MAC[opt_len] = 0; +} + +static void bootfile_name(void *data, int opt_len) +{ + strncpy(boot_file, data, opt_len); + boot_file[opt_len] = 0; +} + +static void uuid_client_identifier(void *data, int opt_len) +{ + int type = *(uint8_t *)data; + if (opt_len != 17 || + (type | have_uuid)) + return; + + have_uuid = 1; + uuid_type = type; + memcpy(uuid, data+1, 16); + uuid[16] = 0; +} + +static void pxelinux_configfile(void *data, int opt_len) +{ + DHCPMagic |= 2; + strncpy(ConfigName, data, opt_len); + ConfigName[opt_len] = 0; +} + +static void pxelinux_pathprefix(void *data,int opt_len) +{ + DHCPMagic |= 4; + strncpy(path_prefix, data, opt_len); + path_prefix[opt_len] = 0; +} + +static void pxelinux_reboottime(void *data, int opt_len) +{ + if ((opt_len && 0xff) != 4) + return ; + + RebootTime = ntohl(*(uint32_t *)data); + DHCPMagic |= 8; /* Got reboot time */ +} + + +struct dhcp_options { + int opt_num; + void (*fun) (void *, int); +}; + +static struct dhcp_options dhcp_opts[] = { + {1, subnet_mask}, + {3, router}, + {6, dns_servers}, + {15, local_domain}, + {43, vendor_encaps}, + {52, option_overload}, + {54, server}, + {61, client_identifier}, + {67, bootfile_name}, + {97, uuid_client_identifier}, + {209, pxelinux_configfile}, + {210, pxelinux_pathprefix}, + {211, pxelinux_reboottime} +}; + +/* + * Parse a sequence of DHCP options, pointed to by _option_; + * -- some DHCP servers leave option fields unterminated + * in violation of the spec. + * + * filter contains the minimum value for the option to recognize + * -- this is used to restrict parsing to PXELINUX-specific options only. + */ +void parse_dhcp_options(void *option, int size, int filter) +{ + uint8_t opt_num; + uint8_t opt_len; + uint8_t opt_filter = filter == 208 ? 208 : 0; + int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]); + int i = 0; + char *p = option; + struct dhcp_options *opt; + + if (opt_filter) + printf("***NOTE!:*** we hit a pxelinux-specific options\n"); + + while (size --) { + opt_num = *p++; + + if (!size) + break; + if (opt_num == 0) + continue; + if (opt_num == 0xff) + break; + + /* Anything else will have a lenght filed */ + opt_len = *p++; /* c <- option lenght */ + size = size - opt_len - 1; + if (size < 0) + break; + if (opt_num < opt_filter) { /* Is the option value valid */ + option += opt_len; /* Try next */ + continue; + } + + opt = dhcp_opts; + for (i = 0; i < opt_entries; i++) { + if (opt_num == opt->opt_num) { + opt->fun(p, opt_len); + break; + } + opt ++; + } + + /* parse next */ + p += opt_len; + } +} + +/* + * + ; + ; parse_dhcp + ; + ; Parse a DHCP packet. This includes dealing with "overloaded" + ; option fields (see RFC 2132, section 9.3) + ; + ; This should fill in the following global variables, if the + ; information is present: + ; + ; MyIP - client IP address + ; server_ip - boot server IP address + ; net_mask - network mask + ; gate_way - default gateway router IP + ; boot_file - boot file name + ; DNSServers - DNS server IPs + ; LocalDomain - Local domain name + ; MAC_len, MAC - Client identifier, if MAC_len == 0 + ; + ; This assumes the DHCP packet is in "trackbuf". + ; +*/ +void parse_dhcp(int pkt_len) +{ + struct bootp_t *dhcp = (struct bootp_t *)trackbuf; + int opt_len; + + over_load = 0; + if (ip_ok(dhcp->yip)) + MyIP = dhcp->yip; + + if (ip_ok(dhcp->sip)) + server_ip = dhcp->sip; + + opt_len = (char *)dhcp + pkt_len - (char *)&dhcp->options; + if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC)) + parse_dhcp_options(&dhcp->options, opt_len, 0); + + if (over_load & 1) + parse_dhcp_options(&dhcp->bootfile, 128, 0); + else if (dhcp->bootfile[0]) + strcpy(boot_file, dhcp->bootfile); + + if (over_load & 2) + parse_dhcp_options(dhcp->sname, 64, 0); +} diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c new file mode 100644 index 00000000..98bc960e --- /dev/null +++ b/core/fs/pxe/dnsresolv.c @@ -0,0 +1,341 @@ +#include <stdio.h> +#include <string.h> +#include <core.h> +#include "pxe.h" + +/* DNS CLASS values we care about */ +#define CLASS_IN 1 + +/* DNS TYPE values we care about */ +#define TYPE_A 1 +#define TYPE_CNAME 5 + +/* + * The DNS header structure + */ +struct dnshdr { + uint16_t id; + uint16_t flags; + /* number of entries in the question section */ + uint16_t qdcount; + /* number of resource records in the answer section */ + uint16_t ancount; + /* number of name server resource records in the authority records section*/ + uint16_t nscount; + /* number of resource records in the additional records section */ + uint16_t arcount; +} __attribute__ ((packed)); + +/* + * The DNS query structure + */ +struct dnsquery { + uint16_t qtype; + uint16_t qclass; +} __attribute__ ((packed)); + +/* + * The DNS Resource recodes structure + */ +struct dnsrr { + uint16_t type; + uint16_t class; + uint32_t ttl; + uint16_t rdlength; /* The lenght of this rr data */ + char rdata[]; +} __attribute__ ((packed)); + + +uint32_t dns_server[DNS_MAX_SERVERS] = {0, }; + + +/* + * Turn a string in _src_ into a DNS "label set" in _dst_; returns the + * number of dots encountered. On return, *dst is updated. + */ +int dns_mangle(char **dst, const char *p) +{ + char *q = *dst; + char *count_ptr; + char c; + int dots = 0; + + count_ptr = q; + *q++ = 0; + + while (1) { + c = *p++; + if (c == 0 || c == ':') + break; + if (c == '.') { + dots++; + count_ptr = q; + *q++ = 0; + continue; + } + + *count_ptr += 1; + *q++ = c; + } + + if (*count_ptr) + *q++ = 0; + + /* update the strings */ + *dst = q; + return dots; +} + + +/* + * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_ + * is allowed pointers relative to a packet in buf. + * + */ +static bool dns_compare(const void *s1, const void *s2, const void *buf) +{ + const uint8_t *q = s1; + const uint8_t *p = s2; + unsigned int c0, c1; + + while (1) { + c0 = p[0]; + if (c0 >= 0xc0) { + /* Follow pointer */ + c1 = p[1]; + p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1; + } else if (c0) { + c0++; /* Include the length byte */ + if (memcmp(q, p, c0)) + return false; + q += c0; + p += c0; + } else { + return *q == 0; + } + } +} + +/* + * Copy a DNS label into a buffer, considering the possibility that we might + * have to follow pointers relative to "buf". + * Returns a pointer to the first free byte *after* the terminal null. + */ +static void *dns_copylabel(void *dst, const void *src, const void *buf) +{ + uint8_t *q = dst; + const uint8_t *p = src; + unsigned int c0, c1; + + while (1) { + c0 = p[0]; + if (c0 >= 0xc0) { + /* Follow pointer */ + c1 = p[1]; + p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1; + } else if (c0) { + c0++; /* Include the length byte */ + memcpy(q, p, c0); + p += c0; + q += c0; + } else { + *q++ = 0; + return q; + } + } +} + +/* + * Skip past a DNS label set in DS:SI + */ +static char *dns_skiplabel(char *label) +{ + uint8_t c; + + while (1) { + c = *label++; + if (c >= 0xc0) + return ++label; /* pointer is two bytes */ + if (c == 0) + return label; + label += c; + } +} + +/* + * Actual resolver function + * Points to a null-terminated or :-terminated string in _name_ + * and returns the ip addr in _ip_ if it exists and can be found. + * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated + * + */ +uint32_t dns_resolv(const char *name) +{ + static char __lowmem DNSSendBuf[PKTBUF_SIZE]; + static char __lowmem DNSRecvBuf[PKTBUF_SIZE]; + char *p; + int err; + int dots; + int same; + int rd_len; + int ques, reps; /* number of questions and replies */ + uint8_t timeout; + const uint8_t *timeout_ptr = TimeoutTable; + uint16_t oldtime; + uint32_t srv; + uint32_t *srv_ptr = dns_server; + struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf; + struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf; + struct dnsquery *query; + struct dnsrr *rr; + static __lowmem struct s_PXENV_UDP_WRITE udp_write; + static __lowmem struct s_PXENV_UDP_READ udp_read; + + /* First, fill the DNS header struct */ + hd1->id++; /* New query ID */ + hd1->flags = htons(0x0100); /* Recursion requested */ + hd1->qdcount = htons(1); /* One question */ + hd1->ancount = 0; /* No answers */ + hd1->nscount = 0; /* No NS */ + hd1->arcount = 0; /* No AR */ + + p = DNSSendBuf + sizeof(struct dnshdr); + dots = dns_mangle(&p, name); /* store the CNAME */ + + if (!dots) { + p--; /* Remove final null */ + /* Uncompressed DNS label set so it ends in null */ + strcpy(p, LocalDomain); + } + + /* Fill the DNS query packet */ + query = (struct dnsquery *)p; + query->qtype = htons(TYPE_A); + query->qclass = htons(CLASS_IN); + p += sizeof(struct dnsquery); + + /* Now send it to name server */ + timeout_ptr = TimeoutTable; + timeout = *timeout_ptr++; + while (srv_ptr < dns_server + DNS_MAX_SERVERS) { + srv = *srv_ptr++; + if (!srv) + continue; /* just move on before runing the time out */ + udp_write.status = 0; + udp_write.ip = srv; + udp_write.gw = ((srv ^ MyIP) & net_mask) ? gate_way : 0; + udp_write.src_port = DNS_LOCAL_PORT; + udp_write.dst_port = DNS_PORT; + udp_write.buffer_size = p - DNSSendBuf; + udp_write.buffer = FAR_PTR(DNSSendBuf); + err = pxe_call(PXENV_UDP_WRITE, &udp_write); + if (err || udp_write.status != 0) + continue; + + oldtime = BIOS_timer; + while (1) { + udp_read.status = 0; + udp_read.src_ip = srv; + udp_read.dest_ip = MyIP; + udp_read.s_port = DNS_PORT; + udp_read.d_port = DNS_LOCAL_PORT; + udp_read.buffer_size = DNS_MAX_PACKET; + udp_read.buffer = FAR_PTR(DNSRecvBuf); + err = pxe_call(PXENV_UDP_READ, &udp_read); + if (err || udp_read.status) + continue; + + /* Got a packet, deal with it... */ + if (hd2->id == hd1->id) + break; + + if ((uint16_t)(BIOS_timer-oldtime) >= timeout) { + /* time out */ + timeout = *timeout_ptr++; + if (!timeout) + return 0; /* All time ticks run out */ + else + goto again; + } + } + if ((hd2->flags ^ 0x80) & htons(0xf80f)) + goto badness; + + ques = htons(hd2->qdcount); /* Questions */ + reps = htons(hd2->ancount); /* Replies */ + p = DNSRecvBuf + sizeof(struct dnshdr); + while (ques--) { + p = dns_skiplabel(p); /* Skip name */ + p += 4; /* Skip question trailer */ + } + + /* Parse the replies */ + while (reps--) { + same = dns_compare(DNSSendBuf + sizeof(struct dnshdr), + p, DNSRecvBuf); + p = dns_skiplabel(p); + rr = (struct dnsrr *)p; + rd_len = ntohs(rr->rdlength); + if (same && ntohs(rr->class) == CLASS_IN) { + switch (ntohs(rr->type)) { + case TYPE_A: + if (rd_len == 4) + return *(uint32_t *)rr->rdata; + break; + case TYPE_CNAME: + dns_copylabel(DNSSendBuf + sizeof(struct dnshdr), + rr->rdata, DNSRecvBuf); + /* + * We should probably rescan the packet from the top + * here, and technically we might have to send a whole + * new request here... + */ + break; + default: + break; + } + } + + /* not the one we want, try next */ + p += sizeof(struct dnsrr) + rd_len; + } + + badness: + /* + * + ; We got back no data from this server. + ; Unfortunately, for a recursive, non-authoritative + ; query there is no such thing as an NXDOMAIN reply, + ; which technically means we can't draw any + ; conclusions. However, in practice that means the + ; domain doesn't exist. If this turns out to be a + ; problem, we may want to add code to go through all + ; the servers before giving up. + + ; If the DNS server wasn't capable of recursion, and + ; isn't capable of giving us an authoritative reply + ; (i.e. neither AA or RA set), then at least try a + ; different setver... + */ + if (hd2->flags == htons(0x480)) + continue; + + break; /* failed */ + + again: + continue; + } + + return 0; +} + + +/* + * the one should be called from ASM file + */ +void pxe_dns_resolv(com32sys_t *regs) +{ + const char *name = MK_PTR(regs->ds, regs->esi.w[0]); + + regs->eax.l = dns_resolv(name); +} diff --git a/core/fs/pxe/idle.c b/core/fs/pxe/idle.c new file mode 100644 index 00000000..73379fe6 --- /dev/null +++ b/core/fs/pxe/idle.c @@ -0,0 +1,109 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <stdio.h> +#include <string.h> +#include <core.h> +#include <fs.h> +#include <minmax.h> +#include <sys/cpu.h> +#include "pxe.h" + +static void pxe_idle_poll(void) +{ + static __lowmem char junk_pkt[PKTBUF_SIZE]; + static __lowmem t_PXENV_UDP_READ read_buf; + + memset(&read_buf, 0, sizeof read_buf); + + read_buf.src_ip = 0; /* Any destination */ + read_buf.dest_ip = MyIP; + read_buf.s_port = 0; /* Any source port */ + read_buf.d_port = htons(9); /* Discard port (not used...) */ + read_buf.buffer_size = sizeof junk_pkt; + read_buf.buffer = FAR_PTR(junk_pkt); + + pxe_call(PXENV_UDP_READ, &read_buf); +} + +static uint32_t pxe_detect_nic_type(void) +{ + static __lowmem t_PXENV_UNDI_GET_NIC_TYPE nic_type; + + if (pxe_call(PXENV_UNDI_GET_NIC_TYPE, &nic_type)) + return -1; /* Unknown NIC */ + + if (nic_type.NicType != PCI_NIC && nic_type.NicType != CardBus_NIC) + return -1; /* Not a PCI NIC */ + + /* + * Return VID:DID as a single number, with the VID in the high word + * -- this is opposite from the usual order, but it makes it easier to + * enforce that the table is sorted. + */ + return (nic_type.info.pci.Vendor_ID << 16) + nic_type.info.pci.Dev_ID; +} + +#define PCI_DEV(vid, did) (((vid) << 16) + (did)) + +/* This array should be sorted!! */ +static const uint32_t pxe_need_idle_drain[] = +{ + /* + * Older Broadcom NICs: they need receive calls on idle to avoid + * FIFO stalls. + */ + PCI_DEV(0x14e4, 0x1659), /* BCM5721 */ + PCI_DEV(0x14e4, 0x165a), /* BCM5722 */ + PCI_DEV(0x14e4, 0x165b), /* BCM5723 */ + PCI_DEV(0x14e4, 0x1668), /* BCM5714 */ + PCI_DEV(0x14e4, 0x1669), /* BCM5714S */ + PCI_DEV(0x14e4, 0x166a), /* BCM5780 */ + PCI_DEV(0x14e4, 0x1673), /* BCM5755M */ + PCI_DEV(0x14e4, 0x1674), /* BCM5756ME */ + PCI_DEV(0x14e4, 0x1678), /* BCM5715 */ + PCI_DEV(0x14e4, 0x1679), /* BCM5715S */ + PCI_DEV(0x14e4, 0x167b), /* BCM5755 */ +}; + +void pxe_idle_init(void) +{ + uint32_t dev_id = pxe_detect_nic_type(); + int l, h; + bool found; + + l = 0; + h = sizeof pxe_need_idle_drain / sizeof pxe_need_idle_drain[0] - 1; + + found = false; + while (h >= l) { + uint32_t e = pxe_need_idle_drain[(l+h) >> 1]; + + if (e == dev_id) { + found = true; + break; + } else if (e < dev_id) { + l = e+1; + } else { + h = e-1; + } + } + + if (found) + idle_hook_func = pxe_idle_poll; +} + +void pxe_idle_cleanup(void) +{ + idle_hook_func = NULL; +} diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c new file mode 100644 index 00000000..f3c9bf30 --- /dev/null +++ b/core/fs/pxe/pxe.c @@ -0,0 +1,1549 @@ +#include <stdio.h> +#include <string.h> +#include <core.h> +#include <fs.h> +#include <minmax.h> +#include <sys/cpu.h> +#include "pxe.h" + +#define GPXE 1 + +uint32_t server_ip = 0; /* IP address of boot server */ +uint32_t net_mask = 0; /* net_mask of this subnet */ +uint32_t gate_way = 0; /* Default router */ +uint16_t server_port = TFTP_PORT; /* TFTP server port */ +uint16_t real_base_mem; /* Amount of DOS memory after freeing */ + +char MAC_str[3 * (MAC_MAX + 1)]; /* MAC address as a string */ +char MAC[MAC_MAX + 1]; /* Actual MAC address */ +uint8_t MAC_len; /* MAC address len */ +uint8_t MAC_type; /* MAC address type */ + +char boot_file[256]; +char path_prefix[256]; +char dot_quad_buf[16]; + +static struct open_file_t Files[MAX_OPEN]; +static int has_gpxe; +static uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0}; +int have_uuid = 0; + +const uint8_t TimeoutTable[] = { + 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44, 53, 64, 77, + 92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0 +}; + +/* PXE unload sequences */ +const uint8_t new_api_unload[] = { + PXENV_UDP_CLOSE, PXENV_UNDI_SHUTDOWN, + PXENV_UNLOAD_STACK, PXENV_STOP_UNDI, 0 +}; +const uint8_t old_api_unload[] = { + PXENV_UDP_CLOSE, PXENV_UNDI_SHUTDOWN, + PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0 +}; + +struct tftp_options { + const char *str_ptr; /* string pointer */ + size_t offset; /* offset into socket structre */ +}; +static const struct tftp_options tftp_options[] = +{ + { "tsize", offsetof(struct open_file_t, tftp_filesize) }, + { "blksize", offsetof(struct open_file_t, tftp_blksize) }, +}; +static const int tftp_nopts = sizeof tftp_options / sizeof tftp_options[0]; + +/* + * Initialize the Files structure + */ +static void files_init(void) +{ + int i; + struct open_file_t *socket = Files; + uint16_t pktbuf = 0; + uint16_t nextport = 49152; + + for (i = 0; i < MAX_OPEN; i++) { + socket->tftp_pktbuf = pktbuf; + socket->tftp_nextport = nextport; + pktbuf += PKTBUF_SIZE; + nextport++; + socket++; + } +} + +/* + * Allocate a local UDP port structure. + * return the socket pointer if success, or null if failure + * + */ +static struct open_file_t *allocate_socket(void) +{ + int i; + struct open_file_t *socket = Files; + uint16_t nextport; + + for (i = 0; i < MAX_OPEN; i++) { + if (!socket->tftp_localport) + break; + socket++; + } + + if (i == MAX_OPEN) + return NULL; + + /* + * Allocate a socket number. Socket numbers are made guaranteed + * unique by including the socket slot number; add a counter value + * to keep the numbers from being likely to get immediately + * reused. The mask enforces wraparound to the range 49152-57343. + */ + nextport = socket->tftp_nextport; + socket->tftp_nextport = (nextport + (1 << MAX_OPEN_LG2)) & 0xdfff; + socket->tftp_localport = htons(nextport); /* Socket now in use */ + return socket; +} + +/* + * free socket in _file_. + */ +static void free_socket(struct open_file_t *file) +{ + /* tftp_nextport and tftp_pktbuf are not cleared */ + memset(file, 0, offsetof(struct open_file_t, tftp_nextport)); +} + +static void pxe_close_file(struct file *file) +{ + /* + * XXX: we really should see if the connection is open as send + * a courtesy ERROR packet so the server knows the connection is + * dead. + */ + free_socket(file->open_file); +} + +/** + * Take a nubmer of bytes in memory and convert to lower-case hxeadecimal + * + * @param: dst, output buffer + * @param: src, input buffer + * @param: count, number of bytes + * + */ +static void lchexbytes(char *dst, const void *src, int count) +{ + uint8_t half; + uint8_t c; + const uint8_t *s = src; + + for(; count > 0; count--) { + c = *s++; + half = ((c >> 4) & 0x0f) + '0'; + *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half; + + half = (c & 0x0f) + '0'; + *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half; + } +} + +/* + * just like the lchexbytes, except to upper-case + * + */ +static void uchexbytes(char *dst, const void *src, int count) +{ + uint8_t half; + uint8_t c; + const uint8_t *s = src; + + for(; count > 0; count--) { + c = *s++; + half = ((c >> 4) & 0x0f) + '0'; + *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half; + + half = (c & 0x0f) + '0'; + *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half; + } +} + +/* + * Tests an IP address in _ip_ for validity; return with 0 for bad, 1 for good. + * We used to refuse class E, but class E addresses are likely to become + * assignable unicast addresses in the near future. + * + */ +int ip_ok(uint32_t ip) +{ + if (ip == -1 || /* Refuse the all-one address */ + (ip & 0xff) == 0 || /* Refuse network zero */ + (ip & 0xff) == 0xff || /* Refuse loopback */ + (ip & 0xf0) == 0xe0 ) /* Refuse class D */ + return 0; + + return 1; +} + + +/* + * Take an IP address (in network byte order) in _ip_ and + * output a dotted quad string to _dst_, returns the length + * of the dotted quad ip string. + * + */ +static int gendotquad(char *dst, uint32_t ip) +{ + int part; + int i = 0, j; + char temp[4]; + char *p = dst; + + for (; i < 4; i++) { + j = 0; + part = ip & 0xff; + do { + temp[j++] = (part % 10) + '0'; + }while(part /= 10); + for (; j > 0; j--) + *p++ = temp[j-1]; + *p++ = '.'; + + ip >>= 8; + } + /* drop the last dot '.' and zero-terminate string*/ + *(--p) = 0; + + return p - dst; +} + +/* + * parse the ip_str and return the ip address with *res. + * return the the string address after the ip string + * + */ +static const char *parse_dotquad(const char *ip_str, uint32_t *res) +{ + const char *p = ip_str; + int i = 0; + uint8_t part = 0; + uint32_t ip = 0; + + for (; i < 4; i++) { + while (is_digit(*p)) { + part = part * 10 + *p - '0'; + p++; + } + if (i != 3 && *p != '.') + return NULL; + + ip = (ip << 8) | part; + part = 0; + p++; + } + p --; + + *res = ip; + return p; +} + +/* + * the ASM pxenv function wrapper, return 1 if error, or 0 + * + */ +int pxe_call(int opcode, void *data) +{ + extern void pxenv(void); + com32sys_t regs; + +#if 0 + printf("pxe_call op %04x data %p\n", opcode, data); +#endif + + memset(®s, 0, sizeof regs); + regs.ebx.w[0] = opcode; + regs.es = SEG(data); + regs.edi.w[0] = OFFS(data); + call16(pxenv, ®s, ®s); + + return regs.eflags.l & EFLAGS_CF; /* CF SET if fail */ +} + +/** + * Send ACK packet. This is a common operation and so is worth canning. + * + * @param: file, TFTP block pointer + * @param: ack_num, Packet # to ack (network byte order) + * + */ +static void ack_packet(struct open_file_t *file, uint16_t ack_num) +{ + int err; + static __lowmem uint16_t ack_packet_buf[2]; + static __lowmem struct s_PXENV_UDP_WRITE udp_write; + + /* Packet number to ack */ + ack_packet_buf[0] = TFTP_ACK; + ack_packet_buf[1] = ack_num; + udp_write.src_port = file->tftp_localport; + udp_write.dst_port = file->tftp_remoteport; + udp_write.ip = file->tftp_remoteip; + udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0; + udp_write.buffer = FAR_PTR(ack_packet_buf); + udp_write.buffer_size = 4; + + err = pxe_call(PXENV_UDP_WRITE, &udp_write); +#if 0 + printf("sent %s\n", err ? "FAILED" : "OK"); +#endif +} + + +/** + * Get a DHCP packet from the PXE stack into the trackbuf + * + * @param: type, packet type + * @return: buffer size + * + */ +static int pxe_get_cached_info(int type) +{ + int err; + static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info; + printf(" %02x", type); + + get_cached_info.Status = 0; + get_cached_info.PacketType = type; + get_cached_info.BufferSize = 8192; + get_cached_info.Buffer = FAR_PTR(trackbuf); + err = pxe_call(PXENV_GET_CACHED_INFO, &get_cached_info); + if (err) { + printf("PXE API call failed, error %04x\n", err); + kaboom(); + } + + return get_cached_info.BufferSize; +} + + + +#if GPXE + +/* + * Return 1 if and only if the buffer pointed to by + * url is a URL (contains ://) + * + */ +static int is_url(const char *url) +{ + while (*url) { + if (!strncmp(url, "://", 3)) + return 1; + + url++; + } + return 0; +} + + +/* + * Return CF=0 if and only if the buffer pointed to by DS:SI is a URL + * (contains ://) *and* the gPXE extensions API is available. No + * registers modified. + */ +static int is_gpxe(char *url) +{ + int err; + static __lowmem struct s_PXENV_FILE_API_CHECK api_check; + char *gpxe_warning_msg = + "URL syntax, but gPXE extensions not detected, tring plain TFTP...\n"; + + if (! is_url(url)) + return 0; + + api_check.Size = sizeof api_check; + api_check.Magic = 0x91d447b2; + /* If has_gpxe is greater than one, means the gpxe status is unknow */ + while (has_gpxe > 1) { + err = pxe_call(PXENV_FILE_API_CHECK, &api_check); + if (err || api_check.Magic != 0xe9c17b20) + printf("%s\n", gpxe_warning_msg); + else + has_gpxe = (~api_check.Provider & 0xffff) & 0x4b ? 0 : 1; + + if (!has_gpxe) + printf("%s\n", gpxe_warning_msg); + } + + return has_gpxe == 1; +} + +/** + * Get a fresh packet from a gPXE socket + * @param: file -> socket structure + * + */ +static void get_packet_gpxe(struct open_file_t *file) +{ + static __lowmem struct s_PXENV_FILE_READ file_read; + int err; + + while (1) { + file_read.FileHandle = file->tftp_remoteport; + file_read.Buffer.offs = file->tftp_pktbuf; + file_read.Buffer.seg = PKTBUF_SEG; + file_read.BufferSize = PKTBUF_SIZE; + err = pxe_call(PXENV_FILE_READ, &file_read); + if (!err) /* successed */ + break; + + if (file_read.Status != PXENV_STATUS_TFTP_OPEN) + kaboom(); + } + + file->tftp_bytesleft = file_read.BufferSize; + file->tftp_filepos += file_read.BufferSize; + + if (file->tftp_bytesleft == 0) + file->tftp_filesize = file->tftp_filepos; + + /* if we're done here, close the file */ + if (file->tftp_filesize > file->tftp_filepos) + return; + + /* Got EOF, close it */ + file->tftp_goteof = 1; + pxe_call(PXENV_FILE_CLOSE, &file_read); +} +#endif /* GPXE */ + + +/* + * mangle a filename pointed to by _src_ into a buffer pointed + * to by _dst_; ends on encountering any whitespace. + * + * The first four bytes of the manged name is the IP address of + * the download host, 0 for no host, or -1 for a gPXE URL. + * + */ +static void pxe_mangle_name(char *dst, const char *src) +{ + const char *p = src; + uint32_t ip = server_ip; + int i = 0; + +#if GPXE + if (is_url(src)) { + ip = -1; + goto store; + } +#endif + + if (*p == 0 || !(p = strstr(src, "::"))) { + /* seems no ip, so make ip to 0 */ + p = src; + ip = 0; + } else if (p == src) { + /* skip the first two-colon */ + p += 2; + } else { + /* + * we have a :: prefix of some sort, it could be either a DNS + * name or dot-quad IP address. Try the dot-quad first. + */ + p = src; + if ((p = parse_dotquad(p, &ip)) && !strncmp(p, "::", 2)) { + p += 2; + } else { + ip = dns_resolv(p); + if (ip && (p = strchr(p, ':')) && p[1] == ':') { + p += 2; + } else { + /* no ip, too */ + p = src; + ip = 0; + } + } + } + + store: + *(uint32_t *)dst = ip; + dst += 4; + i = FILENAME_MAX - 5; + + do { + if (!not_whitespace(*p)) + break; + *dst++ = *p++; + } while (i--); + + i++; + while (i) { + *dst++ = 0; + i--; + } +} + + +/* + * Does the opposite of mangle_name; converts a DOS-mangled + * filename to the conventional representation. This is + * needed for the BOOT_IMAGE= parameter for the kernel. + */ +static char *pxe_unmangle_name(char *dst, const char *src) +{ + uint32_t ip = *(uint32_t *)src; + int ip_len = 0; + + if (ip != 0 && ip != -1) { + ip_len = gendotquad(dst, *(uint32_t *)src); + dst += ip_len; + } + src += 4; + return stpcpy(dst, src); +} + +/* + * Get a fresh packet if the buffer is drained, and we haven't hit + * EOF yet. The buffer should be filled immediately after draining! + */ +static void fill_buffer(struct open_file_t *file) +{ + int err; + int last_pkt; + const uint8_t *timeout_ptr = TimeoutTable; + uint8_t timeout; + uint16_t buffersize; + uint16_t old_time; + void *data = NULL; + static __lowmem struct s_PXENV_UDP_READ udp_read; + + if (file->tftp_bytesleft || file->tftp_goteof) + return; + +#if GPXE + if (file->tftp_localport == 0xffff) { + get_packet_gpxe(file); + return; + } +#endif + + + /* + * Start by ACKing the previous packet; this should cause + * the next packet to be sent. + */ + ack_again: + ack_packet(file, file->tftp_lastpkt); + + timeout_ptr = TimeoutTable; + timeout = *timeout_ptr++; + old_time = BIOS_timer; + while (timeout) { + udp_read.buffer.offs = file->tftp_pktbuf; + udp_read.buffer.seg = PKTBUF_SEG; + udp_read.buffer_size = PKTBUF_SIZE; + udp_read.src_ip = file->tftp_remoteip; + udp_read.dest_ip = MyIP; + udp_read.s_port = file->tftp_remoteport; + udp_read.d_port = file->tftp_localport; + err = pxe_call(PXENV_UDP_READ, &udp_read); + if (err) { + if (BIOS_timer == old_time) + continue; + + BIOS_timer = old_time; + timeout--; /* decrease one timer tick */ + if (!timeout) { + timeout = *timeout_ptr++; + if (!timeout) + break; + } + continue; + } + + if (udp_read.buffer_size < 4) /* Bad size for a DATA packet */ + continue; + + data = MK_PTR(PKTBUF_SEG, file->tftp_pktbuf); + if (*(uint16_t *)data != TFTP_DATA) /* Not a data packet */ + continue; + + /* If goes here, recevie OK, break */ + break; + } + + /* time runs out */ + if (timeout == 0) + kaboom(); + + last_pkt = file->tftp_lastpkt; + last_pkt = ntohs(last_pkt); /* Host byte order */ + last_pkt++; + last_pkt = htons(last_pkt); /* Network byte order */ + if (*(uint16_t *)(data + 2) != last_pkt) { + /* + * Wrong packet, ACK the packet and try again. + * This is presumably because the ACK got lost, + * so the server just resent the previous packet. + */ +#if 0 + printf("Wrong packet, wanted %04x, got %04x\n", \ + htons(last_pkt), htons(*(uint16_t *)(data+2))); +#endif + goto ack_again; + } + + /* It's the packet we want. We're also EOF if the size < blocksize */ + file->tftp_lastpkt = last_pkt; /* Update last packet number */ + buffersize = udp_read.buffer_size - 4; /* Skip TFTP header */ + file->tftp_dataptr = file->tftp_pktbuf + 4; + file->tftp_filepos += buffersize; + file->tftp_bytesleft = buffersize; + if (buffersize < file->tftp_blksize) { + /* it's the last block, ACK packet immediately */ + ack_packet(file, *(uint16_t *)(data + 2)); + + /* Make sure we know we are at end of file */ + file->tftp_filesize = file->tftp_filepos; + file->tftp_goteof = 1; + } +} + + +/** + * getfssec: Get multiple clusters from a file, given the starting cluster. + * In this case, get multiple blocks from a specific TCP connection. + * + * @param: fs, the fs_info structure address, in pxe, we don't use this. + * @param: buf, buffer to store the read data + * @param: openfile, TFTP socket pointer + * @param: blocks, 512-byte block count; 0FFFFh = until end of file + * + * @return: the bytes read + * + */ +static uint32_t pxe_getfssec(struct file *gfile, char *buf, + int blocks, bool *have_more) +{ + struct open_file_t *file = gfile->open_file; + int count = blocks; + int chunk; + int bytes_read = 0; + + count <<= TFTP_BLOCKSIZE_LG2; + while (count) { + fill_buffer(file); /* If we have no 'fresh' buffer, get it */ + if (!file->tftp_bytesleft) + break; + + chunk = count; + if (chunk > file->tftp_bytesleft) + chunk = file->tftp_bytesleft; + file->tftp_bytesleft -= chunk; + memcpy(buf, MK_PTR(PKTBUF_SEG, file->tftp_dataptr), chunk); + file->tftp_dataptr += chunk; + buf += chunk; + bytes_read += chunk; + count -= chunk; + } + + + if (file->tftp_bytesleft || (file->tftp_filepos < file->tftp_filesize)) { + fill_buffer(file); + *have_more = 1; + } else if (file->tftp_goteof) { + /* + * The socket is closed and the buffer drained; the caller will + * call close_file and therefore free the socket. + */ + *have_more = 0; + } + + return bytes_read; + } + + + +/* + * Fill the packet tail with the tftp informations then retures the lenght + */ +static int fill_tail(char *dst) +{ + static const char tail[] = "octet\0""tsize\0""0\0""blksize\0""1408"; + + memcpy(dst, tail, sizeof tail); + return sizeof tail; +} + + +/** + * Open a TFTP connection to the server + * + * @param:filename, the file we wanna open + * + * @out: open_file_t structure, stores in file->open_file + * @ouT: the lenght of this file, stores in file->file_len + * + */ +static void pxe_searchdir(char *filename, struct file *file) +{ + static __lowmem char tftp_proto_err[32]; + char *buf = packet_buf; + char *p = filename; + char *options; + char *data; + struct open_file_t *open_file; + static __lowmem struct s_PXENV_UDP_WRITE udp_write; + static __lowmem struct s_PXENV_UDP_READ udp_read; + static __lowmem struct s_PXENV_FILE_OPEN file_open; + static __lowmem struct s_PXENV_GET_FILE_SIZE get_file_size; + const struct tftp_options *tftp_opt; + int i = 0; + int err; + int buffersize; + const uint8_t *timeout_ptr; + uint8_t timeout; + uint16_t oldtime; + uint16_t tid; + uint16_t opcode; + uint16_t blk_num; + uint32_t ip; + uint32_t opdata, *opdata_ptr; + + open_file = allocate_socket(); + if (!open_file) { + file->file_len = 0; + file->open_file = NULL; + return; + } + + timeout_ptr = TimeoutTable; /* Reset timeout */ + + sendreq: + udp_write.buffer.offs = OFFS_WRT(buf, 0); + udp_write.buffer.seg = 0; + *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */ + buf += 2; + + ip = *(uint32_t *)p; /* ip <- server override (if any) */ + p += 4; + if (ip == 0) { + /* Have prefix */ + strcpy(buf, path_prefix); + buf += strlen(path_prefix); + ip = server_ip; /* Get the default server */ + } + + strcpy(buf, p); /* Copy the filename */ + buf += strlen(p) + 1; /* advance the pointer, null char included */ + +#if GPXE + if (is_gpxe(packet_buf + 2)) { + file_open.Status = PXENV_STATUS_BAD_FUNC; + file_open.FileName.offs = OFFS_WRT(packet_buf + 2, 0); + file_open.FileName.seg = 0; + err = pxe_call(PXENV_FILE_OPEN, &file_open); + if (err) + goto done; + + open_file->tftp_localport = -1; + open_file->tftp_remoteport = file_open.FileHandle; + get_file_size.FileHandle = file_open.FileHandle; + +#if 0 + err = pxe_call(PXENV_GET_FILE_SIZE, &get_file_size); + if (!err) + open_file->tftp_filesize = get_file_size.FileSize; + else +#endif + open_file->tftp_filesize = -1; + goto done; + } +#endif /* GPXE */ + + open_file->tftp_remoteip = ip; + tid = open_file->tftp_localport; /* TID(local port No) */ + udp_write.ip = ip; + udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0; + udp_write.src_port = tid; + udp_write.dst_port = server_port; + buf += fill_tail(buf); + udp_write.buffer_size = buf - packet_buf; + err = pxe_call(PXENV_UDP_WRITE, &udp_write); + if (err || udp_write.status != 0) + goto failure; /* + * In fact, the 'failure' target will not do + * a failure thing; it will move on to the + * next timeout, then tries again until + * _real_ time out + */ + + /* + * Danger, Will Robinson! We need to support tiemout + * and retry lest we just lost a packet ... + */ + + /* Packet transmitted OK, now we need to receive */ + timeout = *timeout_ptr++; + oldtime = BIOS_timer; + while (timeout) { + buf = packet_buf; + udp_read.buffer.offs = OFFS_WRT(buf, 0); + udp_read.buffer.seg = 0; + udp_read.buffer_size = 2048; + udp_read.dest_ip = MyIP; + udp_read.d_port = tid; + err = pxe_call(PXENV_UDP_READ, &udp_read); + if (err) { + if (oldtime == BIOS_timer) + continue; + timeout --; /* Decrease one timer tick */ + if (!timeout) + goto failure; + } + + /* Make sure the packet actually came from the server */ + if (udp_read.src_ip == open_file->tftp_remoteip) + break; + } + + /* Got packet; reset timeout */ + timeout_ptr = TimeoutTable; + open_file->tftp_remoteport = udp_read.s_port; + + /* filesize <- -1 == unknown */ + open_file->tftp_filesize = -1; + /* Default blksize unless blksize option negotiated */ + open_file->tftp_blksize = TFTP_BLOCKSIZE; + buffersize = udp_read.buffer_size - 2; /* bytes after opcode */ + if (buffersize < 0) + goto failure; /* Garbled reply */ + + /* + * Get the opcode type, and parse it + */ + opcode = *(uint16_t *)packet_buf; + switch (opcode) { + case TFTP_ERROR: + open_file->tftp_filesize = 0; + break; /* ERROR reply; don't try again */ + + case TFTP_DATA: + /* + * If the server doesn't support any options, we'll get a + * DATA reply instead of OACK. Stash the data in the file + * buffer and go with the default value for all options... + * + * We got a DATA packet, meaning no options are + * suported. Save the data away and consider the + * length undefined, *unless* this is the only + * data packet... + */ + buffersize -= 2; + if (buffersize < 0) + goto failure; + data = packet_buf + 2; + blk_num = *(uint16_t *)data; + data += 2; + if (blk_num != htons(1)) + goto failure; + open_file->tftp_lastpkt = blk_num; + if (buffersize > TFTP_BLOCKSIZE) + goto err_reply; /* Corrupt */ + else if (buffersize < TFTP_BLOCKSIZE) { + /* + * This is the final EOF packet, already... + * We know the filesize, but we also want to + * ack the packet and set the EOF flag. + */ + open_file->tftp_filesize = buffersize; + open_file->tftp_goteof = 1; + ack_packet(open_file, blk_num); + } + + open_file->tftp_bytesleft = buffersize; + open_file->tftp_dataptr = open_file->tftp_pktbuf; + memcpy(MK_PTR(PKTBUF_SEG, open_file->tftp_pktbuf), data, buffersize); + break; + + case TFTP_OACK: + /* + * Now we need to parse the OACK packet to get the transfer + * and packet sizes. + */ + + options = packet_buf + 2; + p = options; + + while (buffersize) { + char *opt = p; + + /* + * If we find an option which starts with a NUL byte, + * (a null option), we're either seeing garbage that some + * TFTP servers add to the end of the packet, or we have + * no clue how to parse the rest of the packet (what is + * an option name and what is a value?) In either case, + * discard the rest. + */ + if (!*opt) + goto done; + + while (buffersize) { + if (!*p) + break; /* Found a final null */ + *p++ |= 0x20; + buffersize--; + } + if (!buffersize) + break; /* Unterminated option */ + + /* Consume the terminal null */ + p++; + buffersize--; + + if (!buffersize) + break; /* No option data */ + + /* + * Parse option pointed to by options; guaranteed to be + * null-terminated + */ + tftp_opt = tftp_options; + for (i = 0; i < tftp_nopts; i++) { + if (!strcmp(opt, tftp_opt->str_ptr)) + break; + tftp_opt++; + } + if (i == tftp_nopts) + goto err_reply; /* Non-negotitated option returned, + no idea what it means ...*/ + + /* get the address of the filed that we want to write on */ + opdata_ptr = (uint32_t *)((char *)open_file + tftp_opt->offset); + opdata = 0; + + /* do convert a number-string to decimal number, just like atoi */ + while (buffersize--) { + uint8_t d = *p++; + if (d == '\0') + break; /* found a final null */ + d -= '0'; + if (d > 9) + goto err_reply; /* Not a decimal digit */ + opdata = opdata*10 + d; + } + *opdata_ptr = opdata; + } + break; + + default: + printf("TFTP unknown opcode %d\n", ntohs(opcode)); + goto err_reply; + } + +done: + if (!open_file->tftp_filesize) { + free_socket(open_file); + file->file_len = 0; + file->open_file = NULL; + return; + } + file->open_file = (void *)open_file; + file->file_len = open_file->tftp_filesize; + return; + +err_reply: + /* Build the TFTP error packet */ + p = tftp_proto_err; + *(uint16_t *)p = TFTP_ERROR; + p += 2; + *(uint16_t *)p = TFTP_EOPTNEG; + p += 2; + strcat(p, "TFTP_protocol error"); + + udp_write.dst_port = open_file->tftp_remoteport; + udp_write.buffer = FAR_PTR(tftp_proto_err); + udp_write.buffer_size = 24; + pxe_call(PXENV_UDP_WRITE, &udp_write); + printf("TFTP server sent an incomprehesible reply\n"); + kaboom(); + +failure: + timeout_ptr++; + if (*timeout_ptr) + goto sendreq; /* Try again */ +} + + +/* + * Store standard filename prefix + */ +static void get_prefix(void) +{ + int len; + char *p; + char c; + + if (DHCPMagic & 0x04) /* Did we get a path prefix option */ + goto got_prefix; + + strcpy(path_prefix, boot_file); + len = strlen(path_prefix); + p = &path_prefix[len - 1]; + + while (len--) { + c = *p--; + c |= 0x20; + + c = (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c == '.' || c == '-'); + if (!c) + break; + }; + + if (len < 0) + p --; + + *(p + 2) = 0; /* Zero-terminate after delimiter */ + + got_prefix: + printf("TFTP prefix: %s\n", path_prefix); + strcpy(CurrentDirName, path_prefix); +} + + /* + * try to load a config file, if found, return 1, or return 0 + * + */ +static int try_load(char *config_name) +{ + com32sys_t regs; + + printf("Trying to load: %-50s ", config_name); + pxe_mangle_name(KernelName, config_name); + + memset(®s, 0, sizeof regs); + regs.edi.w[0] = OFFS_WRT(KernelName, 0); + call16(core_open, ®s, ®s); + if (regs.eflags.l & EFLAGS_ZF) { + printf(" [FAILED]\n"); + return 0; + } else { + printf(" [ OK ]\n"); + return 1; + } +} + + +/* Load the config file, return 1 if failed, or 0 */ +static int pxe_load_config(void) +{ + const char *cfgprefix = "pxelinux.cfg/"; + const char *default_str = "default"; + char *config_file; + char *last; + char *p; + uint8_t *uuid_ptr; + int tries = 8; + + get_prefix(); + if (DHCPMagic & 0x02) { + /* We got a DHCP option, try it first */ + if (try_load(boot_file)) + return 0; + } + + /* + * Have to guess config file name ... + */ + memcpy(ConfigName, cfgprefix, strlen(cfgprefix)); + config_file = ConfigName + strlen(cfgprefix); + + /* Try loading by UUID */ + if (have_uuid) { + uuid_ptr = uuid_dashes; + p = config_file; + while (*uuid_ptr) { + int len = *uuid_ptr; + char *src = uuid; + + lchexbytes(p, src, len); + p += len * 2; + src += len; + uuid_ptr++; + *p++ = '-'; + } + /* Remove last dash and zero-terminate */ + *--p = '\0'; + if (try_load(ConfigName)) + return 0; + } + + /* Try loading by MAC address */ + strcpy(config_file, MAC_str); + if (try_load(ConfigName)) + return 0; + + /* Nope, try hexadecimal IP prefixes... */ + uchexbytes(config_file, (uint8_t *)&MyIP, 4); /* Convet to hex string */ + last = &config_file[8]; + while (tries) { + *last = '\0'; /* Zero-terminate string */ + if (try_load(ConfigName)) + return 0; + last--; /* Drop one character */ + tries--; + }; + + /* Final attempt: "default" string */ + strcpy(config_file, default_str); + if (try_load(ConfigName)) + return 0; + + printf("Unable to locate configuration file\n"); + kaboom(); +} + +/* + * Generate the botif string, and the hardware-based config string + */ +static void make_bootif_string(void) +{ + char mac[18]; + char *src = mac; + char *dst = MAC_str; + int i = MAC_len + 1; + + *(uint8_t *)src++ = MAC_type; + memcpy(src, MAC, MAC_len); + src = mac; + for (; i > 0; i--) { + lchexbytes(dst, src, 1); + dst += 2; + src += 1; + *dst++ = '-'; + } + *(dst - 1) = 0; /* Drop the last '-' and null-terminate string */ + strcat(BOOTIFStr, "BOOTIF="); + strcat(BOOTIFStr, MAC_str); + +#if 0 + printf("%s\n", BOOTIFStr); +#endif +} +/* + * Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask> + * option into IPOption based on a DHCP packet in trackbuf. + * + */ +static void genipopt(void) +{ + char *p = IPOption; + int ip_len; + + strcpy(p, "ip="); + p += 3; + + ip_len = gendotquad(p, MyIP); + p += ip_len; + *p++ = ':'; + + ip_len = gendotquad(p, server_ip); + p += ip_len; + *p++ = ':'; + + ip_len = gendotquad(p, gate_way); + p += ip_len; + *p++ = ':'; + + ip_len = gendotquad(p, net_mask); +} + + +/* Generate ip= option and print the ip adress */ +static void ip_init(void) +{ + uint32_t ip = MyIP; + + genipopt(); + gendotquad(dot_quad_buf, ip); + + ip = ntohl(ip); + printf("My IP address seems to be %08X %s\n", ip, dot_quad_buf); + printf("%s\n", IPOption); +} + +/* + * Validity check on possible !PXE structure in buf + * return 1 for success, 0 for failure. + * + */ +static int is_pxe(const void *buf) +{ + const struct pxe_t *pxe = buf; + const uint8_t *p = buf; + int i = pxe->structlength; + uint8_t sum = 0; + + if (i < sizeof(struct pxe_t) || + memcmp(pxe->signature, "!PXE", 4)) + return 0; + + while (i--) + sum += *p++; + + return sum == 0; +} + +/* + * Just like is_pxe, it checks PXENV+ structure + * + */ +static int is_pxenv(const void *buf) +{ + const struct pxenv_t *pxenv = buf; + const uint8_t *p = buf; + int i = pxenv->length; + uint8_t sum = 0; + + /* The pxeptr field isn't present in old versions */ + if (i < offsetof(struct pxenv_t, pxeptr) || + memcmp(pxenv->signature, "PXENV+", 6)) + return 0; + + while (i--) + sum += *p++; + + return sum == 0; +} + + + +/* + * memory_scan_for_pxe_struct: + * memory_scan_for_pxenv_struct: + * + * If none of the standard methods find the !PXE/PXENV+ structure, + * look for it by scanning memory. + * + * return the corresponding pxe structure if found, or NULL; + */ +static const void *memory_scan(uintptr_t start, int (*func)(const void *)) +{ + const char *ptr; + + /* Scan each 16 bytes of conventional memory before the VGA region */ + for (ptr = (const char *)start; ptr < (const char *)0xA0000; ptr += 16) { + if (func(ptr)) + return ptr; /* found it! */ + ptr += 16; + } + return NULL; +} + +static const struct pxe_t *memory_scan_for_pxe_struct(void) +{ + extern uint16_t BIOS_fbm; /* Starting segment */ + + return memory_scan(BIOS_fbm << 10, is_pxe); +} + +static const struct pxenv_t *memory_scan_for_pxenv_struct(void) +{ + return memory_scan(0x10000, is_pxenv); +} + +/* + * Find the !PXE structure; we search for the following, in order: + * + * a. !PXE structure as SS:[SP + 4] + * b. PXENV+ structure at [ES:BX] + * c. INT 1Ah AX=0x5650 -> PXENV+ + * d. Search memory for !PXE + * e. Search memory for PXENV+ + * + * If we find a PXENV+ structure, we try to find a !PXE structure from + * if if the API version is 2.1 or later + * + */ +static void pxe_init(void) +{ + extern void pxe_int1a(void); + char plan = 'A'; + uint16_t seg, off; + uint16_t code_seg, code_len; + uint16_t data_seg, data_len; + char *base = GET_PTR(InitStack); + com32sys_t regs; + const char *type; + const struct pxenv_t *pxenv; + const struct pxe_t *pxe; + + /* Assume API version 2.1 */ + APIVer = 0x201; + + /* Plan A: !PXE structure as SS:[SP + 4] */ + off = *(uint16_t *)(base + 48); + seg = *(uint16_t *)(base + 50); + pxe = MK_PTR(seg, off); + if (is_pxe(pxe)) + goto have_pxe; + + /* Plan B: PXENV+ structure at [ES:BX] */ + plan++; + off = *(uint16_t *)(base + 24); /* Original BX */ + seg = *(uint16_t *)(base + 4); /* Original ES */ + pxenv = MK_PTR(seg, off); + if (is_pxenv(pxenv)) + goto have_pxenv; + + /* Plan C: PXENV+ structure via INT 1Ah AX=5650h */ + plan++; + memset(®s, 0, sizeof regs); + regs.eax.w[0] = 0x5650; + call16(pxe_int1a, ®s, ®s); + if (!(regs.eflags.l & EFLAGS_CF) && (regs.eax.w[0] == 0x564e)) { + pxenv = MK_PTR(regs.es, regs.ebx.w[0]); + if (is_pxenv(pxenv)) + goto have_pxenv; + } + + /* Plan D: !PXE memory scan */ + plan++; + if ((pxe = memory_scan_for_pxe_struct())) + goto have_pxe; + + /* Plan E: PXENV+ memory scan */ + plan++; + if ((pxenv = memory_scan_for_pxenv_struct())) + goto have_pxenv; + + /* Found nothing at all !! */ + printf("No !PXE or PXENV+ API found; we're dead...\n"); + kaboom(); + + have_pxenv: + APIVer = pxenv->version; + printf("Found PXENV+ structure\nPXE API version is %04x\n", APIVer); + + /* if the API version number is 0x0201 or higher, use the !PXE structure */ + if (APIVer >= 0x201) { + if (pxenv->length >= sizeof(struct pxenv_t)) { + pxe = GET_PTR(pxenv->pxeptr); + if (is_pxe(pxe)) + goto have_pxe; + /* + * Nope, !PXE structure missing despite API 2.1+, or at least + * the pointer is missing. Do a last-ditch attempt to find it + */ + if ((pxe = memory_scan_for_pxe_struct())) + goto have_pxe; + } + } + + /* Otherwise, no dice, use PXENV+ structure */ + data_len = pxenv->undidatasize; + data_seg = pxenv->undidataseg; + code_len = pxenv->undicodesize; + code_seg = pxenv->undicodeseg; + PXEEntry = pxenv->rmentry; + type = "PXENV+"; + goto have_entrypoint; + + have_pxe: + data_len = pxe->seg[PXE_Seg_UNDIData].size; + data_seg = pxe->seg[PXE_Seg_UNDIData].sel; + code_len = pxe->seg[PXE_Seg_UNDICode].size; + code_seg = pxe->seg[PXE_Seg_UNDICode].sel; + PXEEntry = pxe->entrypointsp; + type = "!PXE"; + + have_entrypoint: + printf("%s entry point found (we hope) at %04X:%04X via plan %c\n", + type, PXEEntry.seg, PXEEntry.offs, plan); + printf("UNDI code segment at %04X len %04X\n", code_seg, code_len); + printf("UNDI data segment at %04X len %04X\n", data_seg, data_len); + + code_seg = code_seg + ((code_len + 15) >> 4); + data_seg = data_seg + ((data_len + 15) >> 4); + + real_base_mem = max(code_seg,data_seg) >> 6; /* Convert to kilobytes */ +} + +/* + * Initialize UDP stack + * + */ +static void udp_init(void) +{ + int err; + static __lowmem struct s_PXENV_UDP_OPEN udp_open; + udp_open.src_ip = MyIP; + err = pxe_call(PXENV_UDP_OPEN, &udp_open); + if (err || udp_open.status) { + printf("Failed to initialize UDP stack "); + printf("%d\n", udp_open.status); + kaboom(); + } +} + + +/* + * Network-specific initialization + */ +static void network_init(void) +{ + struct bootp_t *bp = (struct bootp_t *)trackbuf; + int pkt_len; + + *LocalDomain = 0; /* No LocalDomain received */ + + /* + * Get the DHCP client identifiers (query info 1) + */ + printf("Getting cached packet "); + pkt_len = pxe_get_cached_info(1); + parse_dhcp(pkt_len); + /* + * We don't use flags from the request packet, so + * this is a good time to initialize DHCPMagic... + * Initialize it to 1 meaning we will accept options found; + * in earlier versions of PXELINUX bit 0 was used to indicate + * we have found option 208 with the appropriate magic number; + * we no longer require that, but MAY want to re-introduce + * it in the future for vendor encapsulated options. + */ + *(char *)&DHCPMagic = 1; + + /* + * Get the BOOTP/DHCP packet that brought us file (and an IP + * address). This lives in the DHCPACK packet (query info 2) + */ + pkt_len = pxe_get_cached_info(2); + parse_dhcp(pkt_len); + /* + * Save away MAC address (assume this is in query info 2. If this + * turns out to be problematic it might be better getting it from + * the query info 1 packet + */ + MAC_len = bp->hardlen > 16 ? 0 : bp->hardlen; + MAC_type = bp->hardware; + memcpy(MAC, bp->macaddr, MAC_len); + + /* + * Get the boot file and other info. This lives in the CACHED_REPLY + * packet (query info 3) + */ + pkt_len = pxe_get_cached_info(3); + parse_dhcp(pkt_len); + printf("\n"); + + make_bootif_string(); + ip_init(); + + /* + * Check to see if we got any PXELINUX-specific DHCP options; in particular, + * if we didn't get the magic enable, do not recognize any other options. + */ + if ((DHCPMagic & 1) == 0) + DHCPMagic = 0; + + udp_init(); +} + +/* + * Initialize pxe fs + * + */ +static int pxe_fs_init(struct fs_info *fs) +{ + (void)fs; /* drop the compile warning message */ + + /* Initialize the Files structure */ + files_init(); + + /* do the pxe initialize */ + pxe_init(); + + /* Network-specific initialization */ + network_init(); + + /* Initialize network-card-specific idle handling */ + pxe_idle_init(); + + return 0; +} + +inline void reset_pxe(void) +{ + static __lowmem struct s_PXENV_UDP_CLOSE udp_close; + pxe_call(PXENV_UDP_CLOSE, &udp_close); +} + +/* + * This function unloads the PXE and UNDI stacks and + * unclaims the memory. + */ +void unload_pxe(void) +{ + uint8_t api; + const uint8_t *api_ptr; + uint16_t flag = 0; + int err; + int int_addr; + static __lowmem struct s_PXENV_UNLOAD_STACK unload_stack; + + pxe_idle_cleanup(); + + if (KeepPXE) { + /* + * We want to keep PXE around, but still we should reset + * it to the standard bootup configuration. + */ + reset_pxe(); + return; + } + + api_ptr = major_ver(APIVer) >= 2 ? new_api_unload : old_api_unload; + while((api = *api_ptr++)) { + memset(&unload_stack, 0, sizeof unload_stack); + err = pxe_call(api, &unload_stack); + if (err || unload_stack.Status != PXENV_STATUS_SUCCESS) + goto cant_free; + } + + flag = 0xff00; + if (real_base_mem <= BIOS_fbm) /* Santiy check */ + goto cant_free; + flag ++; + + /* Check that PXE actually unhooked the INT 0x1A chain */ + int_addr = (int)MK_PTR(*(uint16_t *)(4*0x1a+2), *(uint16_t *)(4*0x1a)); + int_addr >>= 10; + if (int_addr >= real_base_mem || int_addr < BIOS_fbm) { + BIOS_fbm = real_base_mem; + return; + } + +cant_free: + printf("Failed to free base memory error %04x-%08x\n", + flag, *(uint32_t *)(4 * 0x1a)); + return; +} + + + +const struct fs_ops pxe_fs_ops = { + .fs_name = "pxe", + .fs_flags = FS_NODEV, + .fs_init = pxe_fs_init, + .searchdir = pxe_searchdir, + .getfssec = pxe_getfssec, + .close_file = pxe_close_file, + .mangle_name = pxe_mangle_name, + .unmangle_name = pxe_unmangle_name, + .load_config = pxe_load_config +}; diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h new file mode 100644 index 00000000..8a2b190c --- /dev/null +++ b/core/fs/pxe/pxe.h @@ -0,0 +1,225 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * pxe.h + * + * PXE opcodes + * + */ +#ifndef PXE_H +#define PXE_H + +#include <syslinux/pxe_api.h> +#include "fs.h" /* For MAX_OPEN, should go away */ + +/* + * Some basic defines... + */ +#define TFTP_PORT htons(69) /* Default TFTP port */ +#define TFTP_BLOCKSIZE_LG2 9 +#define TFTP_BLOCKSIZE (1 << TFTP_BLOCKSIZE_LG2) +#define PKTBUF_SEG 0x4000 +#define PKTBUF_SIZE (65536 / MAX_OPEN) + +#define is_digit(c) (((c) >= '0') && ((c) <= '9')) +#define major_ver(v) (((v) >> 8) && 0xff) + +/* + * TFTP operation codes + */ +#define TFTP_RRQ htons(1) // Read rest +#define TFTP_WRQ htons(2) // Write rest +#define TFTP_DATA htons(3) // Data packet +#define TFTP_ACK htons(4) // ACK packet +#define TFTP_ERROR htons(5) // ERROR packet +#define TFTP_OACK htons(6) // OACK packet + +/* + * TFTP error codes + */ +#define TFTP_EUNDEF htons(0) // Unspecified error +#define TFTP_ENOTFOUND htons(1) // File not found +#define TFTP_EACCESS htons(2) // Access violation +#define TFTP_ENOSPACE htons(3) // Disk full +#define TFTP_EBADOP htons(4) // Invalid TFTP operation +#define TFTP_EBADID htons(5) // Unknown transfer +#define TFTP_EEXISTS htons(6) // File exists +#define TFTP_ENOUSER htons(7) // No such user +#define TFTP_EOPTNEG htons(8) // Option negotiation failure + + +#define BOOTP_OPTION_MAGIC htonl(0x63825363) +#define MAC_MAX 32 + +/* Defines for DNS */ +#define DNS_PORT htons(53) /* Default DNS port */ +#define DNS_MAX_PACKET 512 /* Defined by protocol */ +/* All local DNS queries come from this port */ +#define DNS_LOCAL_PORT htons(60053) +#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */ + + +/* + * structures + */ + +struct pxenv_t { + uint8_t signature[6]; /* PXENV+ */ + uint16_t version; + uint8_t length; + uint8_t checksum; + segoff16_t rmentry; + uint32_t pmoffset; + uint16_t pmselector; + uint16_t stackseg; + uint16_t stacksize; + uint16_t bc_codeseg; + uint16_t bc_codesize; + uint16_t bc_dataseg; + uint16_t bc_datasize; + uint16_t undidataseg; + uint16_t undidatasize; + uint16_t undicodeseg; + uint16_t undicodesize; + segoff16_t pxeptr; +} __packed; + +struct pxe_t { + uint8_t signature[4]; /* !PXE */ + uint8_t structlength; + uint8_t structcksum; + uint8_t structrev; + uint8_t _pad1; + segoff16_t undiromid; + segoff16_t baseromid; + segoff16_t entrypointsp; + segoff16_t entrypointesp; + segoff16_t statuscallout; + uint8_t _pad2; + uint8_t segdesccnt; + uint16_t firstselector; + pxe_segdesc_t seg[7]; +} __packed; + +enum pxe_segments { + PXE_Seg_Stack = 0, + PXE_Seg_UNDIData = 1, + PXE_Seg_UNDICode = 2, + PXE_Seg_UNDICodeWrite = 3, + PXE_Seg_BC_Data = 4, + PXE_Seg_BC_Code = 5, + PXE_Seg_BC_CodeWrite = 6 +}; + +struct bootp_t { + uint8_t opcode; /* BOOTP/DHCP "opcode" */ + uint8_t hardware; /* ARP hreadware type */ + uint8_t hardlen; /* Hardware address length */ + uint8_t gatehops; /* Used by forwarders */ + uint32_t ident; /* Transaction ID */ + uint16_t seconds; /* Seconds elapsed */ + uint16_t flags; /* Broadcast flags */ + uint32_t cip; /* Cient IP */ + uint32_t yip; /* "Your" IP */ + uint32_t sip; /* Next Server IP */ + uint32_t gip; /* Relay agent IP */ + uint8_t macaddr[16]; /* Client MAC address */ + uint8_t sname[64]; /* Server name (optional) */ + char bootfile[128]; /* Boot file name */ + uint32_t option_magic; /* Vendor option magic cookie */ + uint8_t options[1260]; /* Vendor options */ +} __attribute__ ((packed)); + +struct open_file_t { + uint16_t tftp_localport; /* Local port number (0=not in us)*/ + uint16_t tftp_remoteport; /* Remote port number */ + uint32_t tftp_remoteip; /* Remote IP address */ + uint32_t tftp_filepos; /* bytes downloaded (includeing buffer) */ + uint32_t tftp_filesize; /* Total file size(*) */ + uint32_t tftp_blksize; /* Block size for this connection(*) */ + uint16_t tftp_bytesleft; /* Unclaimed data bytes */ + uint16_t tftp_lastpkt; /* Sequence number of last packet (NBO) */ + uint16_t tftp_dataptr; /* Pointer to available data */ + uint8_t tftp_goteof; /* 1 if the EOF packet received */ + uint8_t tftp_unused; /* Currently unused */ + /* These values are preinitialized and not zeroed on close */ + uint16_t tftp_nextport; /* Next port number for this slot (HBO) */ + uint16_t tftp_pktbuf; /* Packet buffer offset */ +} __attribute__ ((packed)); + +/* + * Variable externs + */ +extern uint32_t server_ip; +extern uint32_t MyIP; +extern uint32_t net_mask; +extern uint32_t gate_way; +extern uint16_t server_port; + +extern char MAC_str[]; +extern char MAC[]; +extern char BOOTIFStr[]; +extern uint8_t MAC_len; +extern uint8_t MAC_type; + +extern uint8_t DHCPMagic; +extern uint32_t RebootTime; + +extern char boot_file[]; +extern char path_prefix[]; +extern char LocalDomain[]; + +extern char packet_buf[]; + +extern char IPOption[]; +extern char dot_quad_buf[]; + +extern uint32_t dns_server[]; + +extern uint16_t real_base_mem; +extern uint16_t APIVer; +extern far_ptr_t PXEEntry; +extern uint8_t KeepPXE; + +extern far_ptr_t InitStack; + +extern int have_uuid; +extern uint8_t uuid_type; +extern char uuid[]; + +extern volatile uint16_t BIOS_timer; +extern uint16_t BIOS_fbm; +extern const uint8_t TimeoutTable[]; + + +/* + * functions + */ + +/* pxe.c */ +int ip_ok(uint32_t); +int pxe_call(int, void *); + +/* dhcp_options.c */ +void parse_dhcp(int); +void parse_dhcp_options(void *, int, int); + +/* dnsresolv.c */ +int dns_mangle(char **, const char *); +uint32_t dns_resolv(const char *); + +/* idle.c */ +void pxe_idle_init(void); +void pxe_idle_cleanup(void); + +#endif /* pxe.h */ diff --git a/core/getc.inc b/core/getc.inc index a8d54c7f..48b9f774 100644 --- a/core/getc.inc +++ b/core/getc.inc @@ -60,8 +60,9 @@ getc_file_lg2 equ 4 ; Size of getc_file as a power of 2 ; ; close: Output: CF set if nothing open ; -open: - call searchdir + global core_open +core_open: + pm_call searchdir jz openfd.ret openfd: push bx @@ -82,11 +83,11 @@ openfd: .ret: ret .stack_full: - call close_file + pm_call close_file xor ax,ax ; ZF <- 1 pop bx ret - + getc: push bx push si @@ -135,7 +136,7 @@ getc: mov [di+gc_bufbytes],si ; In case SI == 0 jz .empty mov cx,bytes_per_getc >> SECTOR_SHIFT - call getfssec + pm_call getfssec mov [di+gc_bufbytes],cx mov [di+gc_file],si jcxz .empty @@ -177,7 +178,7 @@ close: push si mov bx,[CurrentGetC] mov si,[bx+gc_file] - call close_file + pm_call close_file add bx,getc_file_size mov [CurrentGetC],bx pop si diff --git a/core/hello.c b/core/hello.c index a4fff7ad..a1591111 100644 --- a/core/hello.c +++ b/core/hello.c @@ -1,5 +1,8 @@ #include <stddef.h> #include <com32.h> +#include <stdio.h> +#include <string.h> + void myputchar(int c) { @@ -21,7 +24,7 @@ void myputs(const char *str) void hello(void) { - static char hello_str[] = "Hello, World! (hello.c)\n"; + static char hello_str[] = "Hello, World!"; - myputs(hello_str); + printf("%s from (%s)\n", hello_str, __FILE__); /* testing */ } diff --git a/core/idle.inc b/core/idle.inc index f563def7..966b6e26 100644 --- a/core/idle.inc +++ b/core/idle.inc @@ -23,7 +23,7 @@ reset_idle: ret do_idle: - push ax + push eax push ds push es mov ax,cs @@ -58,18 +58,24 @@ do_idle: sub ax,[IdleTimer] cmp ax,TICKS_TO_IDLE jb .done - call [IdleHook] + + mov eax,[idle_hook_func] + and eax,eax + jz .no_idle_hook + pm_call eax +.no_idle_hook: cmp word [NoHalt],0 jne .done hlt .done: pop es pop ds - pop ax + pop eax .ret: ret section .data16 -IdleHook dw do_idle.ret + global idle_hook_func +idle_hook_func dd 0 NoHalt dw 0 hlt_err db 'ERROR: idle with IF=0', CR, LF, 0 diff --git a/core/include/cache.h b/core/include/cache.h new file mode 100644 index 00000000..7518bc84 --- /dev/null +++ b/core/include/cache.h @@ -0,0 +1,25 @@ +#ifndef _CACHE_H +#define _CACHE_H + +#include <stdint.h> +#include <com32.h> +#include "disk.h" +#include "fs.h" + +#define MAX_CACHE_ENTRIES 0x10 /* I find even this is enough:) */ + +/* The cache structure */ +struct cache_struct { + block_t block; + struct cache_struct *prev; + struct cache_struct *next; + void *data; +}; + + +/* functions defined in cache.c */ +void cache_init(struct device *, int); +struct cache_struct* get_cache_block(struct device *, block_t); +void print_cache(struct device *); + +#endif /* cache.h */ diff --git a/core/include/core.h b/core/include/core.h index e61bf998..c13aa16f 100644 --- a/core/include/core.h +++ b/core/include/core.h @@ -6,13 +6,42 @@ extern char core_xfer_buf[65536]; extern char core_cache_buf[65536]; +extern char trackbuf[]; +extern char CurrentDirName[]; +extern char ConfigName[]; +extern char KernelName[]; + +/* diskstart.inc isolinux.asm*/ +extern void getlinsec(void); + +/* getc.inc */ +extern void core_open(void); + +/* idle.inc */ +extern void (*idle_hook_func)(void); + +/* hello.c */ +extern void myputs(const char*); void __cdecl core_intcall(uint8_t, const com32sys_t *, com32sys_t *); void __cdecl core_farcall(uint32_t, const com32sys_t *, com32sys_t *); int __cdecl core_cfarcall(uint32_t, const void *, uint32_t); +extern const com32sys_t zero_regs; void call16(void (*)(void), const com32sys_t *, com32sys_t *); +/* + * __lowmem is in the low 1 MB; __bss16 in the low 64K + */ #define __lowmem __attribute((nocommon,section(".lowmem"))) +#define __bss16 __attribute((nocommon,section(".bss16"))) + +/* + * Death! The macro trick is to avoid symbol conflict with + * the real-mode symbol kaboom. + */ +__noreturn _kaboom(void); +#define kaboom() _kaboom() + #endif /* CORE_H */ diff --git a/core/include/disk.h b/core/include/disk.h new file mode 100644 index 00000000..91f7a57a --- /dev/null +++ b/core/include/disk.h @@ -0,0 +1,40 @@ +#ifndef DISK_H +#define DISK_H + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#define SECTOR_SHIFT 9 +#define SECTOR_SIZE (1 << SECTOR_SHIFT) + +typedef uint64_t sector_t; +typedef uint64_t block_t; + + +/* + * struct disk: contains the information about a specific disk and also + * contains the I/O function. + */ +struct disk { + uint8_t disk_number; /* in BIOS style */ + uint8_t type; /* CHS or EDD */ + uint16_t sector_size; /* gener512B or 2048B */ + uint8_t sector_shift; + + uint8_t h, s; /* CHS geometry */ + uint8_t pad; + + sector_t part_start; /* the start address of this partition(in sectors) */ + + int (*rdwr_sectors)(struct disk *, void *, sector_t, size_t, bool); +}; + +extern void read_sectors(char *, sector_t, int); +extern void getoneblk(struct disk *, char *, block_t, int); + +/* diskio.c */ +struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t); +struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t); + +#endif /* DISK_H */ diff --git a/core/include/fs.h b/core/include/fs.h new file mode 100644 index 00000000..df103023 --- /dev/null +++ b/core/include/fs.h @@ -0,0 +1,100 @@ +#ifndef FS_H +#define FS_H + +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <com32.h> +#include "core.h" +#include "disk.h" + +/* + * Maximum number of open files. This is *currently* constrained by the + * fact that PXE needs to be able to fit all its packet buffers into a + * 64K segment; this should be fixed by moving the packet buffers to high + * memory. + */ +#define MAX_OPEN_LG2 5 +#define MAX_OPEN (1 << MAX_OPEN_LG2) + +#define FILENAME_MAX_LG2 8 +#define FILENAME_MAX (1 << FILENAME_MAX_LG2) + +struct fs_info { + const struct fs_ops *fs_ops; + struct device *fs_dev; +}; + +struct open_file_t; /* Filesystem private structure */ +struct dirent; /* Directory entry structure */ + +struct file { + struct open_file_t *open_file; /* Filesystem private data */ + struct fs_info *fs; + uint32_t file_len; +}; + +enum fs_flags { + FS_NODEV = 1, +}; + +struct fs_ops { + /* in fact, we use fs_ops structure to find the right fs */ + const char *fs_name; + enum fs_flags fs_flags; + + int (*fs_init)(struct fs_info *); + void (*searchdir)(char *, struct file *); + uint32_t (*getfssec)(struct file *, char *, int, bool *); + void (*close_file)(struct file *); + void (*mangle_name)(char *, const char *); + char * (*unmangle_name)(char *, const char *); + int (*load_config)(); + + /* the _dir_ stuff */ + void (*opendir)(com32sys_t *); + struct dirent * (*readdir)(struct file *); +}; + +enum dev_type {CHS, EDD}; + +/* + * Generic functions that filesystem drivers may choose to use + */ +void generic_mangle_name(char *, const char *); +#define generic_unmangle_name stpcpy + +/* + * Struct device contains: + * the pointer points to the disk structure, + * the cache stuff. + */ +struct device { + struct disk *disk; + + /* the cache stuff */ + char* cache_data; + void* cache_head; + uint16_t cache_block_size; + uint16_t cache_entries; + uint32_t cache_size; +}; + +/* + * Our definition of "not whitespace" + */ +static inline bool not_whitespace(char c) +{ + return (unsigned char)c > ' '; +} + +/* + * functions + */ +void mangle_name(com32sys_t *); +void searchdir(com32sys_t *); +void _close_file(struct file *); +inline uint16_t file_to_handle(struct file *); +inline struct file *handle_to_file(uint16_t); + +#endif /* FS_H */ diff --git a/core/init.inc b/core/init.inc index ec8c7b3b..5617a697 100644 --- a/core/init.inc +++ b/core/init.inc @@ -34,19 +34,6 @@ common_init: call reset_config ; -; Initialize Files structures (other than zeroing) -; -%if IS_PXELINUX - mov di,Files+tftp_pktbuf - mov cx,MAX_OPEN -.setbufptr: - mov [di],ax - add di,open_file_t_size - add ax,PKTBUF_SIZE - loop .setbufptr -%endif - -; ; Set up the COMBOOT APIs ; call comboot_setup_api diff --git a/core/isolinux.asm b/core/isolinux.asm index bbbee72a..b67bdc19 100644 --- a/core/isolinux.asm +++ b/core/isolinux.asm @@ -26,14 +26,10 @@ ; Some semi-configurable constants... change on your own risk. ; my_id equ isolinux_id -FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null) -FILENAME_MAX equ (1 << FILENAME_MAX_LG2) NULLFILE equ 0 ; Zero byte == null file name NULLOFFSET equ 0 ; Position in which to look retry_count equ 6 ; How patient are we with the BIOS? %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top -MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) -MAX_OPEN equ (1 << MAX_OPEN_LG2) SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement) SECTOR_SIZE equ (1 << SECTOR_SHIFT) @@ -72,12 +68,6 @@ file_left resd 1 ; Number of sectors left %endif %endif - struc dir_t -dir_lba resd 1 ; Directory start (LBA) -dir_len resd 1 ; Length in bytes -dir_clust resd 1 ; Length in clusters - endstruc - ; --------------------------------------------------------------------------- ; BEGIN CODE ; --------------------------------------------------------------------------- @@ -86,6 +76,7 @@ dir_clust resd 1 ; Length in clusters ; Memory below this point is reserved for the BIOS and the MBR ; section .earlybss + global trackbuf trackbufsize equ 8192 trackbuf resb trackbufsize ; Track buffer goes here ; ends at 2800h @@ -94,10 +85,6 @@ trackbuf resb trackbufsize ; Track buffer goes here ; is loaded. DO NOT move this to .bss16/.uibss. section .earlybss alignb 4 -ISOFileName resb 64 ; ISO filename canonicalization buffer -ISOFileNameEnd equ $ -CurrentDir resb dir_t_size ; Current directory -RootDir resb dir_t_size ; Root directory FirstSecSum resd 1 ; Checksum of bytes 64-2048 ImageDwords resd 1 ; isolinux.bin size, dwords InitStack resd 1 ; Initial stack pointer (SS:SP) @@ -190,10 +177,6 @@ dsp_dummy: resb 1 ; Scratch, safe to overwrite _spec_end equ $ _spec_len equ _spec_end - _spec_start - section .bss16 - alignb open_file_t_size -Files resb MAX_OPEN*open_file_t_size - section .init ;; ;; Primary entry point. Because BIOSes are buggy, we only load the first @@ -767,6 +750,7 @@ getonesec: ; ES:BX - Target buffer ; BP - Sector count ; + global getlinsec getlinsec: jmp word [cs:GetlinsecPtr] %ifndef DEBUG_MESSAGES @@ -1099,6 +1083,7 @@ bios_ebios: dw getlinsec_ebios, bios_ebios_str %endif ; Maximum transfer size + global MaxTransfer MaxTransfer dw 127 ; Hard disk modes MaxTransferCD dw 32 ; CD mode @@ -1160,96 +1145,23 @@ all_read: ; (which will be at 16 only for a single-session disk!); from the PVD ; we should be able to find the rest of what we need to know. ; -get_fs_structures: - mov eax,[bi_pvd] - mov bx,trackbuf - call getonesec - - mov eax,[trackbuf+156+2] - mov [RootDir+dir_lba],eax - mov [CurrentDir+dir_lba],eax -%ifdef DEBUG_MESSAGES - mov si,dbg_rootdir_msg - call writemsg - call writehex8 - call crlf -%endif - mov eax,[trackbuf+156+10] - mov [RootDir+dir_len],eax - mov [CurrentDir+dir_len],eax - add eax,SECTOR_SIZE-1 - shr eax,SECTOR_SHIFT - mov [RootDir+dir_clust],eax - mov [CurrentDir+dir_clust],eax - - ; Look for an isolinux directory, and if found, - ; make it the current directory instead of the root - ; directory. - ; Also copy the name of the directory to CurrentDirName - mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName - mov di,boot_dir ; Search for /boot/isolinux - mov al,02h - push di - call searchdir_iso - pop di - jnz .found_dir - mov di,isolinux_dir - mov al,02h ; Search for /isolinux - push di - call searchdir_iso - pop di - jz .no_isolinux_dir -.found_dir: - ; Copy current directory name to CurrentDirName - push si - push di - mov si,di - mov di,CurrentDirName - call strcpy - mov byte [di],0 ;done in case it's not word aligned - dec di - mov byte [di],'/' - pop di - pop si - - mov [CurrentDir+dir_len],eax - mov eax,[si+file_left] - mov [CurrentDir+dir_clust],eax - xor eax,eax ; Free this file pointer entry - xchg eax,[si+file_sector] - mov [CurrentDir+dir_lba],eax -%ifdef DEBUG_MESSAGES - push si - mov si,dbg_isodir_msg - call writemsg - pop si - call writehex8 - call crlf -%endif -.no_isolinux_dir: + pushad + extern iso_fs_ops + mov eax,iso_fs_ops + mov dl,[DriveNumber] + cmp word [BIOSType],bios_cdrom + sete dh ; 1 for cdrom, 0 for hybrid mode + mov ecx,[bsHidden] + mov ebx,[bsHidden+4] + mov si,[bsHeads] + mov di,[bsSecPerTrack] + pm_call fs_init + popad ; ; Locate the configuration file ; -load_config: - pm_call load_env32 -%ifdef DEBUG_MESSAGES - mov si,dbg_config_msg - call writemsg -%endif - - mov si,config_name - mov di,ConfigName - call strcpy - - mov di,ConfigName - call open - jz no_config_file ; Not found or empty - -%ifdef DEBUG_MESSAGES - mov si,dbg_configok_msg - call writemsg -%endif + pm_call load_config ; ; Now we have the config file open. Parse the config file and @@ -1290,7 +1202,7 @@ is_disk_image: mov bx,trackbuf mov cx,1 ; Load 1 sector - call getfssec + pm_call getfssec cmp word [trackbuf+510],0aa55h ; Boot signature jne .bad_image ; Image not bootable @@ -1387,350 +1299,7 @@ is_disk_image: mov al,bl .done_sector: ret -; -; close_file: -; Deallocates a file structure (pointer in SI) -; Assumes CS == DS. -; -close_file: - and si,si - jz .closed - mov dword [si],0 ; First dword == file_left - xor si,si -.closed: ret - -; -; searchdir: -; -; Open a file -; -; On entry: -; DS:DI = filename -; If successful: -; ZF clear -; SI = file pointer -; EAX = file length in bytes -; If unsuccessful -; ZF set -; -; Assumes CS == DS == ES, and trashes BX and CX. -; -; searchdir_iso is a special entry point for ISOLINUX only. In addition -; to the above, searchdir_iso passes a file flag mask in AL. This is useful -; for searching for directories. -; -alloc_failure: - xor ax,ax ; ZF <- 1 - ret - -searchdir: - xor al,al -searchdir_iso: - mov [ISOFlags],al - TRACER 'S' - call allocate_file ; Temporary file structure for directory - jnz alloc_failure - push es - push ds - pop es ; ES = DS - mov si,CurrentDir - cmp byte [di],'/' ; If filename begins with slash - jne .not_rooted - inc di ; Skip leading slash - mov si,RootDir ; Reference root directory instead -.not_rooted: - mov eax,[si+dir_clust] - mov [bx+file_left],eax - shl eax,SECTOR_SHIFT - mov [bx+file_bytesleft],eax - mov eax,[si+dir_lba] - mov [bx+file_sector],eax - mov edx,[si+dir_len] - -.look_for_slash: - mov ax,di -.scan: - mov cl,[di] - inc di - and cl,cl - jz .isfile - cmp cl,'/' - jne .scan - mov [di-1],byte 0 ; Terminate at directory name - mov cl,02h ; Search for directory - xchg cl,[ISOFlags] - - push di ; Save these... - push cx - - ; Create recursion stack frame... - push word .resume ; Where to "return" to - push es -.isfile: xchg ax,di - -.getsome: - ; Get a chunk of the directory - ; This relies on the fact that ISOLINUX doesn't change SI - mov si,trackbuf - TRACER 'g' - pushad - xchg bx,si - mov cx,[BufSafe] - call getfssec - popad - -.compare: - movzx eax,byte [si] ; Length of directory entry - cmp al,33 - jb .next_sector - TRACER 'c' - mov cl,[si+25] - xor cl,[ISOFlags] - test cl, byte 8Eh ; Unwanted file attributes! - jnz .not_file - pusha - movzx cx,byte [si+32] ; File identifier length - add si,byte 33 ; File identifier offset - TRACER 'i' - call iso_compare_names - popa - je .success -.not_file: - sub edx,eax ; Decrease bytes left - jbe .failure - add si,ax ; Advance pointer - -.check_overrun: - ; Did we finish the buffer? - cmp si,trackbuf+trackbufsize - jb .compare ; No, keep going - - jmp short .getsome ; Get some more directory - -.next_sector: - ; Advance to the beginning of next sector - lea ax,[si+SECTOR_SIZE-1] - and ax,~(SECTOR_SIZE-1) - sub ax,si - jmp short .not_file ; We still need to do length checks - -.failure: xor eax,eax ; ZF = 1 - mov [bx+file_sector],eax - pop es - ret - -.success: - mov eax,[si+2] ; Location of extent - mov [bx+file_sector],eax - mov eax,[si+10] ; Data length - mov [bx+file_bytesleft],eax - push eax - add eax,SECTOR_SIZE-1 - shr eax,SECTOR_SHIFT - mov [bx+file_left],eax - pop eax - jz .failure ; Empty file? - ; ZF = 0 - mov si,bx - pop es - ret -.resume: ; We get here if we were only doing part of a lookup - ; This relies on the fact that .success returns bx == si - xchg edx,eax ; Directory length in edx - pop cx ; Old ISOFlags - pop di ; Next filename pointer - mov byte [di-1], '/' ; Restore slash - mov [ISOFlags],cl ; Restore the flags - jz .failure ; Did we fail? If so fail for real! - jmp .look_for_slash ; Otherwise, next level - -; -; allocate_file: Allocate a file structure -; -; If successful: -; ZF set -; BX = file pointer -; In unsuccessful: -; ZF clear -; -allocate_file: - TRACER 'a' - push cx - mov bx,Files - mov cx,MAX_OPEN -.check: cmp dword [bx], byte 0 - je .found - add bx,open_file_t_size ; ZF = 0 - loop .check - ; ZF = 0 if we fell out of the loop -.found: pop cx - ret - -; -; iso_compare_names: -; Compare the names DS:SI and DS:DI and report if they are -; equal from an ISO 9660 perspective. SI is the name from -; the filesystem; CX indicates its length, and ';' terminates. -; DI is expected to end with a null. -; -; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment -; - -iso_compare_names: - ; First, terminate and canonicalize input filename - push di - mov di,ISOFileName -.canon_loop: jcxz .canon_end - lodsb - dec cx - cmp al,';' - je .canon_end - and al,al - je .canon_end - stosb - cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun - jb .canon_loop -.canon_end: - cmp di,ISOFileName - jbe .canon_done - cmp byte [di-1],'.' ; Remove terminal dots - jne .canon_done - dec di - jmp short .canon_end -.canon_done: - mov [di],byte 0 ; Null-terminate string - pop di - mov si,ISOFileName -.compare: - lodsb - mov ah,[di] - inc di - and ax,ax - jz .success ; End of string for both - and al,al ; Is either one end of string? - jz .failure ; If so, failure - and ah,ah - jz .failure - or ax,2020h ; Convert to lower case - cmp al,ah - je .compare -.failure: and ax,ax ; ZF = 0 (at least one will be nonzero) -.success: ret - -; -; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed -; to by ES:DI; ends on encountering any whitespace. -; DI is preserved. -; -; This verifies that a filename is < FILENAME_MAX characters, -; doesn't contain whitespace, zero-pads the output buffer, -; and removes trailing dots and redundant slashes, -; so "repe cmpsb" can do a compare, and the -; path-searching routine gets a bit of an easier job. -; -mangle_name: - push di - push bx - xor ax,ax - mov cx,FILENAME_MAX-1 - mov bx,di - -.mn_loop: - lodsb - cmp al,' ' ; If control or space, end - jna .mn_end - cmp al,ah ; Repeated slash? - je .mn_skip - xor ah,ah - cmp al,'/' - jne .mn_ok - mov ah,al -.mn_ok stosb -.mn_skip: loop .mn_loop -.mn_end: - cmp bx,di ; At the beginning of the buffer? - jbe .mn_zero - cmp byte [es:di-1],'.' ; Terminal dot? - je .mn_kill - cmp byte [es:di-1],'/' ; Terminal slash? - jne .mn_zero -.mn_kill: dec di ; If so, remove it - inc cx - jmp short .mn_end -.mn_zero: - inc cx ; At least one null byte - xor ax,ax ; Zero-fill name - rep stosb - pop bx - pop di - ret ; Done - -; -; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled -; filename to the conventional representation. This is needed -; for the BOOT_IMAGE= parameter for the kernel. -; -; DS:SI -> input mangled file name -; ES:DI -> output buffer -; -; On return, DI points to the first byte after the output name, -; which is set to a null byte. -; -unmangle_name: call strcpy - dec di ; Point to final null byte - ret - -; -; getfssec: Get multiple clusters from a file, given the file pointer. -; -; On entry: -; ES:BX -> Buffer -; SI -> File pointer -; CX -> Cluster count -; On exit: -; SI -> File pointer (or 0 on EOF) -; CF = 1 -> Hit EOF -; ECX -> Bytes actually read -; -getfssec: - TRACER 'F' - push ds - push cs - pop ds ; DS <- CS - - movzx ecx,cx - cmp ecx,[si+file_left] - jna .ok_size - mov ecx,[si+file_left] -.ok_size: - - pushad - mov eax,[si+file_sector] - mov bp,cx - TRACER 'l' - call getlinsec - popad - - ; ECX[31:16] == 0 here... - add [si+file_sector],ecx - sub [si+file_left],ecx - shl ecx,SECTOR_SHIFT ; Convert to bytes - cmp ecx,[si+file_bytesleft] - jb .not_all - mov ecx,[si+file_bytesleft] -.not_all: sub [si+file_bytesleft],ecx - jnz .ret ; CF = 0 in this case... - push eax - xor eax,eax - mov [si+file_sector],eax ; Unused - mov si,ax - pop eax - stc -.ret: - pop ds - TRACER 'f' - ret ; ----------------------------------------------------------------------------- ; Common modules @@ -1745,21 +1314,8 @@ getfssec: ; ----------------------------------------------------------------------------- section .data16 - -default_str db 'default', 0 -default_len equ ($-default_str) -boot_dir db '/boot' ; /boot/isolinux -isolinux_dir db '/isolinux', 0 -config_name db 'isolinux.cfg', 0 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 -%ifdef DEBUG_MESSAGES -dbg_rootdir_msg db 'Root directory at LBA = ', 0 -dbg_isodir_msg db 'isolinux directory at LBA = ', 0 -dbg_config_msg db 'About to load config file...', CR, LF, 0 -dbg_configok_msg db 'Configuration file opened...', CR, LF, 0 -%endif - ; ; Config file keyword table ; diff --git a/core/kaboom.c b/core/kaboom.c new file mode 100644 index 00000000..d639915a --- /dev/null +++ b/core/kaboom.c @@ -0,0 +1,16 @@ +/* + * kaboom.c + */ + +#include "core.h" + +#undef kaboom + +__noreturn _kaboom(void) +{ + extern void kaboom(void); + call16(kaboom, &zero_regs, NULL); + /* Do this if kaboom somehow returns... */ + for (;;) + asm volatile("hlt"); +} diff --git a/core/layout.inc b/core/layout.inc index 3f5a7457..3df07721 100644 --- a/core/layout.inc +++ b/core/layout.inc @@ -125,16 +125,11 @@ auxseg resb aux_size ; is somewhat excessive. Sector alignment is obligatory, however. ; -%if IS_ISOLINUX -; ISOLINUX doesn't have a block cache yet -real_mode_seg equ 4000h -%else global cache_seg, core_cache_buf cache_seg equ 4000h ; 64K area for metadata cache core_cache_buf equ cache_seg << 4 real_mode_seg equ 5000h pktbuf_seg equ cache_seg ; PXELINUX packet buffers -%endif comboot_seg equ real_mode_seg ; COMBOOT image loading zone diff --git a/core/ldlinux.asm b/core/ldlinux.asm index c08799f4..20f0ee94 100644 --- a/core/ldlinux.asm +++ b/core/ldlinux.asm @@ -22,1398 +22,15 @@ ; ; **************************************************************************** -%ifndef IS_MDSLINUX %define IS_SYSLINUX 1 -%endif %include "head.inc" ; ; Some semi-configurable constants... change on your own risk. ; my_id equ syslinux_id -FILENAME_MAX_LG2 equ 6 ; log2(Max filename size Including final null) -FILENAME_MAX equ (1<<FILENAME_MAX_LG2) ; Max mangled filename size -NULLFILE equ 0 ; First char space == null filename -NULLOFFSET equ 0 ; Position in which to look -retry_count equ 16 ; How patient are we with the disk? -%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top -LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with -MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) -MAX_OPEN equ (1 << MAX_OPEN_LG2) + extern vfat_fs_ops +ROOT_FS_OPS equ vfat_fs_ops -SECTOR_SHIFT equ 9 -SECTOR_SIZE equ (1 << SECTOR_SHIFT) - -DIRENT_SHIFT equ 5 -DIRENT_SIZE equ (1 << DIRENT_SHIFT) - -ROOT_DIR_WORD equ 0x002F - -; -; The following structure is used for "virtual kernels"; i.e. LILO-style -; option labels. The options we permit here are `kernel' and `append -; Since there is no room in the bottom 64K for all of these, we -; stick them in high memory and copy them down before we need them. -; - struc vkernel -vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** -vk_rname: resb FILENAME_MAX ; Real name -vk_appendlen: resw 1 -vk_type: resb 1 ; Type of file - alignb 4 -vk_append: resb max_cmd_len+1 ; Command line - alignb 4 -vk_end: equ $ ; Should be <= vk_size - endstruc - -; -; File structure. This holds the information for each currently open file. -; - struc open_file_t -file_sector resd 1 ; Sector pointer (0 = structure free) -file_bytesleft resd 1 ; Number of bytes left -file_left resd 1 ; Number of sectors left - resd 1 ; Unused - endstruc - -; -; Structure for codepage files -; - struc cp -.magic resd 2 ; 8-byte magic number -.reserved resd 6 ; Reserved for future use -.uppercase resb 256 ; Internal upper-case table -.unicode resw 256 ; Unicode matching table -.unicode_alt resw 256 ; Alternate Unicode matching table - endstruc - -%ifndef DEPEND -%if (open_file_t_size & (open_file_t_size-1)) -%error "open_file_t is not a power of 2" -%endif -%endif - -; --------------------------------------------------------------------------- -; BEGIN CODE -; --------------------------------------------------------------------------- - -; -; Memory below this point is reserved for the BIOS and the MBR -; - section .earlybss -trackbufsize equ 8192 -trackbuf resb trackbufsize ; Track buffer goes here - ; ends at 2800h - - section .bss16 - alignb 4 -FAT resd 1 ; Location of (first) FAT -RootDirArea resd 1 ; Location of root directory area -RootDir resd 1 ; Location of root directory proper -DataArea resd 1 ; Location of data area -RootDirSize resd 1 ; Root dir size in sectors -TotalSectors resd 1 ; Total number of sectors -ClustSize resd 1 ; Bytes/cluster -ClustMask resd 1 ; Sectors/cluster - 1 -CopySuper resb 1 ; Distinguish .bs versus .bss -ClustShift resb 1 ; Shift count for sectors/cluster -ClustByteShift resb 1 ; Shift count for bytes/cluster - - alignb open_file_t_size -Files resb MAX_OPEN*open_file_t_size - -; -; Common bootstrap code for disk-based derivatives -; -%include "diskstart.inc" - -; -; Common initialization code -; -%include "init.inc" -%include "cpuinit.inc" - -; -; Compute some information about this filesystem. -; - -; First, generate the map of regions -genfatinfo: - mov edx,[bxSectors] - and dx,dx - jnz .have_secs - mov edx,[bsHugeSectors] -.have_secs: - mov [TotalSectors],edx - - mov eax,[bxResSectors] - mov [FAT],eax ; Beginning of FAT - mov edx,[bxFATsecs] - and dx,dx - jnz .have_fatsecs - mov edx,[bootsec+36] ; FAT32 BPB_FATsz32 -.have_fatsecs: - imul edx,[bxFATs] - add eax,edx - mov [RootDirArea],eax ; Beginning of root directory - mov [RootDir],eax ; For FAT12/16 == root dir location - - mov edx,[bxRootDirEnts] - add dx,SECTOR_SIZE/32-1 - shr dx,SECTOR_SHIFT-5 - mov [RootDirSize],edx - add eax,edx - mov [DataArea],eax ; Beginning of data area - -; Next, generate a cluster size shift count and mask - mov eax,[bxSecPerClust] - bsr cx,ax - mov [ClustShift],cl - push cx - add cl,SECTOR_SHIFT - mov [ClustByteShift],cl - pop cx - dec ax - mov [ClustMask],eax - inc ax - shl eax,SECTOR_SHIFT - mov [ClustSize],eax - -; -; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous. -; -getfattype: - mov eax,[TotalSectors] - sub eax,[DataArea] - shr eax,cl ; cl == ClustShift - mov cl,nextcluster_fat12-(nextcluster+2) - cmp eax,4085 ; FAT12 limit - jb .setsize - mov cl,nextcluster_fat16-(nextcluster+2) - cmp eax,65525 ; FAT16 limit - jb .setsize - ; - ; FAT32, root directory is a cluster chain - ; - mov cl,[ClustShift] - mov eax,[bootsec+44] ; Root directory cluster - sub eax,2 - shl eax,cl - add eax,[DataArea] - mov [RootDir],eax - mov cl,nextcluster_fat28-(nextcluster+2) - mov byte [SuperSize],superblock_len_fat32 -.setsize: - mov byte [nextcluster+1],cl - - -; -; Initialize the metadata cache -; - call initcache - -; -; Now, everything is "up and running"... patch kaboom for more -; verbosity and using the full screen system -; - ; E9 = JMP NEAR - mov di,kaboom.patch - mov al,0e9h - stosb - mov ax,kaboom2-2 - sub ax,di - stosw - -; -; Now we're all set to start with our *real* business. First load the -; configuration file (if any) and parse it. -; -; In previous versions I avoided using 32-bit registers because of a -; rumour some BIOSes clobbered the upper half of 32-bit registers at -; random. I figure, though, that if there are any of those still left -; they probably won't be trying to install Linux on them... -; -; The code is still ripe with 16-bitisms, though. Not worth the hassle -; to take'm out. In fact, we may want to put them back if we're going -; to boot ELKS at some point. -; - -; -; Load configuration file -; - mov si,config_name ; Save configuration file name - mov di,ConfigName - call strcpy - mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName - - mov eax,[RootDir] ; Make the root directory ... - mov [CurrentDir],eax ; ... the current directory - mov di,syslinux_cfg1 - push di - call open - pop di - jnz .config_open - mov di,syslinux_cfg2 - push di - call open - pop di - jnz .config_open - mov di,syslinux_cfg3 - push di - call open - pop di - jz no_config_file -.config_open: - push si - mov si,di - push si - mov di,CurrentDirName - ; This is inefficient as it will copy more than needed - ; but not by too much - call strcpy - mov ax,config_name ;Cut it down - pop si - sub ax,si - mov di,CurrentDirName - add di,ax - mov byte [di],0 - pop si - mov eax,[PrevDir] ; Make the directory with syslinux.cfg ... - mov [CurrentDir],eax ; ... the current directory - -; -; Now we have the config file open. Parse the config file and -; run the user interface. -; -%include "ui.inc" - -; -; allocate_file: Allocate a file structure -; -; If successful: -; ZF set -; BX = file pointer -; In unsuccessful: -; ZF clear -; -allocate_file: - TRACER 'a' - push cx - mov bx,Files - mov cx,MAX_OPEN -.check: cmp dword [bx], byte 0 - je .found - add bx,open_file_t_size ; ZF = 0 - loop .check - ; ZF = 0 if we fell out of the loop -.found: pop cx - ret - -; -; alloc_fill_dir: -; Allocate then fill a file structure for a directory starting in -; sector EAX. -; -; Assumes DS == ES == CS. -; -; If successful: -; ZF clear -; SI = file pointer -; If unsuccessful -; ZF set -; EAX clobbered -; -alloc_fill_dir: - push bx - call allocate_file - jnz .alloc_failure -.found: - mov si,bx - mov [si+file_sector],eax ; Current sector - mov dword [si+file_bytesleft],0 ; Current offset - mov [si+file_left],eax ; Beginning sector - pop bx - ret - -.alloc_failure: - pop bx - xor eax,eax ; ZF <- 1 - ret - -; -; search_dos_dir: -; Search a specific directory for a pre-mangled filename in -; MangledBuf, in the directory starting in sector EAX. -; -; NOTE: This file considers finding a zero-length file an -; error. This is so we don't have to deal with that special -; case elsewhere in the program (most loops have the test -; at the end). -; -; Assumes DS == ES == CS. -; -; If successful: -; ZF clear -; SI = file pointer -; EAX = file length (MAY BE ZERO!) -; DL = file attribute -; DH = clobbered -; If unsuccessful -; ZF set -; EAX, SI, DX clobbered -; - -search_dos_dir: - push bx - call allocate_file - jnz .alloc_failure - - push cx - push gs - push es - push ds - pop es ; ES = DS - - ; Compute the value of a possible VFAT longname - ; "last" entry (which, of course, comes first...) - push ax - push dx - mov ax,[NameLen] - add ax,12 - xor dx,dx - mov cx,13 - div cx - or al,40h - mov [VFATInit],al - mov [VFATNext],al - pop dx - pop ax - -.scansector: - ; EAX <- directory sector to scan - call getcachesector - ; GS:SI now points to this sector - - mov cx,SECTOR_SIZE/32 ; 32 == directory entry size -.scanentry: - cmp byte [gs:si],0 - jz .failure ; Hit directory high water mark - cmp word [gs:si+11],0Fh ; Long filename - jne .short_entry - - ; Process a VFAT long entry - pusha - mov al,[gs:si] - cmp al,[VFATNext] - jne .not_us - mov bl,[gs:si+13] - test al,40h - jz .match_csum - ; Get the initial checksum value - mov [VFATCsum],bl - jmp .done_csum -.match_csum: - cmp bl,[VFATCsum] - jne .not_us ; Checksum mismatch -.done_csum: - and ax,03fh - jz .not_us ; Can't be zero... - dec ax - mov [VFATNext],al ; Optimistically... - mov bx,ax - shl bx,2 ; *4 - add ax,bx ; *5 - add bx,bx ; *8 - add bx,ax ; *13 - cmp bx,[NameLen] - jae .not_us - mov di,[NameStart] - inc si - mov cx,13 -.vfat_cmp: - gs lodsw - push bx - cmp bx,[NameLen] - jae .vfat_tail - movzx bx,byte [bx+di] - add bx,bx - cmp ax,[cp_unicode+bx] ; Primary case - je .ucs_ok - cmp ax,[cp_unicode_alt+bx] ; Alternate case - je .ucs_ok - ; Mismatch... - jmp .not_us_pop -.vfat_tail: - ; *AT* the end we should have 0x0000, *AFTER* the end - ; we should have 0xFFFF... - je .vfat_end - inc ax ; 0xFFFF -> 0x0000 -.vfat_end: - and ax,ax - jnz .not_us_pop -.ucs_ok: - pop bx - inc bx - cmp cx,3 - je .vfat_adj_add2 - cmp cx,9 - jne .vfat_adj_add0 -.vfat_adj_add3: inc si -.vfat_adj_add2: inc si -.vfat_adj_add1: inc si -.vfat_adj_add0: - loop .vfat_cmp - ; Okay, if we got here we had a match on this particular - ; entry... live to see another one. - popa - jmp .next_entry - -.not_us_pop: - pop bx -.not_us: - popa - jmp .nomatch - -.short_entry: - test byte [gs:si+11],8 ; Ignore volume labels - jnz .nomatch - - cmp byte [VFATNext],0 ; Do we have a longname match? - jne .no_long_match - - ; We already have a VFAT longname match, however, - ; the match is only valid if the checksum matches - push cx - push si - push ax - xor ax,ax - mov cx,11 -.csum_loop: - gs lodsb - ror ah,1 - add ah,al - loop .csum_loop - cmp ah,[VFATCsum] - pop ax - pop si - pop cx - je .found ; Got a match on longname - -.no_long_match: ; Look for a shortname match - push cx - push si - push di - mov di,MangledBuf - mov cx,11 - gs repe cmpsb - pop di - pop si - pop cx - je .found -.nomatch: - ; Reset the VFAT matching state machine - mov dh,[VFATInit] - mov [VFATNext],dh -.next_entry: - add si,32 - dec cx - jnz .scanentry - - call nextsector - jnc .scansector ; CF is set if we're at end - - ; If we get here, we failed -.failure: - pop es - pop gs - pop cx -.alloc_failure: - pop bx - xor eax,eax ; ZF <- 1 - ret -.found: - mov eax,[gs:si+28] ; File size - add eax,SECTOR_SIZE-1 - shr eax,SECTOR_SHIFT - mov [bx+4],eax ; Sector count - - mov cl,[ClustShift] - mov dx,[gs:si+20] ; High cluster word - shl edx,16 - mov dx,[gs:si+26] ; Low cluster word - sub edx,2 - shl edx,cl - add edx,[DataArea] - mov [bx],edx ; Starting sector - - mov eax,[gs:si+28] ; File length again - mov dl,[gs:si+11] ; File attribute - mov si,bx ; File pointer... - and si,si ; ZF <- 0 - - pop es - pop gs - pop cx - pop bx - ret - - section .data16 - alignz 4 - ; Note: we have no use of the first 32 bytes (header), - ; nor of the folloing 32 bytes (case mapping of control - ; characters), as long as we adjust the offsets appropriately. -codepage equ $-(32+32) -codepage_data: incbin "codepage.cp",32+32 -cp_uppercase equ codepage+cp.uppercase -cp_unicode equ codepage+cp.unicode -cp_unicode_alt equ codepage+cp.unicode_alt -codepage_end equ $ - - section .text16 -; -; Input: UCS-2 character in AX -; Output: Single byte character in AL, ZF = 1 -; On failure, returns ZF = 0 -; -ucs2_to_cp: - push es - push di - push cx - push cs - pop es - mov di,cp_unicode - mov cx,512 - repne scasw - xchg ax,cx - pop cx - pop di - pop es - not ax ; Doesn't change the flags! - ret - - section .bss16 -VFATInit resb 1 -VFATNext resb 1 -VFATCsum resb 1 - - section .text16 -; -; close_file: -; Deallocates a file structure (pointer in SI) -; Assumes CS == DS. -; -close_file: - and si,si - jz .closed - mov dword [si],0 ; First dword == file_sector - xor si,si -.closed: ret - -; -; close_dir: -; Deallocates a directory structure (pointer in SI) -; Assumes CS == DS. -; -close_dir: - and si,si - jz .closed - mov dword [si],0 ; First dword == file_sector - xor si,si -.closed: ret - -; -; searchdir: -; -; Open a file -; -; On entry: -; DS:DI = filename -; If successful: -; ZF clear -; SI = file pointer -; EAX = file length in bytes -; If unsuccessful -; ZF set -; -; Assumes CS == DS == ES, and trashes BX and CX. -; -searchdir: - mov eax,[CurrentDir] - cmp byte [di],'/' ; Root directory? - jne .notroot - mov eax,[RootDir] - inc di -.notroot: - -.pathwalk: - push eax ; <A> Current directory sector - mov si,di -.findend: - lodsb - cmp al,' ' - jbe .endpath - cmp al,'/' - jne .findend -.endpath: - xchg si,di ; GRC: si begin; di end[ /]+1 - pop eax ; <A> Current directory sector - - ; GRC Here I need to check if di-1 = si which signifies - ; we have the desired directory in EAX - ; What about where the file name = "."; later - mov dx,di - dec dx - cmp dx,si - jz .founddir - - mov [PrevDir],eax ; Remember last directory searched - - push di - call mangle_dos_name ; MangledBuf <- component - call search_dos_dir - pop di - jz .notfound ; Pathname component missing - - cmp byte [di-1],'/' ; Do we expect a directory - je .isdir - - ; Otherwise, it should be a file -.isfile: - test dl,18h ; Subdirectory|Volume Label - jnz .badfile ; If not a file, it's a bad thing - - ; SI and EAX are already set - mov [si+file_bytesleft],eax - push eax - add eax,SECTOR_SIZE-1 - shr eax,SECTOR_SHIFT - mov [si+file_left],eax ; Sectors left - pop eax - and eax,eax ; EAX != 0 - jz .badfile - ret ; Done! - - ; If we expected a directory, it better be one... -.isdir: - test dl,10h ; Subdirectory - jz .badfile - - xor eax,eax - xchg eax,[si+file_sector] ; Get sector number and free file structure - jmp .pathwalk ; Walk the next bit of the path - - ; Found the desired directory; ZF set but EAX not 0 -.founddir: - ret - -.badfile: - xor eax,eax - mov [si],eax ; Free file structure - -.notfound: - xor eax,eax ; Zero out EAX - ret - -; -; readdir: Read one file from a directory -; -; ES:DI -> String buffer (filename) -; DS:SI -> Pointer to open_file_t -; DS Must be the SYSLINUX Data Segment -; -; Returns the file's name in the filename string buffer -; EAX returns the file size -; EBX returns the beginning sector (currently without offsetting) -; DL returns the file type -; The directory handle's data is incremented to reflect a name read. -; -readdir: - push ecx - push bp ; Using bp to transfer between segment registers - push si - push es - push fs ; Using fs to store the current es (from COMBOOT) - push gs - mov bp,es - mov fs,bp - cmp si,0 - jz .fail -.load_handle: - mov eax,[ds:si+file_sector] ; Current sector - mov ebx,[ds:si+file_bytesleft] ; Current offset - cmp eax,0 - jz .fail -.fetch_cache: - call getcachesector -.move_current: - add si,bx ; Resume last position in sector - mov ecx,SECTOR_SIZE ; 0 out high part - sub cx,bx - shr cx,5 ; Number of entries left -.scanentry: - cmp byte [gs:si],0 - jz .fail - cmp word [gs:si+11],0Fh ; Long filename - jne .short_entry - -.vfat_entry: - push eax - push ecx - push si - push di -.vfat_ln_info: ; Get info about the line that we're on - mov al,[gs:si] - test al,40h - jz .vfat_tail_ln - and al,03Fh - mov ah,1 ; On beginning line - jmp .vfat_ck_ln - -.vfat_tail_ln: ; VFAT tail line processing (later in VFAT, head in name) - test al,80h ; Invalid data? - jnz .vfat_abort - mov ah,0 ; Not on beginning line - cmp dl,al - jne .vfat_abort ; Is this the entry we need? - mov bl,[gs:si+13] - cmp bl,[VFATCsum] - je .vfat_cp_ln - jmp .vfat_abort - -.vfat_ck_ln: ; Load this line's VFAT CheckSum - mov bl,[gs:si+13] - mov [VFATCsum],bl -.vfat_cp_ln: ; Copy VFAT line - dec al ; Store the next line we need - mov dx,ax ; Use DX to store the progress - mov cx,13 ; 13 characters per VFAT DIRENT - cbw ; AH <- 0 - mul cl ; Offset for DI - add di,ax ; Increment DI - inc si ; Align to the real characters -.vfat_cp_chr: - gs lodsw ; Unicode here!! - call ucs2_to_cp ; Convert to local codepage - jnz .vfat_abort ; Use short name if character not on codepage - stosb ; CAN NOT OVERRIDE es - cmp al,0 - jz .vfat_find_next ; Null-terminated string; don't process more - cmp cx,3 - je .vfat_adj_add2 - cmp cx,9 - jne .vfat_adj_add0 -.vfat_adj_add3: inc si -.vfat_adj_add2: inc si -.vfat_adj_add1: inc si -.vfat_adj_add0: - loop .vfat_cp_chr - cmp dh,1 ; Is this the first round? - jnz .vfat_find_next -.vfat_null_term: ; Need to null-terminate if first line as we rolled over the end - mov al,0 - stosb - -.vfat_find_next: ;Find the next part of the name - pop di - pop si - pop ecx - pop eax - cmp dl,0 - jz .vfat_find_info ; We're done with the name - add si,DIRENT_SIZE - dec cx - jnz .vfat_entry - call nextsector - jnc .vfat_entry ; CF is set if we're at end - jmp .fail -.vfat_find_info: ; Fetch next entry for the size/"INode" - add si,DIRENT_SIZE - dec cx - jnz .get_info - call nextsector - jnc .get_info ; CF is set if we're at end - jmp .fail -.vfat_abort: ; Something went wrong, skip - pop di - pop si - pop ecx - pop eax - jmp .skip_entry - -.short_entry: - test byte [gs:si+11],8 ; Ignore volume labels //HERE - jnz .skip_entry - mov edx,eax ;Save current sector - push cx - push si - push di - mov cx,8 -.short_file: - gs lodsb - cmp al,'.' - jz .short_dot -.short_file_loop: - cmp al,' ' - jz .short_skip_bs - stosb - loop .short_file_loop - jmp .short_period -.short_skip_bs: ; skip blank spaces in FILENAME (before EXT) - add si,cx - dec si -.short_period: - mov al,'.' - stosb - mov cx,3 -.short_ext: - gs lodsb - cmp al,' ' - jz .short_done - stosb - loop .short_ext - jmp .short_done -.short_dot: - stosb - gs lodsb - cmp al,' ' - jz .short_done - stosb -.short_done: - mov al,0 ; Null-terminate the short strings - stosb - pop di - pop si - pop cx - mov eax,edx -.get_info: - mov ebx,[gs:si+28] ; length - mov dl,[gs:si+11] ; type -.next_entry: - add si,DIRENT_SIZE - dec cx - jnz .store_offset - call nextsector - jnc .store_sect ; CF is set if we're at end - jmp .fail - -.skip_entry: - add si,DIRENT_SIZE - dec cx - jnz .scanentry - call nextsector - jnc .scanentry ; CF is set if we're at end - jmp .fail - -.store_sect: - pop gs - pop fs - pop es - pop si - mov [ds:si+file_sector],eax - mov eax,0 ; Now at beginning of new sector - jmp .success - -.store_offset: - pop gs - pop fs - pop es - pop si ; cx=num remain; SECTOR_SIZE-(cx*32)=cur pos - shl ecx,DIRENT_SHIFT - mov eax,SECTOR_SIZE - sub eax,ecx - and eax,0ffffh - -.success: - mov [ds:si+file_bytesleft],eax - ; "INode" number = ((CurSector-RootSector)*SECTOR_SIZE + Offset)/DIRENT_SIZE) - mov ecx,eax - mov eax,[ds:si+file_sector] - sub eax,[RootDir] - shl eax,SECTOR_SHIFT - add eax,ecx - shr eax,DIRENT_SHIFT - dec eax - xchg eax,ebx ; -> EBX=INode, EAX=FileSize - jmp .done - -.fail: - pop gs - pop fs - pop es - pop si - call close_dir - xor eax,eax - stc -.done: - pop bp - pop ecx -.end: - ret - - section .bss16 - alignb 4 -PrevDir resd 1 ; Last scanned directory - - section .text16 - -; -; -; kaboom2: once everything is loaded, replace the part of kaboom -; starting with "kaboom.patch" with this part - -kaboom2: - mov si,err_bootfailed - call writestr - cmp byte [kaboom.again+1],18h ; INT 18h version? - je .int18 - call getchar - call vgaclearmode - int 19h ; And try once more to boot... -.norge: jmp short .norge ; If int 19h returned; this is the end -.int18: - call vgaclearmode - int 18h -.noreg: jmp short .noreg ; Nynorsk - -; -; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed -; to by ES:DI; ends on encountering any whitespace. -; DI is preserved. -; -; This verifies that a filename is < FILENAME_MAX characters, -; doesn't contain whitespace, zero-pads the output buffer, -; and removes trailing dots and redundant slashes, plus changes -; backslashes to forward slashes, -; so "repe cmpsb" can do a compare, and the path-searching routine -; gets a bit of an easier job. -; -; -mangle_name: - push di - push bx - xor ax,ax - mov cx,FILENAME_MAX-1 - mov bx,di - -.mn_loop: - lodsb - cmp al,' ' ; If control or space, end - jna .mn_end - cmp al,'\' ; Backslash? - jne .mn_not_bs - mov al,'/' ; Change to forward slash -.mn_not_bs: - cmp al,ah ; Repeated slash? - je .mn_skip - xor ah,ah - cmp al,'/' - jne .mn_ok - mov ah,al -.mn_ok stosb -.mn_skip: loop .mn_loop -.mn_end: - cmp bx,di ; At the beginning of the buffer? - jbe .mn_zero - cmp byte [es:di-1],'.' ; Terminal dot? - je .mn_kill - cmp byte [es:di-1],'/' ; Terminal slash? - jne .mn_zero -.mn_kill: dec di ; If so, remove it - inc cx - jmp short .mn_end -.mn_zero: - inc cx ; At least one null byte - xor ax,ax ; Zero-fill name - rep stosb - pop bx - pop di - ret ; Done - -; -; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled -; filename to the conventional representation. This is needed -; for the BOOT_IMAGE= parameter for the kernel. -; NOTE: A 13-byte buffer is mandatory, even if the string is -; known to be shorter. -; -; DS:SI -> input mangled file name -; ES:DI -> output buffer -; -; On return, DI points to the first byte after the output name, -; which is set to a null byte. -; -unmangle_name: call strcpy - dec di ; Point to final null byte - ret - -; -; mangle_dos_name: -; Mangle a DOS filename component pointed to by DS:SI -; into [MangledBuf]; ends on encountering any whitespace or -; slash. -; -; WARNING: saves pointers into the buffer for longname -; matches! -; -; Assumes CS == DS == ES. -; - -mangle_dos_name: - pusha - mov di,MangledBuf - mov [NameStart],si - - mov cx,11 ; # of bytes to write - mov bx,cp_uppercase ; Case-conversion table -.loop: - lodsb - cmp al,' ' ; If control or space, end - jna .end - cmp al,'/' ; Slash, too - je .end - cmp al,'.' ; Period -> space-fill - je .is_period - xlatb ; Convert to upper case - mov ah,cl ; If the first byte (only!)... - cmp ax,0BE5h ; ... equals E5 hex ... - jne .charok - mov al,05h ; ... change it to 05 hex -.charok: stosb - loop .loop ; Don't continue if too long - ; Find the end for the benefit of longname search -.find_end: - lodsb - cmp al,' ' - jna .end - cmp al,'/' - jne .find_end -.end: - dec si - sub si,[NameStart] - mov [NameLen],si - mov al,' ' ; Space-fill name - rep stosb ; Doesn't do anything if CX=0 - popa - ret ; Done - -.is_period: - mov al,' ' ; We need to space-fill -.period_loop: cmp cx,3 ; If <= 3 characters left - jbe .loop ; Just ignore it - stosb ; Otherwise, write a space - loop .period_loop ; Dec CX and *always* jump - - section .bss16 - alignb 2 -NameStart resw 1 -NameLen resw 1 -MangledBuf resb 11 - - section .text16 -; -; getfssec_edx: Get multiple sectors from a file -; -; This routine makes sure the subtransfers do not cross a 64K boundary, -; and will correct the situation if it does, UNLESS *sectors* cross -; 64K boundaries. -; -; ES:BX -> Buffer -; EDX -> Current sector number -; CX -> Sector count (0FFFFh = until end of file) -; Must not exceed the ES segment -; Returns EDX=0, CF=1 on EOF (not necessarily error) -; All arguments are advanced to reflect data read. -; -getfssec_edx: - push ebp - push eax -.getfragment: - xor ebp,ebp ; Fragment sector count - push edx ; Starting sector pointer -.getseccnt: - inc bp - dec cx - jz .do_read - xor eax,eax - mov ax,es - shl ax,4 - add ax,bx ; Now AX = how far into 64K block we are - not ax ; Bytes left in 64K block - inc eax - shr eax,SECTOR_SHIFT ; Sectors left in 64K block - cmp bp,ax - jnb .do_read ; Unless there is at least 1 more sector room... - mov eax,edx ; Current sector - inc edx ; Predict it's the linearly next sector - call nextsector - jc .do_read - cmp edx,eax ; Did it match? - jz .getseccnt -.do_read: - pop eax ; Starting sector pointer - call getlinsecsr - lea eax,[eax+ebp-1] ; This is the last sector actually read - shl bp,9 - add bx,bp ; Adjust buffer pointer - call nextsector - jc .eof - mov edx,eax - and cx,cx - jnz .getfragment -.done: - pop eax - pop ebp - ret -.eof: - xor edx,edx - stc - jmp .done - -; -; getfssec: Get multiple sectors from a file -; -; Same as above, except SI is a pointer to a open_file_t -; -; ES:BX -> Buffer -; DS:SI -> Pointer to open_file_t -; CX -> Sector count (0FFFFh = until end of file) -; Must not exceed the ES segment -; Returns CF=1 on EOF (not necessarily error) -; ECX returns number of bytes read. -; All arguments are advanced to reflect data read. -; -getfssec: - push edx - movzx edx,cx - push edx ; Zero-extended CX - cmp edx,[si+file_left] - jbe .sizeok - mov edx,[si+file_left] - mov cx,dx -.sizeok: - sub [si+file_left],edx - mov edx,[si+file_sector] - call getfssec_edx - mov [si+file_sector],edx - pop ecx ; Sectors requested read - shl ecx,SECTOR_SHIFT - cmp ecx,[si+file_bytesleft] - ja .eof -.noteof: - sub [si+file_bytesleft],ecx ; CF <- 0 - pop edx - ret -.eof: - mov ecx,[si+file_bytesleft] - call close_file - pop edx - stc - ret - -; -; nextcluster: Advance a cluster pointer in EDI to the next cluster -; pointed at in the FAT tables. CF=0 on return if end of file. -; -nextcluster: - jmp strict short nextcluster_fat28 ; This gets patched - -nextcluster_fat12: - push eax - push edx - push bx - push cx - push si - mov edx,edi - shr edi,1 - pushf ; Save the shifted-out LSB (=CF) - add edx,edi - mov eax,edx - shr eax,9 - call getfatsector - mov bx,dx - and bx,1FFh - mov cl,[gs:si+bx] - inc edx - mov eax,edx - shr eax,9 - call getfatsector - mov bx,dx - and bx,1FFh - mov ch,[gs:si+bx] - popf - jnc .even - shr cx,4 -.even: and cx,0FFFh - movzx edi,cx - cmp di,0FF0h - pop si - pop cx - pop bx - pop edx - pop eax - ret - -; -; FAT16 decoding routine. -; -nextcluster_fat16: - push eax - push si - push bx - mov eax,edi - shr eax,SECTOR_SHIFT-1 - call getfatsector - mov bx,di - add bx,bx - and bx,1FEh - movzx edi,word [gs:si+bx] - cmp di,0FFF0h - pop bx - pop si - pop eax - ret -; -; FAT28 ("FAT32") decoding routine. -; -nextcluster_fat28: - push eax - push si - push bx - mov eax,edi - shr eax,SECTOR_SHIFT-2 - call getfatsector - mov bx,di - add bx,bx - add bx,bx - and bx,1FCh - mov edi,dword [gs:si+bx] - and edi,0FFFFFFFh ; 28 bits only - cmp edi,0FFFFFF0h - pop bx - pop si - pop eax - ret - -; -; nextsector: Given a sector in EAX on input, return the next sector -; of the same filesystem object, which may be the root -; directory or a cluster chain. Returns EOF. -; -; Assumes CS == DS. -; -nextsector: - push edi - push edx - mov edx,[DataArea] - mov edi,eax - sub edi,edx - jae .isdata - - ; Root directory - inc eax - cmp eax,edx - cmc - jmp .done - -.isdata: - not edi - test edi,[ClustMask] - jz .endcluster - - ; It's not the final sector in a cluster - inc eax - jmp .done - -.endcluster: - push gs ; nextcluster trashes gs - push cx - not edi - mov cl,[ClustShift] - shr edi,cl - add edi,2 - - ; Now EDI contains the cluster number - call nextcluster - cmc - jc .exit ; There isn't anything else... - - ; New cluster number now in EDI - sub edi,2 - shl edi,cl ; CF <- 0, unless something is very wrong - lea eax,[edi+edx] -.exit: - pop cx - pop gs -.done: - pop edx - pop edi - ret - -; -; getfatsector: Check for a particular sector (in EAX) in the FAT cache, -; and return a pointer in GS:SI, loading it if needed. -; -; Assumes CS == DS. -; -getfatsector: - add eax,[FAT] ; FAT starting address - jmp getcachesector - -; ----------------------------------------------------------------------------- -; Common modules -; ----------------------------------------------------------------------------- - -%include "common.inc" ; Universal modules -%include "plaincon.inc" ; writechr -%include "writestr.inc" ; String output -%include "writehex.inc" ; Hexadecimal output -%include "cache.inc" ; Metadata disk cache -%include "localboot.inc" ; Disk-based local boot - -; ----------------------------------------------------------------------------- -; Begin data section -; ----------------------------------------------------------------------------- - - section .data16 -copyright_str db ' Copyright (C) 1994-' - asciidec YEAR - db ' H. Peter Anvin et al', CR, LF, 0 -err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' - db 'a key to continue.', CR, LF, 0 -syslinux_cfg1 db '/boot' ; /boot/syslinux/syslinux.cfg -syslinux_cfg2 db '/syslinux' ; /syslinux/syslinux.cfg -syslinux_cfg3 db '/' ; /syslinux.cfg -config_name db 'syslinux.cfg', 0 ; syslinux.cfg - -; -; Config file keyword table -; -%include "keywords.inc" - -; -; Extensions to search for (in *forward* order). -; -exten_table: db '.cbt' ; COMBOOT (specific) - db '.bss' ; Boot Sector (add superblock) - db '.bs', 0 ; Boot Sector - db '.com' ; COMBOOT (same as DOS) - db '.c32' ; COM32 -exten_table_end: - dd 0, 0 ; Need 8 null bytes here - -; -; Misc initialized (data) variables -; -%ifdef debug ; This code for debugging only -debug_magic dw 0D00Dh ; Debug code sentinel -%endif - - alignz 4 -BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf -BufSafeBytes dw trackbufsize ; = how many bytes? -%ifndef DEPEND -%if ( trackbufsize % SECTOR_SIZE ) != 0 -%error trackbufsize must be a multiple of SECTOR_SIZE -%endif -%endif +%include "diskfs.inc" diff --git a/core/loadhigh.inc b/core/loadhigh.inc index 5c9969f6..63ab0010 100644 --- a/core/loadhigh.inc +++ b/core/loadhigh.inc @@ -69,7 +69,7 @@ load_high: push edi ; <C> Target buffer mov cx,ax xor bx,bx ; ES:0 - call getfssec ; Load the data into xfer_buf_seg + pm_call getfssec ; Load the data into xfer_buf_seg pop edi ; <C> Target buffer pushf ; <C> EOF status lea ebx,[edi+ecx] ; End of data diff --git a/core/parsecmd.inc b/core/parsecmd.inc index 7dfe1eb6..ab5a7df9 100644 --- a/core/parsecmd.inc +++ b/core/parsecmd.inc @@ -111,6 +111,7 @@ err_badcfg db 'Unknown keyword in configuration file: ',0 err_noparm db 'Missing parameter in configuration file. Keyword: ',0 section .uibss + global KernelName alignb 4 vk_size equ (vk_end + 3) & ~3 VKernelBuf: resb vk_size ; "Current" vkernel diff --git a/core/parseconfig.inc b/core/parseconfig.inc index 02bc4bf8..af7d514f 100644 --- a/core/parseconfig.inc +++ b/core/parseconfig.inc @@ -104,7 +104,7 @@ pc_kernel: cmp byte [VKernel],0 mov [VKernelBuf+vk_type],al call pc_getline mov di,VKernelBuf+vk_rname - call mangle_name + pm_call mangle_name .err: ret ; @@ -147,8 +147,8 @@ pc_setint16: pc_filecmd: push ax ; Function to tailcall call pc_getline mov di,MNameBuf - call mangle_name - call searchdir + pm_call mangle_name + pm_call searchdir jnz .ok pop ax ; Drop the successor function .ok: ret ; Tailcall if OK, error return @@ -160,8 +160,8 @@ pc_filecmd: push ax ; Function to tailcall pc_opencmd: push ax ; Function to tailcall call pc_getline mov di,MNameBuf - call mangle_name - call open + pm_call mangle_name + call core_open jnz .ok pop ax ; Drop the successor function .ok: ret ; Tailcall if OK, error return @@ -289,7 +289,7 @@ pc_serial: call getint pc_filename: push ax call pc_getline pop di - call mangle_name ; Mangle file name + pm_call mangle_name ; Mangle file name ret ; @@ -314,7 +314,7 @@ pc_label: call commit_vk ; Commit any current vkernel mov byte [VKernel],1 ; We've seen a "label" statement mov si,VKernelBuf+vk_vname ; By default, rname == mangled vname mov di,VKernelBuf+vk_rname - call mangle_name + pm_call mangle_name mov si,AppendBuf ; Default append==global append mov di,VKernelBuf+vk_append mov cx,[AppendLen] @@ -409,7 +409,7 @@ commit_vk: mov cx,7 ; "initrd=" rep movsb mov si,InitRD - call unmangle_name + pm_call unmangle_name mov al,' ' stosb diff --git a/core/pxeidle.inc b/core/pxeidle.inc deleted file mode 100644 index ef3e1b7f..00000000 --- a/core/pxeidle.inc +++ /dev/null @@ -1,122 +0,0 @@ -;; -*- fundamental -*- --------------------------------------------------- -;; -;; Copyright 2008 H. Peter Anvin - All Rights Reserved -;; Copyright 2009 Intel Corporation; author: H. Peter Anvin -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -;; Boston MA 02110-1301, USA; either version 2 of the License, or -;; (at your option) any later version; incorporated herein by reference. -;; -;; ----------------------------------------------------------------------- - -;; -;; pxeidle.inc -;; -;; -;; Query for the NIC type, and detect certain special cases. -;; - - section .text16 - -;; -;; Initializes the idle mechanism based on the device type -;; -;; Assumes CS == DS == ES -;; -pxe_detect_nic_type: - pushad - - mov di,pxenv_get_nic_type - mov bx,PXENV_UNDI_GET_NIC_TYPE - call pxenv - jc .done - cmp word [di],0 - jne .done - cmp byte [di+2],2 ; PCI_NIC - jne .done ; No list for non-PCI nics - - mov cx,pxe_idle_pci_list.len - mov si,pxe_idle_pci_list -.look_for_id: - lodsd - cmp eax,[di+3] ; VID:DID - je .found_device - loop .look_for_id -.done: - popad - ret - -.found_device: - mov word [IdleHook],check_for_arp - jmp .done - -;; -;; List of devices for which we want to actually issue idle calls. -;; - section .data16 - alignz 4 -pxe_idle_pci_list: -; -; Older Broadcom NICs; these need idle calls to avoid FIFO stalls. -; - dw 0x14e4, 0x1659 ; BCM5721 - dw 0x14e4, 0x165a ; BCM5722 - dw 0x14e4, 0x165b ; BCM5723 - dw 0x14e4, 0x1668 ; BCM5714 - dw 0x14e4, 0x1669 ; BCM5714S - dw 0x14e4, 0x166a ; BCM5780 - dw 0x14e4, 0x166b ; BCM5780S - dw 0x14e4, 0x1673 ; BCM5755M - dw 0x14e4, 0x1674 ; BCM5756ME - dw 0x14e4, 0x1678 ; BCM5715 - dw 0x14e4, 0x1679 ; BCM5715S - dw 0x14e4, 0x167b ; BCM5755 -; -.len equ ($-pxe_idle_pci_list) >> 2 - - section .bss16 -pxenv_get_nic_type: -.status: resw 1 -.nic_type: resb 1 -.vid: resw 1 -.did: resw 1 -.base_class: resb 1 -.sub_class: resb 1 -.prog_intf: resb 1 -.rev: resb 1 -.busdevfunc: resw 1 -.svid: resw 1 -.sdid: resw 1 - - section .text16 -; -; Call the receive loop while idle. This is done mostly so we can respond to -; ARP messages, but perhaps in the future this can be used to do network -; console. -; -; hpa sez: people using automatic control on the serial port get very -; unhappy if we poll for ARP too often (the PXE stack is pretty slow, -; typically.) Therefore, only poll if at least 4 BIOS timer ticks have -; passed since the last poll, and reset this when a character is -; received (call reset_idle). -; -; Note: we only do this if pxe_detect_nic_type has set the IdleHook -; to point to this routine. -; -check_for_arp: - pushad - mov di,packet_buf - mov [pxe_udp_read_pkt.buffer],di - mov [pxe_udp_read_pkt.buffer+2],ds - mov word [pxe_udp_read_pkt.buffersize],packet_buf_size - mov eax,[MyIP] - mov [pxe_udp_read_pkt.dip],eax - mov word [pxe_udp_read_pkt.lport],htons(9) ; discard port - mov di,pxe_udp_read_pkt - mov bx,PXENV_UDP_READ - call pxenv - ; Ignore result... - popad - ret diff --git a/core/pxelinux.asm b/core/pxelinux.asm index f51e7cd6..5512e843 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -29,23 +29,10 @@ ; Some semi-configurable constants... change on your own risk. ; my_id equ pxelinux_id -FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null) -FILENAME_MAX equ (1 << FILENAME_MAX_LG2) NULLFILE equ 0 ; Zero byte == null file name NULLOFFSET equ 4 ; Position in which to look REBOOT_TIME equ 5*60 ; If failure, time until full reset %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top -MAX_OPEN_LG2 equ 5 ; log2(Max number of open sockets) -MAX_OPEN equ (1 << MAX_OPEN_LG2) -PKTBUF_SIZE equ (65536/MAX_OPEN) ; Per-socket packet buffer size -TFTP_PORT equ htons(69) ; Default TFTP port -; Desired TFTP block size -; For Ethernet MTU is normally 1500. Unfortunately there seems to -; be a fair number of networks with "substandard" MTUs which break. -; The code assumes TFTP_LARGEBLK <= 2K. -TFTP_MTU equ 1440 -TFTP_LARGEBLK equ (TFTP_MTU-20-8-4) ; MTU - IP hdr - UDP hdr - TFTP hdr -; Standard TFTP block size TFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block) TFTP_BLOCKSIZE equ (1 << TFTP_BLOCKSIZE_LG2) @@ -58,29 +45,6 @@ SECTOR_SHIFT equ TFTP_BLOCKSIZE_LG2 SECTOR_SIZE equ TFTP_BLOCKSIZE ; -; TFTP operation codes -; -TFTP_RRQ equ htons(1) ; Read request -TFTP_WRQ equ htons(2) ; Write request -TFTP_DATA equ htons(3) ; Data packet -TFTP_ACK equ htons(4) ; ACK packet -TFTP_ERROR equ htons(5) ; ERROR packet -TFTP_OACK equ htons(6) ; OACK packet - -; -; TFTP error codes -; -TFTP_EUNDEF equ htons(0) ; Unspecified error -TFTP_ENOTFOUND equ htons(1) ; File not found -TFTP_EACCESS equ htons(2) ; Access violation -TFTP_ENOSPACE equ htons(3) ; Disk full -TFTP_EBADOP equ htons(4) ; Invalid TFTP operation -TFTP_EBADID equ htons(5) ; Unknown transfer -TFTP_EEXISTS equ htons(6) ; File exists -TFTP_ENOUSER equ htons(7) ; No such user -TFTP_EOPTNEG equ htons(8) ; Option negotiation failure - -; ; The following structure is used for "virtual kernels"; i.e. LILO-style ; option labels. The options we permit here are `kernel' and `append ; Since there is no room in the bottom 64K for all of these, we @@ -98,60 +62,6 @@ vk_append: resb max_cmd_len+1 ; Command line vk_end: equ $ ; Should be <= vk_size endstruc -; -; BOOTP/DHCP packet pattern -; - struc bootp_t -bootp: -.opcode resb 1 ; BOOTP/DHCP "opcode" -.hardware resb 1 ; ARP hardware type -.hardlen resb 1 ; Hardware address length -.gatehops resb 1 ; Used by forwarders -.ident resd 1 ; Transaction ID -.seconds resw 1 ; Seconds elapsed -.flags resw 1 ; Broadcast flags -.cip resd 1 ; Client IP -.yip resd 1 ; "Your" IP -.sip resd 1 ; Next server IP -.gip resd 1 ; Relay agent IP -.macaddr resb 16 ; Client MAC address -.sname resb 64 ; Server name (optional) -.bootfile resb 128 ; Boot file name -.option_magic resd 1 ; Vendor option magic cookie -.options resb 1260 ; Vendor options - endstruc - -BOOTP_OPTION_MAGIC equ htonl(0x63825363) ; See RFC 2132 - -; -; TFTP connection data structure. Each one of these corresponds to a local -; UDP port. The size of this structure must be a power of 2. -; HBO = host byte order; NBO = network byte order -; (*) = written by options negotiation code, must be dword sized -; -; For a gPXE connection, we set the local port number to -1 and the -; remote port number contains the gPXE file handle. -; - struc open_file_t -tftp_localport resw 1 ; Local port number (0 = not in use) -tftp_remoteport resw 1 ; Remote port number -tftp_remoteip resd 1 ; Remote IP address -tftp_filepos resd 1 ; Bytes downloaded (including buffer) -tftp_filesize resd 1 ; Total file size(*) -tftp_blksize resd 1 ; Block size for this connection(*) -tftp_bytesleft resw 1 ; Unclaimed data bytes -tftp_lastpkt resw 1 ; Sequence number of last packet (NBO) -tftp_dataptr resw 1 ; Pointer to available data -tftp_goteof resb 1 ; 1 if the EOF packet received - resb 3 ; Currently unusued - ; At end since it should not be zeroed on socked close -tftp_pktbuf resw 1 ; Packet buffer offset - endstruc -%ifndef DEPEND -%if (open_file_t_size & (open_file_t_size-1)) -%error "open_file_t is not a power of 2" -%endif -%endif ; --------------------------------------------------------------------------- ; BEGIN CODE @@ -161,57 +71,36 @@ tftp_pktbuf resw 1 ; Packet buffer offset ; Memory below this point is reserved for the BIOS and the MBR ; section .earlybss + global trackbuf trackbufsize equ 8192 trackbuf resb trackbufsize ; Track buffer goes here ; ends at 2800h - section .bss16 - alignb open_file_t_size -Files resb MAX_OPEN*open_file_t_size + ; These fields save information from before the time + ; .bss is zeroed... must be in .earlybss + global InitStack +InitStack resd 1 + section .bss16 alignb FILENAME_MAX -BootFile resb 256 ; Boot file from DHCP packet -PathPrefix resb 256 ; Path prefix derived from boot file -DotQuadBuf resb 16 ; Buffer for dotted-quad IP address + global IPOption IPOption resb 80 ; ip= option buffer -InitStack resd 1 ; Pointer to reset stack (SS:SP) PXEStack resd 1 ; Saved stack during PXE call alignb 4 + global DHCPMagic, RebootTime, APIVer RebootTime resd 1 ; Reboot timeout, if set by option -StrucPtr resd 1 ; Pointer to PXENV+ or !PXE structure +StrucPtr resw 2 ; Pointer to PXENV+ or !PXE structure APIVer resw 1 ; PXE API version found LocalBootType resw 1 ; Local boot return code -RealBaseMem resw 1 ; Amount of DOS memory after freeing -OverLoad resb 1 ; Set if DHCP packet uses "overloading" DHCPMagic resb 1 ; PXELINUX magic flags ; The relative position of these fields matter! -MAC_MAX equ 32 ; Handle hardware addresses this long -MACLen resb 1 ; MAC address len -MACType resb 1 ; MAC address type -MAC resb MAC_MAX+1 ; Actual MAC address + global BOOTIFStr BOOTIFStr resb 7 ; Space for "BOOTIF=" -MACStr resb 3*(MAC_MAX+1) ; MAC address as a string - -; The relative position of these fields matter! -UUIDType resb 1 ; Type byte from DHCP option -UUID resb 16 ; UUID, from the PXE stack -UUIDNull resb 1 ; dhcp_copyoption zero-terminates - -; -; PXE packets which don't need static initialization -; - alignb 4 -pxe_unload_stack_pkt: -.status: resw 1 ; Status -.reserved: resb 10 ; Reserved -pxe_unload_stack_pkt_len equ $-pxe_unload_stack_pkt - - alignb 16 - ; BOOTP/DHCP packet buffer section .bss16 + global packet_buf alignb 16 packet_buf resb 2048 ; Transfer packet packet_buf_size equ $-packet_buf @@ -277,329 +166,11 @@ _start1: call writestr_early ; -; Assume API version 2.1, in case we find the !PXE structure without -; finding the PXENV+ structure. This should really look at the Base -; Code ROM ID structure in have_pxe, but this is adequate for now -- -; if we have !PXE, we have to be 2.1 or higher, and we don't care -; about higher versions than that. +; do fs initialize ; - mov word [APIVer],0201h - -; -; Now we need to find the !PXE structure. -; We search for the following, in order: -; -; a. !PXE structure as SS:[SP+4] -; b. PXENV+ structure at [ES:BX] -; c. INT 1Ah AX=5650h -> PXENV+ -; d. Search memory for !PXE -; e. Search memory for PXENV+ -; -; If we find a PXENV+ structure, we try to find a !PXE structure from -; it if the API version is 2.1 or later. -; - ; Plan A: !PXE structure as SS:[SP+4] - lgs bp,[InitStack] ; GS:BP -> original stack - les bx,[gs:bp+48] - call is_pxe - je have_pxe - - ; Plan B: PXENV+ structure at [ES:BX] - inc byte [plan] - mov bx,[gs:bp+24] ; Original BX - mov es,[gs:bp+4] ; Original ES - call is_pxenv - je have_pxenv - - ; Plan C: PXENV+ structure via INT 1Ah AX=5650h - inc byte [plan] - mov ax, 5650h -%if USE_PXE_PROVIDED_STACK == 0 - lss sp,[InitStack] -%endif - int 1Ah ; May trash regs -%if USE_PXE_PROVIDED_STACK == 0 - lss esp,[BaseStack] -%endif - sti ; Work around Etherboot bug - - jc no_int1a - cmp ax,564Eh - jne no_int1a - - call is_pxenv - je have_pxenv - -no_int1a: - ; Plan D: !PXE memory scan - inc byte [plan] - call memory_scan_for_pxe_struct ; !PXE scan - je have_pxe - - ; Plan E: PXENV+ memory scan - inc byte [plan] - call memory_scan_for_pxenv_struct ; PXENV+ scan - je have_pxenv - - ; Found nothing at all!! -no_pxe: - mov si,err_nopxe - call writestr_early - jmp kaboom - -have_pxenv: - mov [StrucPtr],bx - mov [StrucPtr+2],es - - mov si,found_pxenv - call writestr_early - - mov si,apiver_str - call writestr_early - mov ax,[es:bx+6] - mov [APIVer],ax - call writehex4 - call crlf - - cmp ax,0201h ; API version 2.1 or higher - jb .old_api - cmp byte [es:bx+8],2Ch ; Space for !PXE pointer? - jb .pxescan - les bx,[es:bx+28h] ; !PXE structure pointer - call is_pxe - je have_pxe - - ; Nope, !PXE structure missing despite API 2.1+, or at least - ; the pointer is missing. Do a last-ditch attempt to find it. -.pxescan: - call memory_scan_for_pxe_struct - je have_pxe - - ; Otherwise, no dice, use PXENV+ structure -.old_api: - les bx,[StrucPtr] - push word [es:bx+22h] ; UNDI data len - push word [es:bx+20h] ; UNDI data seg - push word [es:bx+26h] ; UNDI code len - push word [es:bx+24h] ; UNDI code seg - push dword [es:bx+0Ah] ; PXENV+ entry point - - mov si,pxenventry_msg - jmp have_entrypoint - -have_pxe: - mov [StrucPtr],bx - mov [StrucPtr+2],es - - push word [es:bx+2Eh] ; UNDI data len - push word [es:bx+28h] ; UNDI data seg - push word [es:bx+36h] ; UNDI code len - push word [es:bx+30h] ; UNDI code seg - push dword [es:bx+10h] ; !PXE entry point - - mov si,pxeentry_msg - -have_entrypoint: - push cs - pop es ; Restore CS == DS == ES - - call writestr_early ; !PXE or PXENV+ entry found - - pop dword [PXEEntry] - mov ax,[PXEEntry+2] - call writehex4 - mov al,':' - call writechr - mov ax,[PXEEntry] - call writehex4 - - mov si,viaplan_msg - call writestr_early - - mov si,undi_code_msg - call writestr_early - pop ax ; UNDI code segment - call writehex4 - xchg dx,ax - mov si,len_msg - call writestr_early - pop ax ; UNDI code length - call writehex4 - call crlf - add ax,15 - shr ax,4 - add dx,ax ; DX = seg of end of UNDI code - - mov si,undi_data_msg - call writestr_early - pop ax ; UNDI data segment - call writehex4 - xchg bx,ax - mov si,len_msg - call writestr_early - pop ax ; UNDI data length - call writehex4 - call crlf - add ax,15 - shr ax,4 - add ax,bx ; AX = seg of end of UNDI data - - cmp ax,dx - ja .data_on_top - xchg ax,dx -.data_on_top: - ; Could we safely add 63 here before the shift? - shr ax,6 ; Convert to kilobytes - mov [RealBaseMem],ax - - -; -; Network-specific initialization -; - xor ax,ax - mov [LocalDomain],al ; No LocalDomain received - -; -; The DHCP client identifiers are best gotten from the DHCPREQUEST -; packet (query info 1). -; -query_bootp_1: - mov si,get_packet_msg - call writestr_early - - mov dl,1 - call pxe_get_cached_info - call parse_dhcp - - ; We don't use flags from the request packet, so - ; this is a good time to initialize DHCPMagic... - ; Initialize it to 1 meaning we will accept options found; - ; in earlier versions of PXELINUX bit 0 was used to indicate - ; we have found option 208 with the appropriate magic number; - ; we no longer require that, but MAY want to re-introduce - ; it in the future for vendor encapsulated options. - mov byte [DHCPMagic],1 - -; -; Now attempt to get the BOOTP/DHCP packet that brought us life (and an IP -; address). This lives in the DHCPACK packet (query info 2). -; -query_bootp_2: - mov dl,2 - call pxe_get_cached_info - call parse_dhcp ; Parse DHCP packet -; -; Save away MAC address (assume this is in query info 2. If this -; turns out to be problematic it might be better getting it from -; the query info 1 packet.) -; -.save_mac: - movzx cx,byte [trackbuf+bootp.hardlen] - cmp cx,16 - jna .mac_ok - xor cx,cx ; Bad hardware address length -.mac_ok: - mov [MACLen],cl - mov al,[trackbuf+bootp.hardware] - mov [MACType],al - mov si,trackbuf+bootp.macaddr - mov di,MAC - rep movsb - -; Enable this if we really need to zero-pad this field... -; mov cx,MAC+MAC_MAX+1 -; sub cx,di -; xor ax,ax -; rep stosb - -; -; Now, get the boot file and other info. This lives in the CACHED_REPLY -; packet (query info 3). -; -query_bootp_3: - mov dl,3 - call pxe_get_cached_info - call parse_dhcp ; Parse DHCP packet - call crlf - -; -; Generate the bootif string, and the hardware-based config string. -; -make_bootif_string: - mov si,bootif_str - mov di,BOOTIFStr - mov cx,bootif_str_len - rep movsb - - movzx cx,byte [MACLen] - mov si,MACType - inc cx -.hexify_mac: - push cx - mov cl,1 ; CH == 0 already - call lchexbytes - mov al,'-' - stosb - pop cx - loop .hexify_mac - mov [di-1],cl ; Null-terminate and strip final dash -; -; Generate ip= option -; - call genipopt - -; -; Print IP address -; - mov eax,[MyIP] - mov di,DotQuadBuf - push di - call gendotquad ; This takes network byte order input - - xchg ah,al ; Convert to host byte order - ror eax,16 ; (BSWAP doesn't work on 386) - xchg ah,al - - mov si,myipaddr_msg - call writestr_early - call writehex8 - mov al,' ' - call writechr - pop si ; DotQuadBuf - call writestr_early - call crlf - - mov si,IPOption - call writestr_early - call crlf - -; -; Check to see if we got any PXELINUX-specific DHCP options; in particular, -; if we didn't get the magic enable, do not recognize any other options. -; -check_dhcp_magic: - test byte [DHCPMagic], 1 ; If we didn't get the magic enable... - jnz .got_magic - mov byte [DHCPMagic], 0 ; If not, kill all other options -.got_magic: - - -; -; Initialize UDP stack -; -udp_init: - mov eax,[MyIP] - mov [pxe_udp_open_pkt.sip],eax - mov di,pxe_udp_open_pkt - mov bx,PXENV_UDP_OPEN - call pxenv - jc .failed - cmp word [pxe_udp_open_pkt.status], byte 0 - je .success -.failed: mov si,err_udpinit - call writestr_early - jmp kaboom -.success: + extern pxe_fs_ops + mov eax,pxe_fs_ops + pm_call fs_init ; ; Common initialization code @@ -607,9 +178,8 @@ udp_init: %include "cpuinit.inc" ; -; Detect NIC type and initialize the idle mechanism +; Initialize the idle mechanism ; - call pxe_detect_nic_type call reset_idle ; @@ -627,145 +197,9 @@ udp_init: ; ; -; Store standard filename prefix -; -prefix: test byte [DHCPMagic], 04h ; Did we get a path prefix option - jnz .got_prefix - mov si,BootFile - mov di,PathPrefix - cld - call strcpy - mov cx,di - sub cx,PathPrefix+1 - std - lea si,[di-2] ; Skip final null! -.find_alnum: lodsb - or al,20h - cmp al,'.' ; Count . or - as alphanum - je .alnum - cmp al,'-' - je .alnum - cmp al,'0' - jb .notalnum - cmp al,'9' - jbe .alnum - cmp al,'a' - jb .notalnum - cmp al,'z' - ja .notalnum -.alnum: loop .find_alnum - dec si -.notalnum: mov byte [si+2],0 ; Zero-terminate after delimiter - cld -.got_prefix: - mov si,tftpprefix_msg - call writestr_early - mov si,PathPrefix - call writestr_early - call crlf - - ; Set CurrentDirName - push di - mov si,PathPrefix - mov di,CurrentDirName - call strcpy - pop di - -; ; Load configuration file ; -find_config: - -; -; Begin looking for configuration file -; -config_scan: - test byte [DHCPMagic], 02h - jz .no_option - - ; We got a DHCP option, try it first - call .try - jnz .success - -.no_option: - mov di,ConfigName - mov si,cfgprefix - mov cx,cfgprefix_len - rep movsb - - ; Have to guess config file name... - - ; Try loading by UUID. - cmp byte [HaveUUID],0 - je .no_uuid - - push di - mov bx,uuid_dashes - mov si,UUID -.gen_uuid: - movzx cx,byte [bx] - jcxz .done_uuid - inc bx - call lchexbytes - mov al,'-' - stosb - jmp .gen_uuid -.done_uuid: - mov [di-1],cl ; Remove last dash and zero-terminate - pop di - call .try - jnz .success -.no_uuid: - - ; Try loading by MAC address - push di - mov si,MACStr - call strcpy - pop di - call .try - jnz .success - - ; Nope, try hexadecimal IP prefixes... -.scan_ip: - mov cx,4 - mov si,MyIP - call uchexbytes ; Convert to hex string - - mov cx,8 ; Up to 8 attempts -.tryagain: - mov byte [di],0 ; Zero-terminate string - call .try - jnz .success - dec di ; Drop one character - loop .tryagain - - ; Final attempt: "default" string - mov si,default_str ; "default" string - call strcpy - call .try - jnz .success - - mov si,err_noconfig - call writestr_early - jmp kaboom - -.try: - pusha - mov si,trying_msg - call writestr_early - mov di,ConfigName - mov si,di - call writestr_early - call crlf - mov si,di - mov di,KernelName ; Borrow this buffer for mangled name - call mangle_name - call open - popa - ret - - -.success: + pm_call load_config ; ; Linux kernel loading code is common. However, we need to define @@ -775,7 +209,7 @@ config_scan: ; Unload PXE stack %define HAVE_UNLOAD_PREP %macro UNLOAD_PREP 0 - call unload_pxe + pm_call unload_pxe %endmacro ; @@ -814,6 +248,7 @@ local_boot: ; kaboom: write a message and bail out. Wait for quite a while, ; or a user keypress, then do a hard reboot. ; + global kaboom kaboom: RESET_STACK_AND_SEGS AX .patch: mov si,bailmsg @@ -848,759 +283,6 @@ kaboom: mov word [BIOS_magic],0 ; Cold reboot jmp 0F000h:0FFF0h ; Reset vector address -; -; memory_scan_for_pxe_struct: -; memory_scan_for_pxenv_struct: -; -; If none of the standard methods find the !PXE/PXENV+ structure, -; look for it by scanning memory. -; -; On exit, if found: -; ZF = 1, ES:BX -> !PXE structure -; Otherwise: -; ZF = 0 -; -; Assumes DS == CS -; Clobbers AX, BX, CX, DX, SI, ES -; -memory_scan_for_pxe_struct: - mov dx,is_pxe - mov ax,[BIOS_fbm] ; Starting segment - shl ax,(10-4) ; Kilobytes -> paragraphs - jmp memory_scan_common - -memory_scan_for_pxenv_struct: - mov ax,1000h ; Starting segment - mov dx,is_pxenv - ; fall through - -memory_scan_common: - dec ax ; To skip inc ax -.mismatch: - inc ax - cmp ax,0A000h-1 ; End of memory - ja .not_found ; ZF = 0 on not found - mov es,ax - xor bx,bx - call dx - jne .mismatch -.not_found: - ret - -; -; is_pxe: -; Validity check on possible !PXE structure in ES:BX -; is_pxenv: -; Validity check on possible PXENV+ structure in ES:BX -; -; Return ZF = 1 on success -; -; Clobbers CX and SI -; -is_struc: -.pxe: - cmp dword [es:bx],'!PXE' - jne .bad - movzx cx,byte [es:bx+4] - cmp cx,58h - jae .checksum - ret -.pxenv: - cmp dword [es:bx],'PXEN' - jne .bad - cmp word [es:bx+4],'V+' - jne .bad - movzx cx,[es:bx+8] - cmp cx,28h - jb .bad -.checksum: - push ax - mov si,bx - xor ax,ax -.loop: - es lodsb - add ah,al - loop .loop - pop ax -.bad: - ret - -is_pxe equ is_struc.pxe -is_pxenv equ is_struc.pxenv - -; -; close_file: -; Deallocates a file structure (pointer in SI) -; Assumes CS == DS. -; -; XXX: We should check to see if this file is still open on the server -; side and send a courtesy ERROR packet to the server. -; -close_file: - and si,si - jz .closed - mov word [si],0 ; Not in use -.closed: ret - -; -; searchdir: -; -; Open a TFTP connection to the server -; -; On entry: -; DS:DI = mangled filename -; If successful: -; ZF clear -; SI = socket pointer -; EAX = file length in bytes, or -1 if unknown -; If unsuccessful -; ZF set -; - -searchdir: - push es - push bx - push cx - mov ax,ds - mov es,ax - mov si,di - push bp - mov bp,sp - - call allocate_socket - jz .ret - - mov ax,TimeoutTable ; Reset timeout - -.sendreq: push ax ; [bp-2] - Timeout pointer - push si ; [bp-4] - File name - - mov di,packet_buf - mov [pxe_udp_write_pkt.buffer],di - - mov ax,TFTP_RRQ ; TFTP opcode - stosw - - lodsd ; EAX <- server override (if any) - and eax,eax - jnz .noprefix ; No prefix, and we have the server - - push si ; Add common prefix - mov si,PathPrefix - call strcpy - dec di - pop si - - mov eax,[ServerIP] ; Get default server - -.noprefix: - call strcpy ; Filename -%if GPXE - mov si,packet_buf+2 - call is_gpxe - jnc .gpxe -%endif - - mov [bx+tftp_remoteip],eax - - push bx ; [bp-6] - TFTP block - mov bx,[bx] - push bx ; [bp-8] - TID (local port no) - - mov [pxe_udp_write_pkt.sip],eax - ; Now figure out the gateway - xor eax,[MyIP] - and eax,[Netmask] - jz .nogwneeded - mov eax,[Gateway] -.nogwneeded: - mov [pxe_udp_write_pkt.gip],eax - mov [pxe_udp_write_pkt.lport],bx - mov ax,[ServerPort] - mov [pxe_udp_write_pkt.rport],ax - mov si,tftp_tail - mov cx,tftp_tail_len - rep movsb - sub di,packet_buf ; Get packet size - mov [pxe_udp_write_pkt.buffersize],di - - mov di,pxe_udp_write_pkt - mov bx,PXENV_UDP_WRITE - call pxenv - jc .failure - cmp word [pxe_udp_write_pkt.status],byte 0 - jne .failure - - ; - ; Danger, Will Robinson! We need to support timeout - ; and retry lest we just lost a packet... - ; - - ; Packet transmitted OK, now we need to receive -.getpacket: mov bx,[bp-2] - movzx bx,byte [bx] - push bx ; [bp-10] - timeout in ticks - push word [BIOS_timer] ; [bp-12] - -.pkt_loop: mov bx,[bp-8] ; TID - mov di,packet_buf - mov [pxe_udp_read_pkt.buffer],di - mov [pxe_udp_read_pkt.buffer+2],ds - mov word [pxe_udp_read_pkt.buffersize],packet_buf_size - mov eax,[MyIP] - mov [pxe_udp_read_pkt.dip],eax - mov [pxe_udp_read_pkt.lport],bx - mov di,pxe_udp_read_pkt - mov bx,PXENV_UDP_READ - call pxenv - jnc .got_packet ; Wait for packet -.no_packet: - mov dx,[BIOS_timer] - cmp dx,[bp-12] - je .pkt_loop - mov [bp-12],dx - dec word [bp-10] - jnz .pkt_loop - pop ax ; Adjust stack - pop ax - jmp .failure - -.got_packet: - mov si,[bp-6] ; TFTP pointer - mov bx,[bp-8] ; TID - - ; Make sure the packet actually came from the server - ; This is technically not to the TFTP spec? - mov eax,[si+tftp_remoteip] - cmp [pxe_udp_read_pkt.sip],eax - jne .no_packet - - ; Got packet - reset timeout - mov word [bp-2],TimeoutTable - - pop ax ; Adjust stack - pop ax - - mov ax,[pxe_udp_read_pkt.rport] - mov [si+tftp_remoteport],ax - - ; filesize <- -1 == unknown - mov dword [si+tftp_filesize], -1 - ; Default blksize unless blksize option negotiated - mov word [si+tftp_blksize], TFTP_BLOCKSIZE - - movzx ecx,word [pxe_udp_read_pkt.buffersize] - sub cx,2 ; CX <- bytes after opcode - jb .failure ; Garbled reply - - mov si,packet_buf - lodsw - - cmp ax, TFTP_ERROR - je .bailnow ; ERROR reply: don't try again - - ; If the server doesn't support any options, we'll get - ; a DATA reply instead of OACK. Stash the data in - ; the file buffer and go with the default value for - ; all options... - cmp ax, TFTP_DATA - je .no_oack - - cmp ax, TFTP_OACK - jne .err_reply ; Unknown packet type - - ; Now we need to parse the OACK packet to get the transfer - ; and packet sizes. - ; SI -> first byte of options; [E]CX -> byte count -.parse_oack: - jcxz .done_pkt ; No options acked - -.get_opt_name: - ; If we find an option which starts with a NUL byte, - ; (a null option), we're either seeing garbage that some - ; TFTP servers add to the end of the packet, or we have - ; no clue how to parse the rest of the packet (what is - ; an option name and what is a value?) In either case, - ; discard the rest. - cmp byte [si],0 - je .done_pkt - - mov di,si - mov bx,si -.opt_name_loop: lodsb - and al,al - jz .got_opt_name - or al,20h ; Convert to lowercase - stosb - loop .opt_name_loop - ; We ran out, and no final null - jmp .done_pkt ; Ignore runt option -.got_opt_name: ; si -> option value - dec cx ; bytes left in pkt - jz .done_pkt ; Option w/o value, ignore - - ; Parse option pointed to by bx; guaranteed to be - ; null-terminated. - push cx - push si - mov si,bx ; -> option name - mov bx,tftp_opt_table - mov cx,tftp_opts -.opt_loop: - push cx - push si - mov di,[bx] ; Option pointer - mov cx,[bx+2] ; Option len - repe cmpsb - pop si - pop cx - je .get_value ; OK, known option - add bx,6 - loop .opt_loop - - pop si - pop cx - ; Non-negotiated option returned, no idea what it means... - jmp .err_reply - -.get_value: pop si ; si -> option value - pop cx ; cx -> bytes left in pkt - mov bx,[bx+4] ; Pointer to data target - add bx,[bp-6] ; TFTP socket pointer - xor eax,eax - xor edx,edx -.value_loop: lodsb - and al,al - jz .got_value - sub al,'0' - cmp al, 9 - ja .err_reply ; Not a decimal digit - imul edx,10 - add edx,eax - mov [bx],edx - loop .value_loop - ; Ran out before final null, accept anyway - jmp short .done_pkt - -.got_value: - dec cx - jnz .get_opt_name ; Not end of packet - - ; ZF == 1 - - ; Success, done! -.done_pkt: - pop si ; Junk - pop si ; We want the packet ptr in SI - - mov eax,[si+tftp_filesize] -.got_file: ; SI->socket structure, EAX = size - and eax,eax ; Set ZF depending on file size - jz .error_si ; ZF = 1 need to free the socket -.ret: - leave ; SP <- BP, POP BP - pop cx - pop bx - pop es - ret - - -.no_oack: ; We got a DATA packet, meaning no options are - ; suported. Save the data away and consider the length - ; undefined, *unless* this is the only data packet... - mov bx,[bp-6] ; File pointer - sub cx,2 ; Too short? - jb .failure - lodsw ; Block number - cmp ax,htons(1) - jne .failure - mov [bx+tftp_lastpkt],ax - cmp cx,TFTP_BLOCKSIZE - ja .err_reply ; Corrupt... - je .not_eof - ; This was the final EOF packet, already... - ; We know the filesize, but we also want to ack the - ; packet and set the EOF flag. - mov [bx+tftp_filesize],ecx - mov byte [bx+tftp_goteof],1 - push si - mov si,bx - ; AX = htons(1) already - call ack_packet - pop si -.not_eof: - mov [bx+tftp_bytesleft],cx - mov ax,pktbuf_seg - push es - mov es,ax - mov di,tftp_pktbuf - mov [bx+tftp_dataptr],di - add cx,3 - shr cx,2 - rep movsd - pop es - jmp .done_pkt - -.err_reply: ; TFTP protocol error. Send ERROR reply. - ; ServerIP and gateway are already programmed in - mov si,[bp-6] - mov ax,[si+tftp_remoteport] - mov word [pxe_udp_write_pkt.rport],ax - mov word [pxe_udp_write_pkt.buffer],tftp_proto_err - mov word [pxe_udp_write_pkt.buffersize],tftp_proto_err_len - mov di,pxe_udp_write_pkt - mov bx,PXENV_UDP_WRITE - call pxenv - - ; Write an error message and explode - mov si,err_damage - call writestr_early - jmp kaboom - -.bailnow: - ; Immediate error - no retry - mov word [bp-2],TimeoutTableEnd-1 - -.failure: pop bx ; Junk - pop bx - pop si - pop ax - inc ax - cmp ax,TimeoutTableEnd - jb .sendreq ; Try again - -.error: mov si,bx ; Socket pointer -.error_si: ; Socket pointer already in SI - call free_socket ; ZF <- 1, SI <- 0 - jmp .ret - - -%if GPXE -.gpxe: - push bx ; Socket pointer - mov di,gpxe_file_open - mov word [di],2 ; PXENV_STATUS_BAD_FUNC - mov word [di+4],packet_buf+2 ; Completed URL - mov [di+6],ds - mov bx,PXENV_FILE_OPEN - call pxenv - pop si ; Socket pointer in SI - jc .error_si - - mov ax,[di+2] - mov word [si+tftp_localport],-1 ; gPXE URL - mov [si+tftp_remoteport],ax - mov di,gpxe_get_file_size - mov [di+2],ax - -%if 0 - ; Disable this for now since gPXE doesn't always - ; return valid information in PXENV_GET_FILE_SIZE - mov bx,PXENV_GET_FILE_SIZE - call pxenv - mov eax,[di+4] ; File size - jnc .oksize -%endif - or eax,-1 ; Size unknown -.oksize: - mov [si+tftp_filesize],eax - jmp .got_file -%endif ; GPXE - -; -; allocate_socket: Allocate a local UDP port structure -; -; If successful: -; ZF set -; BX = socket pointer -; If unsuccessful: -; ZF clear -; -allocate_socket: - push cx - mov bx,Files - mov cx,MAX_OPEN -.check: cmp word [bx], byte 0 - je .found - add bx,open_file_t_size - loop .check - xor cx,cx ; ZF = 1 - pop cx - ret - ; Allocate a socket number. Socket numbers are made - ; guaranteed unique by including the socket slot number - ; (inverted, because we use the loop counter cx); add a - ; counter value to keep the numbers from being likely to - ; get immediately reused. - ; - ; The NextSocket variable also contains the top two bits - ; set. This generates a value in the range 49152 to - ; 57343. -.found: - dec cx - push ax - mov ax,[NextSocket] - inc ax - and ax,((1 << (13-MAX_OPEN_LG2))-1) | 0xC000 - mov [NextSocket],ax - shl cx,13-MAX_OPEN_LG2 - add cx,ax ; ZF = 0 - xchg ch,cl ; Convert to network byte order - mov [bx],cx ; Socket in use - pop ax - pop cx - ret - -; -; Free socket: socket in SI; return SI = 0, ZF = 1 for convenience -; -free_socket: - push es - pusha - xor ax,ax - mov es,ax - mov di,si - mov cx,tftp_pktbuf >> 1 ; tftp_pktbuf is not cleared - rep stosw - popa - pop es - xor si,si - ret - -; -; parse_dotquad: -; Read a dot-quad pathname in DS:SI and output an IP -; address in EAX, with SI pointing to the first -; nonmatching character. -; -; Return CF=1 on error. -; -; No segment assumptions permitted. -; -parse_dotquad: - push cx - mov cx,4 - xor eax,eax -.parseloop: - mov ch,ah - mov ah,al - lodsb - sub al,'0' - jb .notnumeric - cmp al,9 - ja .notnumeric - aad ; AL += 10 * AH; AH = 0; - xchg ah,ch - jmp .parseloop -.notnumeric: - cmp al,'.'-'0' - pushf - mov al,ah - mov ah,ch - xor ch,ch - ror eax,8 - popf - jne .error - loop .parseloop - jmp .done -.error: - loop .realerror ; If CX := 1 then we're done - clc - jmp .done -.realerror: - stc -.done: - dec si ; CF unchanged! - pop cx - ret - -; -; is_url: Return CF=0 if and only if the buffer pointed to by -; DS:SI is a URL (contains ://). No registers modified. -; -%if GPXE -is_url: - push si - push eax -.loop: - mov eax,[si] - inc si - and al,al - jz .not_url - and eax,0FFFFFFh - cmp eax,'://' - jne .loop -.done: - ; CF=0 here - pop eax - pop si - ret -.not_url: - stc - jmp .done - -; -; is_gpxe: Return CF=0 if and only if the buffer pointed to by -; DS:SI is a URL (contains ://) *and* the gPXE extensions -; API is available. No registers modified. -; -is_gpxe: - call is_url - jc .ret ; Not a URL, don't bother -.again: - cmp byte [HasGPXE],1 - ja .unknown - ; CF=1 if not available (0), - ; CF=0 if known available (1). -.ret: ret - -.unknown: - ; If we get here, the gPXE status is unknown. - push es - pushad - push ds - pop es - mov di,gpxe_file_api_check - mov bx,PXENV_FILE_API_CHECK ; BH = 0 - call pxenv - jc .nogood - cmp dword [di+4],0xe9c17b20 - jne .nogood - mov ax,[di+12] ; Don't care about the upper half... - not ax ; Set bits of *missing* functions... - and ax,01001011b ; The functions we care about - setz bh - jz .done -.nogood: - mov si,gpxe_warning_msg - call writestr_early -.done: - mov [HasGPXE],bh - popad - pop es - jmp .again - - section .data16 -gpxe_warning_msg: - db 'URL syntax, but gPXE extensions not detected, ' - db 'trying plain TFTP...', CR, LF, 0 -HasGPXE db -1 ; Unknown - section .text16 - -%endif - -; -; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed -; to by ES:DI; ends on encountering any whitespace. -; DI is preserved. -; -; This verifies that a filename is < FILENAME_MAX characters -; and doesn't contain whitespace, and zero-pads the output buffer, -; so "repe cmpsb" can do a compare. -; -; The first four bytes of the manged name is the IP address of -; the download host, 0 for no host, or -1 for a gPXE URL. -; -; No segment assumptions permitted. -; -mangle_name: - push di -%if GPXE - call is_url - jc .not_url - or eax,-1 ; It's a URL - jmp .prefix_done -.not_url: -%endif ; GPXE - push si - mov eax,[cs:ServerIP] - cmp byte [si],0 - je .noip ; Null filename?!?! - cmp word [si],'::' ; Leading ::? - je .gotprefix - -.more: - inc si - cmp byte [si],0 - je .noip - cmp word [si],'::' - jne .more - - ; We have a :: prefix of some sort, it could be either - ; a DNS name or a dot-quad IP address. Try the dot-quad - ; first... -.here: - pop si - push si - call parse_dotquad - jc .notdq - cmp word [si],'::' - je .gotprefix -.notdq: - pop si - push si - call dns_resolv - cmp word [si],'::' - jne .noip - and eax,eax - jnz .gotprefix - -.noip: - pop si - xor eax,eax - jmp .prefix_done - -.gotprefix: - pop cx ; Adjust stack - inc si ; Skip double colon - inc si - -.prefix_done: - stosd ; Save IP address prefix - mov cx,FILENAME_MAX-5 - -.mn_loop: - lodsb - cmp al,' ' ; If control or space, end - jna .mn_end - stosb - loop .mn_loop -.mn_end: - inc cx ; At least one null byte - xor ax,ax ; Zero-fill name - rep stosb ; Doesn't do anything if CX=0 - pop di - ret ; Done - -; -; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled -; filename to the conventional representation. This is needed -; for the BOOT_IMAGE= parameter for the kernel. -; -; NOTE: The output buffer needs to be able to hold an -; expanded IP address. -; -; DS:SI -> input mangled file name -; ES:DI -> output buffer -; -; On return, DI points to the first byte after the output name, -; which is set to a null byte. -; -unmangle_name: - push eax - lodsd - and eax,eax - jz .noip - cmp eax,-1 - jz .noip ; URL - call gendotquad - mov ax,'::' - stosw -.noip: - call strcpy - dec di ; Point to final null byte - pop eax - ret ; ; pxenv @@ -1613,6 +295,7 @@ unmangle_name: ; ; While we're at it, save and restore all registers. ; + global pxenv pxenv: pushfd pushad @@ -1647,906 +330,32 @@ pxenv: ret ; Must be after function def due to NASM bug + global PXEEntry PXEEntry equ pxenv.jump+1 section .bss16 alignb 2 PXEStatus resb 2 - section .text16 - -; -; getfssec: Get multiple clusters from a file, given the starting cluster. -; -; In this case, get multiple blocks from a specific TCP connection. -; -; On entry: -; ES:BX -> Buffer -; SI -> TFTP socket pointer -; CX -> 512-byte block count; 0FFFFh = until end of file -; On exit: -; SI -> TFTP socket pointer (or 0 on EOF) -; CF = 1 -> Hit EOF -; ECX -> number of bytes actually read -; -getfssec: - push eax - push edi - push bx - push si - push fs - mov di,bx - mov ax,pktbuf_seg - mov fs,ax - - xor eax,eax - movzx ecx,cx - shl ecx,TFTP_BLOCKSIZE_LG2 ; Convert to bytes - push ecx ; Initial request size - jz .hit_eof ; Nothing to do? - -.need_more: - call fill_buffer - movzx eax,word [si+tftp_bytesleft] - and ax,ax - jz .hit_eof - - push ecx - cmp ecx,eax - jna .ok_size - mov ecx,eax -.ok_size: - mov ax,cx ; EAX<31:16> == ECX<31:16> == 0 - mov bx,[si+tftp_dataptr] - sub [si+tftp_bytesleft],cx - xchg si,bx - fs rep movsb ; Copy from packet buffer - xchg si,bx - mov [si+tftp_dataptr],bx - - pop ecx - sub ecx,eax - jnz .need_more - -.hit_eof: - call fill_buffer - - pop eax ; Initial request amount - xchg eax,ecx - sub ecx,eax ; ... minus anything not gotten - - pop fs - pop si - - ; Is there anything left of this? - mov eax,[si+tftp_filesize] - sub eax,[si+tftp_filepos] - jnz .bytes_left - - cmp [si+tftp_bytesleft],ax ; AX == 0 - jne .bytes_left - - cmp byte [si+tftp_goteof],0 - je .done - ; I'm 99% sure this can't happen, but... - call fill_buffer ; Receive/ACK the EOF packet -.done: - ; The socket is closed and the buffer drained - ; Close socket structure and re-init for next user - call free_socket - stc - jmp .ret -.bytes_left: - clc -.ret: - pop bx - pop edi - pop eax - ret - -; -; Get a fresh packet if the buffer is drained, and we haven't hit -; EOF yet. The buffer should be filled immediately after draining! -; -; expects fs -> pktbuf_seg and ds:si -> socket structure -; -fill_buffer: - cmp word [si+tftp_bytesleft],0 - je .empty - ret ; Otherwise, nothing to do - -.empty: - push es - pushad - mov ax,ds - mov es,ax - - ; Note: getting the EOF packet is not the same thing - ; as tftp_filepos == tftp_filesize; if the EOF packet - ; is empty the latter condition can be true without - ; having gotten the official EOF. - cmp byte [si+tftp_goteof],0 - jne .ret ; Already EOF - -%if GPXE - cmp word [si+tftp_localport], -1 - jne .get_packet_tftp - call get_packet_gpxe - jmp .ret -.get_packet_tftp: -%endif ; GPXE - - ; TFTP code... -.packet_loop: - ; Start by ACKing the previous packet; this should cause the - ; next packet to be sent. - mov bx,TimeoutTable - -.send_ack: push bx ; <D> Retry pointer - movzx cx,byte [bx] ; Timeout - - mov ax,[si+tftp_lastpkt] - call ack_packet ; Send ACK - - ; We used to test the error code here, but sometimes - ; PXE would return negative status even though we really - ; did send the ACK. Now, just treat a failed send as - ; a normally lost packet, and let it time out in due - ; course of events. - -.send_ok: ; Now wait for packet. - mov dx,[BIOS_timer] ; Get current time - -.wait_data: push cx ; <E> Timeout - push dx ; <F> Old time - - mov bx,[si+tftp_pktbuf] - mov [pxe_udp_read_pkt.buffer],bx - mov [pxe_udp_read_pkt.buffer+2],fs - mov [pxe_udp_read_pkt.buffersize],word PKTBUF_SIZE - mov eax,[si+tftp_remoteip] - mov [pxe_udp_read_pkt.sip],eax - mov eax,[MyIP] - mov [pxe_udp_read_pkt.dip],eax - mov ax,[si+tftp_remoteport] - mov [pxe_udp_read_pkt.rport],ax - mov ax,[si+tftp_localport] - mov [pxe_udp_read_pkt.lport],ax - mov di,pxe_udp_read_pkt - mov bx,PXENV_UDP_READ - call pxenv - jnc .recv_ok - - ; No packet, or receive failure - mov dx,[BIOS_timer] - pop ax ; <F> Old time - pop cx ; <E> Timeout - cmp ax,dx ; Same time -> don't advance timeout - je .wait_data ; Same clock tick - loop .wait_data ; Decrease timeout - - pop bx ; <D> Didn't get any, send another ACK - inc bx - cmp bx,TimeoutTableEnd - jb .send_ack - jmp kaboom ; Forget it... - -.recv_ok: pop dx ; <F> - pop cx ; <E> - - cmp word [pxe_udp_read_pkt.buffersize],byte 4 - jb .wait_data ; Bad size for a DATA packet - - mov bx,[si+tftp_pktbuf] - cmp word [fs:bx],TFTP_DATA ; Not a data packet? - jne .wait_data ; Then wait for something else - - mov ax,[si+tftp_lastpkt] - xchg ah,al ; Host byte order - inc ax ; Which packet are we waiting for? - xchg ah,al ; Network byte order - cmp [fs:bx+2],ax - je .right_packet - - ; Wrong packet, ACK the packet and then try again - ; This is presumably because the ACK got lost, - ; so the server just resent the previous packet - mov ax,[fs:bx+2] - call ack_packet - jmp .send_ok ; Reset timeout - -.right_packet: ; It's the packet we want. We're also EOF if the - ; size < blocksize - - pop cx ; <D> Don't need the retry count anymore - - mov [si+tftp_lastpkt],ax ; Update last packet number - - movzx ecx,word [pxe_udp_read_pkt.buffersize] - sub cx,byte 4 ; Skip TFTP header - - ; Set pointer to data block - lea ax,[bx+4] ; Data past TFTP header - mov [si+tftp_dataptr],ax - - add [si+tftp_filepos],ecx - mov [si+tftp_bytesleft],cx - - cmp cx,[si+tftp_blksize] ; Is it a full block? - jb .last_block ; If not, it's EOF - -.ret: - popad - pop es - ret - - -.last_block: ; Last block - ACK packet immediately - mov ax,[fs:bx+2] - call ack_packet - - ; Make sure we know we are at end of file - mov eax,[si+tftp_filepos] - mov [si+tftp_filesize],eax - mov byte [si+tftp_goteof],1 - - jmp .ret - -; -; TimeoutTable: list of timeouts (in 18.2 Hz timer ticks) -; -; This is roughly an exponential backoff... -; - section .data16 -TimeoutTable: - db 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18 - db 21, 26, 31, 37, 44, 53, 64, 77, 92, 110, 132 - db 159, 191, 229, 255, 255, 255, 255 -TimeoutTableEnd equ $ - - section .text16 -; -; ack_packet: -; -; Send ACK packet. This is a common operation and so is worth canning. -; -; Entry: -; SI = TFTP block -; AX = Packet # to ack (network byte order) -; Exit: -; All registers preserved -; -; This function uses the pxe_udp_write_pkt but not the packet_buf. -; -ack_packet: - pushad - mov [ack_packet_buf+2],ax ; Packet number to ack - mov ax,[si] - mov [pxe_udp_write_pkt.lport],ax - mov ax,[si+tftp_remoteport] - mov [pxe_udp_write_pkt.rport],ax - mov eax,[si+tftp_remoteip] - mov [pxe_udp_write_pkt.sip],eax - xor eax,[MyIP] - and eax,[Netmask] - jz .nogw - mov eax,[Gateway] -.nogw: - mov [pxe_udp_write_pkt.gip],eax - mov [pxe_udp_write_pkt.buffer],word ack_packet_buf - mov [pxe_udp_write_pkt.buffersize], word 4 - mov di,pxe_udp_write_pkt - mov bx,PXENV_UDP_WRITE - call pxenv - popad - ret - -%if GPXE -; -; Get a fresh packet from a gPXE socket; expects fs -> pktbuf_seg -; and ds:si -> socket structure -; -; Assumes CS == DS == ES. -; -get_packet_gpxe: - mov di,gpxe_file_read - - mov ax,[si+tftp_remoteport] ; gPXE filehandle - mov [di+2],ax - mov ax,[si+tftp_pktbuf] - mov [di+6],ax - mov [si+tftp_dataptr],ax - mov [di+8],fs - -.again: - mov word [di+4],PKTBUF_SIZE - mov bx,PXENV_FILE_READ - call pxenv - jnc .ok ; Got data or EOF - cmp word [di],PXENV_STATUS_TFTP_OPEN ; == EWOULDBLOCK - je .again - jmp kaboom ; Otherwise error... - -.ok: - movzx eax,word [di+4] ; Bytes read - mov [si+tftp_bytesleft],ax ; Bytes in buffer - add [si+tftp_filepos],eax ; Position in file - - and ax,ax ; EOF? - mov eax,[si+tftp_filepos] - - jnz .got_stuff - - ; We got EOF here, make sure the upper layers know - mov [si+tftp_filesize],eax - -.got_stuff: - ; If we're done here, close the file - cmp [si+tftp_filesize],eax - ja .done ; Not EOF, there is still data... - - ; Reuse the previous [es:di] structure since the - ; relevant fields are all the same - mov byte [si+tftp_goteof],1 - - mov bx,PXENV_FILE_CLOSE - call pxenv - ; Ignore return... -.done: - ret -%endif ; GPXE - -; -; unload_pxe: -; -; This function unloads the PXE and UNDI stacks and unclaims -; the memory. -; -unload_pxe: - cmp byte [KeepPXE],0 ; Should we keep PXE around? - jne reset_pxe - - push ds - push es - - mov ax,cs - mov ds,ax - mov es,ax - - mov si,new_api_unload - cmp byte [APIVer+1],2 ; Major API version >= 2? - jae .new_api - mov si,old_api_unload -.new_api: - -.call_loop: xor ax,ax - lodsb - and ax,ax - jz .call_done - xchg bx,ax - mov di,pxe_unload_stack_pkt - push di - xor ax,ax - mov cx,pxe_unload_stack_pkt_len >> 1 - rep stosw - pop di - call pxenv - jc .cant_free - mov ax,word [pxe_unload_stack_pkt.status] - cmp ax,PXENV_STATUS_SUCCESS - jne .cant_free - jmp .call_loop - -.call_done: - mov bx,0FF00h - - mov dx,[RealBaseMem] - cmp dx,[BIOS_fbm] ; Sanity check - jna .cant_free - inc bx - - ; Check that PXE actually unhooked the INT 1Ah chain - movzx eax,word [4*0x1a] - movzx ecx,word [4*0x1a+2] - shl ecx,4 - add eax,ecx - shr eax,10 - cmp ax,dx ; Not in range - jae .ok - cmp ax,[BIOS_fbm] - jae .cant_free - ; inc bx - -.ok: - mov [BIOS_fbm],dx -.pop_ret: - pop es - pop ds - ret - -.cant_free: - mov si,cant_free_msg - call writestr_early - push ax - xchg bx,ax - call writehex4 - mov al,'-' - call writechr - pop ax - call writehex4 - mov al,'-' - call writechr - mov eax,[4*0x1a] - call writehex8 - call crlf - jmp .pop_ret - - ; We want to keep PXE around, but still we should reset - ; it to the standard bootup configuration -reset_pxe: - push es - push cs - pop es - mov bx,PXENV_UDP_CLOSE - mov di,pxe_udp_close_pkt - call pxenv - pop es - ret - -; -; gendotquad -; -; Take an IP address (in network byte order) in EAX and -; output a dotted quad string to ES:DI. -; DI points to terminal null at end of string on exit. -; -gendotquad: - push eax - push cx - mov cx,4 -.genchar: - push eax - cmp al,10 ; < 10? - jb .lt10 ; If so, skip first 2 digits - - cmp al,100 ; < 100 - jb .lt100 ; If so, skip first digit - - aam 100 - ; Now AH = 100-digit; AL = remainder - add ah,'0' - mov [es:di],ah - inc di - -.lt100: - aam 10 - ; Now AH = 10-digit; AL = remainder - add ah,'0' - mov [es:di],ah - inc di - -.lt10: - add al,'0' - stosb - mov al,'.' - stosb - pop eax - ror eax,8 ; Move next char into LSB - loop .genchar - dec di - mov [es:di], byte 0 - pop cx - pop eax - ret -; -; uchexbytes/lchexbytes -; -; Take a number of bytes in memory and convert to upper/lower-case -; hexadecimal -; -; Input: -; DS:SI = input bytes -; ES:DI = output buffer -; CX = number of bytes -; Output: -; DS:SI = first byte after -; ES:DI = first byte after -; CX = 0 -; -; Trashes AX, DX -; - -lchexbytes: - mov dl,'a'-'9'-1 - jmp xchexbytes -uchexbytes: - mov dl,'A'-'9'-1 -xchexbytes: -.loop: - lodsb - mov ah,al - shr al,4 - call .outchar - mov al,ah - call .outchar - loop .loop - ret -.outchar: - and al,0Fh - add al,'0' - cmp al,'9' - jna .done - add al,dl -.done: - stosb - ret - -; -; pxe_get_cached_info -; -; Get a DHCP packet from the PXE stack into the trackbuf. -; -; Input: -; DL = packet type -; Output: -; CX = buffer size -; -; Assumes CS == DS == ES. -; -pxe_get_cached_info: - pushad - mov al,' ' - call writechr - mov al,dl - call writehex2 - mov di,pxe_bootp_query_pkt - push di - xor ax,ax - stosw ; Status - movzx ax,dl - stosw ; Packet type - mov ax,trackbufsize - stosw ; Buffer size - mov ax,trackbuf - stosw ; Buffer offset - xor ax,ax - stosw ; Buffer segment - - pop di ; DI -> parameter set - mov bx,PXENV_GET_CACHED_INFO - call pxenv - jc .err - - popad - mov cx,[pxe_bootp_query_pkt.buffersize] - ret - -.err: - mov si,err_pxefailed - call writestr_early - call writehex4 - call crlf - jmp kaboom - - section .data16 -get_packet_msg db 'Getting cached packet', 0 section .text16 ; -; ip_ok +; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method +; for finding the PXE entry point. ; -; Tests an IP address in EAX for validity; return with ZF=1 for bad. -; We used to refuse class E, but class E addresses are likely to become -; assignable unicast addresses in the near future. -; -ip_ok: - push ax - cmp eax,-1 ; Refuse the all-ones address - jz .out - and al,al ; Refuse network zero - jz .out - cmp al,127 ; Refuse loopback - jz .out - and al,0F0h - cmp al,224 ; Refuse class D -.out: - pop ax - ret - -; -; parse_dhcp -; -; Parse a DHCP packet. This includes dealing with "overloaded" -; option fields (see RFC 2132, section 9.3) -; -; This should fill in the following global variables, if the -; information is present: -; -; MyIP - client IP address -; ServerIP - boot server IP address -; Netmask - network mask -; Gateway - default gateway router IP -; BootFile - boot file name -; DNSServers - DNS server IPs -; LocalDomain - Local domain name -; MACLen, MAC - Client identifier, if MACLen == 0 -; -; This assumes the DHCP packet is in "trackbuf" and the length -; of the packet in in CX on entry. -; - -parse_dhcp: - mov byte [OverLoad],0 ; Assume no overload - mov eax, [trackbuf+bootp.yip] - call ip_ok - jz .noyip - mov [MyIP], eax -.noyip: - mov eax, [trackbuf+bootp.sip] - and eax, eax - call ip_ok - jz .nosip - mov [ServerIP], eax -.nosip: - sub cx, bootp.options - jbe .nooptions - mov si, trackbuf+bootp.option_magic - lodsd - cmp eax, BOOTP_OPTION_MAGIC - jne .nooptions - call parse_dhcp_options -.nooptions: - mov si, trackbuf+bootp.bootfile - test byte [OverLoad],1 - jz .nofileoverload - mov cx,128 - call parse_dhcp_options - jmp short .parsed_file -.nofileoverload: - cmp byte [si], 0 - jz .parsed_file ; No bootfile name - mov di,BootFile - mov cx,32 - rep movsd - xor al,al - stosb ; Null-terminate -.parsed_file: - mov si, trackbuf+bootp.sname - test byte [OverLoad],2 - jz .nosnameoverload - mov cx,64 - call parse_dhcp_options -.nosnameoverload: - ret - -; -; Parse a sequence of DHCP options, pointed to by DS:SI; the field -; size is CX -- some DHCP servers leave option fields unterminated -; in violation of the spec. -; -; For parse_some_dhcp_options, DH contains the minimum value for -; the option to recognize -- this is used to restrict parsing to -; PXELINUX-specific options only. -; -parse_dhcp_options: - xor dx,dx - -parse_some_dhcp_options: -.loop: - and cx,cx - jz .done - - lodsb - dec cx - jz .done ; Last byte; must be PAD, END or malformed - cmp al, 0 ; PAD option - je .loop - cmp al,255 ; END option - je .done - - ; Anything else will have a length field - mov dl,al ; DL <- option number - xor ax,ax - lodsb ; AX <- option length - dec cx - sub cx,ax ; Decrement bytes left counter - jb .done ; Malformed option: length > field size - - cmp dl,dh ; Is the option value valid? - jb .opt_done - - mov bx,dhcp_option_list -.find_option: - cmp bx,dhcp_option_list_end - jae .opt_done - cmp dl,[bx] - je .found_option - add bx,3 - jmp .find_option -.found_option: - pushad - call [bx+1] - popad - -; Fall through - ; Unknown option. Skip to the next one. -.opt_done: - add si,ax - jmp .loop -.done: - ret - - section .data16 -dhcp_option_list: - section .text16 - -%macro dopt 2 - section .data16 - db %1 - dw dopt_%2 - section .text16 -dopt_%2: -%endmacro - -; -; Parse individual DHCP options. SI points to the option data and -; AX to the option length. DL contains the option number. -; All registers are saved around the routine. -; - dopt 1, subnet_mask - mov ebx,[si] - mov [Netmask],ebx - ret - - dopt 3, router - mov ebx,[si] - mov [Gateway],ebx - ret - - dopt 6, dns_servers - mov cx,ax - shr cx,2 - cmp cl,DNS_MAX_SERVERS - jna .oklen - mov cl,DNS_MAX_SERVERS -.oklen: - mov di,DNSServers - rep movsd - mov [LastDNSServer],di - ret - - dopt 15, local_domain - mov bx,si - add bx,ax - xor ax,ax - xchg [bx],al ; Zero-terminate option - mov di,LocalDomain - call dns_mangle ; Convert to DNS label set - mov [bx],al ; Restore ending byte - ret - - dopt 43, vendor_encaps - mov dh,208 ; Only recognize PXELINUX options - mov cx,ax ; Length of option = max bytes to parse - call parse_some_dhcp_options ; Parse recursive structure - ret - - dopt 52, option_overload - mov bl,[si] - mov [OverLoad],bl - ret - - dopt 54, server - mov eax,[si] - cmp dword [ServerIP],0 - jne .skip ; Already have a next server IP - call ip_ok - jz .skip - mov [ServerIP],eax -.skip: ret - - dopt 61, client_identifier - cmp ax,MAC_MAX ; Too long? - ja .skip - cmp ax,2 ; Too short? - jb .skip - cmp [MACLen],ah ; Only do this if MACLen == 0 - jne .skip - push ax - lodsb ; Client identifier type - cmp al,[MACType] - pop ax - jne .skip ; Client identifier is not a MAC - dec ax - mov [MACLen],al - mov di,MAC - jmp dhcp_copyoption -.skip: ret - - dopt 67, bootfile_name - mov di,BootFile - jmp dhcp_copyoption - - dopt 97, uuid_client_identifier - cmp ax,17 ; type byte + 16 bytes UUID - jne .skip - mov dl,[si] ; Must have type 0 == UUID - or dl,[HaveUUID] ; Capture only the first instance - jnz .skip - mov byte [HaveUUID],1 ; Got UUID - mov di,UUIDType - jmp dhcp_copyoption -.skip: ret - - dopt 209, pxelinux_configfile - mov di,ConfigName - or byte [DHCPMagic],2 ; Got config file - jmp dhcp_copyoption - - dopt 210, pxelinux_pathprefix - mov di,PathPrefix - or byte [DHCPMagic],4 ; Got path prefix - jmp dhcp_copyoption - - dopt 211, pxelinux_reboottime - cmp al,4 - jne .done - mov ebx,[si] - xchg bl,bh ; Convert to host byte order - rol ebx,16 - xchg bl,bh - mov [RebootTime],ebx - or byte [DHCPMagic],8 ; Got RebootTime -.done: ret - - ; Common code for copying an option verbatim - ; Copies the option into ES:DI and null-terminates it. - ; Returns with AX=0 and SI past the option. -dhcp_copyoption: - xchg cx,ax ; CX <- option length - rep movsb - xchg cx,ax ; AX <- 0 - stosb ; Null-terminate + global pxe_int1a +pxe_int1a: +%if USE_PXE_PROVIDED_STACK == 0 + mov [cs:PXEStack],sp + mov [cs:PXEStack+2],ss + lss sp,[cs:InitStack] +%endif + int 1Ah ; May trash registers +%if USE_PXE_PROVIDED_STACK == 0 + lss sp,[cs:PXEStack] +%endif ret - section .data16 -dhcp_option_list_end: - section .text16 - - section .data16 -HaveUUID db 0 -uuid_dashes db 4,2,2,2,6,0 ; Bytes per UUID dashed section - section .text16 - -; -; genipopt -; -; Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask> -; option into IPOption based on a DHCP packet in trackbuf. -; Assumes CS == DS == ES. -; -genipopt: - pushad - mov di,IPOption - mov eax,'ip=' - stosd - dec di - mov eax,[MyIP] - call gendotquad - mov al,':' - stosb - mov eax,[ServerIP] - call gendotquad - mov al,':' - stosb - mov eax,[Gateway] - call gendotquad - mov al,':' - stosb - mov eax,[Netmask] - call gendotquad ; Zero-terminates its output - popad - ret ; ----------------------------------------------------------------------------- ; Common modules @@ -2557,8 +366,6 @@ genipopt: writestr_early equ writestr %include "writehex.inc" ; Hexadecimal output %include "rawcon.inc" ; Console I/O w/o using the console functions -%include "dnsresolv.inc" ; DNS resolver -%include "pxeidle.inc" ; PXE-specific idle mechanism ; ----------------------------------------------------------------------------- ; Begin data section @@ -2571,36 +378,9 @@ copyright_str db ' Copyright (C) 1994-' db ' H. Peter Anvin et al', CR, LF, 0 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0 bailmsg equ err_bootfailed -err_nopxe db "No !PXE or PXENV+ API found; we're dead...", CR, LF, 0 -err_pxefailed db 'PXE API call failed, error ', 0 -err_udpinit db 'Failed to initialize UDP stack', CR, LF, 0 -err_noconfig db 'Unable to locate configuration file', CR, LF, 0 -err_damage db 'TFTP server sent an incomprehesible reply', CR, LF, 0 -found_pxenv db 'Found PXENV+ structure', CR, LF, 0 -apiver_str db 'PXE API version is ',0 -pxeentry_msg db '!PXE entry point found (we hope) at ', 0 -pxenventry_msg db 'PXENV+ entry point found (we hope) at ', 0 -viaplan_msg db ' via plan ' -plan db 'A', CR, LF, 0 -trymempxe_msg db 'Scanning memory for !PXE structure... ', 0 -trymempxenv_msg db 'Scanning memory for PXENV+ structure... ', 0 -undi_data_msg db 'UNDI data segment at ',0 -undi_code_msg db 'UNDI code segment at ',0 -len_msg db ' len ', 0 -cant_free_msg db 'Failed to free base memory, error ', 0 -notfound_msg db 'not found', CR, LF, 0 -myipaddr_msg db 'My IP address seems to be ',0 -tftpprefix_msg db 'TFTP prefix: ', 0 localboot_msg db 'Booting from local disk...', CR, LF, 0 -trying_msg db 'Trying to load: ', 0 -default_str db 'default', 0 syslinux_banner db CR, LF, 'PXELINUX ', VERSION_STR, ' ', DATE_STR, ' ', 0 -cfgprefix db 'pxelinux.cfg/' ; No final null! -cfgprefix_len equ ($-cfgprefix) -; This one we make ourselves -bootif_str db 'BOOTIF=' -bootif_str_len equ $-bootif_str ; ; Config file keyword table ; @@ -2619,144 +399,20 @@ exten_table_end: dd 0, 0 ; Need 8 null bytes here ; -; PXE unload sequences -; -new_api_unload: - db PXENV_UDP_CLOSE - db PXENV_UNDI_SHUTDOWN - db PXENV_UNLOAD_STACK - db PXENV_STOP_UNDI - db 0 -old_api_unload: - db PXENV_UDP_CLOSE - db PXENV_UNDI_SHUTDOWN - db PXENV_UNLOAD_STACK - db PXENV_UNDI_CLEANUP - db 0 - -; -; PXE query packets partially filled in -; - section .bss16 -pxe_bootp_query_pkt: -.status: resw 1 ; Status -.packettype: resw 1 ; Boot server packet type -.buffersize: resw 1 ; Packet size -.buffer: resw 2 ; seg:off of buffer -.bufferlimit: resw 1 ; Unused - -pxe_udp_open_pkt: -.status: resw 1 ; Status -.sip: resd 1 ; Source (our) IP - -pxe_udp_close_pkt: -.status: resw 1 ; Status - -pxe_udp_write_pkt: -.status: resw 1 ; Status -.sip: resd 1 ; Server IP -.gip: resd 1 ; Gateway IP -.lport: resw 1 ; Local port -.rport: resw 1 ; Remote port -.buffersize: resw 1 ; Size of packet -.buffer: resw 2 ; seg:off of buffer - -pxe_udp_read_pkt: -.status: resw 1 ; Status -.sip: resd 1 ; Source IP -.dip: resd 1 ; Destination (our) IP -.rport: resw 1 ; Remote port -.lport: resw 1 ; Local port -.buffersize: resw 1 ; Max packet size -.buffer: resw 2 ; seg:off of buffer - -%if GPXE - - section .data16 - -gpxe_file_api_check: -.status: dw 0 ; Status -.size: dw 20 ; Size in bytes -.magic: dd 0x91d447b2 ; Magic number -.provider: dd 0 -.apimask: dd 0 -.flags: dd 0 - - section .bss16 - -gpxe_file_open: -.status: resw 1 ; Status -.filehandle: resw 1 ; FileHandle -.filename: resd 1 ; seg:off of FileName -.reserved: resd 1 - -gpxe_get_file_size: -.status: resw 1 ; Status -.filehandle: resw 1 ; FileHandle -.filesize: resd 1 ; FileSize - -gpxe_file_read: -.status: resw 1 ; Status -.filehandle: resw 1 ; FileHandle -.buffersize: resw 1 ; BufferSize -.buffer: resd 1 ; seg:off of buffer - -%endif ; GPXE - -; ; Misc initialized (data) variables ; section .data16 alignz 4 + global BaseStack, KeepPXE BaseStack dd StackTop ; ESP of base stack dw 0 ; SS of base stack -NextSocket dw 49152 ; Counter for allocating socket numbers KeepPXE db 0 ; Should PXE be kept around? ; -; TFTP commands -; -tftp_tail db 'octet', 0 ; Octet mode -tsize_str db 'tsize' ,0 ; Request size -tsize_len equ ($-tsize_str) - db '0', 0 -blksize_str db 'blksize', 0 ; Request large blocks -blksize_len equ ($-blksize_str) - asciidec TFTP_LARGEBLK - db 0 -tftp_tail_len equ ($-tftp_tail) - - alignz 2 -; -; Options negotiation parsing table (string pointer, string len, offset -; into socket structure) -; -tftp_opt_table: - dw tsize_str, tsize_len, tftp_filesize - dw blksize_str, blksize_len, tftp_blksize -tftp_opts equ ($-tftp_opt_table)/6 - -; -; Error packet to return on TFTP protocol error -; Most of our errors are OACK parsing errors, so use that error code -; -tftp_proto_err dw TFTP_ERROR ; ERROR packet - dw TFTP_EOPTNEG ; ERROR 8: OACK error - db 'TFTP protocol error', 0 ; Error message -tftp_proto_err_len equ ($-tftp_proto_err) - - alignz 4 -ack_packet_buf: dw TFTP_ACK, 0 ; TFTP ACK packet - -; ; IP information (initialized to "unknown" values) -MyIP dd 0 ; My IP address -ServerIP dd 0 ; IP address of boot server -Netmask dd 0 ; Netmask of this subnet -Gateway dd 0 ; Default router -ServerPort dw TFTP_PORT ; TFTP server port - + global MyIP +MyIP dd 0 ; My IP address ; ; Variables that are uninitialized in SYSLINUX but initialized here ; diff --git a/core/runkernel.inc b/core/runkernel.inc index 8d0f2968..68ab9fac 100644 --- a/core/runkernel.inc +++ b/core/runkernel.inc @@ -58,7 +58,7 @@ is_linux_kernel: mov cx,8000h >> SECTOR_SHIFT ; Half a moby (32K) xor bx,bx pop si ; <A> file pointer - call getfssec + pm_call getfssec cmp cx,1024 jb kernel_corrupt cmp word [es:bs_bootsign],0AA55h @@ -538,7 +538,7 @@ parse_load_initrd: push di mov di,InitRD ; Target buffer for mangled name - call mangle_name + pm_call mangle_name pop di call loadinitrd @@ -585,11 +585,11 @@ loadinitrd: push edi mov si,InitRD mov di,InitRDCName - call unmangle_name ; Create human-readable name + pm_call unmangle_name ; Create human-readable name sub di,InitRDCName mov [InitRDCNameLen],di mov di,InitRD - call searchdir ; Look for it in directory + pm_call searchdir ; Look for it in directory pop edi jz .notthere diff --git a/core/syslinux.ld b/core/syslinux.ld index 46017148..92ad3aa3 100644 --- a/core/syslinux.ld +++ b/core/syslinux.ld @@ -364,15 +364,17 @@ SECTIONS /* * We don't need .rel.dyn so put it here where we can simply - * remove it. + * remove it. Putting it in /DISCARD/ doesn't work because it + * is linker-generated. */ .rel.dyn : { *(.rel.dyn) } - /* No "interpreter" applicable */ + /* Stuff we don't need... */ /DISCARD/ : { *(.interp) + *(.eh_frame) } } diff --git a/core/ui.inc b/core/ui.inc index 3e42a97d..87d0c647 100644 --- a/core/ui.inc +++ b/core/ui.inc @@ -237,7 +237,7 @@ show_help: ; AX = func key # (0 = F1, 9 = F10, 11 = F12) xchg di,ax cmp byte [di+NULLOFFSET],NULLFILE je short fk_nofile ; Undefined F-key - call open + call core_open jz short fk_nofile ; File not found call crlf call get_msg_file @@ -318,7 +318,7 @@ load_kernel: ; Load the kernel now mov si,command_line mov di,KernelName push si - call mangle_name + pm_call mangle_name pop si ; ; Fast-forward to first option (we start over from the beginning, since @@ -448,7 +448,7 @@ get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/e mov bx,exten_table .search_loop: push bx mov di,KernelName ; Search on disk - call searchdir + pm_call searchdir pop bx jnz kernel_good mov eax,[bx] ; Try a different extension @@ -472,7 +472,7 @@ bad_kernel: mov si,KernelName mov di,KernelCName push di - call unmangle_name ; Get human form + pm_call unmangle_name ; Get human form mov si,err_notfound ; Complain about missing kernel call writestr pop si ; KernelCName @@ -601,7 +601,7 @@ kernel_good: mov si,KernelName mov di,KernelCName - call unmangle_name + pm_call unmangle_name sub di,KernelCName mov [KernelCNameLen],di diff --git a/doc/memdisk.txt b/doc/memdisk.txt index 79d76400..58ec748b 100644 --- a/doc/memdisk.txt +++ b/doc/memdisk.txt @@ -122,6 +122,12 @@ f) The following option can be used to pause to view the messages: pause Wait for a keypress right before booting +g) The following option can be used to set the real-mode stack size. + The default is 512 bytes, but if there is a failure it might be + interesting to set it to something larger: + + stack=size Set the stack to "size" bytes + Some interesting things to note: diff --git a/extlinux/main.c b/extlinux/main.c index 06306b39..0ab47539 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -14,7 +14,7 @@ /* * extlinux.c * - * Install the extlinux boot block on an ext2/3 filesystem + * Install the extlinux boot block on an ext2/3/4 filesystem */ #define _GNU_SOURCE /* Enable everything */ @@ -618,7 +618,7 @@ int install_bootblock(int fd, const char *device) } if (sb.s_magic != EXT2_SUPER_MAGIC) { - fprintf(stderr, "no ext2/ext3 superblock found on %s\n", device); + fprintf(stderr, "no ext2/3/4 superblock found on %s\n", device); return 1; } @@ -766,7 +766,8 @@ static const char *find_device(const char *mtab_file, dev_t dev) while ((mnt = getmntent(mtab))) { if ((!strcmp(mnt->mnt_type, "ext2") || - !strcmp(mnt->mnt_type, "ext3")) && + !strcmp(mnt->mnt_type, "ext3") || + !strcmp(mnt->mnt_type, "ext4")) && !stat(mnt->mnt_fsname, &dst) && dst.st_rdev == dev) { devname = strdup(mnt->mnt_fsname); break; @@ -796,7 +797,7 @@ int install_loader(const char *path, int update_only) } if (sfs.f_type != EXT2_SUPER_MAGIC) { - fprintf(stderr, "%s: not an ext2/ext3 filesystem: %s\n", program, path); + fprintf(stderr, "%s: not an ext2/3/4 filesystem: %s\n", program, path); return 1; } diff --git a/memdisk/Makefile b/memdisk/Makefile index e1a89351..d185d87c 100644 --- a/memdisk/Makefile +++ b/memdisk/Makefile @@ -49,6 +49,7 @@ all: memdisk # e820test # tidy, clean removes everything except the final binary tidy dist: rm -f *.o *.s *.tmp *.o16 *.s16 *.bin *.lst *.elf e820test .*.d + rm -f *.map clean: tidy diff --git a/memdisk/memdisk_chs.asm b/memdisk/memdisk_chs.asm index 4b06a856..94dad9db 100644 --- a/memdisk/memdisk_chs.asm +++ b/memdisk/memdisk_chs.asm @@ -1,2 +1,3 @@ + [map all memdisk_chs.map] %define EDD 0 %include "memdisk.inc" diff --git a/memdisk/memdisk_edd.asm b/memdisk/memdisk_edd.asm index d2e7b1cf..6f909d74 100644 --- a/memdisk/memdisk_edd.asm +++ b/memdisk/memdisk_edd.asm @@ -1,2 +1,3 @@ + [map all memdisk_edd.map] %define EDD 1 %include "memdisk.inc" diff --git a/memdisk/setup.c b/memdisk/setup.c index caee377a..52781694 100644 --- a/memdisk/setup.c +++ b/memdisk/setup.c @@ -729,7 +729,24 @@ static uint8_t checksum_buf(const void *buf, int count) return c; } -#define STACK_NEEDED 512 /* Number of bytes of stack */ +static int stack_needed(void) +{ + const unsigned int min_stack = 128; /* Minimum stack size */ + const unsigned int def_stack = 512; /* Default stack size */ + unsigned int v = 0; + const char *p; + + if (CMD_HASDATA(p = getcmditem("stack"))) + v = atou(p); + + if (!v) + v = def_stack; + + if (v < min_stack) + v = min_stack; + + return v; +} struct real_mode_args rm_args; @@ -749,7 +766,8 @@ void setup(const struct real_mode_args *rm_args_ptr) uint16_t dosmem_k; uint32_t stddosmem; const struct geometry *geometry; - int total_size, cmdlinelen; + unsigned int total_size; + unsigned int cmdline_len, stack_len, e820_len; com32sys_t regs; uint32_t ramdisk_image, ramdisk_size; uint32_t boot_base, rm_base; @@ -931,11 +949,15 @@ void setup(const struct real_mode_args *rm_args_ptr) map -- 12 bytes per range; we may need as many as 2 additional ranges (each insertrange() can worst-case turn 1 area into 3) plus the terminating range, over what nranges currently show. */ - cmdlinelen = strlen(shdr->cmdline) + 1; total_size = hptr->total_size; /* Actual memdisk code */ - total_size += (nranges + 3) * sizeof(ranges[0]); /* E820 memory ranges */ - total_size += cmdlinelen; /* Command line */ - total_size += STACK_NEEDED; /* Stack */ + e820_len = (nranges + 3) * sizeof(ranges[0]); + total_size += e820_len; /* E820 memory ranges */ + cmdline_len = strlen(shdr->cmdline) + 1; + total_size += cmdline_len; /* Command line */ + stack_len = stack_needed(); + total_size += stack_len; /* Stack */ + printf("Code %u, meminfo %u, cmdline %u, stack %u\n", + hptr->total_size, e820_len, cmdline_len, stack_len); printf("Total size needed = %u bytes, allocating %uK\n", total_size, (total_size + 0x3ff) >> 10); @@ -1053,7 +1075,7 @@ void setup(const struct real_mode_args *rm_args_ptr) /* Actually copy to low memory */ dpp = mempcpy(dpp, memdisk_hook, bin_size); dpp = mempcpy(dpp, ranges, (nranges + 1) * sizeof(ranges[0])); - dpp = mempcpy(dpp, shdr->cmdline, cmdlinelen + 1); + dpp = mempcpy(dpp, shdr->cmdline, cmdline_len); } /* Update various BIOS magic data areas (gotta love this shit) */ |