LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Etienne Lorrain <etienne_lorrain@yahoo.fr>
To: linux-kernel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] Compressed ia32 ELF file generation for loading by Gujin 2/3
Date: Mon, 5 Feb 2007 23:58:20 +0000 (GMT) [thread overview]
Message-ID: <94642.67267.qm@web26914.mail.ukl.yahoo.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 373 bytes --]
That is the main file BIOS information gathering realmode.c
___________________________________________________________________________
Découvrez une nouvelle façon d'obtenir des réponses à toutes vos questions !
Profitez des connaissances, des opinions et des expériences des internautes sur Yahoo! Questions/Réponses
http://fr.answers.yahoo.com
[-- Attachment #2: gujin-patch-2.6.20-2 --]
[-- Type: application/octet-stream, Size: 64516 bytes --]
diff -uprN -X linux-2.6.20/Documentation/dontdiff linux-2.6.20/arch/i386/kernel/realmode.c linux-2.6.20-gujin/arch/i386/kernel/realmode.c
--- linux-2.6.20/arch/i386/kernel/realmode.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20-gujin/arch/i386/kernel/realmode.c 2007-02-05 21:27:01.000000000 +0000
@@ -0,0 +1,1997 @@
+/*
+ * This file "realmode.c" is licensed with the same license as the Linux
+ * kernel; anyway the mapping of the data structure produced is owned by
+ * Linux kernel copyright owner(s) for a long time.
+ *
+ * The main use of this file is to produce the real-mode part of the
+ * ELF file vmlinux (at the root of the linux tree), this file will
+ * be (usually) stripped of debug info and then compressed by GZIP
+ * to make a "Gujin native bootable file" with the "kgz" extension.
+ * This real-mode part is removed (by objdump) from the binary later
+ * in the process if you generate a bzImage file.
+ * This real-mode part is used at boot time to get informations from
+ * the BIOS: memory size, disk present, video mode... and is no more
+ * accessible once the processor has switch to protected-mode.
+ *
+ * Gujin homepage is at: http://gujin.org/ ; it is itself licensed
+ * under the terms of the GNU General Public License, version 2.
+ * Gujin is Copyright (C) 1999-2005 Etienne Lorrain, fingerprint (2D3AF3EA):
+ * 2471 DF64 9DEE 41D4 C8DB 9667 E448 FF8C 2D3A F3EA
+ * E-Mail: etienne dot lorrain at gujin dot org
+ *
+ * First version has been written by Etienne Lorrain in December 2004.
+ */
+
+/*
+ * Do not touch - used to generate real mode ia32 code and manage
+ * the inter-segment call transparently, after maximum 4 Kbytes
+ * of real mode rodata/data has been copied into %ds segment.
+ *
+ * Having constant/initialised variable in here is a bit tricky,
+ * it uses the fact that since Gujin-1.0, the segment ".fourKsegment"
+ * containning the only variable "fourKbuffer" (of size 4 Kbytes)
+ * is located at %ds:0 i.e. before the ".rodata" of Gujin.
+ * Note that here the code segment is local but the data segment
+ * (and the stack segment) is the one of Gujin for obvious reasons.
+ * The first person modifying data at address over %ds:0x1000
+ * get all the blame for any bug happening in Gujin, in between
+ * the last and the next big bang, and it is a pretty long time.
+ * <smile>You don't like my memory protection system?</smile>
+ */
+asm(" .psize 0 \n"
+ " .code16gcc \n"
+ " .section .init.text16,\"ax\",@progbits \n"
+ " push %di \n"
+ " push %si \n"
+ " mov $_sdata16,%si \n"
+ " mov %si,%di \n"
+ " mov $_edata16,%cx \n"
+ " and $0xFFF,%cx \n"
+ " sub %si,%cx \n"
+ " shr $2,%cx \n"
+ " rep movsl %cs:(%si),%es:(%di) \n"
+ " pop %si \n"
+ " pop %di \n"
+ " calll linux_set_params \n"
+ " lretw \n"
+ " .previous \n"
+);
+
+#include "asm/realmode.h"
+
+/*
+ * Those need to be used because there is no way to set the default
+ * segment name used for ".text", ".data", ".rodata*" and ".bss"
+ * It would be nice to be able to do: asm(".equ .data, .data16");
+ * or shall that be managed by the compiler - and by compilation
+ * switch or by the attribute of functions?
+ * This file is pre-linked (section with same name grouped together)
+ * in "arch/i386/kernel/built-in.o" so no hope to manage it in
+ * the final linker file if it uses the same section names.
+ * Maybe if "arch/i386/kernel/built-in.o" could be an archive?
+ * Maybe it is "the right way (TM)" to use different section names
+ * so that those functions can be located in different source files.
+ * Maybe the section name shall be automatically changed using
+ * objcopy in the realmode.o file, just after compilation.
+ * Maybe the segment names shall be changed by sed in the
+ * assembler file.
+ * The method used here works and is as fool proof as possible.
+ *
+ * Unfortunately, I do not know how to use inline strings here,
+ * i.e. puts("hello world"); will not work due to the segment
+ * used to store the constant "hello world".
+ * Same for the implicit table generated by a big switch().
+ * This would generate a prohibited cross reference at linker time.
+ *
+ * I also need to add that using GCC to generate real-mode i386
+ * executable has a major limitation: no use of library compiled
+ * for protected mode. If your source make GCC to call memcpy(),
+ * memset(), strcpy()... then you have to provide them yourself.
+ * The same thing apply if you multiply or divide 64 bit numbers
+ * by non power of two. Adding and substracting of long long is OK.
+ */
+#define CONST __attribute__ ((section (".rodata16"))) const
+#define VARIABLE __attribute__ ((section (".data16")))
+#define BSS __attribute__ ((section (".bss16")))
+#define CODE __attribute__ ((section (".text16")))
+
+#if 0
+/*
+ * When compiling this file, some combination of GCC and options
+ * will call memset() in the assembly generated. You can check it
+ * by typing "make arch/i386/kernel/realmode.s".
+ * They cannot be inline because they are _called_ by the compiler.
+ * It is not possible to access the standard one because its
+ * hexadecimal coding is for protected mode, and not possible to
+ * code it in assembler because of we do not know the calling
+ * convension (GCC optimisations like "-mtrd", "-mregparm=3").
+ * We also cannot have two memcpy() nor memset() in the same
+ * final link, so we rename them in assembler.
+ * This part is currently disabled due to a problem in the linker
+ * but right now no GCC switch combination produces such
+ * memset/memcpy calls with a Linux supported compiler.
+ */
+CODE void code16_memcpy (char *dest, const char *src, unsigned nb)
+{
+ while (nb--)
+ *dest++ = *src++;
+}
+CODE void code16_memset (char *dest, unsigned val, unsigned nb)
+{
+ while (nb--)
+ *dest++ = val;
+}
+asm (
+ "memcpy = code16_memcpy \n"
+ "memset = code16_memset \n"
+);
+#endif
+
+/**
+ ** Few debug functions and how to use them, including how to declare
+ ** variables and constants. For complex debug, you may want to
+ ** check dbgload.exe of Gujin. The following debug uses the VIDEO BIOS
+ ** to display messages so will not work in VESA modes when the VESA
+ ** BIOS do not support printing characters in current video mode
+ ** (bit BIOS_output_supported of VESA_modeinfo_t / struct screen_info)
+ **/
+//#define TEST_VGAPRINT
+
+#ifdef TEST_VGAPRINT
+CONST char test_before[] = "test: 0x";
+VARIABLE unsigned test_val = 0x089ABC0;
+CONST char test_middle[] = ", test_val2 = 0x";
+BSS unsigned test_val2;
+VARIABLE char test_after[] = ".\r\n";
+
+#define PUSHALL "pushw %%ds; pushw %%es; pushw %%fs; pushw %%gs; pushal\n"
+#define POPALL "popal; popw %%gs; popw %%fs; popw %%es; popw %%ds\n"
+
+CODE static void vgaputs (const char *string)
+{
+ while (*string != '\0')
+ asm(PUSHALL
+ " movw $0x0007,%%bx\n int $0x10 \n"
+ POPALL
+ : : "a" (0x0E00 | (unsigned char)*string++));
+}
+
+CODE static void vgaputx (unsigned val)
+{
+ unsigned digit_shift = 7 * 4;
+
+ while (digit_shift && (val & (0xF << digit_shift)) == 0)
+ digit_shift -= 4;
+ for (;;) {
+ asm(PUSHALL
+ " movw $0x0007,%%bx \n"
+ " sahf # clear AF \n"
+ " aaa \n"
+ " aad $0x11 \n"
+ " add $0x0E30,%%ax \n"
+ " int $0x10 \n"
+ POPALL
+ : : "a" ((val >> digit_shift) & 0x0F));
+ if (digit_shift == 0)
+ break;
+ digit_shift -= 4;
+ }
+}
+
+CODE static inline void vga_wait_seconds (unsigned seconds)
+{
+ unsigned nb_microsec = seconds * 1000 * 1000;
+ unsigned short status;
+
+ asm volatile (" int $0x15 # _BIOS_wait "
+ : "=a" (status)
+ : "a" ((unsigned short)0x8600), "d" (nb_microsec & 0xFFFF),
+ "c" (nb_microsec >> 16));
+}
+
+extern inline void test_vgaprint (void)
+{
+ unsigned stackptr;
+ static CONST char stkmsg[] = ", sp = 0x";
+
+ asm (" mov %%esp,%0 " : "=r" (stackptr));
+ test_val2 = 0x1234fedc;
+
+ vgaputs(test_before);
+ vgaputx(test_val);
+ vgaputs(test_middle);
+ vgaputx(test_val2);
+ vgaputs(stkmsg);
+ vgaputx(stackptr);
+ vgaputs(test_after);
+ vga_wait_seconds(7);
+}
+
+#define DBG(startstr, variable, endstr) { \
+ static CONST char before[]=startstr, after[] = endstr; \
+ vgaputs(before); vgaputx(variable); vgaputs(after); \
+ }
+#define DBG_WAIT() vga_wait_seconds(7)
+#else
+#define test_vgaprint() /*nothing*/
+#define DBG(startstr, variable, endstr) /*nothing*/
+#define DBG_WAIT() /*nothing*/
+#endif
+
+/**
+ ** All the non BIOS related, low level functions we use:
+ **/
+extern inline unsigned peekb (farptr adr)
+{
+ unsigned returned;
+ unsigned short scratch;
+ extern char memory[];
+
+ asm(" pushl %2 \n"
+ " popw %w0 \n"
+ " popw %%fs \n"
+ " movzbl %%fs:(%w0),%1 \n"
+ : "=bSDB" (scratch), "=r" (returned)
+ : "g" (adr), "m" (*memory) );
+ return returned;
+}
+
+extern inline unsigned peekw (farptr adr)
+{
+ unsigned returned;
+ unsigned short scratch;
+ extern char memory[];
+
+ asm(" pushl %2 \n"
+ " popw %w0 \n"
+ " popw %%fs \n"
+ " movzwl %%fs:(%w0),%1 \n"
+ : "=bSDB" (scratch), "=r" (returned)
+ : "g" (adr), "m" (*memory) );
+ return returned;
+}
+
+extern inline void outb (unsigned short port, unsigned char data)
+{
+ asm volatile (" outb %0,%1 " : : "a" (data), "dN" (port));
+}
+
+extern inline unsigned char inb (unsigned short port)
+{
+ unsigned char result;
+ asm volatile (" inb %1,%0 " : "=a" (result) : "dN" (port));
+ return result;
+}
+
+extern inline void short_delay (unsigned count)
+{
+ asm volatile (" loopl . \n" : "+c" (count));
+}
+
+extern inline unsigned char getnvram (unsigned char addr)
+{
+ outb(0x70, addr & ~0x80); /* bit 7 cleared: NMI enabled */
+ short_delay(1000); /* wait 1000 assembly instructions */
+ return inb(0x71);
+}
+
+__attribute__ ((const)) extern inline farptr
+stack_farptr (const void *data)
+{
+ unsigned stackseg_mask; /* stack is max 64 K */
+
+ asm (" mov %%ss,%0 \n" : "=r" (stackseg_mask));
+ return (farptr)((stackseg_mask << 16) | (unsigned) data);
+}
+
+/**
+ ** Generic BIOS calls:
+ **/
+
+extern inline struct shift_flags_str {
+ unsigned char right_shift_key_pressed : 1;
+ unsigned char left_shift_key_pressed : 1;
+ unsigned char control_key_pressed : 1;
+ unsigned char alternate_key_pressed : 1;
+ unsigned char scroll_lock_active : 1;
+ unsigned char num_lock_active : 1;
+ unsigned char caps_lock_active : 1;
+ unsigned char insert_active : 1;
+} _BIOS_get_shift_flags (void)
+{
+ struct shift_flags_str flags;
+
+ asm (" int $0x16 # _BIOS_get_shift_flags"
+ : "=a" (flags)
+ : "a" ((unsigned short)0x0200) );
+ return flags;
+}
+
+extern inline farptr _BIOS_getConfiguration (void)
+{
+ unsigned char error;
+ farptr conf;
+
+ asm (" pushl %%es \n"
+ " stc \n"
+ " int $0x15 # _BIOS_getConfiguration \n"
+ " setc %%al \n"
+ " pushw %%es \n"
+ " pushw %%bx \n"
+ " popl %%ebx \n"
+ " popl %%es \n"
+ : "=a" (error), "=b" (conf)
+ : "a" ((unsigned short)0xC000) );
+ if (error)
+ return (farptr)0;
+ return conf;
+}
+
+extern inline void
+get_bios_conf (farptr adr, struct sys_desc_table_info *sys_desc_table)
+{
+ unsigned nbbyte = sizeof(struct sys_desc_table_info);
+
+ asm (" pushl %%esi \n"
+ " popw %%si \n"
+ " popw %%fs \n"
+ " cld \n"
+ " rep movsb %%fs:(%%si),%%es:(%%di) \n"
+ : "+S" (adr), "+D" (sys_desc_table), "+c" (nbbyte), "=X" (*sys_desc_table)
+ );
+}
+
+extern inline unsigned char
+_BIOS_getExtendedMemory (unsigned short *sizeinKb)
+{
+ unsigned char error;
+
+ asm (" int $0x15 # _BIOS_getExtendedMemory \n"
+ " setc %0 \n"
+ : "=qm" (error), "=a" (*sizeinKb)
+ : "a" ((unsigned short)0x8800)
+ );
+ return error; /* 0 if no error */
+}
+
+struct MemoryMap_str {
+ unsigned long long base, length;
+ enum { MemAvailable = 1, MemSpecial = 2,
+ Mem_ACPI_reclaim = 3, Mem_ACPI_NVS = 4
+ } type:32;
+} __attribute__ ((packed));
+
+extern inline unsigned
+_BIOS_QueryMemoryMap (unsigned *cont_val, unsigned bufsize,
+ struct e820map_info *buffer)
+{
+ /* inline */ const unsigned smapsig = 0x534D4150; /* 'SMAP' in big endian */
+ unsigned smap_res = 0xE820U, actual_len;
+
+ asm volatile (" int $0x15 # _BIOS_QueryMemoryMap \n"
+ " jnc 1f \n"
+ " xorl %%eax,%%eax \n"
+ " 1: \n"
+ : "+a" (smap_res), "+b" (*cont_val),
+ "=c" (actual_len), "=X" (*buffer)
+ : "c" (bufsize), "d" (smapsig), "D" (buffer) /* in fact %%es:%%di */
+ );
+ if (smap_res != smapsig)
+ return 0;
+ return actual_len;
+}
+
+extern inline unsigned char
+_APM_installation_check (unsigned short *BCD_version, unsigned short *flags)
+{
+ unsigned char error;
+ unsigned short sig;
+
+ asm (" int $0x15 # _APM_installation_check \n"
+ " setc %0 \n"
+ : "=qm" (error), "=a" (*BCD_version), "=b" (sig), "=c" (*flags)
+ : "a" ((unsigned short)0x5300), "b" (0)
+ );
+ if (error) {
+ *BCD_version &= 0xFF00; /* keep there error code */
+ *flags = 0;
+ }
+ return error || sig != 0x504D; /* "PM" */
+}
+
+extern inline unsigned short _APM_disconnect (void)
+{
+ unsigned short error;
+
+ asm volatile (" int $0x15 # _APM_disconnect \n"
+ " setc %%al \n"
+ : "=a" (error)
+ : "a" ((unsigned short)0x5304), "b" (0) );
+ if ((error & 0xFF) == 0)
+ return 0;
+ return error;
+}
+
+extern inline unsigned char
+_APM_connect_32bit (unsigned short *RM_segbase_32,
+ unsigned *entry_point_offset_32,
+ unsigned short *RM_segbase_code16,
+ unsigned short *RM_segbase_data16,
+ /* APM v1.1: */
+ unsigned short *APM_BIOS_codeseg_len,
+ unsigned short *APM_BIOS_dataseg_len)
+{
+ unsigned char error;
+
+ asm volatile (" xorl %%edi,%%edi \n"
+ " xorl %%esi,%%esi \n"
+ " int $0x15 # _APM_connect_32bit \n"
+ " setc %0 \n"
+ : "=qm" (error),
+ "=a" (*RM_segbase_32), "=b" (*entry_point_offset_32),
+ "=c" (*RM_segbase_code16), "=d" (*RM_segbase_data16),
+ "=S" (*APM_BIOS_codeseg_len),
+ "=D" (*APM_BIOS_dataseg_len)
+ : "a" ((unsigned short)0x5303), "b" (0)
+ );
+ return error;
+}
+
+/**
+ ** Video BIOS: EGA, VGA, VESA and EDID.
+ **/
+union EGA_bx_union {
+ struct {
+ enum { EGA_64K, EGA_128K, EGA_192K, EGA_256K } memory:8;
+ enum { EGA_COLOR_3Dx, EGA_MONO_3Bx } IOaddr:8;
+ } enums;
+ unsigned short IOaddr_memory;
+} __attribute__ ((packed));
+
+struct EGA_cx_str {
+ unsigned short switch1off : 1;
+ unsigned short switch2off : 1;
+ unsigned short switch3off : 1;
+ unsigned short switch4off : 1;
+ unsigned short switch_unused : 4;
+ unsigned short FEAT1line_state2 : 1;
+ unsigned short FEAT0line_state2 : 1;
+ unsigned short FEAT1line_state1 : 1;
+ unsigned short FEAT0line_state1 : 1;
+ unsigned short FEAT_unused : 4;
+} __attribute__ ((packed));
+
+extern inline void
+_EGA_getdisplay (union EGA_bx_union *EGA_bx, struct EGA_cx_str *EGA_cx)
+{
+ unsigned short destroyed_tseng_ET4000_V8_00;
+ asm (" int $0x10 # _EGA_getdisplay "
+ : "=b" (*EGA_bx), "=c" (*EGA_cx),
+ "=a" (destroyed_tseng_ET4000_V8_00)
+ : "a" ((unsigned short)0x1200),
+ "b" ((unsigned short)0xFF10) /* %bh = 0xFF to see if supported */
+ );
+}
+
+extern inline void
+_VGA_getcursor (unsigned char page, unsigned char *row, unsigned char *col,
+ unsigned char *cursorstart, unsigned char *cursorstop)
+{
+ unsigned short row_col, cstart_cstop;
+ unsigned short destroyed_Phoenix_BIOS;
+
+ asm (" int $0x10 # getcursor "
+ : "=d" (row_col), "=c" (cstart_cstop),
+ "=a" (destroyed_Phoenix_BIOS)
+ : "a" ((unsigned short)0x0300), "b" ((unsigned short)page << 8)
+ );
+ *col = (unsigned char)row_col;
+ *row = row_col >> 8;
+ *cursorstart = cstart_cstop >> 8; /* bug reported with mono displays */
+ *cursorstop = (unsigned char)cstart_cstop;
+}
+
+extern inline char
+_VGA_getmode (unsigned char *nbcol, unsigned char *page)
+{
+ unsigned short nbcol_mode;
+ unsigned short tmppage;
+
+ asm (" int $0x10 # getmode "
+ : "=b" (tmppage), "=a" (nbcol_mode)
+ : "a" ((unsigned short)0x0F00)
+ );
+ *nbcol = nbcol_mode >> 8;
+ *page = tmppage >> 8;
+
+ return (char)nbcol_mode; /* bit 7 set if last setmode had it */
+}
+
+extern inline unsigned
+_VGA_get_display_combination_code (unsigned char *active_dcc,
+ unsigned char *alternate_dcc)
+{
+ unsigned char result;
+ unsigned short alternate_active;
+
+ asm (" int $0x10 # get_display_combination_code "
+ : "=a" (result), "=b" (alternate_active)
+ : "a" ((unsigned short)0x1A00)
+ );
+ *active_dcc = (unsigned char)alternate_active;
+ *alternate_dcc = alternate_active >> 8;
+
+ return (result != 0x1A);
+}
+
+typedef struct {
+ char VbeSignature[4]; /* "VESA" but NOT zero terminated. */
+ unsigned short VbeVersion;
+ farptr OemStringPtr;
+ struct vesa_capabilities_str Capabilities;
+ farptr VideoModePtr;
+ unsigned short TotalMemory; /* in 64K blocks */
+ /* if VBE 2.0+ (else structure is 256 bytes) : */
+ unsigned short OemSoftwareRev;
+ farptr OemVendorNamePtr;
+ farptr OemProductNamePtr;
+ farptr OemProductRevPtr;
+
+ unsigned char Reserved[222]; /* ONLY VESA version 1.2- info */
+ unsigned char OemData[256]; /* will not kill VESA1.2- */
+} __attribute__ ((packed)) VESA_VbeInfoBlock;
+
+typedef struct {
+ struct vesa_mode_attribute_str ModeAttributes;
+ struct {
+ unsigned char win_exist : 1;
+ unsigned char win_readable : 1;
+ unsigned char win_writable : 1;
+ unsigned char padding : 5;
+ } __attribute__ ((packed)) WinAAttributes, WinBAttributes;
+ unsigned short WinGranularity; /* in Kb */
+ unsigned short WinSize; /* in Kb */
+ unsigned short WinASegment;
+ unsigned short WinBSegment;
+ farptr WinFuncPtr;
+ unsigned short BytesPerScanLine;
+ /* optional part, see "attribute.optional_info_available": */
+ unsigned short XResolution; /* char in text modes,
+ pixel in graphic modes */
+ unsigned short YResolution;
+ unsigned char XCharSize;
+ unsigned char YCharSize;
+ unsigned char NumberOfPlanes;
+ unsigned char BitsPerPixel;
+ unsigned char NumberOfBanks; /* unused here : no multipaged screen */
+ enum { mem_text = 0, mem_CGA, mem_HGC, mem_EGA, mem_packedpixel,
+ mem_seq256, mem_HiColor24, mem_YUV
+ } MemoryModel : 8;
+ /* mem_seq256 = non chain 4 */
+ unsigned char BankSize; /* in Kb, unused here */
+ unsigned char NumberOfImagePages;
+ unsigned char Reserved;
+ /* VBE 1.2+: */
+ struct vesa_color_layout_str layout;
+ struct {
+ unsigned char color_ramp_programmable : 1;
+ unsigned char reserved_space_usable : 1;
+ } __attribute__ ((packed)) DirectColorModeInfo;
+ /* VBE 2.0: */
+ unsigned PhysBasePtr;
+ unsigned OffScreenMemOffset;
+ unsigned short OffScreenMemSize; /* in Kb */
+ unsigned char Reserved2[206];
+} __attribute__ ((packed)) VESA_modeinfo_t;
+
+extern inline unsigned
+_VESA_getinfo (VESA_VbeInfoBlock *VESA_info)
+{
+ unsigned short cmd_status = 0x4F00;
+
+ if (sizeof(VESA_VbeInfoBlock) != 512)
+ __ERROR();
+
+ asm (" int $0x10 # _VESA_getinfo "
+ : "+a"(cmd_status), "=X" (*VESA_info)
+ : "D"(VESA_info) /* in fact %es:%di */
+ );
+ return (cmd_status != 0x004F);
+}
+
+extern inline unsigned
+_VESA_getmodeinfo (VESA_modeinfo_t *VESA_modeinfo, unsigned short mode)
+{
+ unsigned short cmd_status = 0x4F01;
+
+ if (sizeof(VESA_modeinfo_t) != 256)
+ __ERROR();
+
+ asm (" int $0x10 # _VESA_getmodeinfo "
+ : "+a" (cmd_status), "=X" (*VESA_modeinfo)
+ : "c" (mode), "D" (VESA_modeinfo) /* in fact %es:%di */
+ );
+ return (cmd_status != 0x004F);
+}
+
+extern inline unsigned _VESA_getmode (unsigned short *mode)
+{
+ unsigned short cmd_status = 0x4F03;
+
+ asm (" int $0x10 # _VESA_getmode "
+ : "+a" (cmd_status),
+ "=b" (*mode) /* *mode contains bits 13, 14 & 15 */
+ );
+ return (cmd_status != 0x004F);
+}
+
+extern inline unsigned _VESA_setDACwidth (unsigned char depth)
+{
+ unsigned short cmd_status = 0x4F08;
+ unsigned short result = depth << 8; /* %bl = 0 */
+
+ asm volatile (" int $0x10 # _VESA_setDACwidth " /* VESA 1.2+ */
+ : "+a" (cmd_status), "+b" (result)
+ );
+ return (cmd_status != 0x004F || (result >> 8) != depth);
+}
+
+/* VESA 2.0+ */
+extern inline unsigned
+_VESA_GetPMinterface (farptr *addr, unsigned short *len)
+{
+ unsigned short cmd_status = 0x4F0A;
+
+ asm (" pushl %%es \n"
+ " xorw %%di,%%di \n"
+ " mov %%di,%%es \n"
+ " int $0x10 # _VESA_GetPMinterface \n"
+ " pushw %%es \n"
+ " pushw %%di \n"
+ " popl %%edi \n"
+ " popl %%es \n"
+ : "+a" (cmd_status), "=D" (*addr), "=c" (*len)
+ : "b" (0), "c" ((unsigned short)0)
+ );
+
+ return (cmd_status != 0x004F);
+}
+
+extern inline unsigned _EDID_detect (void)
+{
+ unsigned short cmd_status = 0x4F15, unknown1, unknown2;
+ /* %cx modified by NVIDIA RIVA TNT2 Model 64/Model 64 Pro */
+
+ asm (
+" pushw %%es \n"
+" movw %%di,%%es \n"
+" int $0x10 # _EDID_detect \n"
+" popw %%es \n"
+ : "+a" (cmd_status), "=b" (unknown1), "=c" (unknown2)
+ : "b" (0), "c" (0), "D" (0)
+ );
+ return (cmd_status != 0x004F);
+}
+
+extern inline unsigned _EDID_read (VBE_EDID_t *info)
+{
+ unsigned short cmd_status = 0x4F15;
+ unsigned char tmp = 1;
+ unsigned short unknown1 = 0, unknown2 = 1;
+
+ if (sizeof (VBE_EDID_t) != 0x80)
+ __ERROR();
+
+ asm (" int $0x10 # _EDID_read"
+ : "+a" (cmd_status), "=X" (*info)
+ : "b" (tmp), "D" (info), /* in fact %es:%di */
+ "c" (unknown1), "d" (unknown2)
+ );
+ /* returns 0x014F if monitor non EDID */
+ return (cmd_status != 0x004F);
+}
+
+/**
+ ** Disk BIOS:
+ **/
+extern inline unsigned
+_BIOSDISK_getparam (unsigned char disk,
+ unsigned short *tmpcx, unsigned short *tmpdx,
+ farptr *DBTadr, unsigned char *CmosDriveType,
+ unsigned char *status)
+{
+ unsigned char carry;
+
+ asm (" pushl %%es \n"
+ " xorw %%di,%%di \n"
+ " mov %%di,%%es \n"
+ " int $0x13 # _BIOSDISK_getparam \n"
+ " pushw %%es \n"
+ " pushw %%di \n"
+ " popl %%edi \n"
+ " popl %%es \n"
+ " mov %%ah,%1 \n"
+ " setc %0 \n"
+ : "=qm" (carry), "=qm" (*status), "=c" (*tmpcx), "=d" (*tmpdx),
+ "=b" (*CmosDriveType), "=D" (*DBTadr)
+ : "a"((unsigned short)0x0800), "d" (disk), "b" (0)
+ );
+
+ return carry;
+}
+
+extern inline unsigned char
+_BIOSDISK_gettype (unsigned char disk, unsigned *nbsect, unsigned char *status)
+{
+ unsigned char carry;
+ unsigned dummy;
+
+ asm (" xor %%dh,%%dh \n"
+ " xor %%cx,%%cx \n"
+ " int $0x13 # _BIOSDISK_gettype \n"
+ " shll $16,%%ecx \n"
+ " movw %%dx,%%cx \n"
+ " movb %%ah,%1 \n"
+ " setc %0 \n"
+ : "=qm" (carry), "=qm" (*status), "=c" (*nbsect), "=d" (dummy)
+ : "a" ((unsigned short)0x1500),
+ "d" (disk) /* disk = 0x80..0x8F else old Compaq bug */
+ );
+
+ return carry;
+}
+
+extern inline void
+get_drive_info (farptr indirect_ptr, union drive_info *diskinfo)
+{
+ unsigned nbbyte = sizeof(*diskinfo);
+
+ asm (" pushl %%esi \n"
+ " popw %%si \n"
+ " popw %%fs \n"
+ " pushl %%fs:(%%si) \n"
+ " popw %%si \n"
+ " popw %%fs \n"
+ " cld \n"
+ " rep movsb %%fs:(%%si),%%es:(%%di) \n"
+ : "+S" (indirect_ptr), "+D" (diskinfo), "+c" (nbbyte), "=X" (*diskinfo)
+ );
+}
+
+extern inline unsigned char
+_BIOSDISK_RWsector (unsigned char drive,
+ unsigned short cylinder, unsigned char head,
+ unsigned char sector, unsigned char nbsector,
+ farptr buffer, const unsigned read)
+{
+ unsigned short result, buggy_bios;
+
+ asm volatile (" pushl %%es \n"
+ " pushl %%ebx \n"
+ " popw %%bx \n"
+ " popw %%es \n"
+ " stc # buggy BIOSes \n"
+ " int $0x13 # _BIOSDISK_RWsector \n"
+ " sti # buggy BIOSes \n"
+ " popl %%es \n"
+ " setc %%al \n"
+ : "=a" (result), "=d" (buggy_bios)
+ : "a" ((read? 0x0200 : 0x0300) | nbsector),
+ "b" (buffer),
+ "c" ((cylinder << 8) | ((cylinder >> 2) & 0xC0)
+ | (sector & 0x3F)),
+ "d" ((((unsigned short)head) << 8) | drive)
+ );
+ if (result & 0x00FF)
+ return result >> 8;
+ return 0;
+}
+
+typedef struct {
+ unsigned short buffersize;
+ unsigned short infobit;
+ unsigned nbcylinder;
+ unsigned nbhead;
+ unsigned nbsectorpertrack;
+ unsigned long long nbtotalsector;
+ unsigned short bytepersector;
+ /* V2.0+ : */
+ farptr configptr; /* for instance ebiosPhoenix realmode address */
+ /* V3.0+ : */
+ unsigned short signature0xBEDD;
+ unsigned char lendevicepath; /* 0x24 for v3.0 */
+ unsigned char reserved[3];
+ unsigned char bustype[4]; /* exactly "ISA" or "PCI" */
+ unsigned char Interface[8]; /* exactly "ATA", "ATAPI",
+ "SCSI", "USB"... */
+ union interface_path_u {
+ struct {
+ unsigned short addr;
+ unsigned char pad[6];
+ } __attribute__ ((packed)) isa;
+ struct {
+ unsigned char busnr;
+ unsigned char devicenr;
+ unsigned char functionnr;
+ unsigned char pad[5];
+ } __attribute__ ((packed)) pci;
+ } bus;
+ union device_path_u {
+ struct {
+ unsigned char slave; /* 0 if master, 1 if slave */
+ unsigned char pad[7];
+ unsigned long long reserved; /* Not present in some docs... */
+ } __attribute__ ((packed)) ata;
+ struct {
+ unsigned char slave; /* 0 if master, 1 if slave */
+ unsigned char logical_unit_nr;
+ unsigned char pad[6];
+ } __attribute__ ((packed)) atapi;
+ struct {
+ unsigned char logical_unit_nr;
+ unsigned char pad[7];
+ } __attribute__ ((packed)) scsi;
+ struct {
+ unsigned char tobedefined;
+ unsigned char pad[7];
+ } __attribute__ ((packed)) usb;
+ struct {
+ unsigned long long FireWireGeneralUniqueID;
+ } __attribute__ ((packed)) ieee1394;
+ struct {
+ unsigned long long WorldWideNumber;
+ } __attribute__ ((packed)) FibreChannel;
+ } device;
+ unsigned char zero;
+ unsigned char bytechecksum; /* byte sum [0x1E..0x49] = 0 */
+} __attribute__ ((packed)) ebiosinfo_t;
+
+typedef struct {
+ unsigned short extended_fct : 1;
+ unsigned short removable : 1;
+ unsigned short enhanced : 1;
+ unsigned short reserved : 13;
+} __attribute__ ((packed)) ebios_bitmap_t;
+
+extern inline unsigned char
+_EBIOSDISK_probe (unsigned char disk, unsigned char *version,
+ unsigned char *extension, ebios_bitmap_t *bitmap)
+{
+ unsigned char carry;
+ unsigned short signat0xAA55;
+
+ asm (" int $0x13 # _EBIOSDISK_probe \n"
+ " mov %%ah,%1 \n"
+ " mov %%dh,%2 \n"
+ " setc %0 \n"
+ : "=qm" (carry), "=qm" (*version), "=qm" (*extension),
+ "=b" (signat0xAA55), "=c" (*bitmap)
+ : "a" ((unsigned short)0x4100), "b" ((unsigned short)0x55AA),
+ "d"(disk)
+ );
+
+ return carry || (signat0xAA55 != 0xAA55);
+}
+
+extern inline unsigned char
+_EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
+ unsigned char *status)
+{
+ unsigned char carry;
+
+ asm (" int $0x13 # _EBIOSDISK_getparam \n"
+ " mov %%ah,%1 \n"
+ " setc %0 \n"
+ : "=qm" (carry), "=qm" (*status)
+ : "a" ((unsigned short)0x4800), "d" (disk), "S" (ebiosinfo)
+ );
+
+ return carry;
+}
+
+/*
+ * Well, I do not know what that does, but because it is included in Linux
+ * kernel it has to be GPL - source code given in its most readable form...
+ */
+extern inline void
+_X86SpeedStepSmi (struct X86SpeedStepSmi_s *data)
+{
+ asm(" int $0x15 # _X86SpeedStepSmi "
+ : "=a" (data->data1), "=b" (data->data2),
+ "=c" (data->data3), "=d" (data->data4)
+ : "a" (0x0000E980), "d" (0x47534943) );
+}
+
+/**
+ ** Fill in each of the sub-structures:
+ **/
+CODE static inline void
+vmlinuz_EGA (struct screen_info *screen_info)
+{
+ union EGA_bx_union EGA_bx;
+ struct EGA_cx_str EGA_cx;
+
+ _EGA_getdisplay(&EGA_bx, &EGA_cx);
+ screen_info->orig_video_ega_bx = EGA_bx.IOaddr_memory;
+ screen_info->orig_video_isVGA = 0;
+ if (EGA_bx.enums.IOaddr == EGA_COLOR_3Dx
+ || EGA_bx.enums.IOaddr == EGA_MONO_3Bx) {
+ unsigned char active_dcc, alternate_dcc;
+
+ if (_VGA_get_display_combination_code(&active_dcc,
+ &alternate_dcc) == 0)
+ screen_info->orig_video_isVGA = 1;
+
+ screen_info->orig_video_lines = peekb((farptr)0x00400084) + 1;
+ screen_info->orig_font_height = peekw((farptr)0x00400085);
+ } else { /* EGA_bx.enums.IOaddr unchanged => CGA/MDA/HGA */
+ screen_info->orig_video_lines = 25;
+ screen_info->orig_font_height = 0; /* i.e. invalid */
+ }
+}
+
+CODE static inline void
+vmlinuz_getcursor (struct screen_info *screen_info)
+{
+#if 1 /* what is the best ? IHMO using the BIOS functions */
+ unsigned char row, col;
+ unsigned char cursorstart, cursorstop;
+
+ _VGA_getcursor(screen_info->orig_video_page,
+ &row, &col, &cursorstart, &cursorstop);
+ screen_info->orig_x = col;
+ screen_info->orig_y = row;
+#else
+ farptr ptr = 0x00400050 + 2 * screen_info->orig_video_page;
+
+ screen_info->orig_x = peekb(ptr);
+ screen_info->orig_y = peekb(ptr + 1);
+#endif
+}
+
+CODE static inline void
+vmlinuz_VGA (struct screen_info *screen_info, int proposed_line)
+{
+ unsigned char mode, nbcol, page;
+
+ mode = _VGA_getmode(&nbcol, &page);
+ screen_info->orig_video_mode = mode & 0x7F;
+ screen_info->orig_video_cols = nbcol;
+ screen_info->orig_video_page = page; /* not tested if != 0 */
+ if (proposed_line >= 0) {
+ screen_info->orig_y = proposed_line;
+ screen_info->orig_x = 0;
+ } else {
+ vmlinuz_getcursor(screen_info);
+ /* We try not to erase the text written later by Gujin: */
+ screen_info->orig_x = 0;
+ if (screen_info->orig_y + 4 < screen_info->orig_video_lines)
+ screen_info->orig_y += 4;
+ else
+ screen_info->orig_y = screen_info->orig_video_lines - 1;
+ }
+}
+
+CODE static inline void
+vmlinuz_VESA (struct screen_info *screen_info, unsigned mode)
+{
+ VESA_modeinfo_t modeinfo;
+
+ if (_VESA_getmodeinfo(&modeinfo, mode & 0x01FF) == 0) {
+ if (modeinfo.MemoryModel == mem_text
+ && modeinfo.NumberOfPlanes == 4) {
+ /* correct some buggy video BIOS: */
+ modeinfo.BytesPerScanLine = 2 * modeinfo.XResolution;
+ modeinfo.BitsPerPixel = 4;
+ }
+ if (modeinfo.MemoryModel == mem_text)
+ screen_info->lfb_base = 0xB8000;
+ else if (modeinfo.ModeAttributes.linear_framebuffer_supported) {
+ /* no text modes with linear framebuffer */
+ screen_info->orig_video_isVGA = 0x23;
+ screen_info->lfb_base = modeinfo.PhysBasePtr;
+ } else
+ screen_info->lfb_base = 0xA0000;
+ screen_info->lfb_linelength = modeinfo.BytesPerScanLine;
+ screen_info->lfb_width = modeinfo.XResolution;
+ screen_info->lfb_height = modeinfo.YResolution;
+ screen_info->lfb_depth = modeinfo.BitsPerPixel;
+ screen_info->lfb_pages = modeinfo.NumberOfImagePages;
+ screen_info->vesa_attrib = modeinfo.ModeAttributes;
+ screen_info->layout = modeinfo.layout;
+ } else
+ screen_info->lfb_base = 0;
+}
+
+CODE static void
+vmlinuz_VIDEO (struct screen_info *screen_info, unsigned short *acpi_vidmode,
+ int proposed_line)
+{
+ VESA_VbeInfoBlock infoblock;
+
+ vmlinuz_EGA(screen_info);
+ vmlinuz_VGA(screen_info, proposed_line);
+ *acpi_vidmode = screen_info->orig_video_mode;
+
+ /* normaly only for graphic modes: */
+ if (_VESA_getinfo(&infoblock) == 0) {
+ unsigned short mode, len;
+ farptr addr;
+
+ screen_info->lfb_size = infoblock.TotalMemory;
+ screen_info->capabilities = infoblock.Capabilities;
+ if (_VESA_getmode(&mode) == 0) {
+ vmlinuz_VESA(screen_info, mode);
+ *acpi_vidmode = mode;
+#if 0 /* After doing that, we should program again the DAC with the right values... */
+ /* Linux do not manage text modes and DAC 8 bits: */
+ if (screen_info->lfb_base != 0xB8000
+ && screen_info->lfb_depth <= 8
+ && infoblock.Capabilities.DAC8bit_present) {
+ if (_VESA_setDACwidth (8) == 0) {
+ screen_info->layout = (const struct vesa_color_layout_str){
+ {8, 0}, {8, 0}, {8, 0}, {8, 0}};
+ }
+ else {
+ screen_info->layout = (const struct vesa_color_layout_str){
+ {6, 0}, {6, 0}, {6, 0}, {6, 0}};
+ }
+ }
+#endif
+ }
+
+ /* Note: We can have a PM interface even if getmodeinfo
+ failed, for instance if we are in text mode 3 */
+ if (_VESA_GetPMinterface(&addr, &len) == 0) {
+ screen_info->vesapm_seg = addr >> 16;
+ screen_info->vesapm_off = addr & 0xFFFF;
+ }
+ }
+}
+
+CODE static inline unsigned short vmlinuz_EXT_MEM_K (void)
+{
+ unsigned short EXT_MEM_K;
+
+ if (_BIOS_getExtendedMemory(&EXT_MEM_K) != 0 || EXT_MEM_K == 0)
+ EXT_MEM_K = (((unsigned short)getnvram(0x18)) << 8)
+ + getnvram(0x17);
+ return EXT_MEM_K;
+}
+
+CODE static inline void
+vmlinuz_APM (struct apm_bios_info *apm_bios_info)
+{
+ if (_APM_installation_check(&apm_bios_info->version,
+ &apm_bios_info->flags) == 0) {
+ _APM_disconnect(); /* ignore possible error */
+ if ((apm_bios_info->flags & 2) == 0) {
+ /* no 32 bits support, ignore APM */
+ } else if (_APM_connect_32bit(&apm_bios_info->cseg,
+ &apm_bios_info->offset,
+ &apm_bios_info->cseg_16,
+ &apm_bios_info->dseg,
+ &apm_bios_info->cseg_len,
+ &apm_bios_info->dseg_len) != 0) {
+ apm_bios_info->flags &= ~2; /* remove 32bits support */
+ } else {
+ /* Redo the installation check as the 32 bit connect
+ modifies the flags returned on some BIOSs : */
+ if (_APM_installation_check(&apm_bios_info->version,
+ &apm_bios_info->flags) != 0) {
+ apm_bios_info->flags &= ~2;
+ _APM_disconnect();
+ }
+ }
+ }
+}
+
+CODE static inline void
+vmlinuz_CONFIG (struct sys_desc_table_info *sys_desc_table)
+{
+ farptr adr = _BIOS_getConfiguration();
+
+ if (adr != 0)
+ get_bios_conf(adr, sys_desc_table);
+}
+
+CODE static inline void
+vmlinuz_EDID (VBE_EDID_t *edid_data)
+{
+ if (_EDID_detect() != 0 || _EDID_read(edid_data) != 0) {
+ unsigned char *ptr = (unsigned char *)edid_data;
+ unsigned cpt = sizeof(VBE_EDID_t);
+ /* failed, reset complete area: */
+ while (--cpt)
+ *ptr++ = 0x13;
+ }
+}
+
+CODE static inline unsigned
+vmlinuz_E820 (struct e820map_info *e820map, unsigned e820map_bufsize)
+{
+ unsigned bufsize = e820map_bufsize, cont_val = 0, actual_len;
+ /* Use that to avoid data in .rodata with GCC-2.95.3: */
+ unsigned element_size = sizeof(struct e820map_info);
+
+ while ( bufsize >= element_size
+ && (actual_len = _BIOS_QueryMemoryMap(&cont_val,
+ bufsize, e820map)) != 0
+ && cont_val != 0) {
+ bufsize -= actual_len;
+ e820map = (void *)e820map + actual_len;
+ }
+ return (e820map_bufsize - bufsize) / element_size;
+}
+
+CODE static inline unsigned
+vmlinuz_MBRSIG (unsigned *MBRSIG, unsigned total_MBRSIG_entries)
+{
+ unsigned buffer[512 / sizeof(unsigned)], cpt;
+#define EDD_MBR_SIG_OFFSET 0x1B8 /* offset of signature in the MBR */
+
+ for (cpt = 0; cpt < total_MBRSIG_entries; cpt++) {
+ if (_BIOSDISK_RWsector(0x80 + cpt, 0, 0, 1, 1,
+ stack_farptr(buffer), 1) != 0)
+ return cpt;
+ *MBRSIG++ = buffer[EDD_MBR_SIG_OFFSET / sizeof(unsigned)];
+ }
+ return cpt;
+}
+
+CODE static inline unsigned
+vmlinuz_EDD (struct edd_info *edd, unsigned total_EDD_entries)
+{
+ unsigned cpt, eddcpt;
+
+ for (cpt = eddcpt = 0; cpt < 16 && eddcpt < total_EDD_entries; cpt++) {
+ unsigned char extension, status;
+ unsigned short tmpcx, tmpdx;
+ farptr DBTadr;
+ unsigned char CmosDriveType, stat;
+ struct edd_info *eddptr = &edd[eddcpt];
+
+ if (_EBIOSDISK_probe(0x80 + cpt, &eddptr->version, &extension,
+ (ebios_bitmap_t *) &eddptr->interface_support))
+ continue;
+ eddptr->device = 0x80 + cpt;
+ eddptr->params.length = sizeof(eddptr->params);
+ eddptr->params.info_flags = 0; /* buggy BIOS ? */
+ /* Don't check for fail return, it doesn't matter: */
+ _EBIOSDISK_getparam(0x80 + cpt,
+ (ebiosinfo_t *) &eddptr->params, &status);
+ if (_BIOSDISK_getparam(0x80 + cpt, &tmpcx, &tmpdx,
+ &DBTadr, &CmosDriveType, &stat) != 0) {
+ eddptr->max_cyl = 0;
+ eddptr->max_sect = eddptr->max_head = 0;
+ } else {
+ eddptr->max_head = tmpdx >> 8;
+ eddptr->max_sect = tmpcx & 0x3F;
+ eddptr->max_cyl = ((tmpcx & 0xC0) << 2) | (tmpcx >> 8);
+ }
+ eddcpt++;
+ }
+ return eddcpt;
+}
+
+
+/**
+ ** Command line stuff:
+ **/
+CODE static inline void
+vmlinuz_CMDLINE (char *command_line, const unsigned char *proposed_cmdline,
+ farptr extra_cmdline_farptr,
+ const char *cmdline_name, const char *cmdline_extraparam)
+{
+ char *cmdptr = command_line;
+
+ /* insert at beginning the name of the uncompressed GZIP file: */
+ if (cmdline_name && *cmdline_name) {
+ do
+ *cmdptr++ = *cmdline_name++;
+ while (*cmdline_name);
+ *cmdptr++ = ' ';
+ }
+
+ /* insert then: console=ttyS?,9600,n,7 or video=vesa,
+ keyboard=??, NumLock=on/off, mouse=/dev/psaux,
+ COLS=, LINES= proposed by Gujin */
+ if (proposed_cmdline && *proposed_cmdline) {
+ do
+ *cmdptr++ = *proposed_cmdline++;
+ while (*proposed_cmdline);
+ *cmdptr++ = ' ';
+ }
+
+ /* Add nearby end the Gujin gujin_param.extra_cmdline field: */
+ /* We assume there gujin_param.extra_cmdline is correctly zero terminated */
+ /* Note: we will have "root=" parameter from Gujin setup screen first,
+ so that if the one in the GZIP comment if erroneous, we can just
+ overwrite it with the Gujin setup (TOCHECK: when two "root=" are
+ given on the command line, only the first one is taken) */
+ if (extra_cmdline_farptr != 0 && peekb(extra_cmdline_farptr) != 0) {
+ *cmdptr++ = ' '; /* two spaces as separator */
+ for (;;) {
+ *cmdptr = peekb(extra_cmdline_farptr++);
+ if (*cmdptr < ' ') { /* stop at \0, \n, \r or \t */
+ *cmdptr = '\0';
+ break;
+ }
+ cmdptr++;
+ }
+ }
+
+ /* add at end the params in the comment part of the GZIP file: */
+ /* This may or may not stop at the first newline */
+ if (cmdline_extraparam && *cmdline_extraparam) {
+ *cmdptr++ = ' ';
+ do
+ *cmdptr++ = *cmdline_extraparam++;
+ while (*cmdline_extraparam != 0 && *cmdline_extraparam != '\n');
+ }
+ *cmdptr = '\0';
+}
+
+/**
+ ** OPTIONAL: If we want to use the data structures of Gujin to try to
+ ** find and match the root filesystem of the kernel loaded (that part
+ ** can be completely disabled):
+ **/
+#ifdef ROOT_EXTENSIVE_SEARCH
+
+struct desc_str {
+ unsigned inode;
+ unsigned filesize;
+ unsigned char disk;
+ unsigned char partition; /* 0xFF for MBR */
+ unsigned char name_offset; /* to after the pattern */
+ enum curdir_e { inRoot = 0, inSlashBoot, inSlashImage } curdir : 3;
+ enum boottype_e { is_MBR, is_PBR, is_kernel_with_header,
+ is_kernel_without_header, is_initrd,
+ is_bdi_file, is_el_torito, is_initramfs } boottype : 3;
+ unsigned char unused : 2;
+#define NAME_LENGTH 52
+ char filename[NAME_LENGTH];
+} __attribute__ ((packed));
+
+struct gpl_compliant_str {
+ unsigned signature;
+ unsigned version;
+ unsigned feature;
+ unsigned size;
+ struct setjmp_buf {
+ unsigned esi, edi, ebp, ebx;
+ unsigned short gs, fs, es, ds;
+ unsigned short flags, ip, cs, sp, ss;
+ } __attribute__ ((packed)) jmpbuf;
+ /* unsigned short padding */
+ unsigned filename_array, gdt, regs, fourKbuffer;
+ unsigned LOADER, STATE, UI, MOUSE, DI, UTIL, BOOTWAY;
+};
+
+typedef struct {
+ unsigned char header_id_0x01;
+ enum { platform_80x86 = 0, platform_PowerPC = 1,
+ platform_Mac = 2 } platform_id : 8;
+ unsigned short reserved;
+ unsigned char manufacturer[0x1B - 0x04 +1];
+ unsigned short checksum;
+ unsigned char signature1_0x55;
+ unsigned char signature2_0xAA;
+} __attribute__ ((packed)) ISO9660_Validation_entry;
+
+typedef struct {
+ unsigned char boot_indicator; /* 0x88: bootable, 0x00: non bootable */
+ enum { boot_media_noemul = 0, boot_media_120 = 1, boot_media_144 = 2,
+ boot_media_288 = 3, boot_media_hd = 4 } boot_media_type : 8;
+ unsigned short load_segment; /* 0x7c0 if null */
+ unsigned char system_type;
+ unsigned char unused;
+ unsigned short sector_count;
+ unsigned sector_lba;
+ unsigned char reserved[0x1F - 0x0C +1];
+} __attribute__ ((packed)) ISO9660_Default_entry;
+
+struct diskparam_str {
+ enum { bios_chs, ebios_lba,
+ hardide_chs, hardide_lba, hardide_lba48, hardide_atapi,
+ dos_part
+ } access : 8;
+ unsigned char disknb; /* BIOS number or DOS letter
+ or 0=master, non zero=slave */
+ unsigned char biostype; /* 1:floppy w/o change detect,
+ 2: with, 3: HD */
+ unsigned char drivetype; /* 1: 360K, 2: 1.2M, 3: 720K,
+ 4: 1.44M, 6: 2.88M, 0x10: ATAPI */
+ unsigned char diskname[32];
+
+ struct ide_attribute_str {
+ unsigned smart : 1;
+ unsigned host_protected_area : 1;
+ unsigned security : 1;
+ unsigned lba48 : 1;
+ unsigned removable : 1;
+ unsigned SAORAB : 1;
+ unsigned config_overlay : 1;
+ unsigned reserved : 25;
+ } ide_attribute;
+ struct error_log_str {
+ unsigned read_media : 1;
+ unsigned write_media : 1;
+ unsigned access_over_disk_tryed : 1;
+ unsigned access_over_partition_tryed : 1;
+ unsigned no_ebios_fct : 1;
+ unsigned ebios_size_zero : 1;
+ unsigned chs_bios_part_mismatch : 1;
+ unsigned chs_ajusted_bootsect : 1;
+ unsigned diskheader_ignored : 1;
+ unsigned disk_locked : 1;
+ unsigned disk_was_pw_locked : 1;
+ unsigned SMART_disabled : 1;
+ unsigned SMART_failure : 1;
+ unsigned analyse_partition_failed : 1;
+ unsigned NB_PARTITION_exceded : 1;
+ unsigned partition_overlap : 1;
+ unsigned partition_over_limit : 1;
+ unsigned beer_checksum_error : 1;
+ unsigned beer_in_extended_partition : 1;
+ unsigned reserved : 13;
+ } error_log;
+ unsigned short bytepersector;
+ unsigned short nbhead; /* DOS: MediaDescriptorByte */
+ unsigned nbcylinder; /* DOS: ClustersOnDisk */
+ unsigned BEER_size;
+ unsigned long long BEER_sector;
+ unsigned long long BEER_HostProtectedArea_start;
+ unsigned long long BEER_ReservedAreaBootCodeAddress;
+ unsigned long long BEER_disksize;
+ signed long long fulldisk_offset; /* Nb sectors before MBR */
+ unsigned long long fulldisk_size; /* only if MBR is offseted */
+ unsigned long long nbtotalsector;
+ unsigned long long config_max_lba;
+ unsigned short nbsectorpertrack; /* DOS: SectorPerCluster */
+
+ unsigned short infobit; /* Int13/48 extensions */
+ unsigned char ebios_version; /* if present, used if access = ebios */
+ unsigned char ebios_extension;
+ ebios_bitmap_t ebios_bitmap;
+ unsigned short reserved3; /* ebios_bitmap is 16 bits */
+
+ unsigned char ebios_bustype[4]; /* exactly "ISA" or "PCI" */
+ unsigned char ebios_Interface[8]; /* exactly "ATA", "ATAPI",
+ "SCSI", "USB"...*/
+ union interface_path_u ebios_bus;
+ union device_path_u ebios_device;
+
+ unsigned short reserved4;
+
+ unsigned short ide_master_password_revision; /* if command_supported1.security */
+ unsigned short ideIOadr; /* if known, else 0 */
+ unsigned short ideIOctrladr; /* if known, else 0 */
+ unsigned char lba_slave_mask; /* see Phenix Bios (head | mask) */
+ unsigned char irq; /* if known, else 0 */
+ unsigned char multiplemode; /* int 0x13/0x21,0x22,0x24 or hardide,
+ set but not used. */
+ unsigned char BEER_device_index;
+ struct config_multiword_dma_s {
+ unsigned short mode0 : 1;
+ unsigned short mode1 : 1; /* and below */
+ unsigned short mode2 : 1; /* and below */
+ unsigned short reserved : 13;
+ } __attribute__ ((packed)) initial_multiDMA, maximum_multiDMA;
+ struct config_ultra_dma_s {
+ unsigned short mode0 : 1;
+ unsigned short mode1 : 1; /* and below */
+ unsigned short mode2 : 1; /* and below */
+ unsigned short mode3 : 1; /* and below */
+ unsigned short mode4 : 1; /* and below */
+ unsigned short mode5 : 1; /* and below */
+ unsigned short reserved : 10;
+ } __attribute__ ((packed)) initial_ultraDMA, maximum_ultraDMA;
+ struct config_feature_s {
+ unsigned short smart_feature : 1;
+ unsigned short smart_selftest : 1;
+ unsigned short smart_errorlog : 1;
+ unsigned short security : 1;
+ unsigned short standby_powerup : 1;
+ unsigned short RW_DMA_queued : 1;
+ unsigned short acoustic : 1;
+ unsigned short host_prot_area : 1;
+ unsigned short lba48 : 1;
+ unsigned short reserved : 7;
+ } __attribute__ ((packed)) initial_feature, maximum_feature;
+ unsigned CalibrationIdeloop; /* nanoseconds (10^-9) per loop */
+
+ /* Following three only for C/H/S partition, from standard BIOS: */
+ unsigned short bios_nbcylinder; /* max 1024 */
+ unsigned char bios_nbhead; /* max 256 */
+ unsigned char bios_nbsectorpertrack; /* max 63 */
+
+ unsigned char bootable; /* nonzero: bootable,
+ > 1 when special bootsector recognised */
+ unsigned char OSdisknumber; /* as written in the boot block */
+
+ unsigned short nbpartition;
+ unsigned short nbOSnumber;
+ unsigned short reserved5;
+ /* Following value is current extended primary partition,
+ if there is more than one extended primary partition. */
+ unsigned first_ext_partition_start; /* NOT A LONG LONG */
+ struct partition_str {
+ unsigned long long start, length;
+ /* OSnumber should be equal to the # in /dev/hda#: */
+ unsigned char type, OSnumber;
+ struct partition_misc_str {
+ /* order as found on disk: */
+ unsigned char order : 6;
+ unsigned char fsanalyse_toobig : 1;
+ unsigned char fsanalyse_error : 1;
+ unsigned char maybe_root : 1;
+ unsigned char fat_bootable : 1;
+ unsigned char beer_partition : 1;
+ unsigned char swap_partition : 1;
+ unsigned char reserved : 2;
+ enum part_state {
+ part_invalid = 0, part_active,
+ part_inactive, part_extended
+ } active : 2;
+ } __attribute__ ((packed)) misc;
+#define MAX_DISKNAMESIZE (64 - 20 - 4) /* bigger than "floppy" */
+ unsigned char name[MAX_DISKNAMESIZE];
+ union {
+ ISO9660_Validation_entry *validation; /* first one only */
+ ISO9660_Default_entry *catalog; /* array index >= 1 */
+ } ElTorito;
+ } __attribute__ ((packed)) *partition;
+
+ unsigned nbfreelist;
+ struct freelist_str {
+ unsigned long long start, length;
+ } *freelist;
+ char set_max_password[32];
+ } *param;
+
+struct disk_interface_str {
+ unsigned nbdisk;
+ unsigned char max_disk, max_partition, max_freelist, max_IDE_found;
+ unsigned short sizeof_diskparam_str, sizeof_partition_str;
+ unsigned short sizeof_freelist_str, sizeof_IDE_found_str;
+ unsigned char nb_bios_fd, nb_bios_hd, cannot_reset_floppy,
+ nb_bios_blacklist;
+ unsigned char bios_blacklist[4];
+ unsigned reserved1[2];
+ unsigned char (*readsector) (struct diskparam_str *dp, int partition,
+ unsigned long long lba, unsigned number,
+ farptr buffer);
+ unsigned char (*writesector) (struct diskparam_str *dp, int partition,
+ unsigned long long lba, unsigned number,
+ farptr buffer);
+ int (*ideSecurity) (struct diskparam_str *, char *,
+ unsigned);
+ unsigned long long last_lba_read_or_write;
+ struct diskparam_str *param;
+ unsigned nb_IDE_found;
+ struct IDE_found_str {
+ unsigned short ideIOadr;
+ unsigned short ideIOctrladr;
+ unsigned char irq;
+ unsigned char bios_order;
+ unsigned short reserved;
+ } *IDE_found;
+};
+
+CODE static inline int
+add_hexletter (unsigned short *val, unsigned char hexletter)
+{
+ if (hexletter >= '0' && hexletter <= '9')
+ *val = (*val << 4) + hexletter - '0';
+ else if (hexletter >= 'a' && hexletter <= 'f')
+ *val = (*val << 4) + hexletter - 'a' + 10;
+ else if (hexletter >= 'A' && hexletter <= 'F')
+ *val = (*val << 4) + hexletter - 'A' + 10;
+ else
+ return 1;
+ return 0;
+}
+
+/* If the "ide[0-9]=" are already given on the command line, that may
+ indicate the user wants a special order - and we probe that order
+ to guess the root partition: */
+CODE static inline void
+init_IDE_found_from_cmdline (struct IDE_found_str *IDE_found,
+ const unsigned nb_IDE_found, const char *cmdptr)
+{
+ while (*cmdptr) {
+ if (cmdptr[0] == 'i' && cmdptr[1] == 'd' && cmdptr[2] == 'e'
+ && cmdptr[3] >= '0' && cmdptr[3] <= '9'
+ && cmdptr[4] == '='
+ && cmdptr[5] == '0' && cmdptr[6] == 'x') {
+ unsigned short IOaddr = 0, IOctrladr = 0;
+ unsigned short index = cmdptr[3] - '0';
+ unsigned char irq = 0;
+
+ cmdptr += 7;
+ while (add_hexletter (&IOaddr, *cmdptr) == 0)
+ cmdptr++;
+ /* Why did you read up to here? Don't you trust me? */
+ if (cmdptr[0] == ',' && cmdptr[1] == '0'
+ && cmdptr[2] == 'x') {
+ cmdptr += 3;
+ while (add_hexletter (&IOctrladr, *cmdptr) == 0)
+ cmdptr++;
+ if (*cmdptr == ',') {
+ cmdptr++;
+ while (*cmdptr >= '0' && *cmdptr <= '9')
+ irq = (irq * 10) + *cmdptr++ - '0';
+ }
+ }
+
+ /* first unknown char shall be spacing or end of string */
+ if ( (*cmdptr == ' ' || *cmdptr == '\0')
+ && index < nb_IDE_found)
+ IDE_found[index] = (struct IDE_found_str) {
+ .ideIOadr = IOaddr,
+ .ideIOctrladr = IOctrladr,
+ .irq = irq,
+ .bios_order = 0xFF,
+ .reserved = 0
+ };
+ }
+ else
+ cmdptr++;
+ }
+}
+
+/* If no "ide[0-9]=" given, we use the BIOS order found by Gujin;
+ if Gujin knows more IDEs (just one ide added like: ide2=0x...
+ but not ide0= and ide1=) add the obvious missing ones,
+ without erasing nor offseting the user given information: */
+CODE static inline void
+init_IDE_found_from_DI (struct IDE_found_str *IDE_found,
+ const unsigned nb_IDE_found,
+ const struct disk_interface_str *DI)
+{
+ unsigned cpt;
+
+ for (cpt = 0; cpt < DI->nb_IDE_found; cpt++) {
+ unsigned i, j;
+ for (i = 0; i < nb_IDE_found; i++)
+ if (IDE_found[i].ideIOadr == DI->IDE_found[cpt].ideIOadr)
+ break;
+ if (i < nb_IDE_found)
+ continue; /* already given */
+ for (j = 0; j < nb_IDE_found; j++)
+ if (IDE_found[j].ideIOadr == 0)
+ break; /* first unused */
+ if (j < nb_IDE_found)
+ IDE_found[j] = DI->IDE_found[cpt];
+ }
+}
+
+CODE static inline void
+finalise_cmdline (struct IDE_found_str *IDE_found, unsigned nb_IDE_found,
+ char *command_line)
+{
+ static CONST char itoa_array[] = "0123456789abcdef";
+ unsigned cpt;
+ char *cmdptr = command_line;
+
+ while (*cmdptr != '\0')
+ cmdptr++;
+ for (cpt = 0; cpt < nb_IDE_found; cpt++) {
+ unsigned short val;
+ if ( IDE_found[cpt].ideIOadr == 0
+ || IDE_found[cpt].bios_order == 0xFF)
+ continue;
+ if (cmdptr - command_line > 1024)
+ break;
+ *cmdptr++ = ' ';
+ *cmdptr++ = 'i'; *cmdptr++ = 'd'; *cmdptr++ = 'e';
+ *cmdptr++ = '0' + cpt;
+ *cmdptr++ = '='; *cmdptr++ = '0'; *cmdptr++ = 'x';
+ val = IDE_found[cpt].ideIOadr;
+ if (val & 0xF000)
+ *cmdptr++ = itoa_array[val >> 12];
+ *cmdptr++ = itoa_array[(val >> 8) & 0x0F];
+ *cmdptr++ = itoa_array[(val >> 4) & 0x0F];
+ *cmdptr++ = itoa_array[(val >> 0) & 0x0F];
+ val = IDE_found[cpt].ideIOctrladr;
+ if (val) {
+ *cmdptr++ = ',';
+ *cmdptr++ = '0';
+ *cmdptr++ = 'x';
+ if (val & 0xF000)
+ *cmdptr++ = itoa_array[val >> 12];
+ *cmdptr++ = itoa_array[(val >> 8) & 0x0F];
+ *cmdptr++ = itoa_array[(val >> 4) & 0x0F];
+ *cmdptr++ = itoa_array[(val >> 0) & 0x0F];
+ val = IDE_found[cpt].irq; /* < 100 */
+ if (val) {
+ *cmdptr++ = ',';
+ *cmdptr++ = itoa_array[val / 10];
+ *cmdptr++ = itoa_array[val % 10];
+ }
+ }
+ *cmdptr = '\0';
+ }
+}
+
+/* root= parameter not present, set it depending on system_desc->disk,
+ system_desc->partition and the number of slash in the kernel name as
+ found in the GZIP name field.
+ Note that we assume that IF the kernel file loaded was in the top
+ directory AND the partition size is too small, it is a "/boot"
+ partition and the real root is the NEXT partition of type 0x83 if it exists.
+ Gujin prefers a lot having only one root partition containning everything
+ including "/boot", but try to stay compatible. */
+CODE static inline void
+add_root_parameter (const struct desc_str *system_desc, char *cmdptr,
+ const struct IDE_found_str IDE_found[10],
+ const unsigned nb_IDE_found,
+ const struct disk_interface_str *DI,
+ const unsigned nb_slash_in_kernelname)
+ {
+ const struct diskparam_str *const dp = &DI->param[system_desc->disk];
+ const unsigned min_part_size = 640 * 1024 * 1024 / dp->bytepersector;
+ unsigned OSnumber = dp->partition[system_desc->partition].OSnumber;
+ static CONST char root_pattern[] = " root=/dev/";
+
+ if ( system_desc->curdir == inRoot
+ && nb_slash_in_kernelname != 1 /* not really created in root dir */
+ && dp->partition[system_desc->partition].length < min_part_size) {
+ /* find the next bigger 0x83 partition on same disk: */
+ unsigned partition;
+ for (partition = system_desc->partition;
+ partition < dp->nbpartition;
+ partition++)
+ if ( dp->partition[partition].length > min_part_size
+ && dp->partition[partition].type == 0x83) {
+ OSnumber = dp->partition[partition].OSnumber;
+ break;
+ }
+ }
+
+ if (dp->ideIOadr != 0) {
+ /* seriously looks like an IDE disk, isn't it? */
+ unsigned cptide;
+ for (cptide = 0; cptide < nb_IDE_found; cptide++)
+ if (dp->ideIOadr == IDE_found[cptide].ideIOadr)
+ break;
+ if (cptide < nb_IDE_found) {
+ const char *ptr = root_pattern;
+ while (*ptr)
+ *cmdptr++ = *ptr++;
+ *cmdptr++ = 'h';
+ *cmdptr++ = 'd';
+ *cmdptr++ = 'a' + 2 * cptide + !!(dp->lba_slave_mask & 0x10);
+ *cmdptr++ = '0' + OSnumber;
+ *cmdptr = '\0';
+ }
+ } else {
+ /* count number of [E]BIOS hard disks and compare to the
+ number of IDE hard disk to know if there are SCSI disks: */
+ unsigned cpt_bios_disk = 0, cpt_ide_disk = 0, cptdisk;
+ unsigned char maybe_scsi = 0;
+ const char *ptr = root_pattern;
+
+ for (cptdisk = 0; cptdisk < DI->nbdisk; cptdisk++) {
+ if ( DI->param[cptdisk].access == bios_chs
+ || DI->param[cptdisk].access == ebios_lba) {
+ if (DI->param[cptdisk].disknb >= 0x80) {
+ cpt_bios_disk++;
+ if (DI->param[cptdisk].ideIOadr == 0)
+ maybe_scsi = 1;
+ } /* else floppy disk */
+ }
+ else if (DI->param[cptdisk].access == hardide_chs
+ || DI->param[cptdisk].access == hardide_lba
+ || DI->param[cptdisk].access == hardide_lba48)
+ cpt_ide_disk++; /* not CDROM, not empty IDE */
+ }
+ while (*ptr)
+ *cmdptr++ = *ptr++;
+ /* If we have the same amount or less BIOS disks than IDE
+ disks, we assume we have a normal (or a very old w/o EBIOS) PC
+ without SCSI or USB drives, then assume BIOS mapping like
+ IDE mapping: 0x80 master on IDE0; else we assume all SCSI
+ drives are after the BIOS/IDE drives: */
+ if (maybe_scsi != 0 && cpt_bios_disk > cpt_ide_disk
+ && dp->disknb >= 0x80 + cpt_bios_disk)
+ *cmdptr++ = 's';
+ else {
+ cpt_bios_disk = 0; /* no sda to hda correction */
+ *cmdptr++ = 'h';
+ }
+ *cmdptr++ = 'd';
+ /* If bootsector OSdisknumber initialised to something
+ else than 0 or 0x80, we assume the user forced
+ it and use that value ('a' for number 0x80): */
+ if ((dp->OSdisknumber & 0x7F) != 0)
+ *cmdptr++ = 'a' + (dp->OSdisknumber & 0x7F);
+ else
+ *cmdptr++ = 'a' + dp->disknb - 0x80 - cpt_bios_disk;
+ *cmdptr++ = '0' + OSnumber;
+ *cmdptr = '\0';
+ }
+}
+
+CODE static void
+vmlinuz_ROOT (const struct desc_str *system_desc,
+ const struct gpl_compliant_str *togpl,
+ char *command_line, unsigned nb_slash_in_kernelname)
+{
+ const struct disk_interface_str *DI =
+ (const struct disk_interface_str *)togpl->DI;
+ char *cmdptr;
+#if 0 /* problem with linker, so do not call memset */
+ struct IDE_found_str IDE_found[10] = {};
+#else
+ struct IDE_found_str IDE_found[10];
+ unsigned i = sizeof (IDE_found) / sizeof(IDE_found[0]);
+ while (i--)
+ IDE_found[i].ideIOadr = IDE_found[i].ideIOctrladr
+ = IDE_found[i].irq = IDE_found[i].bios_order
+ = IDE_found[i].reserved = 0;
+#endif
+
+#if 0
+ DBG("togpl = 0x", (unsigned)togpl, ": ");
+ DBG("signature = 0x", togpl->signature, ", ");
+ DBG("version = 0x", togpl->version, ", ");
+ DBG("feature = 0x", togpl->feature, ", ");
+ DBG("size = 0x", togpl->size, ", ");
+ DBG("offsetof(struct gpl_compliant_str, DI) + 4 = 0x",
+ offsetof(struct gpl_compliant_str, DI) + 4, "\r\n");
+ DBG_WAIT();
+#endif
+
+ if (togpl == 0 || togpl->signature != 16980327
+ || (togpl->version >> 8) != 1 || (togpl->feature & 1) == 0
+ || togpl->size <= offsetof(struct gpl_compliant_str, DI) + 4)
+ return;
+
+ init_IDE_found_from_cmdline (IDE_found,
+ sizeof(IDE_found)/sizeof(IDE_found[0]), command_line);
+ init_IDE_found_from_DI (IDE_found,
+ sizeof(IDE_found)/sizeof(IDE_found[0]), DI);
+
+#if 0
+ {
+ unsigned cpt;
+
+ for (cpt = 0; cpt < sizeof(IDE_found)/sizeof(IDE_found[0]); cpt++) {
+ DBG("IDE_found[cpt = 0x", cpt, "] : ");
+ DBG("ideIOadr = 0x", IDE_found[cpt].ideIOadr, ", ");
+ DBG("ideIOctrladr = 0x", IDE_found[cpt].ideIOctrladr, ", ");
+ DBG("irq = 0x", IDE_found[cpt].irq, ", ");
+ DBG("bios_order = 0x", IDE_found[cpt].bios_order, "\r\n");
+ }
+ DBG_WAIT();
+ }
+#endif
+
+ /* If "root=" is given, do not try to guess it: */
+ for (cmdptr = command_line; *cmdptr != '\0'; cmdptr++)
+ if (cmdptr[0] == 'r' && cmdptr[1] == 'o' && cmdptr[2] == 'o'
+ && cmdptr[3] == 't' && cmdptr[4] == '=')
+ break;
+
+ /* sizeof struct diskparam_str 256, sizeof struct partition_str 64 */
+ if (*cmdptr == '\0'
+ && sizeof (struct diskparam_str) == DI->sizeof_diskparam_str
+ && sizeof (struct partition_str) == DI->sizeof_partition_str
+ && DI->param[system_desc->disk].bytepersector != 0)
+ add_root_parameter (system_desc, cmdptr, IDE_found,
+ sizeof(IDE_found)/sizeof(IDE_found[0]),
+ DI, nb_slash_in_kernelname);
+
+ /* Add this after "root=", limited command line length */
+ finalise_cmdline (IDE_found,
+ sizeof(IDE_found)/sizeof(IDE_found[0]), command_line);
+}
+
+#else /* ROOT_EXTENSIVE_SEARCH */
+
+struct desc_str;
+struct gpl_compliant_str;
+#define vmlinuz_ROOT(a, b, c, d) /* nothing */
+
+#endif /* ROOT_EXTENSIVE_SEARCH */
+
+CODE static inline void
+vmlinuz_DISKS (union drive_info *drive1, union drive_info *drive2
+#ifdef ROOT_EXTENSIVE_SEARCH
+ , const struct disk_interface_str *DI
+#endif
+ )
+{
+ unsigned nbsect;
+ unsigned char status, disk = 0x80;
+ union drive_info *drive = drive1;
+ farptr vectoradr = (farptr)(0x41 * 4);
+
+ while (disk <= 0x81) {
+#ifdef ROOT_EXTENSIVE_SEARCH
+ /* Some old and common SCSI card will do an invalid
+ instruction exception in _BIOSDISK_gettype, if the
+ BIOS has not been updated */
+ int cpt;
+ for (cpt = 0; cpt < DI->nb_bios_blacklist; cpt++)
+ if (DI->bios_blacklist[cpt] == disk)
+ break;
+ if (cpt < DI->nb_bios_blacklist)
+ continue;
+#endif
+
+ if (_BIOSDISK_gettype (disk, &nbsect, &status) == 0)
+ get_drive_info (vectoradr, drive);
+ disk++;
+ vectoradr = (farptr)(0x46 * 4);
+ drive = drive2;
+ }
+}
+
+/**
+ ** THE function:
+ **/
+struct LOADER_str {
+ unsigned short sizeof_loader_str, sizeof_fileload_str;
+ struct fileload_str {
+ /* input: */
+ unsigned load_address, max_size_or_crc32;
+ /* only for XMS use: */
+ unsigned KBalloced;
+ unsigned short handle;
+ /* For reference: */
+ unsigned short BOOTWAY_desc_index;
+ /* output: */
+ unsigned compressed_size, uncompressed_size;
+ } fileload[3], *curfileload; /* kernel and initrd */
+ int initrd_index;
+ unsigned short minor_major_root;
+ unsigned short license_compliant;
+ unsigned vmlinuz_byte_treated; /* header + kernel GZIP */
+ unsigned uncompressed_signature;
+ unsigned ramdisk_max;
+ unsigned accept_uncompressed_initrd_filesize;
+ unsigned char post_comment_row, post_comment_col;
+ unsigned short reserved1;
+ unsigned reserved[5];
+ /* Initialised from the "comment" line of the GZIP file */
+ union {
+ unsigned array[32];
+ struct {
+ unsigned NONGPL_productID;
+ unsigned NONGPL_productNB;
+ unsigned min_gujin_version; /* 0x100 for 1.0 */
+ unsigned late_relocation_address;
+ unsigned runadr;
+ unsigned paramadr; /* usually 0x00080000 */
+ unsigned realfct_size; /* in bytes */
+ unsigned minram; /* in kilobytes */
+ unsigned option;
+ unsigned maskcpu;
+ unsigned maskDflags; /* request those bits set,
+ cpuid 0x00000001 in edx (usual) */
+ unsigned maskCflags; /* request those bits set,
+ cpuid 0x00000001 in ecx (new) */
+ unsigned maskBflags; /* unused on PCs */
+ unsigned maskAflags; /* request those bits set,
+ cpuid 0x80000001 */
+ unsigned maskvesa; /* if bit (8-1) set,
+ VESA 8BPP supported */
+ unsigned maskresolution; /* bit set => exclude
+ those modes */
+ } elem;
+ } comment;
+ /* related to Linux version: */
+ char cmdline_extraparam[512];
+ char cmdline_name[128];
+};
+
+CODE __attribute__ ((cdecl, regparm(0))) unsigned
+linux_set_params (unsigned local_return_address,
+ unsigned totalmem,
+ struct loader_t bootloader_type,
+ struct linux_param *LnxParam,
+ const struct LOADER_str *loader,
+ const struct gpl_compliant_str *togpl,
+ const struct desc_str *system_desc,
+ int proposed_row,
+ char **stringptr,
+ unsigned char *proposed_cmdline)
+{
+ unsigned char *ptr;
+ unsigned nb_slash_in_kernelname = 0;
+ test_linux_param_struct();
+
+ vmlinuz_VIDEO (&LnxParam->screen_info, &LnxParam->in_out.vid_mode,
+ proposed_row);
+
+ /* Just needed for old kernels, before 2.2.x: */
+ LnxParam->screen_info.EXT_MEM_K = vmlinuz_EXT_MEM_K();
+
+ /* old Command Line magic for 2.2- kernels: */
+ LnxParam->screen_info.CL_MAGIC = 0xA33F;
+ LnxParam->screen_info.CL_OFFSET = offsetof(struct linux_param,
+ command_line);
+ /* New Command Line magic for 2.4+ kernels: */
+ LnxParam->in_out.cmd_line_ptr = loader->comment.elem.paramadr
+ + offsetof (struct linux_param, command_line);
+
+/* LnxParam->in_out.header_signature.longword = { { 'H', 'd', 'r', 'S' } }; */
+ LnxParam->in_out.header_version_number = 0x0202;
+ LnxParam->in_out.ramdisk_image = loader->fileload[1].load_address;
+ LnxParam->in_out.ramdisk_size = loader->fileload[1].uncompressed_size;
+ LnxParam->in_out.type_of_loader = bootloader_type;
+
+ LnxParam->ALT_MEM_K = totalmem;
+
+ vmlinuz_APM (&LnxParam->apm_bios_info);
+
+ _X86SpeedStepSmi (&LnxParam->X86SpeedStepSmi);
+ vmlinuz_DISKS (&LnxParam->drive1, &LnxParam->drive2
+#ifdef ROOT_EXTENSIVE_SEARCH
+ , (const struct disk_interface_str *)togpl->DI
+#endif
+ );
+ vmlinuz_CONFIG (&LnxParam->sys_desc_table);
+ /* do vmlinuz_EDID() before vmlinuz_E820() so that if the later
+ function describes more than 18 (and less than 32) blocks of memory,
+ the more important information erases the less important one.
+ Since 2.6.12 there isn't any overwrite problem.*/
+ vmlinuz_EDID (&LnxParam->edid_data);
+ LnxParam->nb_E820_entries = vmlinuz_E820 (LnxParam->e820map,
+ sizeof(LnxParam->e820map));
+
+ /* Now the command line stuff: */
+ vmlinuz_CMDLINE (LnxParam->command_line, proposed_cmdline,
+ *(farptr *)stringptr,
+ loader->cmdline_name, loader->cmdline_extraparam);
+
+ for (ptr = LnxParam->command_line; *ptr != '\0'; ptr++) {
+ /* Do not try to be intelligent and do a 32 bits compare,
+ it will generate constant in .rodata.str1.1 or .rodata
+ with a version of GCC or another. */
+ if (ptr[0] == 'e' && ptr[1] == 'd' && ptr[2] == 'd'
+ && ptr[3] == '=')
+ break;
+ }
+ /* I do not know about edd=skipmbr, if there is a read error
+ Gujin will not even boot up to there... */
+ if (*ptr == '\0' || ptr[4] != 'o' || ptr[5] != 'f' || ptr[6] != 'f') {
+ LnxParam->nb_MBRSIG_entries = vmlinuz_MBRSIG (LnxParam->MBRSIG,
+ sizeof(LnxParam->MBRSIG)/sizeof(LnxParam->MBRSIG[0]));
+ LnxParam->nb_EDD_entries = vmlinuz_EDD (LnxParam->edd,
+ sizeof(LnxParam->edd)/sizeof(LnxParam->edd[0]));
+ }
+
+ for (ptr = LnxParam->command_line; *ptr != '\0'; ptr++) {
+#define endparam(c) ((c) == ' ' || (c) == '\n' || (c) == '\t' || (c) == '\0')
+ if (ptr[0] == 'r' && (ptr[1] == 'w' || ptr[1] == 'o')
+ && endparam(ptr[2])) {
+ LnxParam->in_out.root_flags.read_only
+ = (ptr[1] == 'w')? 0 : 1;
+ break;
+ } else {
+ while (!endparam(*ptr))
+ ptr++;
+ }
+ }
+
+ if (loader->cmdline_name)
+ for (ptr = (unsigned char *)loader->cmdline_name;
+ *ptr != '\0';
+ ptr++)
+ if (*ptr == '/')
+ nb_slash_in_kernelname++;
+ vmlinuz_ROOT (system_desc, togpl, LnxParam->command_line,
+ nb_slash_in_kernelname);
+
+ test_vgaprint();
+
+ *stringptr = 0; /* Gujin will not print anything by default */
+// *stringptr = LnxParam->command_line;
+
+ return 0;
+}
reply other threads:[~2007-02-06 0:05 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=94642.67267.qm@web26914.mail.ukl.yahoo.com \
--to=etienne_lorrain@yahoo.fr \
--cc=linux-kernel@vger.kernel.org \
--subject='Re: [PATCH] Compressed ia32 ELF file generation for loading by Gujin 2/3' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).