This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
Re: bzImage support for i386 targets
- From: Ian Campbell <icampbell at arcom dot com>
- To: ecos-discuss at ecos dot sourceware dot org
- Date: Thu, 04 Mar 2004 09:36:34 +0000
- Subject: Re: [ECOS] bzImage support for i386 targets
- Organization: Arcom Control Systems
- References: <1077889352.19779.17.camel@rh.intotoind.com> <404646C9.7000502@eCosCentric.com>
> 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