Index: hal/i386/arch/current/cdl/hal_i386.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/hal/i386/arch/current/cdl/hal_i386.cdl,v retrieving revision 1.10 diff -u -b -B -w -p -u -r1.10 hal_i386.cdl --- hal/i386/arch/current/cdl/hal_i386.cdl 23 May 2002 23:03:02 -0000 1.10 +++ hal/i386/arch/current/cdl/hal_i386.cdl 20 Feb 2003 11:50:42 -0000 @@ -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 Thu Apr 11 15:25:15 2002 +++ hal/i386/arch/current/src/redboot_linux_exec.c Mon Feb 17 16:54:13 2003 @@ -0,0 +1,338 @@ +#include +#include + +#include +#ifdef CYGPKG_REDBOOT_NETWORKING +#include +#endif + +#include +#include +#include CYGHWR_MEMORY_LAYOUT_H + +#include + +/* + * 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; +}; + + +static 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, + (void **)&wait_time, (bool *)&wait_time_set, "wait timeout"); + init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM, + (void **)&base_addr, (bool *)&base_addr_set, "base address"); + init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM, + (void **)&length, (bool *)&length_set, "length"); + init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_STR, + (void **)&cmd_line, (bool *)&cmd_line_set, "kernel command line"); + init_opts(&opts[4], 'r', true, OPTION_ARG_TYPE_NUM, + (void **)&ramdisk_addr, (bool *)&ramdisk_addr_set, "ramdisk_addr"); + init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM, + (void **)&ramdisk_size, (bool *)&ramdisk_size_set, "ramdisk_size"); + if (!scan_opts(argc, argv, 1, opts, 6, NULL, 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; + + // Stop all network devices +#ifdef CYGPKG_REDBOOT_NETWORKING + __local_enet_sc->funs->stop(__local_enet_sc); +#endif + + 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); + + cyg_pci_init(); + + 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 [-l ]]\n" + " [-r [-s ]]\n" + " [-c \"kernel command line\"]", + do_linux + ); +