This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: bzImage support for i386 targets


> I'm not familiar with that patch, but bzImages don't contain address 
> information so won't you have to load them at a specific address, and then 
> use exec with -b ? But don't take my word for it as I haven't looked at the 
> patch.

I don't know about the patch from Masato Tarunishi, but I posted a patch
a while ago which can boot zImage and bzImage on X86 boards, we have
product which has been using it for ages.

http://sources.redhat.com/ml/ecos-patches/2003-02/msg00122.html

I've attached our most recent code. It works pretty much like the arm
HAL 'exec' command, it'll copy things to the right place etc.

Ian.

-- 
Ian Campbell, Senior Design Engineer
                                        Web: http://www.arcom.com
Arcom, Clifton Road, 			Direct: +44 (0)1223 403 465
Cambridge CB1 7EA, United Kingdom	Phone:  +44 (0)1223 411 200


_____________________________________________________________________
The message in this transmission is sent in confidence for the attention of the addressee only and should not be disclosed to any other party. Unauthorised recipients are requested to preserve this confidentiality. Please advise the sender if the addressee is not resident at the receiving end.  Email to and from Arcom is automatically monitored for operational and lawful business reasons.

This message has been checked for all viruses by MessageLabs Virus Control Centre.
--- packages/hal/i386/arch/current/cdl/hal_i386.cdl	29 May 2003 10:54:25 -0000	1.1.1.1
+++ packages/hal/i386/arch/current/cdl/hal_i386.cdl	29 May 2003 13:26:30 -0000	1.2
@@ -152,6 +152,30 @@ cdl_package CYGPKG_HAL_I386 {
 	}
     }
     
+    cdl_component CYGPKG_REDBOOT_I386_OPTIONS {
+        display       "Redboot for I386 options"
+        flavor        none
+        no_define
+        parent        CYGPKG_REDBOOT
+        active_if     CYGPKG_REDBOOT
+        description   "
+            This option lists the target's requirements for a valid Redboot
+            configuration."
+                                                                                                                               
+        cdl_component CYGPKG_REDBOOT_I386_LINUX_EXEC {
+            display        "Provide the exec command in RedBoot"
+            flavor         none
+            parent         CYGPKG_REDBOOT_I386_OPTIONS
+            active_if      CYGBLD_BUILD_REDBOOT_WITH_EXEC
+            description    "
+                This option contains requirements for booting linux
+                from RedBoot. The component is enabled/disabled from
+                RedBoots CDL."
+            compile -library=libextras.a redboot_linux_exec.c 
+	}
+ 
+    }
+ 
     cdl_option CYGBLD_LINKER_SCRIPT {
         display "Linker script"
         flavor data
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ packages/hal/i386/arch/current/src/redboot_linux_exec.c	1 Oct 2003 08:47:32 -0000	1.2
@@ -0,0 +1,343 @@
+#include <pkgconf/hal.h>
+#include <redboot.h>
+
+#ifdef CYGPKG_IO_PCI
+#include <cyg/io/pci.h>
+#endif
+
+#ifdef CYGPKG_IO_ETH_DRIVERS
+#include <cyg/io/eth/eth_drv.h>
+#endif
+ 
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_cache.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+#include <cyg/hal/hal_io.h>
+
+/* 
+ * Code to launch a Linux image directly in protected mode.
+ *
+ * Jumps directly to the protected mode part of the kernel
+ */
+ 
+typedef void (*trampoline_func)(unsigned long base, unsigned long length, unsigned long entry);
+
+// Defines for the linux loader
+#define SETUP_SIZE_OFF 	497
+#define SECTSIZE       	512
+#define SETUP_VERSION  	0x0201
+#define SETUP_HIGH     	0x01
+#define BIG_SYSSEG     	0x10000
+#define DEF_BOOTLSEG	0x9020
+
+// From etherboot, this is the header to the image startup code
+// see Documentation/i386/boot.txt
+    /* Boot sector: bootsect.S */
+    /* VERSION: ALL */
+struct bootsect_header {
+    cyg_uint8		pad0[0x1f1];
+    cyg_uint8		setup_sects;
+    cyg_uint16		root_flags;	// If set, the root is mounted readonly
+    cyg_uint16		syssize;	// DO NOT USE - for bootsect.S use only
+    cyg_uint16		swap_dev;	// DO NOT USE - obsolete
+    cyg_uint16		ram_size;	// DO NOT USE - for bootsect.S use only
+    cyg_uint16		vid_mode;	// Video mode control
+    cyg_uint16		root_dev;	// Default root device number
+    cyg_uint16		boot_flag;	// 0xAA55 magic number
+};
+
+    /* setup.S */
+    /* VERSION: 2.00+ */
+struct setup_header {
+    cyg_uint8 		jump[2];
+    cyg_uint8 		magic[4];     	// "HdrS"
+    cyg_uint16 		version;      	// >= 0x0201 for initrd
+    cyg_uint8 		realmode_swtch[4];
+    cyg_uint16 		start_sys_seg;
+    cyg_uint16 		kernel_version;
+    /* note: above part of header is compatible with loadlin-1.5 (header v1.5),*/
+    /*       must not change it */
+    cyg_uint8 		type_of_loader;
+    cyg_uint8 		loadflags;
+    cyg_uint16 		setup_move_size;
+    unsigned long 	code32_start;
+    unsigned long 	ramdisk_image;
+    unsigned long 	ramdisk_size;
+    unsigned long 	bootsect_kludge;
+    /* VERSION: 2.01+ */
+    cyg_uint16 		heap_end_ptr;
+    cyg_uint16 		pad1;
+    /* VERSION: 2.02+ */
+    unsigned long 	cmd_line_ptr;
+    /* VERSION: 2.03+ */
+    unsigned long 	initrd_addr_max;
+};
+
+
+void
+do_linux(int argc, char **argv)
+{    
+    unsigned long entry;
+    unsigned long oldints;
+    bool wait_time_set;
+    int  wait_time, res;
+    bool  base_addr_set, length_set, cmd_line_set;
+    bool ramdisk_addr_set, ramdisk_size_set;
+    unsigned long base_addr, length;
+    unsigned long ramdisk_addr, ramdisk_size;
+    struct option_info opts[6];
+    char *cmd_line;
+    char line[8];
+    cyg_uint32 mem_size;
+    cyg_uint32 int15_e801;
+    extern char __tramp_start__[], __tramp_end__[];
+    trampoline_func trampoline = (trampoline_func)CYGHWR_REDBOOT_I386_TRAMPOLINE_ADDRESS;
+    struct bootsect_header *bs_header;
+    struct setup_header *s_header;
+    int setup_sects;
+
+    base_addr = load_address;
+    length = load_address_end - load_address;
+    // Round length up to the next quad word
+    length = (length + 3) & ~0x3;
+
+    ramdisk_size = 4096*1024;
+    init_opts(&opts[0], 'w', true, OPTION_ARG_TYPE_NUM,
+              &wait_time, &wait_time_set, "wait timeout");
+    init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM,
+              &base_addr, &base_addr_set, "base address");
+    init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
+              &length, &length_set, "length");
+    init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_STR,
+              &cmd_line, &cmd_line_set, "kernel command line");
+    init_opts(&opts[4], 'r', true, OPTION_ARG_TYPE_NUM,
+              &ramdisk_addr, &ramdisk_addr_set, "ramdisk_addr");
+    init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
+              &ramdisk_size, &ramdisk_size_set, "ramdisk_size");
+    if (!scan_opts(argc, argv, 1, opts, 6, 0, 0, "starting address"))
+    {
+        return;
+    }
+
+    if (wait_time_set) {
+        int script_timeout_ms = wait_time * 1000;
+#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
+        unsigned char *hold_script = script;
+        script = (unsigned char *)0;
+#endif
+        diag_printf("About to boot linux kernel at %p - abort with ^C within %d seconds\n",
+                    (void *)base_addr, wait_time);
+        while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
+            res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
+            if (res == _GETS_CTRLC) {
+#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
+                script = hold_script;  // Re-enable script
+#endif
+                return;
+            }
+            script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
+        }
+    }
+
+    if (base_addr_set && !length_set) {
+        diag_printf("Length required for non-standard base address\n");
+        return;
+    }
+
+    bs_header = (struct bootsect_header *)base_addr;
+    s_header = (struct setup_header *)(base_addr + SECTSIZE);
+
+    if (bs_header->boot_flag != 0xAA55) {
+        diag_printf("Bootsector magic not found (0x%04x @ 0x%04x)\n", bs_header->boot_flag, &bs_header->boot_flag);
+        return;
+    }
+    if (memcmp(s_header->magic,"HdrS",4) != 0) {
+        diag_printf("Linux header (HdrS) not found\n");
+        return;
+    }
+    if (s_header->version < SETUP_VERSION) {
+        diag_printf("Linux header version = 0x%04x. Needs to be at least 0x%04x\n",
+                    s_header->version, SETUP_VERSION);
+        return;
+    }
+
+    setup_sects = bs_header->setup_sects ? bs_header->setup_sects : 4;
+
+    entry = s_header->code32_start;
+    // + 1 for boot sector
+    base_addr += (setup_sects + 1 ) * SECTSIZE;
+    length -= (setup_sects + 1 ) * SECTSIZE;
+
+    mem_size = (unsigned long)(ram_end); /* ram_start is the start of usable RAM, so 
+                                          * not useful here, because we want the whole 
+                                          * of RAM. I'm pretty sure X86 always has RAM
+                                          * starting at 0.
+                                          */
+    //diag_printf("ram_start=%p ram_end=%p size=%p\n", ram_start, ram_end, mem_size);
+    mem_size >>= 10;   // convert from bytes to kilobytes.
+    // Result of int15 ax=0xe801
+    int15_e801 = mem_size - 1024 ; // 1M+ only
+
+    diag_printf("Linux Protected mode base address %p length %p. Entry at %p.\n",
+                (void*)base_addr, (void*)length, (void*)entry);
+
+    // Stop all network devices
+#ifdef CYGPKG_IO_ETH_DRIVERS
+    eth_drv_stop();
+#endif
+
+#ifdef CYGPKG_IO_PCI
+    cyg_pci_init();
+#endif
+
+    HAL_DISABLE_INTERRUPTS(oldints);
+    HAL_DCACHE_SYNC();
+    HAL_ICACHE_DISABLE();
+    HAL_DCACHE_DISABLE();
+    HAL_DCACHE_SYNC();
+    HAL_ICACHE_INVALIDATE_ALL();
+    HAL_DCACHE_INVALIDATE_ALL();
+
+    // Clear the data area
+    memset ( (void*)0x90000, 0, 512 );
+
+    if ( cmd_line_set )
+        strcpy( (char*)0x93400, cmd_line );
+    else
+        strcpy( (char*)0x93400, "auto");
+
+    memcpy(0x90000+SECTSIZE, s_header, sizeof(struct setup_header));
+    s_header = (struct setup_header*)(0x90000+SECTSIZE);
+
+    s_header->version = SETUP_VERSION;
+
+    // Command Line
+    s_header->cmd_line_ptr = 0x93400;
+ 
+    // Loader type
+    s_header->type_of_loader = 0xFF;
+
+    // Fill in the interesting bits of data area...
+    // ... Memory sizes
+    *(cyg_uint16*)(0x90002) = 0; 	// force use of e801 result below.
+    *(cyg_uint32*)(0x901e0) = int15_e801;
+
+    // ... No e820 map!
+    *(cyg_uint8*) (0x901e8) = 0; 	// Length of map
+
+    // ... Video stuff
+    *(cyg_uint8*) (0x90000) = 0; 	// orig_x
+    *(cyg_uint8*) (0x90001) = 0; 	// orig_y
+    *(cyg_uint8*) (0x90006) = 2; 	// orig_video_mode
+    *(cyg_uint8*) (0x90007) = 80;	// orig_video_cols
+    *(cyg_uint8*) (0x9000E) = 25;	// orig_video_lines
+    *(cyg_uint8*) (0x9000F) = 0;	// orig_video_isVGA
+
+    // Copy trampoline to trampoline address
+    memcpy((char *)CYGHWR_REDBOOT_I386_TRAMPOLINE_ADDRESS,
+           __tramp_start__,
+           __tramp_end__ - __tramp_start__);
+
+    trampoline(base_addr, length, entry);
+
+#define _QUOTE_STRING(__x__) 	#__x__
+#define QUOTE_STRING(__x__)	_QUOTE_STRING(__x__)
+
+    asm volatile (
+        "__tramp_start__:\n"
+	"	push   %%ebp;\n"
+	"	mov    %%esp,%%ebp;\n"
+
+	/* STACK IS:
+         * OLD BP		0x4(%ebp)
+         * ENTRY		0x8(%ebp)
+         * LENGTH		0xC(%ebp)
+         * BASE ADDRESS		0x10(%ebp) */
+        
+	"	movl	0x10(%%ebp), %%ebx;\n"	/* Save entry point in EBX, because we overwrite the stack */
+
+	"	cli;\n"				/* no interrupts allowed ! */
+	
+	"	movb	$0x80, %%al;\n"		/* disable NMI for bootup */
+	"	outb	%%al, $0x70;\n"		/* sequence */
+
+	/* Copy GDT to RAM at 0x90400 */
+	"	movl	$(linux_gdt_end - linux_gdt), %%ecx;\n"	/* Length */
+	"	shrl	$2, %%ecx;\n"			/* Bytes -> Longs */
+	"	leal	linux_gdt, %%eax;\n"		/* Source */
+	"	movl	%%eax, %%esi;\n"
+	"	movl	$(0x90400), %%edi;\n"		/* Dest */
+	"1:\n"
+	"	lodsl;\n"
+	"	stosl;\n"
+	"	loop	1b;\n"
+
+	/* If necessary, copy linux image to correct location */
+	"	movl	0x8(%%ebp), %%esi;\n"		/* Source */
+	"	movl	%%ebx, %%edi;\n"		/* Destination (saved in EBX above) */
+	"	cmpl	%%edi, %%esi;\n"
+	"	je	2f;\n"
+	"	movl 	0xC(%%ebp), %%ecx;\n"		/* Length */
+	"	shrl	$2, %%ecx;\n"			/* Bytes to Longs */
+	"1:\n"
+	"	lodsl;\n"
+	"	stosl;\n"
+	"	loop	1b;\n"
+	"2:\n"
+	
+	/* Create a GDT descriptor at 0 and load it */
+	"	movl	$0x90000, %%esi;\n"
+	"	movw	$(linux_gdt_end - linux_gdt), %%ax;\n"
+        "	dec     %%ax;\n"
+	"	movw	%%ax,0;\n"
+	"	movl	$0x90400,%%eax;\n"
+	"	movl	%%eax,2;\n"
+	"	lgdt	0;\n"
+	
+	/* Reload segment registers */
+	"	mov	$(0x18), %%eax;\n"
+	"	movl 	%%eax, %%ds;\n"
+	"	movl 	%%eax, %%es;\n"
+	"	movl 	%%eax, %%fs;\n"
+	"	movl 	%%eax, %%gs;\n"
+	
+        /* Reload CS */
+        "	ljmp	$(0x10), $(1f - __tramp_start__ + " QUOTE_STRING(CYGHWR_REDBOOT_I386_TRAMPOLINE_ADDRESS) ");\n"
+	"1:\n"
+
+	/* Start kernel */
+        "	jmp	*%%ebx;\n"
+
+	".ALIGN 4, 0xCC;\n"
+
+	"__tramp_end__:\n"
+
+	/* Descriptor tables */
+	"linux_gdt:\n"
+	"	.word	0, 0, 0, 0;\n"			/* dummy */
+	"	.word	0, 0, 0, 0;\n"			/* unused */
+
+	"	.word	0xFFFF;\n"			/* 4Gb - (0x100000*0x1000 = 4Gb) */
+	"	.word	0;\n"				/* base address = 0 */
+	"	.word	0x9A00;\n"			/* code read/exec */
+	"	.word	0x00CF;\n"			/* granularity = 4096, 386 */
+							/*  (+5th nibble of limit) */
+
+	"	.word	0xFFFF;\n"			/* 4Gb - (0x100000*0x1000 = 4Gb) */
+	"	.word	0;\n"				/* base address = 0 */
+	"	.word	0x9200;\n"			/* data read/write */
+	"	.word	0x00CF;\n"			/* granularity = 4096, 386 */
+							/*  (+5th nibble of limit) */
+	"linux_gdt_end:\n"
+        : : : "eax", "ebx", "ecx");
+}
+
+RedBoot_cmd("linux",
+	    "Execute a Linux image",
+	    "[-w timeout] [-b <base address> [-l <image length>]]\n"
+	    "        [-r <ramdisk addr> [-s <ramdisk length>]]\n"
+            "        [-c \"kernel command line\"]",
+	    do_linux
+    );
+

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]