OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [hal/] [i386/] [arch/] [current/] [src/] [redboot_linux_exec.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//=============================================================================
2
//
3
//      redboot_linux_exec.c
4
//
5
//      Boot linux from RedBoot
6
//
7
//=============================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2005 Free Software Foundation, Inc.                        
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//=============================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):   Ian Campbell
43
// Contributors:
44
// Date:        29 Oct 2004
45
// Purpose:     Boot Linux from Redboot
46
// Description: 
47
//
48
//####DESCRIPTIONEND####
49
//
50
//=============================================================================
51
 
52
#include <pkgconf/hal.h>
53
#include <redboot.h>
54
 
55
#ifdef CYGPKG_IO_PCI
56
#include <cyg/io/pci.h>
57
#endif
58
 
59
#ifdef CYGPKG_IO_ETH_DRIVERS
60
#include <cyg/io/eth/eth_drv.h>
61
#endif
62
 
63
#include <cyg/hal/hal_intr.h>
64
#include <cyg/hal/hal_cache.h>
65
#include CYGHWR_MEMORY_LAYOUT_H
66
 
67
#include <cyg/hal/hal_io.h>
68
 
69
/*
70
 * Code to launch a Linux image directly in protected mode.
71
 *
72
 * Jumps directly to the protected mode part of the kernel
73
 */
74
 
75
typedef void (*trampoline_func)
76
     (unsigned long base, unsigned long length, unsigned long entry);
77
 
78
// Defines for the linux loader
79
#define SETUP_SIZE_OFF  497
80
#define SECTSIZE        512
81
#define SETUP_VERSION   0x0201
82
#define SETUP_HIGH      0x01
83
#define BIG_SYSSEG      0x10000
84
#define DEF_BOOTLSEG    0x9020
85
 
86
// From etherboot, this is the header to the image startup code
87
// see Documentation/i386/boot.txt
88
/* Boot sector: bootsect.S */
89
/* VERSION: ALL */
90
struct bootsect_header {
91
     cyg_uint8          pad0[0x1f1];
92
     cyg_uint8          setup_sects;
93
     cyg_uint16         root_flags;     // If set, the root is mounted readonly
94
     cyg_uint16         syssize;        // DO NOT USE - for bootsect.S use only
95
     cyg_uint16         swap_dev;       // DO NOT USE - obsolete
96
     cyg_uint16         ram_size;       // DO NOT USE - for bootsect.S use only
97
     cyg_uint16         vid_mode;       // Video mode control
98
     cyg_uint16         root_dev;       // Default root device number
99
     cyg_uint16         boot_flag;      // 0xAA55 magic number
100
} __attribute__((packed));
101
 
102
/* setup.S */
103
/* VERSION: 2.00+ */
104
struct setup_header {
105
     cyg_uint8          jump[2];
106
     cyg_uint8          magic[4];       // "HdrS"
107
     cyg_uint16         version;        // >= 0x0201 for initrd
108
     cyg_uint8          realmode_swtch[4];
109
     cyg_uint16         start_sys_seg;
110
     cyg_uint16         kernel_version;
111
     /* note: above part of header is compatible with loadlin-1.5
112
      * (header v1.5), must not change it */
113
     cyg_uint8          type_of_loader;
114
     cyg_uint8          loadflags;
115
     cyg_uint16         setup_move_size;
116
     unsigned long      code32_start;
117
     unsigned long      ramdisk_image;
118
     unsigned long      ramdisk_size;
119
     unsigned long      bootsect_kludge;
120
     /* VERSION: 2.01+ */
121
     cyg_uint16         heap_end_ptr;
122
     cyg_uint16         pad1;
123
     /* VERSION: 2.02+ */
124
     unsigned long      cmd_line_ptr;
125
     /* VERSION: 2.03+ */
126
     unsigned long      initrd_addr_max;
127
} __attribute__((packed));
128
 
129
#define PARAM                   0x90000
130
#define PARAM_ORIG_X            *(cyg_uint8*) (PARAM+0x000)
131
#define PARAM_ORIG_Y            *(cyg_uint8*) (PARAM+0x001)
132
#define PARAM_EXT_MEM_K         *(cyg_uint16*)(PARAM+0x002)
133
#define PARAM_ORIG_VIDEO_PAGE   *(cyg_uint16*)(PARAM+0x004)
134
#define PARAM_ORIG_VIDEO_MODE   *(cyg_uint8*) (PARAM+0x006)
135
#define PARAM_ORIG_VIDEO_COLS   *(cyg_uint8*) (PARAM+0x007)
136
#define PARAM_ORIG_VIDEO_EGA_BX *(cyg_uint16*)(PARAM+0x00a)
137
#define PARAM_ORIG_VIDEO_LINES  *(cyg_uint8*) (PARAM+0x00E)
138
#define PARAM_ORIG_VIDEO_ISVGA  *(cyg_uint8*) (PARAM+0x00F)
139
#define PARAM_ORIG_VIDEO_POINTS *(cyg_uint16*)(PARAM+0x010)
140
 
141
#define PARAM_ALT_MEM_K         *(cyg_uint32*)(PARAM+0x1e0)
142
#define PARAM_E820NR            *(cyg_uint8*) (PARAM+0x1e8)
143
#define PARAM_VID_MODE          *(cyg_uint16*)(PARAM+0x1fa)
144
#define PARAM_E820MAP           (struct e820entry*)(PARAM+0x2d0);
145
#define PARAM_CMDLINE           (char *)(PARAM+0x3400)
146
 
147
void
148
do_exec(int argc, char **argv)
149
{
150
     unsigned long entry;
151
     unsigned long oldints;
152
     bool wait_time_set;
153
     int  wait_time, res;
154
     bool  base_addr_set, length_set, cmd_line_set;
155
     bool ramdisk_addr_set, ramdisk_size_set;
156
     unsigned long base_addr, length;
157
     unsigned long ramdisk_addr, ramdisk_size;
158
     struct option_info opts[6];
159
     char *cmd_line;
160
     char line[8];
161
     cyg_uint32 mem_size;
162
     cyg_uint32 int15_e801;
163
     extern char __tramp_start__[], __tramp_end__[];
164
     trampoline_func trampoline =
165
          (trampoline_func)CYGHWR_REDBOOT_I386_TRAMPOLINE_ADDRESS;
166
     struct bootsect_header *bs_header;
167
     struct setup_header *s_header;
168
     int setup_sects;
169
     int xpos = 0, ypos = 0;
170
 
171
     base_addr = load_address;
172
     length = load_address_end - load_address;
173
     // Round length up to the next quad word
174
     length = (length + 3) & ~0x3;
175
 
176
     ramdisk_size = 4096*1024;
177
     init_opts(&opts[0], 'w', true, OPTION_ARG_TYPE_NUM,
178
               &wait_time, &wait_time_set, "wait timeout");
179
     init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM,
180
               &base_addr, &base_addr_set, "base address");
181
     init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
182
               &length, &length_set, "length");
183
     init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_STR,
184
               &cmd_line, &cmd_line_set, "kernel command line");
185
     init_opts(&opts[4], 'r', true, OPTION_ARG_TYPE_NUM,
186
               &ramdisk_addr, &ramdisk_addr_set, "ramdisk_addr");
187
     init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
188
               &ramdisk_size, &ramdisk_size_set, "ramdisk_size");
189
     if (!scan_opts(argc, argv, 1, opts, 6, 0, 0, "starting address"))
190
     {
191
          return;
192
     }
193
 
194
     if (wait_time_set) {
195
          int script_timeout_ms = wait_time * 1000;
196
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
197
          unsigned char *hold_script = script;
198
          script = (unsigned char *)0;
199
#endif
200
          diag_printf("About to boot linux kernel at %p - "
201
                      "abort with ^C within %d seconds\n",
202
                      (void *)base_addr, wait_time);
203
          while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
204
               res = _rb_gets(line, sizeof(line),
205
                              CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
206
               if (res == _GETS_CTRLC) {
207
#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
208
                    script = hold_script;  // Re-enable script
209
#endif
210
                    return;
211
               }
212
               script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
213
          }
214
     }
215
 
216
     if (base_addr_set && !length_set) {
217
          diag_printf("Length required for non-standard base address\n");
218
          return;
219
     }
220
 
221
     bs_header = (struct bootsect_header *)base_addr;
222
     s_header = (struct setup_header *)(base_addr + SECTSIZE);
223
 
224
     if (bs_header->boot_flag != 0xAA55) {
225
          diag_printf("Bootsector magic not found (0x%04x @ %4p)\n",
226
                      bs_header->boot_flag, &bs_header->boot_flag);
227
          return;
228
     }
229
     if (memcmp(s_header->magic,"HdrS",4) != 0) {
230
          diag_printf("Linux header (HdrS) not found\n");
231
          return;
232
     }
233
     if (s_header->version < SETUP_VERSION) {
234
          diag_printf("Linux header version = 0x%04x. "
235
                      "Needs to be at least 0x%04x\n",
236
                      s_header->version, SETUP_VERSION);
237
          return;
238
     }
239
 
240
     setup_sects = bs_header->setup_sects ? bs_header->setup_sects : 4;
241
 
242
     entry = s_header->code32_start;
243
     // + 1 for boot sector
244
     base_addr += (setup_sects + 1 ) * SECTSIZE;
245
     length -= (setup_sects + 1 ) * SECTSIZE;
246
 
247
     mem_size = (cyg_uint32)HAL_MEM_REAL_REGION_TOP((cyg_uint8 *)0x1000000);
248
     mem_size >>= 10;   // convert from bytes to kilobytes.
249
     // Result of int15 ax=0xe801
250
     int15_e801 = mem_size - 1024 ; // 1M+ only
251
 
252
     // Stop all network devices
253
#ifdef CYGPKG_IO_ETH_DRIVERS
254
     eth_drv_stop();
255
#endif
256
 
257
#ifdef CYGPKG_IO_PCI
258
     cyg_pci_init();
259
#endif
260
 
261
#if CYGINT_HAL_I386_PCMB_SCREEN_SUPPORT > 0
262
     cyg_hal_plf_screen_position(&xpos, &ypos);
263
#endif
264
 
265
     HAL_DISABLE_INTERRUPTS(oldints);
266
     HAL_DCACHE_SYNC();
267
     HAL_ICACHE_DISABLE();
268
     HAL_DCACHE_DISABLE();
269
     HAL_DCACHE_SYNC();
270
     HAL_ICACHE_INVALIDATE_ALL();
271
     HAL_DCACHE_INVALIDATE_ALL();
272
 
273
     // Clear the data area
274
     memset ( (void*)PARAM, 0, 512 );
275
 
276
     if ( cmd_line_set )
277
          strcpy( PARAM_CMDLINE, cmd_line );
278
     else
279
          strcpy( PARAM_CMDLINE, "auto");
280
 
281
     memcpy((void*)(PARAM+SECTSIZE), s_header, sizeof(struct setup_header));
282
     s_header = (struct setup_header*)(0x90000+SECTSIZE);
283
 
284
     s_header->version = SETUP_VERSION;
285
 
286
     // Command Line
287
     s_header->cmd_line_ptr = 0x93400;
288
 
289
     // Loader type
290
     s_header->type_of_loader = 0xFF;
291
 
292
     // Fill in the interesting bits of data area...
293
     // ... Memory sizes
294
     PARAM_EXT_MEM_K = int15_e801;
295
     PARAM_ALT_MEM_K = int15_e801;
296
 
297
     // ... No e820 map!
298
     PARAM_E820NR = 0;   // Length of map
299
 
300
     // ... Video stuff
301
     PARAM_ORIG_X = xpos;
302
     PARAM_ORIG_Y = ypos;
303
     PARAM_ORIG_VIDEO_MODE = 2;
304
     PARAM_ORIG_VIDEO_COLS = 80;
305
     PARAM_ORIG_VIDEO_LINES = 25;
306
     PARAM_ORIG_VIDEO_ISVGA = 0;
307
 
308
     // Copy trampoline to trampoline address
309
     memcpy((char *)CYGHWR_REDBOOT_I386_TRAMPOLINE_ADDRESS,
310
            __tramp_start__,
311
            __tramp_end__ - __tramp_start__);
312
 
313
     trampoline(base_addr, length, entry);
314
 
315
#define _QUOTE_STRING(__x__)    #__x__
316
#define QUOTE_STRING(__x__)     _QUOTE_STRING(__x__)
317
 
318
     asm volatile (
319
          "__tramp_start__:\n"
320
          "       push   %%ebp;\n"
321
          "       mov    %%esp,%%ebp;\n"
322
 
323
          /* STACK IS:
324
           * OLD BP               0x4(%ebp)
325
           * ENTRY                0x8(%ebp)
326
           * LENGTH               0xC(%ebp)
327
           * BASE ADDRESS         0x10(%ebp) */
328
 
329
          "       movl    0x10(%%ebp), %%ebx;\n"  /* Save entry point
330
                                                     in EBX, because
331
                                                     we overwrite the
332
                                                     stack */
333
 
334
          "       cli;\n"                         /* no interrupts allowed ! */
335
 
336
          "       movb    $0x80, %%al;\n"         /* disable NMI for bootup */
337
          "       outb    %%al, $0x70;\n"         /* sequence */
338
 
339
          /* Copy GDT to RAM at 0x90400 */
340
          "       movl    $(linux_gdt_end - linux_gdt), %%ecx;\n" /* Length */
341
          "       shrl    $2, %%ecx;\n"                   /* Bytes -> Longs */
342
          "       leal    linux_gdt, %%eax;\n"            /* Source */
343
          "       movl    %%eax, %%esi;\n"
344
          "       movl    $(0x90400), %%edi;\n"           /* Dest */
345
          "1:\n"
346
          "       lodsl;\n"
347
          "       stosl;\n"
348
          "       loop    1b;\n"
349
 
350
          /* If necessary, copy linux image to correct location */
351
          "       movl    0x8(%%ebp), %%esi;\n"           /* Source */
352
          "       movl    %%ebx, %%edi;\n"                /* Destination
353
                                                           * (saved in
354
                                                           * EBX
355
                                                           * above) */
356
          "       cmpl    %%edi, %%esi;\n"
357
          "       je      2f;\n"
358
          "       movl    0xC(%%ebp), %%ecx;\n"           /* Length */
359
          "       shrl    $2, %%ecx;\n"                   /* Bytes to Longs */
360
          "1:\n"
361
          "       lodsl;\n"
362
          "       stosl;\n"
363
          "       loop    1b;\n"
364
          "2:\n"
365
 
366
          /* Create a GDT descriptor at 0 and load it */
367
          "       movl    $0x90000, %%esi;\n"
368
          "       movw    $(linux_gdt_end - linux_gdt), %%ax;\n"
369
          "       dec     %%ax;\n"
370
          "       movw    %%ax,0;\n"
371
          "       movl    $0x90400,%%eax;\n"
372
          "       movl    %%eax,2;\n"
373
          "       lgdt    0;\n"
374
 
375
          /* Reload segment registers */
376
          "       mov     $(0x18), %%eax;\n"
377
          "       movl    %%eax, %%ds;\n"
378
          "       movl    %%eax, %%es;\n"
379
          "       movl    %%eax, %%fs;\n"
380
          "       movl    %%eax, %%gs;\n"
381
 
382
          /* Reload CS */
383
          "       ljmp    $(0x10), $(1f - __tramp_start__ + "
384
          QUOTE_STRING(CYGHWR_REDBOOT_I386_TRAMPOLINE_ADDRESS) ");\n"
385
          "1:\n"
386
 
387
          /* Start kernel */
388
          "       jmp     *%%ebx;\n"
389
 
390
          ".ALIGN 4, 0xCC;\n"
391
 
392
          "__tramp_end__:\n"
393
 
394
          /* Descriptor tables */
395
          "linux_gdt:\n"
396
          "       .word   0, 0, 0, 0;\n"    /* dummy */
397
          "       .word   0, 0, 0, 0;\n"    /* unused */
398
          "       .word   0xFFFF;\n"        /* 4Gb - (0x100000*0x1000
399
                                               * = * 4Gb) */
400
          "       .word   0;\n"             /* base address = 0 */
401
          "       .word   0x9A00;\n"        /* code read/exec */
402
          "       .word   0x00CF;\n"        /* granularity = 4096, 386 */
403
          /*  (+5th nibble of limit) */
404
          "       .word   0xFFFF;\n"        /* 4Gb - (0x100000*0x1000 = 4Gb) */
405
          "       .word   0;\n"             /* base address = 0 */
406
          "       .word   0x9200;\n"        /* data read/write */
407
          "       .word   0x00CF;\n"        /* granularity = 4096, 386 */
408
                                            /*  (+5th nibble of limit) */
409
          "linux_gdt_end:\n"
410
          : : : "eax", "ebx", "ecx");
411
}
412
 
413
RedBoot_cmd("exec",
414
            "Execute a Linux image",
415
            "[-w timeout] [-b <base address> [-l <image length>]]\n"
416
            "        [-r <ramdisk addr> [-s <ramdisk length>]]\n"
417
            "        [-c \"kernel command line\"]",
418
            do_exec
419
     );

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.