* [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11
@ 2002-05-02 14:42 Eric W. Biederman
2002-04-27 2:56 ` Pavel Machek
2002-05-02 14:45 ` [PATCH 2.5.12] x86 Boot enhancements, linker fixes 2/11 Eric W. Biederman
0 siblings, 2 replies; 20+ messages in thread
From: Eric W. Biederman @ 2002-05-02 14:42 UTC (permalink / raw)
To: Linus Torvalds, Dave Jones; +Cc: linux-kernel
This is the first in a set of 11 patches that enhance the x86 boot
process.
This takes work that I am using everyday and makes a good version
of it that can be included in the kernel.
The major themes are:
- cleanups
- setup.c splitting to handle multiple BIOS flavors.
- Needed to handle LinuxBIOS.
- a 32bit entry point.
- Needed if you don't have a traditional x86 BIOS
- Needed for reliable linux booting linux patches until
the kernel can be fixed. On some systems running linux trashes
he BIOS.
- bean counting of the bootimage.
- Needed for computing the lowest possible ramdisk address about
2.6M with my test kernels.
- Useful for knowing what is actually happening in the boot
process.
If you'd like I'll rip out support for zImages.
The last time I posted this code I heard no criticism of it.
Since last time I posted this code I have made 2 functional changes.
- make clean now deletes the bzElf images
- The linker script now reserves room for the bootmem bitmap,
and with that information I have enough information to load
the ramdisk immediately after the kernel in ram.
#1 boot.boot_params
============================================================
- Introduce asm-i386/boot_param.h and struct boot_params
- Implement struct boot_params in misc.c & setup.c
This removes a lot of magic macros and by keeping all of the
boot parameters in a structure it becomes much easier to track
which boot_paramters we have and where they live. Additionally
this keeps the names more uniform making grepping easier.
#2 boot.vmlinuxlds
============================================================
- i386/Makefile remove bogus linker command line of -e stext
- Fix vmlinux.lds so vmlinux knows it loads at 0x100000 (1MB)
- Fix vmlinux.lds so we correctly use startup_32 for our entry point
- Fix vmlinux.lds so we reserve the bootmem bitmap at the end
of the bss segment.
- Make startup_32 global
#3 boot.spring-cleaning
============================================================
Some pieces of code only make sense if we are a bzImage or
a zImage. Since size is relatively important use conditional
compilation to select between the two.
Plus this clearly marks dead code that we can kill we we drop
support for the zImage format.
#4 boot.syntax
============================================================
All changes are syntactic the generated code is not affected.
- e820.h Add define E820ENTRY_SIZE
- boot.h Add defines for address space divisions.
- Add define KERNEL_START in setup.S so if I need this
value more than once it is easy to get at.
#5 boot.heap
============================================================
Modify video.S so that mode_list is also allocated from
the boot time heap. This probably saves a little memory,
and makes a compiled in command line a sane thing to implement.
- Made certain we don't overwrite code with the E820_MAP
Previously we actually reserved to much memory.
- Changed the lables around the setup.S to _setup && _esetup
The Effective the bootsector size is reduced by 200 bytes.
#6 boot.clean_32bit_entries
============================================================
In general allow any kernel entry point to work given any set of
initial register values, while saving the original registers
values so the C code can do something with it if we desire.
- trampoline.S fix comments, and enter the kernel at
secondary_startup_32 instead of startup_32
- trampoline.S fix gdt_48 to have the correct gdt limit
- Save all of the registers we get from any 32bit entry point,
and don't assume they have any particular value.
- head.S split up startup_32
- secondary_startup_32 handles the SMP case
- move finding the command line to startup.c
- Don't copy the kernel parameters to the initial_zero_page,
instead just pass setup.c where they are located.
- Seperate the segments used by setup.S from the rest of the kernel.
This way bootloader can continue to make assumptions about
which segments setup.S uses while the rest of the kernel
can do whatever is convinient.
- Move boot specific defines into boot.h
#7 boot.footprint
============================================================
Solve the space/reliability tradeoff misc.c asks bootloaders
to make, with belt and suspenders.
- modify misc.c to relocate the real mode code to maximize low
memory usage.
- modify misc.c to do inplace decompression
- modify setup.S to query int12 to get the low memory size
- Introduce STAY_PUT flag for bootloaders that don't pass a
command_line but still don't need the bootsector to relocate
itself.
The kernel now uses approximately 78KB of memory below 1MB and 8 bytes
more than the decompressesed kernel above 1MB. And if required
everything except the 5KB of real mode code can go above 1MB.
The 78KB below 1MB is 5KB real mode code 10KB decompressor code 61KB bss.
The change is especially nice because now in my worst case of only
using 5KB real mode data, I do better than the best case with previous
kernels (assuming it isn't a zImage). With the the bootmem bitmap
reserved in vmlinux.lds I can put initrds down at 2.6MB and not have
to worry about them getting stomped :)
#8 boot.build
============================================================
Rework the actual build/link step for kernel images.
- remove the need for objcopy
- Kill the ROOT_DEV Makefile variable, the implementation
was only half correct and there are much better ways
to specify your root device than modifying the kernel Makefile.
- Don't loose information when the executable is built
Except for a few extra fields in setup.S the binary image
is unchanged.
#9 boot.proto
============================================================
Update the boot protocol to include:
- A compiled in command line
- A 32bit entry point
- File and memory usage information enabling a 1 to 1
conversion between the bzImage format and the static ELF
executable file format.
- In setup.c split the parameters between those that
are compiled in or specified by the bootloader and
those that are queried from the BIOS.
#10 boot.linuxbios
============================================================
Support for reading information from the linuxbios table.
For now I just get the memory size more to come as things
evolve.
#11 boot.elf
============================================================
Add support for generating an ELF executable kernel. External
tools are only needed now to manipulate the command line,
and to add a ramdisk. For netbooting this is very handy.
To revert to a bzImgae you simply strip off the the ELF header.
This should keep the kinds of kernel images floating around low.
diff -uNr linux-2.5.12/Documentation/i386/zero-page.txt linux-2.5.12.boot.boot_params/Documentation/i386/zero-page.txt
--- linux-2.5.12/Documentation/i386/zero-page.txt Mon Aug 30 11:47:02 1999
+++ linux-2.5.12.boot.boot_params/Documentation/i386/zero-page.txt Wed May 1 09:38:29 2002
@@ -9,7 +9,11 @@
arch/i386/boot/video.S
arch/i386/kernel/head.S
arch/i386/kernel/setup.c
-
+
+See include/asm-i386/boot_param.h a structure is kept there with
+uptodate information. The kernel no longer copies this information
+into the empty zero page, but instead uses it directly.
+
Offset Type Description
------ ---- -----------
@@ -65,7 +69,7 @@
0x21c unsigned long INITRD_SIZE, size in bytes of ramdisk image
0x220 4 bytes (setup.S)
0x224 unsigned short setup.S heap end pointer
-0x2d0 - 0x600 E820MAP
+0x2d0 - 0x550 E820MAP
0x800 string, 2K max COMMAND_LINE, the kernel commandline as
copied using CL_OFFSET.
diff -uNr linux-2.5.12/arch/i386/boot/compressed/misc.c linux-2.5.12.boot.boot_params/arch/i386/boot/compressed/misc.c
--- linux-2.5.12/arch/i386/boot/compressed/misc.c Mon Nov 12 10:59:43 2001
+++ linux-2.5.12.boot.boot_params/arch/i386/boot/compressed/misc.c Wed May 1 09:38:29 2002
@@ -13,6 +13,9 @@
#include <linux/vmalloc.h>
#include <linux/tty.h>
#include <asm/io.h>
+#include <linux/apm_bios.h>
+#include <asm/e820.h>
+#include <asm/boot_param.h>
/*
* gzip declarations
@@ -84,13 +87,9 @@
/*
* This is set up by the setup-routine at boot-time
*/
-static unsigned char *real_mode; /* Pointer to real-mode data */
-
-#define EXT_MEM_K (*(unsigned short *)(real_mode + 0x2))
-#ifndef STANDARD_MEMORY_BIOS_CALL
-#define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0))
-#endif
-#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
+static struct boot_params *real_mode; /* Pointer to real-mode data */
+/* Amount of memory in kilobytes, if it isn't set assume enough */
+static unsigned long mem_k = 0xFFFFFFFF;
extern char input_data[];
extern int input_len;
@@ -176,8 +175,8 @@
int x,y,pos;
char c;
- x = SCREEN_INFO.orig_x;
- y = SCREEN_INFO.orig_y;
+ x = real_mode->screen.info.orig_x;
+ y = real_mode->screen.info.orig_y;
while ( ( c = *s++ ) != '\0' ) {
if ( c == '\n' ) {
@@ -198,8 +197,8 @@
}
}
- SCREEN_INFO.orig_x = x;
- SCREEN_INFO.orig_y = y;
+ real_mode->screen.info.orig_x = x;
+ real_mode->screen.info.orig_y = y;
pos = (x + cols * y) * 2; /* Update cursor position */
outb_p(14, vidport);
@@ -208,6 +207,20 @@
outb_p(0xff & (pos >> 1), vidport+1);
}
+static void vid_puts_init(void)
+{
+ if (real_mode->screen.info.orig_video_mode == 7) {
+ vidmem = (char *) 0xb0000;
+ vidport = 0x3b4;
+ } else {
+ vidmem = (char *) 0xb8000;
+ vidport = 0x3d4;
+ }
+
+ lines = real_mode->screen.info.orig_video_lines;
+ cols = real_mode->screen.info.orig_video_cols;
+}
+
static void* memset(void* s, int c, size_t n)
{
int i;
@@ -307,11 +320,7 @@
static void setup_normal_output_buffer(void)
{
-#ifdef STANDARD_MEMORY_BIOS_CALL
- if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
-#else
- if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n");
-#endif
+ if (mem_k < 2048) error("Less than 2MB of memory.\n");
output_data = (char *)0x100000; /* Points to 1M */
free_mem_end_ptr = (long)real_mode;
}
@@ -324,11 +333,7 @@
static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
{
high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
-#ifdef STANDARD_MEMORY_BIOS_CALL
- if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n");
-#else
- if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory.\n");
-#endif
+ if (mem_k < (4*1024)) error("Less than 4MB of memory.\n");
mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
@@ -360,16 +365,15 @@
{
real_mode = rmode;
- if (SCREEN_INFO.orig_video_mode == 7) {
- vidmem = (char *) 0xb0000;
- vidport = 0x3b4;
- } else {
- vidmem = (char *) 0xb8000;
- vidport = 0x3d4;
- }
+ vid_puts_init();
- lines = SCREEN_INFO.orig_video_lines;
- cols = SCREEN_INFO.orig_video_cols;
+ mem_k = real_mode->screen.overlap.ext_mem_k;
+#ifndef STANDARD_MEMORY_BIOS_CALL
+ if (real_mode->alt_mem_k > mem_k) {
+ mem_k = real_mode->alt_mem_k;
+ }
+#endif
+ mem_k += 1024;
if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
else setup_output_buffer_if_we_run_high(mv);
diff -uNr linux-2.5.12/arch/i386/kernel/setup.c linux-2.5.12.boot.boot_params/arch/i386/kernel/setup.c
--- linux-2.5.12/arch/i386/kernel/setup.c Mon Apr 29 00:17:11 2002
+++ linux-2.5.12.boot.boot_params/arch/i386/kernel/setup.c Wed May 1 09:38:30 2002
@@ -116,6 +116,7 @@
#include <asm/dma.h>
#include <asm/mpspec.h>
#include <asm/mmu_context.h>
+#include <asm/boot_param.h>
/*
* Machine setup..
@@ -146,14 +147,9 @@
/*
* Setup options
*/
-struct drive_info_struct { char dummy[32]; } drive_info;
+struct drive_info_struct drive_info;
struct screen_info screen_info;
struct apm_info apm_info;
-struct sys_desc_table_struct {
- unsigned short length;
- unsigned char table[0];
-};
-
struct e820map e820;
unsigned char aux_device_present;
@@ -168,34 +164,9 @@
static int disable_x86_serial_nr __initdata = 1;
static int disable_x86_fxsr __initdata = 0;
-/*
- * This is set up by the setup-routine at boot-time
- */
-#define PARAM ((unsigned char *)empty_zero_page)
-#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
-#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
-#define E820_MAP_NR (*(char*) (PARAM+E820NR))
-#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
-#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-#define COMMAND_LINE ((char *) (PARAM+2048))
+#define COMMAND_LINE (((char *)empty_zero_page)+2048)
#define COMMAND_LINE_SIZE 256
-#define RAMDISK_IMAGE_START_MASK 0x07FF
-#define RAMDISK_PROMPT_FLAG 0x8000
-#define RAMDISK_LOAD_FLAG 0x4000
-
-
static char command_line[COMMAND_LINE_SIZE];
char saved_command_line[COMMAND_LINE_SIZE];
@@ -557,7 +528,7 @@
*/
#define LOWMEMSIZE() (0x9f000)
-static void __init setup_memory_region(void)
+static void __init setup_memory_region(struct boot_params *params)
{
char *who = "BIOS-e820";
@@ -567,16 +538,16 @@
* Otherwise fake a memory map; one section from 0k->640k,
* the next section from 1mb->appropriate_mem_k
*/
- sanitize_e820_map(E820_MAP, &E820_MAP_NR);
- if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+ sanitize_e820_map(params->e820_map, ¶ms->e820_map_nr);
+ if (copy_e820_map(params->e820_map, params->e820_map_nr) < 0) {
unsigned long mem_size;
/* compare results from other methods and take the greater */
- if (ALT_MEM_K < EXT_MEM_K) {
- mem_size = EXT_MEM_K;
+ if (params->alt_mem_k < params->screen.overlap.ext_mem_k) {
+ mem_size = params->screen.overlap.ext_mem_k;
who = "BIOS-88";
} else {
- mem_size = ALT_MEM_K;
+ mem_size = params->alt_mem_k;
who = "BIOS-e801";
}
@@ -672,31 +643,36 @@
unsigned long bootmap_size, low_mem_size;
unsigned long start_pfn, max_low_pfn;
int i;
+ struct boot_params *params;
#ifdef CONFIG_VISWS
visws_get_board_type_and_rev();
#endif
- ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
- drive_info = DRIVE_INFO;
- screen_info = SCREEN_INFO;
- apm_info.bios = APM_BIOS_INFO;
- if( SYS_DESC_TABLE.length != 0 ) {
- MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
- machine_id = SYS_DESC_TABLE.table[0];
- machine_submodel_id = SYS_DESC_TABLE.table[1];
- BIOS_revision = SYS_DESC_TABLE.table[2];
+ /*
+ * This is set up by the setup-routine at boot-time
+ */
+ params = (struct boot_params *)empty_zero_page;
+ ROOT_DEV = to_kdev_t(params->root_dev);
+ drive_info = params->drive_info;
+ screen_info = params->screen.info;
+ apm_info.bios = params->apm_bios_info;
+ if( params->sys_desc_table.length != 0 ) {
+ MCA_bus = params->sys_desc_table.table[3] &0x2;
+ machine_id = params->sys_desc_table.table[0];
+ machine_submodel_id = params->sys_desc_table.table[1];
+ BIOS_revision = params->sys_desc_table.table[2];
}
- aux_device_present = AUX_DEVICE_INFO;
+ aux_device_present = params->aux_device_info;
#ifdef CONFIG_BLK_DEV_RAM
- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+ rd_image_start = params->ramdisk_flags & RAMDISK_IMAGE_START_MASK;
+ rd_prompt = ((params->ramdisk_flags & RAMDISK_PROMPT_FLAG) != 0);
+ rd_doload = ((params->ramdisk_flags & RAMDISK_LOAD_FLAG) != 0);
#endif
- setup_memory_region();
+ setup_memory_region(params);
- if (!MOUNT_ROOT_RDONLY)
+ if (!params->mount_root_rdonly)
root_mountflags &= ~MS_RDONLY;
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
@@ -881,18 +857,21 @@
find_smp_config();
#endif
#ifdef CONFIG_BLK_DEV_INITRD
- if (LOADER_TYPE && INITRD_START) {
- if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
- reserve_bootmem(INITRD_START, INITRD_SIZE);
- initrd_start =
- INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
- initrd_end = initrd_start+INITRD_SIZE;
+ if (params->type_of_loader && params->initrd_start) {
+ initrd_start = params->initrd_start ?
+ params->initrd_start + PAGE_OFFSET : 0;
+ initrd_end = initrd_start + params->initrd_size;
+ }
+ if (initrd_start) {
+ if ((initrd_end - PAGE_OFFSET) <= (max_low_pfn << PAGE_SHIFT)) {
+ reserve_bootmem(initrd_start - PAGE_OFFSET,
+ initrd_end - initrd_start);
}
else {
printk(KERN_ERR "initrd extends beyond end of memory "
- "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
- INITRD_START + INITRD_SIZE,
- max_low_pfn << PAGE_SHIFT);
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_end - PAGE_OFFSET,
+ max_low_pfn << PAGE_SHIFT);
initrd_start = 0;
}
}
diff -uNr linux-2.5.12/include/asm-i386/boot_param.h linux-2.5.12.boot.boot_params/include/asm-i386/boot_param.h
--- linux-2.5.12/include/asm-i386/boot_param.h Wed Dec 31 17:00:00 1969
+++ linux-2.5.12.boot.boot_params/include/asm-i386/boot_param.h Wed May 1 09:38:30 2002
@@ -0,0 +1,79 @@
+#ifndef __I386_BOOT_PARAM_H
+#define __I386_BOOT_PARAM_H
+
+struct drive_info_struct { __u8 dummy[32]; };
+struct sys_desc_table {
+ __u16 length;
+ __u8 table[318];
+};
+struct screen_info_overlap {
+ __u8 reserved1[2]; /* 0x00 */
+ __u16 ext_mem_k; /* 0x02 */
+ __u8 reserved2[0x20 - 0x04]; /* 0x04 */
+ __u16 cl_magic; /* 0x20 */
+#define CL_MAGIC_VALUE 0xA33F
+ __u16 cl_offset; /* 0x22 */
+ __u8 reserved3[0x40 - 0x24]; /* 0x24 */
+};
+
+struct boot_params {
+ union { /* 0x00 */
+ struct screen_info info;
+ struct screen_info_overlap overlap;
+ } screen;
+
+ struct apm_bios_info apm_bios_info; /* 0x40 */
+ __u8 reserved4[0x80 - 0x54]; /* 0x54 */
+ struct drive_info_struct drive_info; /* 0x80 */
+ struct sys_desc_table sys_desc_table; /* 0xa0 */
+ __u32 alt_mem_k; /* 0x1e0 */
+ __u8 reserved5[4]; /* 0x1e4 */
+ __u8 e820_map_nr; /* 0x1e8 */
+ __u8 reserved6[8]; /* 0x1e9 */
+ __u8 setup_sects; /* 0x1f1 */
+ __u16 mount_root_rdonly; /* 0x1f2 */
+ __u16 syssize; /* 0x1f4 */
+ __u16 swapdev; /* 0x1f6 */
+ __u16 ramdisk_flags; /* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK 0x07FF
+#define RAMDISK_PROMPT_FLAG 0x8000
+#define RAMDISK_LOAD_FLAG 0x4000
+ __u16 vid_mode; /* 0x1fa */
+ __u16 root_dev; /* 0x1fc */
+ __u8 reserved9[1]; /* 0x1fe */
+ __u8 aux_device_info; /* 0x1ff */
+ /* 2.00+ */
+ __u8 jump[2]; /* 0x200 */
+ __u8 header_magic[4]; /* 0x202 */
+ __u16 version; /* 0x206 */
+ __u16 realmode_swtch[2]; /* 0x208 */
+ __u16 start_sys_seg; /* 0x20c */
+ __u16 kernel_version; /* 0x20e */
+ __u8 type_of_loader; /* 0x210 */
+#define LOADER_LILO 0x00
+#define LOADER_LOADLIN 0x10
+#define LOADER_BOOTSECT_LOADER 0x20
+#define LOADER_SYSLINUX 0x30
+#define LOADER_ETHERBOOT 0x40
+#define LOADER_UNKNOWN 0xFF
+ __u8 loadflags; /* 0x211 */
+#define LOADFLAG_LOADED_HIGH 1
+#define LOADFLAG_STAY_PUT 0x40
+#define LOADFLAG_CAN_USE_HEAP 0x80
+ __u16 setup_move_size; /* 0x212 */
+ __u32 code32_start; /* 0x214 */
+ __u32 initrd_start; /* 0x218 */
+ __u32 initrd_size; /* 0x21c */
+ __u8 reserved13[4]; /* 0x220 */
+ /* 2.01+ */
+ __u16 heap_end_ptr; /* 0x224 */
+ __u8 pad1[2]; /* 0x226 */
+ /* 2.02+ */
+ __u32 cmd_line_ptr; /* 0x228 */
+ /* 2.03+ */
+ __u32 ramdisk_max; /* 0x22c */
+ __u8 reserved15[0x2d0 - 0x230]; /* 0x230 */
+ struct e820entry e820_map[E820MAX]; /* 0x2d0 */
+ /* 0x550 */
+} __attribute__((packed));
+#endif /* __I386_BOOT_PARAM_H */
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 2002-05-02 14:42 [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 Eric W. Biederman @ 2002-04-27 2:56 ` Pavel Machek 2002-05-06 10:13 ` Eric W. Biederman 2002-05-02 14:45 ` [PATCH 2.5.12] x86 Boot enhancements, linker fixes 2/11 Eric W. Biederman 1 sibling, 1 reply; 20+ messages in thread From: Pavel Machek @ 2002-04-27 2:56 UTC (permalink / raw) To: Eric W. Biederman; +Cc: Linus Torvalds, Dave Jones, linux-kernel Hi! > #5 boot.heap > ============================================================ > Modify video.S so that mode_list is also allocated from > the boot time heap. This probably saves a little memory, > and makes a compiled in command line a sane thing to implement. Do you see easy way to pass video mode used to kernel? S3 suspend support is going to need that.. Pavel -- Philips Velo 1: 1"x4"x8", 300gram, 60, 12MB, 40bogomips, linux, mutt, details at http://atrey.karlin.mff.cuni.cz/~pavel/velo/index.html. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 2002-04-27 2:56 ` Pavel Machek @ 2002-05-06 10:13 ` Eric W. Biederman 2002-05-06 15:19 ` Pavel Machek 0 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-06 10:13 UTC (permalink / raw) To: Pavel Machek; +Cc: linux-kernel Pavel Machek <pavel@suse.cz> writes: > Hi! > > > #5 boot.heap > > ============================================================ > > Modify video.S so that mode_list is also allocated from > > the boot time heap. This probably saves a little memory, > > and makes a compiled in command line a sane thing to implement. > > Do you see easy way to pass video mode used to kernel? S3 suspend support > is going to need that.. Do you mean something other than the vga= command line option? Which actually just sets a 16bit mode in the kernel parameter structure. Eric ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 2002-05-06 10:13 ` Eric W. Biederman @ 2002-05-06 15:19 ` Pavel Machek 2002-05-06 17:55 ` Eric W. Biederman 0 siblings, 1 reply; 20+ messages in thread From: Pavel Machek @ 2002-05-06 15:19 UTC (permalink / raw) To: Eric W. Biederman; +Cc: linux-kernel Hi! > > > #5 boot.heap > > > ============================================================ > > > Modify video.S so that mode_list is also allocated from > > > the boot time heap. This probably saves a little memory, > > > and makes a compiled in command line a sane thing to implement. > > > > Do you see easy way to pass video mode used to kernel? S3 suspend support > > is going to need that.. > > Do you mean something other than the vga= command line option? > Which actually just sets a 16bit mode in the kernel parameter structure. In case of vga=ask, it is kernel that gets number from the user, right? I'd need to know what mode was actually selected, so I can restore it after S3 resume. Pavel -- Casualities in World Trade Center: ~3k dead inside the building, cryptography in U.S.A. and free speech in Czech Republic. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 2002-05-06 15:19 ` Pavel Machek @ 2002-05-06 17:55 ` Eric W. Biederman 2002-05-06 20:20 ` Pavel Machek 0 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-06 17:55 UTC (permalink / raw) To: Pavel Machek; +Cc: linux-kernel Pavel Machek <pavel@suse.cz> writes: > Hi! > > > > > #5 boot.heap > > > > ============================================================ > > > > Modify video.S so that mode_list is also allocated from > > > > the boot time heap. This probably saves a little memory, > > > > and makes a compiled in command line a sane thing to implement. > > > > > > Do you see easy way to pass video mode used to kernel? S3 suspend support > > > is going to need that.. > > > > Do you mean something other than the vga= command line option? > > Which actually just sets a 16bit mode in the kernel parameter structure. > > In case of vga=ask, it is kernel that gets number from the user, > right? Right. > I'd need to know what mode was actually selected, so I can restore it > after S3 resume. I guess that works. In this case it makes sense for the kernel to store it in the same variable the video mode is specified in. This may require an extra store but it should be trivial to implement. How are you handling the case of X and friends? Are you making certain to switch to kernel controlled vt? My hunch is that this is a decent argument for real framebuffer drivers in the kernel. But that is a separate problem. Eric ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 2002-05-06 17:55 ` Eric W. Biederman @ 2002-05-06 20:20 ` Pavel Machek 0 siblings, 0 replies; 20+ messages in thread From: Pavel Machek @ 2002-05-06 20:20 UTC (permalink / raw) To: Eric W. Biederman; +Cc: linux-kernel Hi! > > > Do you mean something other than the vga= command line option? > > > Which actually just sets a 16bit mode in the kernel parameter structure. > > > > In case of vga=ask, it is kernel that gets number from the user, > > right? > > Right. > > > I'd need to know what mode was actually selected, so I can restore it > > after S3 resume. > > I guess that works. In this case it makes sense for the kernel to > store it in the same variable the video mode is specified in. This > may require an extra store but it should be trivial to implement. > > How are you handling the case of X and friends? Are you making > certain to switch to kernel controlled vt? Switch to kernel-controlled-console with messages about suspend is how I'm handling this in S4 (suspend-to-disk). > My hunch is that this is a decent argument for real framebuffer drivers > in the kernel. But that is a separate problem. Well, not neccessary since I can switch consoles back and forth in kernel just fine. Pavel -- Casualities in World Trade Center: ~3k dead inside the building, cryptography in U.S.A. and free speech in Czech Republic. ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, linker fixes 2/11 2002-05-02 14:42 [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 Eric W. Biederman 2002-04-27 2:56 ` Pavel Machek @ 2002-05-02 14:45 ` Eric W. Biederman 2002-05-02 14:48 ` [PATCH 2.5.12] x86 Boot enhancements, bzImage/zImage code differentiation 3/11 Eric W. Biederman 1 sibling, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 14:45 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel diff -uNr linux-2.5.12.boot.boot_params/arch/i386/Makefile linux-2.5.12.boot.vmlinuxlds/arch/i386/Makefile --- linux-2.5.12.boot.boot_params/arch/i386/Makefile Thu Apr 12 13:20:31 2001 +++ linux-2.5.12.boot.vmlinuxlds/arch/i386/Makefile Wed May 1 09:38:47 2002 @@ -18,7 +18,7 @@ LD=$(CROSS_COMPILE)ld -m elf_i386 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S -LDFLAGS=-e stext +LDFLAGS= LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS) CFLAGS += -pipe diff -uNr linux-2.5.12.boot.boot_params/arch/i386/kernel/head.S linux-2.5.12.boot.vmlinuxlds/arch/i386/kernel/head.S --- linux-2.5.12.boot.boot_params/arch/i386/kernel/head.S Mon Apr 29 00:17:11 2002 +++ linux-2.5.12.boot.vmlinuxlds/arch/i386/kernel/head.S Wed May 1 09:38:47 2002 @@ -41,7 +41,7 @@ * * On entry, %esi points to the real-mode code as a 32-bit pointer. */ -startup_32: +ENTRY(startup_32) /* * Set segments to known values */ diff -uNr linux-2.5.12.boot.boot_params/arch/i386/vmlinux.lds linux-2.5.12.boot.vmlinuxlds/arch/i386/vmlinux.lds --- linux-2.5.12.boot.boot_params/arch/i386/vmlinux.lds Sun Mar 10 20:09:08 2002 +++ linux-2.5.12.boot.vmlinuxlds/arch/i386/vmlinux.lds Wed May 1 09:38:47 2002 @@ -3,7 +3,13 @@ */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) -ENTRY(_start) +physical_startup_32 = startup_32 - 0xC0000000; +ENTRY(physical_startup_32) +PHDRS +{ + text PT_LOAD AT(0x100000); + +} SECTIONS { . = 0xC0000000 + 0x100000; @@ -12,7 +18,7 @@ *(.text) *(.fixup) *(.gnu.warning) - } = 0x9090 + } :text = 0x9090 _etext = .; /* End of text section */ @@ -73,8 +79,16 @@ __bss_start = .; /* BSS */ .bss : { *(.bss) + _end = . ; + /* Reserve space for the bootmem bitmap, + * With a start at 0xC0000000 this is just 32k in the worst case. + * + * Ideally this would be in an initdata segment but that causes + * problems with memory being reserved twice. + */ + . = ALIGN(4096); + . = . + 32768; } - _end = . ; /* Sections to be discarded */ /DISCARD/ : { ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, bzImage/zImage code differentiation 3/11 2002-05-02 14:45 ` [PATCH 2.5.12] x86 Boot enhancements, linker fixes 2/11 Eric W. Biederman @ 2002-05-02 14:48 ` Eric W. Biederman 2002-05-02 14:51 ` [PATCH 2.5.12] x86 Boot enhancements, constants 4/11 Eric W. Biederman 0 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 14:48 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply Differentiate the code that is needed in setup.S for zImage and bzImages. Eric diff -uNr linux-2.5.12.boot.vmlinuxlds/arch/i386/boot/setup.S linux-2.5.12.boot.spring-cleaning/arch/i386/boot/setup.S --- linux-2.5.12.boot.vmlinuxlds/arch/i386/boot/setup.S Mon Apr 29 00:17:11 2002 +++ linux-2.5.12.boot.spring-cleaning/arch/i386/boot/setup.S Wed May 1 09:38:54 2002 @@ -166,7 +166,12 @@ # End of setup header ##################################################### start_of_setup: +#ifndef __BIG_KERNEL__ # Bootlin depends on this being done early +#NOTE: Bootlin was written before the kernel had hooks for anything +# used the BIOS calls setup.S made as hooks (ouch!) +# Bootlin only loaded zImages, so we can drop support for it +# when we are loading a bzImage. movw $0x01500, %ax movb $0x81, %dl int $0x13 @@ -177,6 +182,7 @@ movb $0x80, %dl int $0x13 #endif +#endif /* __BIG_KERNEL__ */ # Set %ds = %cs, we know that SETUPSEG = %cs at this point movw %cs, %ax # aka SETUPSEG @@ -226,6 +232,7 @@ # We now have to find the rest of the setup code/data bad_sig: +#ifndef __BIG_KERNEL__ movw %cs, %ax # SETUPSEG subw $DELTA_INITSEG, %ax # INITSEG movw %ax, %ds @@ -255,7 +262,7 @@ jne no_sig jmp good_sig - +#endif /* __BIG_KERNEL__ */ no_sig: lea no_sig_mess, %si call prtstr @@ -268,10 +275,8 @@ movw %cs, %ax # aka SETUPSEG subw $DELTA_INITSEG, %ax # aka INITSEG movw %ax, %ds +#ifdef __BIG_KERNEL__ # Check if an old loader tries to load a big-kernel - testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel? - jz loader_ok # No, no danger for old loaders. - cmpb $0, %cs:type_of_loader # Do we have a loader that # can deal with us? jnz loader_ok # Yes, continue. @@ -284,6 +289,7 @@ jmp no_sig_loop loader_panic_mess: .string "Wrong loader, giving up..." +#endif /* __BIG_KERNEL__ */ loader_ok: # Get memory size (extended mem, kB) @@ -561,15 +567,8 @@ movl %cs:code32_start, %eax movl %eax, %cs:code32 -# Now we move the system to its rightful place ... but we check if we have a -# big-kernel. In that case we *must* not move it ... - testb $LOADED_HIGH, %cs:loadflags - jz do_move0 # .. then we have a normal low - # loaded zImage - # .. or else we have a high - # loaded bzImage - jmp end_move # ... and we skip moving - +#ifndef __BIG_KERNEL__ +# Move the kernel image where it expects to be loaded. do_move0: movw $0x100, %ax # start of destination segment movw %cs, %bp # aka SETUPSEG @@ -595,6 +594,8 @@ jb do_move end_move: +#endif /* !__BIG_KERNEL__ */ + # then we load the segment descriptors movw %cs, %ax # aka SETUPSEG movw %ax, %ds ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, constants 4/11 2002-05-02 14:48 ` [PATCH 2.5.12] x86 Boot enhancements, bzImage/zImage code differentiation 3/11 Eric W. Biederman @ 2002-05-02 14:51 ` Eric W. Biederman 2002-05-02 14:55 ` [PATCH 2.5.12] x86 Boot enhancements, heap 5/11 Eric W. Biederman 0 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 14:51 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This patch introduces several constants to the x86 boot process. Eric diff -uNr linux-2.5.12.boot.spring-cleaning/arch/i386/boot/setup.S linux-2.5.12.boot.syntax/arch/i386/boot/setup.S --- linux-2.5.12.boot.spring-cleaning/arch/i386/boot/setup.S Wed May 1 09:38:54 2002 +++ linux-2.5.12.boot.syntax/arch/i386/boot/setup.S Wed May 1 09:39:11 2002 @@ -59,6 +59,12 @@ #define SIG1 0xAA55 #define SIG2 0x5A5A +#ifndef __BIG_KERNEL__ +#define KERNEL_START LOW_BASE /* zImage */ +#else +#define KERNEL_START HIGH_BASE /* bzImage */ +#endif + INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment @@ -118,13 +124,8 @@ # loader knows how much data behind # us also needs to be loaded. -code32_start: # here loaders can put a different +code32_start: .long KERNEL_START # here loaders can put a different # start address for 32-bit code. -#ifndef __BIG_KERNEL__ - .long 0x1000 # 0x1000 = default for zImage -#else - .long 0x100000 # 0x100000 = default for big kernel -#endif ramdisk_image: .long 0 # address of loaded ramdisk image # Here the loader puts the 32-bit @@ -343,7 +344,7 @@ incb (E820NR) movw %di, %ax - addw $20, %ax + addw $E820ENTRY_SIZE, %ax movw %ax, %di again820: cmpl $0, %ebx # check to see if diff -uNr linux-2.5.12.boot.spring-cleaning/include/asm-i386/boot.h linux-2.5.12.boot.syntax/include/asm-i386/boot.h --- linux-2.5.12.boot.spring-cleaning/include/asm-i386/boot.h Wed Apr 16 15:15:00 1997 +++ linux-2.5.12.boot.syntax/include/asm-i386/boot.h Wed May 1 09:39:11 2002 @@ -1,6 +1,19 @@ #ifndef _LINUX_BOOT_H #define _LINUX_BOOT_H +/* Address space division during load */ + /* Memory below 640 we can use for loading */ +#define LOW_BASE 0x001000 +#define LOW_MAX 0x0a0000 /* Maximum low memory address to use */ + /* Memory above 640 we can use for loading */ +#define HIGH_BASE 0x100000 +#define HIGH_MAX __MAXMEM + /* Subset of the low segment that is generally safe to + * use for loading. + */ +#define REAL_BASE 0x010000 +#define REAL_MAX 0x090000 + /* Don't touch these, unless you really know what you're doing. */ #define DEF_INITSEG 0x9000 #define DEF_SYSSEG 0x1000 diff -uNr linux-2.5.12.boot.spring-cleaning/include/asm-i386/e820.h linux-2.5.12.boot.syntax/include/asm-i386/e820.h --- linux-2.5.12.boot.spring-cleaning/include/asm-i386/e820.h Fri Aug 18 10:30:51 2000 +++ linux-2.5.12.boot.syntax/include/asm-i386/e820.h Wed May 1 09:39:11 2002 @@ -15,6 +15,7 @@ #define E820MAP 0x2d0 /* our map */ #define E820MAX 32 /* number of entries in E820MAP */ #define E820NR 0x1e8 /* # entries in E820MAP */ +#define E820ENTRY_SIZE 20 /* size of an E820MAP entry */ #define E820_RAM 1 #define E820_RESERVED 2 ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, heap 5/11 2002-05-02 14:51 ` [PATCH 2.5.12] x86 Boot enhancements, constants 4/11 Eric W. Biederman @ 2002-05-02 14:55 ` Eric W. Biederman 2002-05-02 15:00 ` [PATCH 2.5.12] x86 Boot enhancements, 32bit entries 6/11 Eric W. Biederman 0 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 14:55 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This patch introduces better heap management into setup.S this allows a compiled in command line to be introduced later on. Eric diff -uNr linux-2.5.12.boot.syntax/arch/i386/boot/setup.S linux-2.5.12.boot.heap/arch/i386/boot/setup.S --- linux-2.5.12.boot.syntax/arch/i386/boot/setup.S Wed May 1 09:39:11 2002 +++ linux-2.5.12.boot.heap/arch/i386/boot/setup.S Wed May 1 09:39:29 2002 @@ -65,6 +65,8 @@ #define KERNEL_START HIGH_BASE /* bzImage */ #endif +#define DELTA_BOOTSECT 512 + INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment @@ -73,15 +75,10 @@ DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020 .code16 -.globl begtext, begdata, begbss, endtext, enddata, endbss +.globl _setup, _esetup .text -begtext: -.data -begdata: -.bss -begbss: -.text +_setup: start: jmp trampoline @@ -137,7 +134,7 @@ bootsect_kludge: .word bootsect_helper, SETUPSEG -heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later) +heap_end_ptr: .word _esetup_heap # (Header version 0x0201 or later) # space from here (exclusive) down to # end of setup code can be used by setup # for local heap purposes. @@ -162,8 +159,12 @@ # The highest safe address for # the contents of an initrd +# variables private to setup.S (not for bootloaders) +real_filesz: # Datasize of the real mode kernel + .long (_esetup - _setup) + DELTA_BOOTSECT trampoline: call start_of_setup - .space 1024 + # Don't let the E820 map overlap code + . = (E820MAP - DELTA_BOOTSECT) + (E820MAX * E820ENTRY_SIZE) # End of setup header ##################################################### start_of_setup: @@ -1042,11 +1043,8 @@ # After this point, there is some free space which is used by the video mode # handling code to store the temporary mode table (not used by the kernel). -modelist: - -.text -endtext: -.data -enddata: -.bss -endbss: +_esetup: +.section ".setup.heap", "a", @nobits +_setup_heap: +. = DEF_HEAP_SIZE +_esetup_heap: diff -uNr linux-2.5.12.boot.syntax/arch/i386/boot/video.S linux-2.5.12.boot.heap/arch/i386/boot/video.S --- linux-2.5.12.boot.syntax/arch/i386/boot/video.S Thu Jul 5 12:28:16 2001 +++ linux-2.5.12.boot.heap/arch/i386/boot/video.S Wed May 1 09:39:29 2002 @@ -117,6 +117,12 @@ xorw %ax, %ax movw %ax, %gs # GS is zero cld + + # Setup the heap + movl real_filesz, %eax + subl $DELTA_BOOTSECT, %eax + movw %ax, heap_start + call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA) #ifdef CONFIG_VIDEO_SELECT movw %fs:(0x01fa), %ax # User selected video mode @@ -201,7 +207,7 @@ #ifdef CONFIG_VIDEO_SELECT # Fetching of VESA frame buffer parameters mopar_gr: - leaw modelist+1024, %di + movw heap_start, %di movb $0x23, %fs:(PARAM_HAVE_VGA) movw 16(%di), %ax movw %ax, %fs:(PARAM_LFB_LINELENGTH) @@ -223,7 +229,7 @@ movl %eax, %fs:(PARAM_LFB_COLORS+4) # get video mem size - leaw modelist+1024, %di + movw heap_start, %di movw $0x4f00, %ax int $0x10 xorl %eax, %eax @@ -284,7 +290,7 @@ leaw listhdr, %si # Table header call prtstr movb $0x30, %dl # DL holds mode number - leaw modelist, %si + movw modelist, %si lm1: cmpw $ASK_VGA, (%si) # End? jz lm2 @@ -529,7 +535,7 @@ jmp _m_s check_vesa: - leaw modelist+1024, %di + movw heap_start, %di subb $VIDEO_FIRST_VESA>>8, %bh movw %bx, %cx # Get mode information structure movw $0x4f01, %ax @@ -774,12 +780,13 @@ mulb %ah movw %ax, %cx # CX=number of characters addw %ax, %ax # Calculate image size - addw $modelist+1024+4, %ax + addw heap_start, %ax + addw $4, %ax cmpw heap_end_ptr, %ax jnc sts1 # Unfortunately, out of memory movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params - leaw modelist+1024, %di + movw heap_start, %di stosw movw %bx, %ax stosw @@ -802,7 +809,7 @@ call mode_params # Get parameters of current mode movb %fs:(PARAM_VIDEO_LINES), %cl movb %fs:(PARAM_VIDEO_COLS), %ch - leaw modelist+1024, %si # Screen buffer + movw heap_start, %si # Screen buffer lodsw # Set cursor position movw %ax, %dx cmpb %cl, %dh @@ -883,7 +890,8 @@ orw %di, %di jnz mtab1x - leaw modelist, %di # Store standard modes: + movw heap_start, %di # Store standard modes: + movw %di, modelist movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL) stosl movb adapter, %al # CGA/MDA/HGA -- no more modes @@ -929,13 +937,13 @@ mtabe: #ifdef CONFIG_VIDEO_COMPACT - leaw modelist, %si + movw modelist, %si movw %di, %dx movw %si, %di cmt1: cmpw %dx, %si # Scan all modes jz cmt2 - leaw modelist, %bx # Find in previous entries + movw modelist, %bx # Find in previous entries movw 2(%si), %cx cmt3: cmpw %bx, %si jz cmt4 @@ -957,7 +965,8 @@ movw $ASK_VGA, (%di) # End marker movw %di, mt_end -mtab1: leaw modelist, %si # SI=mode list, DI=list end + movw %di, heap_start +mtab1: movw modelist, %si # SI=mode list, DI=list end ret0: ret # Modes usable on all standard VGAs @@ -1932,3 +1941,5 @@ adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA video_segment: .word 0xb800 # Video memory segment force_size: .word 0 # Use this size instead of the one in BIOS vars +modelist: .word 0 # Start of modelist on the heap +heap_start: .word 0 # low heap address diff -uNr linux-2.5.12.boot.syntax/include/asm-i386/boot.h linux-2.5.12.boot.heap/include/asm-i386/boot.h --- linux-2.5.12.boot.syntax/include/asm-i386/boot.h Wed May 1 09:39:11 2002 +++ linux-2.5.12.boot.heap/include/asm-i386/boot.h Wed May 1 09:39:29 2002 @@ -19,6 +19,7 @@ #define DEF_SYSSEG 0x1000 #define DEF_SETUPSEG 0x9020 #define DEF_SYSSIZE 0x7F00 +#define DEF_HEAP_SIZE 1024 /* Internal svga startup constants */ #define NORMAL_VGA 0xffff /* 80x25 mode */ diff -uNr linux-2.5.12.boot.syntax/include/asm-i386/boot_param.h linux-2.5.12.boot.heap/include/asm-i386/boot_param.h --- linux-2.5.12.boot.syntax/include/asm-i386/boot_param.h Wed May 1 09:38:30 2002 +++ linux-2.5.12.boot.heap/include/asm-i386/boot_param.h Wed May 1 09:39:29 2002 @@ -72,7 +72,9 @@ __u32 cmd_line_ptr; /* 0x228 */ /* 2.03+ */ __u32 ramdisk_max; /* 0x22c */ - __u8 reserved15[0x2d0 - 0x230]; /* 0x230 */ + /* Below this point for internal kernel use only */ + __u32 real_filesz; /* 0x230 */ + __u8 reserved15[0x2d0 - 0x234]; /* 0x234 */ struct e820entry e820_map[E820MAX]; /* 0x2d0 */ /* 0x550 */ } __attribute__((packed)); ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, 32bit entries 6/11 2002-05-02 14:55 ` [PATCH 2.5.12] x86 Boot enhancements, heap 5/11 Eric W. Biederman @ 2002-05-02 15:00 ` Eric W. Biederman 2002-04-27 4:53 ` Pavel Machek 2002-05-02 15:05 ` [PATCH 2.5.12] x86 Boot enhancements, footprint reduction 7/11 Eric W. Biederman 0 siblings, 2 replies; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 15:00 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This patch cleans up the 32bit kernel entry points so they don't assume who their caller is, making them usable by other than setup.S For arch/i386/kernel/head.S this untangles the secondary cpu and the bootstrap entry points making the code more readable. Eric diff -uNr linux-2.5.12.boot.heap/arch/i386/boot/compressed/head.S linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/head.S --- linux-2.5.12.boot.heap/arch/i386/boot/compressed/head.S Mon Apr 29 00:17:11 2002 +++ linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/head.S Wed May 1 09:39:47 2002 @@ -25,24 +25,30 @@ #include <linux/linkage.h> #include <asm/segment.h> +#include <asm/boot.h> .globl startup_32 startup_32: cld cli - movl $(__KERNEL_DS),%eax - movl %eax,%ds - movl %eax,%es - movl %eax,%fs - movl %eax,%gs - lss stack_start,%esp - xorl %eax,%eax -1: incl %eax # check that A20 really IS enabled - movl %eax,0x000000 # loop forever if it isn't - cmpl %eax,0x100000 - je 1b + /* + * Save the initial registers + */ + movl %eax, eax + movl %ebx, ebx + movl %ecx, ecx + movl %edx, edx + movl %esi, esi + movl %edi, edi + movl %esp, esp + movl %ebp, ebp + + /* + * Setup the stack + */ + movl stack_start, %esp /* * Initialize eflags. Some BIOS's leave bits like NT set. This would @@ -66,16 +72,10 @@ */ subl $16,%esp # place for structure on the stack movl %esp,%eax - pushl %esi # real mode pointer as second arg pushl %eax # address of structure as first arg call decompress_kernel - orl %eax,%eax - jnz 3f - popl %esi # discard address - popl %esi # real mode pointer - xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 - + orl %eax,%eax + jz out /* * We come here, if we were loaded high. * We need to move the move-in-place routine down to 0x1000 @@ -83,8 +83,21 @@ * which we got from the stack. */ 3: - movl $move_routine_start,%esi - movl $0x1000,%edi + /* Relocate the move routine */ + movl $move_routine_start,%esi #src + movl %eax,%edi #dest + movl %eax, %ebp #saved dest + movl %edi, %eax + subl %esi, %eax # The relocation factor + addl %eax, reloc1 + addl %eax, reloc2 + addl %eax, reloc3 + addl %eax, reloc4 + addl %eax, reloc5 + addl %eax, reloc6 + addl %eax, reloc7 + addl %eax, reloc8 + addl %eax, reloc9 movl $move_routine_end,%ecx subl %esi,%ecx addl $3,%ecx @@ -93,20 +106,23 @@ rep movsl + /* Load it's arguments and jump to the move routine */ popl %esi # discard the address - popl %ebx # real mode pointer popl %esi # low_buffer_start popl %ecx # lcount popl %edx # high_buffer_start popl %eax # hcount - movl $0x100000,%edi + movl $HIGH_BASE,%edi cli # make sure we don't get interrupted - ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine + jmpl *%ebp /* * Routine (template) for moving the decompressed kernel in place, - * if we were high loaded. This _must_ PIC-code ! + * if we were high loaded. This _must_ be PIC-code ! + * Or it must be anotated with lables so it can be manually relocated. */ + .globl move_routine_start, move_routine_end + .balign 4 move_routine_start: movl %ecx,%ebp shrl $2,%ecx @@ -122,7 +138,35 @@ shrl $2,%ecx rep movsl - movl %ebx,%esi # Restore setup pointer - xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 +out: + .byte 0xa1 # movl eax, %eax +reloc1: .long eax + .byte 0x8b, 0x1d # movl ebx, %ebx +reloc2: .long ebx + .byte 0x8b, 0x0d # movl ecx, %ecx +reloc3: .long ecx + .byte 0x8b, 0x15 # movl edx, %edx +reloc4: .long edx + .byte 0x8b, 0x35 # movl esi, %esi +reloc5: .long esi + .byte 0x8b, 0x3d # movl edi, %edi +reloc6: .long edi + .byte 0x8b, 0x25 # movl esp, %esp +reloc7: .long esp + .byte 0x8b, 0x2d # movl ebp, %ebp +reloc8: .long ebp + .byte 0xff, 0x25 # jmpl *(kernel_start) +reloc9: .long kernel_start + .balign 4 +ENTRY(initial_regs) +eax: .long 0x12345678 /* eax */ +ebx: .long 0x12345678 /* ebx */ +ecx: .long 0x12345678 /* ecx */ +edx: .long 0x12345678 /* edx */ +esi: .long 0x12345678 /* esi */ +edi: .long 0x12345678 /* edi */ +esp: .long 0x12345678 /* esp */ +ebp: .long 0x12345678 /* ebp */ +kernel_start: + .long HIGH_BASE move_routine_end: diff -uNr linux-2.5.12.boot.heap/arch/i386/boot/compressed/misc.c linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/misc.c --- linux-2.5.12.boot.heap/arch/i386/boot/compressed/misc.c Wed May 1 09:38:29 2002 +++ linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/misc.c Wed May 1 09:39:47 2002 @@ -16,6 +16,7 @@ #include <linux/apm_bios.h> #include <asm/e820.h> #include <asm/boot_param.h> +#include <asm/boot.h> /* * gzip declarations @@ -111,10 +112,11 @@ static long free_mem_ptr = (long)&end; static long free_mem_end_ptr; -#define INPLACE_MOVE_ROUTINE 0x1000 -#define LOW_BUFFER_START 0x2000 -#define LOW_BUFFER_MAX 0x90000 -#define HEAP_SIZE 0x3000 +/* Decompressor constants */ +#define HEAP_SIZE 0x003000 +static unsigned long move_routine; +extern unsigned char move_routine_end[], move_routine_start[]; + static unsigned int low_buffer_end, low_buffer_size; static int high_loaded =0; static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; @@ -170,11 +172,15 @@ vidmem[i] = ' '; } +static int vid_initialized = 0; static void puts(const char *s) { int x,y,pos; char c; + if (!vid_initialized) + return; + x = real_mode->screen.info.orig_x; y = real_mode->screen.info.orig_y; @@ -209,6 +215,7 @@ static void vid_puts_init(void) { + vid_initialized = 1; if (real_mode->screen.info.orig_video_mode == 7) { vidmem = (char *) 0xb0000; vidport = 0x3b4; @@ -315,8 +322,10 @@ struct { long * a; - short b; - } stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS }; + } stack_start = { & user_stack [STACK_SIZE] }; + +extern struct initial_regs32 initial_regs; +extern __u32 kernel_start; static void setup_normal_output_buffer(void) { @@ -333,11 +342,13 @@ static void setup_output_buffer_if_we_run_high(struct moveparams *mv) { high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); + move_routine = LOW_BASE; if (mem_k < (4*1024)) error("Less than 4MB of memory.\n"); - mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START; - low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX - ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; - low_buffer_size = low_buffer_end - LOW_BUFFER_START; + mv->low_buffer_start = output_data = + (char *)move_routine + (move_routine_end - move_routine_start); + low_buffer_end = ((unsigned int)real_mode > LOW_MAX + ? LOW_MAX : (unsigned int)real_mode) & ~0xfff; + low_buffer_size = low_buffer_end - (unsigned long)mv->low_buffer_start; high_loaded = 1; free_mem_end_ptr = (long)high_buffer_start; if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) { @@ -346,6 +357,7 @@ } else mv->hcount = -1; mv->high_buffer_start = high_buffer_start; + if ((ulg)output_data >= low_buffer_end) output_data=high_buffer_start; } static void close_output_buffer_if_we_run_high(struct moveparams *mv) @@ -361,21 +373,28 @@ } -asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) +asmlinkage unsigned long decompress_kernel(struct moveparams *mv) { - real_mode = rmode; - - vid_puts_init(); + /* If we don't know better assume we can't use any + * real mode memory, and we have enough protected mode memory. + */ + real_mode = 0; + if ((initial_regs.ebp == ENTRY16) || (initial_regs.ebp == ENTRY32)) { + real_mode = (struct boot_params *)initial_regs.esi; + } + if (initial_regs.ebp == ENTRY16) { + vid_puts_init(); - mem_k = real_mode->screen.overlap.ext_mem_k; + mem_k = real_mode->screen.overlap.ext_mem_k; #ifndef STANDARD_MEMORY_BIOS_CALL - if (real_mode->alt_mem_k > mem_k) { - mem_k = real_mode->alt_mem_k; - } + if (real_mode->alt_mem_k > mem_k) { + mem_k = real_mode->alt_mem_k; + } #endif - mem_k += 1024; + mem_k += 1024; + } - if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); + if (free_mem_ptr < HIGH_BASE) setup_normal_output_buffer(); else setup_output_buffer_if_we_run_high(mv); makecrc(); @@ -383,5 +402,5 @@ gunzip(); puts("Ok, booting the kernel.\n"); if (high_loaded) close_output_buffer_if_we_run_high(mv); - return high_loaded; + return move_routine; } diff -uNr linux-2.5.12.boot.heap/arch/i386/boot/setup.S linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/setup.S --- linux-2.5.12.boot.heap/arch/i386/boot/setup.S Wed May 1 09:39:29 2002 +++ linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/setup.S Wed May 1 09:39:47 2002 @@ -67,6 +67,12 @@ #define DELTA_BOOTSECT 512 +/* Segments used by setup.S */ +#define __SETUP_CS 0x10 +#define __SETUP_DS 0x18 +#define __SETUP_REAL_CS 0x20 +#define __SETUP_REAL_DS 0x28 + INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment @@ -798,13 +804,22 @@ jmp flush_instr flush_instr: - xorw %bx, %bx # Flag to indicate a boot xorl %esi, %esi # Pointer to real-mode code movw %cs, %si subw $DELTA_INITSEG, %si shll $4, %esi # Convert to 32-bit pointer + movl $ENTRY16, %ebp # Magic to indicate 16bit entry + +# Setup the data segments + movw $(__SETUP_DS), %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + # NOTE: For high loaded big kernels we need a -# jmpi 0x100000,__KERNEL_CS +# jmpi 0x100000,__SETUP_CS # # but we yet haven't reloaded the CS register, so the default size # of the target offset still is 16 bit. @@ -815,7 +830,7 @@ .byte 0x66, 0xea # prefix + jmpi-opcode code32: .long 0x1000 # will be set to 0x100000 # for big kernels - .word __KERNEL_CS + .word __SETUP_CS # Here's a bunch of information about your current kernel.. kernel_version: .ascii UTS_RELEASE diff -uNr linux-2.5.12.boot.heap/arch/i386/kernel/head.S linux-2.5.12.boot.clean_32bit_entries/arch/i386/kernel/head.S --- linux-2.5.12.boot.heap/arch/i386/kernel/head.S Wed May 1 09:38:47 2002 +++ linux-2.5.12.boot.clean_32bit_entries/arch/i386/kernel/head.S Wed May 1 09:39:47 2002 @@ -16,12 +16,6 @@ #include <asm/pgtable.h> #include <asm/desc.h> -#define OLD_CL_MAGIC_ADDR 0x90020 -#define OLD_CL_MAGIC 0xA33F -#define OLD_CL_BASE_ADDR 0x90000 -#define OLD_CL_OFFSET 0x90022 -#define NEW_CL_POINTER 0x228 /* Relative to real mode data */ - /* * References to members of the boot_cpu_data structure. */ @@ -39,46 +33,41 @@ /* * swapper_pg_dir is the main page directory, address 0x00101000 * - * On entry, %esi points to the real-mode code as a 32-bit pointer. + * On entry + * %ds, %es, %ss, %fs, %gs 32bit data segment base=0 mask=0xffffffff + * */ ENTRY(startup_32) /* - * Set segments to known values + * Set eflags to a safe state */ cld - movl $(__KERNEL_DS),%eax + cli +/* + * Save the initial registers + */ + movl %eax, initial_regs-__PAGE_OFFSET+0 + movl %ebx, initial_regs-__PAGE_OFFSET+4 + movl %ecx, initial_regs-__PAGE_OFFSET+8 + movl %edx, initial_regs-__PAGE_OFFSET+12 + movl %esi, initial_regs-__PAGE_OFFSET+16 + movl %edi, initial_regs-__PAGE_OFFSET+20 + movl %esp, initial_regs-__PAGE_OFFSET+24 + movl %ebp, initial_regs-__PAGE_OFFSET+28 + +/* + * Set segments to known values + */ + lgdt gdt_48-__PAGE_OFFSET + ljmp $__KERNEL_CS,$1f-__PAGE_OFFSET +1: movl $__KERNEL_DS,%eax movl %eax,%ds movl %eax,%es movl %eax,%fs movl %eax,%gs -#ifdef CONFIG_SMP - orw %bx,%bx - jz 1f + movl %eax,%ss /* - * New page tables may be in 4Mbyte page mode and may - * be using the global pages. - * - * NOTE! If we are on a 486 we may have no cr4 at all! - * So we do not try to touch it unless we really have - * some bits in it to set. This won't work if the BSP - * implements cr4 but this AP does not -- very unlikely - * but be warned! The same applies to the pse feature - * if not equally supported. --macro - * - * NOTE! We have to correct for the fact that we're - * not yet offset PAGE_OFFSET.. - */ -#define cr4_bits mmu_cr4_features-__PAGE_OFFSET - cmpl $0,cr4_bits - je 3f - movl %cr4,%eax # Turn on paging options (PSE,PAE,..) - orl cr4_bits,%eax - movl %eax,%cr4 - jmp 3f -1: -#endif -/* * Initialize page tables */ movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */ @@ -106,14 +95,13 @@ /* Set up the stack pointer */ lss stack_start,%esp -#ifdef CONFIG_SMP - orw %bx,%bx - jz 1f /* Initial CPU cleans BSS */ +/* + * Initialize eflags. Some BIOS's leave bits like NT set. This would + * confuse the debugger if this code is traced. + * XXX - best to initialize before switching to protected mode. + */ pushl $0 popfl - jmp checkCPUtype -1: -#endif CONFIG_SMP /* * Clear BSS first so that there are no surprises... @@ -131,42 +119,76 @@ * in 16-bit mode for the "real" operations. */ call setup_idt + + call checkCPUtype + call start_kernel +L6: + jmp L6 # main should never return here, but + # just in case, we know what happens. + + +#ifdef CONFIG_SMP +ENTRY(secondary_startup_32) /* - * Initialize eflags. Some BIOS's leave bits like NT set. This would - * confuse the debugger if this code is traced. - * XXX - best to initialize before switching to protected mode. + * Set eflags to a safe state */ - pushl $0 - popfl + cld + cli + +/* + * Set segments to known values + */ + movl $(__KERNEL_DS), %eax + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + movl %eax,%gs + movl %eax,%ss + /* - * Copy bootup parameters out of the way. First 2kB of - * _empty_zero_page is for boot parameters, second 2kB - * is for the command line. + * New page tables may be in 4Mbyte page mode and may + * be using the global pages. * - * Note: %esi still has the pointer to the real-mode data. + * NOTE! If we are on a 486 we may have no cr4 at all! + * So we do not try to touch it unless we really have + * some bits in it to set. This won't work if the BSP + * implements cr4 but this AP does not -- very unlikely + * but be warned! The same applies to the pse feature + * if not equally supported. --macro + * + * NOTE! We have to correct for the fact that we're + * not yet offset PAGE_OFFSET.. */ - movl $empty_zero_page,%edi - movl $512,%ecx - cld - rep - movsl - xorl %eax,%eax - movl $512,%ecx - rep - stosl - movl empty_zero_page+NEW_CL_POINTER,%esi - andl %esi,%esi - jnz 2f # New command line protocol - cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR - jne 1f - movzwl OLD_CL_OFFSET,%esi - addl $(OLD_CL_BASE_ADDR),%esi -2: - movl $empty_zero_page+2048,%edi - movl $512,%ecx - rep - movsl +#define cr4_bits mmu_cr4_features-__PAGE_OFFSET + cmpl $0,cr4_bits + je 3f + movl %cr4,%eax # Turn on paging options (PSE,PAE,..) + orl cr4_bits,%eax + movl %eax,%cr4 +/* + * Enable paging + */ +3: + movl $swapper_pg_dir-__PAGE_OFFSET,%eax + movl %eax,%cr3 /* set the page table pointer.. */ + movl %cr0,%eax + orl $0x80000000,%eax + movl %eax,%cr0 /* ..and set paging (PG) bit */ + jmp 1f /* flush the prefetch-queue */ 1: + movl $1f,%eax + jmp *%eax /* make sure eip is relocated */ +1: + /* Set up the stack pointer */ + lss stack_start,%esp + call checkCPUtype + call initialize_secondary +L7: + jmp L7 # initialize_secondary should never return here, but + # just in case, we know what happens. +#endif /* CONFIG_SMP */ + + checkCPUtype: movl $-1,X86_CPUID # -1 for no CPUID initially @@ -240,40 +262,11 @@ orl $2,%eax # set MP 2: movl %eax,%cr0 call check_x87 - incb ready - lgdt gdt_descr + /* Now that we know the cpu, setup the idt & ldt */ lidt idt_descr - ljmp $(__KERNEL_CS),$1f -1: movl $(__KERNEL_DS),%eax # reload all the segment registers - movl %eax,%ds # after changing gdt. - movl %eax,%es - movl %eax,%fs - movl %eax,%gs -#ifdef CONFIG_SMP - movl $(__KERNEL_DS), %eax - movl %eax,%ss # Reload the stack pointer (segment only) -#else - lss stack_start,%esp # Load processor stack -#endif xorl %eax,%eax lldt %ax - cld # gcc2 wants the direction flag cleared at all times -#ifdef CONFIG_SMP - movb ready, %cl - cmpb $1,%cl - je 1f # the first CPU calls start_kernel - # all other CPUs call initialize_secondary - call initialize_secondary - jmp L6 -1: -#endif - call start_kernel -L6: - jmp L6 # main should never return here, but - # just in case, we know what happens. - -ready: .byte 0 - + ret /* * We depend on ET to be correct. This checks for 287/387. */ @@ -372,6 +365,10 @@ gdt: .long gdt_table + .word 0 +gdt_48: + .word GDT_ENTRIES*8-1 + .long gdt_table-__PAGE_OFFSET /* * This is initialized to create an identity-mapping at 0-8M (for bootup * purposes) and another mapping of the 0-8M area at virtual address diff -uNr linux-2.5.12.boot.heap/arch/i386/kernel/setup.c linux-2.5.12.boot.clean_32bit_entries/arch/i386/kernel/setup.c --- linux-2.5.12.boot.heap/arch/i386/kernel/setup.c Wed May 1 09:38:30 2002 +++ linux-2.5.12.boot.clean_32bit_entries/arch/i386/kernel/setup.c Wed May 1 09:39:48 2002 @@ -116,6 +116,7 @@ #include <asm/dma.h> #include <asm/mpspec.h> #include <asm/mmu_context.h> +#include <asm/boot.h> #include <asm/boot_param.h> /* @@ -164,8 +165,8 @@ static int disable_x86_serial_nr __initdata = 1; static int disable_x86_fxsr __initdata = 0; -#define COMMAND_LINE (((char *)empty_zero_page)+2048) -#define COMMAND_LINE_SIZE 256 +/* Don't let the initial_regs sit in the BSS */ +struct initial_regs32 initial_regs __initdata = { 0 }; static char command_line[COMMAND_LINE_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; @@ -562,13 +563,12 @@ static void __init parse_mem_cmdline (char ** cmdline_p) { - char c = ' ', *to = command_line, *from = COMMAND_LINE; + char c = ' ', *to = command_line, *from = saved_command_line; int len = 0; int usermem = 0; /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + memcpy(saved_command_line, command_line, sizeof(saved_command_line)); for (;;) { /* @@ -638,21 +638,42 @@ } } -void __init setup_arch(char **cmdline_p) +static void init_settings(void) { - unsigned long bootmap_size, low_mem_size; - unsigned long start_pfn, max_low_pfn; - int i; - struct boot_params *params; - -#ifdef CONFIG_VISWS - visws_get_board_type_and_rev(); + ROOT_DEV = to_kdev_t(0x0000); + memset(&drive_info, 0, sizeof(drive_info)); + memset(&screen_info, 0, sizeof(screen_info)); + memset(&apm_info.bios, 0, sizeof(apm_info.bios)); + aux_device_present = 0; +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = 0; + rd_prompt = 0; + rd_doload = 0; +#endif + e820.nr_map = 0; + saved_command_line[0] = '\0'; +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = 0; + initrd_end = 0; #endif + /* set default screen information */ + screen_info.orig_x = 0; + screen_info.orig_y = 25; + screen_info.orig_video_page = 0; + screen_info.orig_video_mode = 0; + screen_info.orig_video_cols = 80; + screen_info.orig_video_lines = 25; + screen_info.orig_video_ega_bx = 0; + screen_info.orig_video_isVGA = 1; + screen_info.orig_video_points = 16; +} +static void read_entry16_params(struct boot_params *params) +{ + char *cmdline; /* - * This is set up by the setup-routine at boot-time + * These values are set up by the setup-routine at boot-time */ - params = (struct boot_params *)empty_zero_page; ROOT_DEV = to_kdev_t(params->root_dev); drive_info = params->drive_info; screen_info = params->screen.info; @@ -674,6 +695,60 @@ if (!params->mount_root_rdonly) root_mountflags &= ~MS_RDONLY; + + cmdline = ""; + if (params->cmd_line_ptr) { + /* New command line protocol */ + cmdline = (char *)(params->cmd_line_ptr); + } + else if (params->screen.overlap.cl_magic == CL_MAGIC_VALUE) { + cmdline = (char *)params + params->screen.overlap.cl_offset; + } + memcpy(command_line, cmdline, COMMAND_LINE_SIZE); + command_line[COMMAND_LINE_SIZE -1] = '\0'; + +#ifdef CONFIG_BLK_DEV_INITRD + if (params->type_of_loader && params->initrd_start) { + initrd_start = params->initrd_start ? + params->initrd_start + PAGE_OFFSET : 0; + initrd_end = initrd_start + params->initrd_size; + } +#endif +} +static void parse_params(char **cmdline_p) +{ + struct boot_params *params; + int entry16; + + params = (struct boot_params *)initial_regs.esi; + entry16 = initial_regs.ebp == ENTRY16; + + init_settings(); + + if (entry16) { + read_entry16_params(params); + } + + /* Read user specified params */ + parse_mem_cmdline(cmdline_p); + + if (e820.nr_map == 0) { + panic("Unknown memory size\n"); + } +} + +void __init setup_arch(char **cmdline_p) +{ + unsigned long bootmap_size, low_mem_size; + unsigned long start_pfn, max_low_pfn; + int i; + +#ifdef CONFIG_VISWS + visws_get_board_type_and_rev(); +#endif + + parse_params(cmdline_p); + init_mm.start_code = (unsigned long) &_text; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; @@ -684,8 +759,6 @@ data_resource.start = virt_to_phys(&_etext); data_resource.end = virt_to_phys(&_edata)-1; - parse_mem_cmdline(cmdline_p); - #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) #define PFN_PHYS(x) ((x) << PAGE_SHIFT) @@ -857,11 +930,6 @@ find_smp_config(); #endif #ifdef CONFIG_BLK_DEV_INITRD - if (params->type_of_loader && params->initrd_start) { - initrd_start = params->initrd_start ? - params->initrd_start + PAGE_OFFSET : 0; - initrd_end = initrd_start + params->initrd_size; - } if (initrd_start) { if ((initrd_end - PAGE_OFFSET) <= (max_low_pfn << PAGE_SHIFT)) { reserve_bootmem(initrd_start - PAGE_OFFSET, diff -uNr linux-2.5.12.boot.heap/arch/i386/kernel/trampoline.S linux-2.5.12.boot.clean_32bit_entries/arch/i386/kernel/trampoline.S --- linux-2.5.12.boot.heap/arch/i386/kernel/trampoline.S Mon Apr 29 00:17:11 2002 +++ linux-2.5.12.boot.clean_32bit_entries/arch/i386/kernel/trampoline.S Wed May 1 09:39:48 2002 @@ -12,10 +12,6 @@ * In fact we don't actually need a stack so we don't * set one up. * - * We jump into the boot/compressed/head.S code. So you'd - * better be running a compressed kernel image or you - * won't get very far. - * * On entry to trampoline_data, the processor is in real mode * with 16-bit addressing and 16-bit data. CS has some value * and IP is zero. Thus, data addresses need to be absolute @@ -23,12 +19,16 @@ * * If you work on this file, check the object module with objdump * --full-contents --reloc to make sure there are no relocation - * entries except for the gdt one.. + * entries except for gdt & secondary_startup_32.. */ #include <linux/linkage.h> +#include <linux/threads.h> #include <asm/segment.h> #include <asm/page.h> +#include <asm/desc.h> + +#define GDT_ENTRIES (__TSS(NR_CPUS)) .data @@ -42,7 +42,6 @@ mov %cs, %ax # Code and data in the same place mov %ax, %ds - mov $1, %bx # Flag an SMP trampoline cli # We should be safe anyway movl $0xA5A5A5A5, trampoline_data - r_base @@ -56,15 +55,16 @@ lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmpl $__KERNEL_CS, $0x00100000 - # jump to startup_32 in arch/i386/kernel/head.S + # jump to secondary_startup_32 in arch/i386/kernel/head.S + ljmpl $__KERNEL_CS, $(secondary_startup_32 - __PAGE_OFFSET) + idt_48: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L gdt_48: - .word 0x0800 # gdt limit = 2048, 256 GDT entries + .word GDT_ENTRIES*8-1 # gdt limit .long gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) .globl trampoline_end diff -uNr linux-2.5.12.boot.heap/include/asm-i386/boot.h linux-2.5.12.boot.clean_32bit_entries/include/asm-i386/boot.h --- linux-2.5.12.boot.heap/include/asm-i386/boot.h Wed May 1 09:39:29 2002 +++ linux-2.5.12.boot.clean_32bit_entries/include/asm-i386/boot.h Wed May 1 09:39:48 2002 @@ -26,4 +26,14 @@ #define EXTENDED_VGA 0xfffe /* 80x50 mode */ #define ASK_VGA 0xfffd /* ask for it at bootup */ +/* Entry point ID constants */ +#define ENTRY16 0x73726468 /* 'hdrs' */ +#define ENTRY32 0x53524448 /* 'HDRS' */ + +/* Maximum command line size */ +#define COMMAND_LINE_SIZE 256 + +/* Initial page table size 8MB */ +#define INITIAL_PAGE_TABLE_SIZE 0x800000 + #endif diff -uNr linux-2.5.12.boot.heap/include/asm-i386/boot_param.h linux-2.5.12.boot.clean_32bit_entries/include/asm-i386/boot_param.h --- linux-2.5.12.boot.heap/include/asm-i386/boot_param.h Wed May 1 09:39:29 2002 +++ linux-2.5.12.boot.clean_32bit_entries/include/asm-i386/boot_param.h Wed May 1 09:39:48 2002 @@ -1,6 +1,16 @@ #ifndef __I386_BOOT_PARAM_H #define __I386_BOOT_PARAM_H +struct initial_regs32 { + const __u32 eax; + const __u32 ebx; + const __u32 ecx; + const __u32 edx; + const __u32 esi; + const __u32 edi; + const __u32 esp; + const __u32 ebp; +}; struct drive_info_struct { __u8 dummy[32]; }; struct sys_desc_table { __u16 length; ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, 32bit entries 6/11 2002-05-02 15:00 ` [PATCH 2.5.12] x86 Boot enhancements, 32bit entries 6/11 Eric W. Biederman @ 2002-04-27 4:53 ` Pavel Machek 2002-05-02 15:05 ` [PATCH 2.5.12] x86 Boot enhancements, footprint reduction 7/11 Eric W. Biederman 1 sibling, 0 replies; 20+ messages in thread From: Pavel Machek @ 2002-04-27 4:53 UTC (permalink / raw) To: Eric W. Biederman; +Cc: Linus Torvalds, Dave Jones, linux-kernel Hi! > This patch cleans up the 32bit kernel entry points so they don't > assume who their caller is, making them usable by other than setup.S > > For arch/i386/kernel/head.S this untangles the secondary cpu and the bootstrap > entry points making the code more readable. Hmm, but making variables called eax, ebx, ... is surely going to confuse someone. What about bootup_eax, .. ? > + /* > + * Save the initial registers > + */ > + movl %eax, eax > + movl %ebx, ebx > + movl %ecx, ecx > + movl %edx, edx > + movl %esi, esi > + movl %edi, edi > + movl %esp, esp > + movl %ebp, ebp > + > + /* > + * Setup the stack > + */ > + movl stack_start, %esp Pavel -- Philips Velo 1: 1"x4"x8", 300gram, 60, 12MB, 40bogomips, linux, mutt, details at http://atrey.karlin.mff.cuni.cz/~pavel/velo/index.html. ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, footprint reduction 7/11 2002-05-02 15:00 ` [PATCH 2.5.12] x86 Boot enhancements, 32bit entries 6/11 Eric W. Biederman 2002-04-27 4:53 ` Pavel Machek @ 2002-05-02 15:05 ` Eric W. Biederman 2002-05-02 15:07 ` [PATCH 2.5.12] x86 Boot enhancements, build beancounting 8/11 Eric W. Biederman 1 sibling, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 15:05 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This reduces the boot footprint of the Linux kernel by making the kernel decompressor an inplace algorithm, making bzImages more efficient with memory than zImages. It fixes the bug of asking bootloaders to make a tradeoff between reliability and memory efficiency. Eric diff -uNr linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/Makefile linux-2.5.12.boot.footprint/arch/i386/boot/compressed/Makefile --- linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/Makefile Sun Mar 10 20:07:02 2002 +++ linux-2.5.12.boot.footprint/arch/i386/boot/compressed/Makefile Wed May 1 09:40:06 2002 @@ -9,8 +9,6 @@ OBJECTS = $(HEAD) misc.o -ZLDFLAGS = -e startup_32 - # # ZIMAGE_OFFSET is the load offset of the compression loader # BZIMAGE_OFFSET is the load offset of the high loaded compression loader @@ -18,8 +16,8 @@ ZIMAGE_OFFSET = 0x1000 BZIMAGE_OFFSET = 0x100000 -ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS) -BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS) +ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) -T vmlinuz.lds +BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) -T vmlinuz.lds all: vmlinux @@ -42,7 +40,7 @@ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ $(OBJCOPY) $(SYSTEM) $$tmppiggy; \ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ - echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ + echo "SECTIONS { .input : { *(.data) }}" > $$tmppiggy.lnk; \ $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk diff -uNr linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/head.S linux-2.5.12.boot.footprint/arch/i386/boot/compressed/head.S --- linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/head.S Wed May 1 09:39:47 2002 +++ linux-2.5.12.boot.footprint/arch/i386/boot/compressed/head.S Wed May 1 09:40:06 2002 @@ -30,6 +30,20 @@ .globl startup_32 startup_32: + jmp 1f + .balign 4 + .globl input_addr, input_len, output_overhang + .globl kernel_base, kernel_memsz, kernel_filesz + .globl unzip_memsz, unzip_filesz +input_addr: .long input_data +input_len: .long input_data_len +output_overhang: .long input_data_len # Will be set to 8 later... +kernel_base: .long HIGH_BASE +kernel_memsz: .long 0 +kernel_filesz: .long 0 +unzip_memsz: .long _end +unzip_filesz: .long _edata +1: cld cli @@ -44,6 +58,18 @@ movl %edi, edi movl %esp, esp movl %ebp, ebp + + /* + * Move the input data off the bss segment + */ + std + movl $input_data_end -1, %esi + movl %esi, %edi + addl $input_data_shift, %edi + movl $input_data_len, %ecx + rep movsb + cld + addl $input_data_shift, input_addr /* * Setup the stack diff -uNr linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/misc.c linux-2.5.12.boot.footprint/arch/i386/boot/compressed/misc.c --- linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/misc.c Wed May 1 09:39:47 2002 +++ linux-2.5.12.boot.footprint/arch/i386/boot/compressed/misc.c Wed May 1 09:40:06 2002 @@ -9,8 +9,8 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ +#include <linux/string.h> /* for: memset, memmove */ #include <linux/linkage.h> -#include <linux/vmalloc.h> #include <linux/tty.h> #include <asm/io.h> #include <linux/apm_bios.h> @@ -25,16 +25,11 @@ #define OF(args) args #define STATIC static -#undef memset -#undef memcpy - /* * Why do we do this? Don't ask me.. * * Incomprehensible are the ways of bootloaders. */ -static void* memset(void *, int, size_t); -static void* memcpy(void *, __const void *, size_t); #define memzero(s, n) memset ((s), 0, (n)) typedef unsigned char uch; @@ -51,15 +46,6 @@ static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ static unsigned outcnt = 0; /* bytes in output buffer */ -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ -#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ -#define RESERVED 0xC0 /* bit 6,7: reserved */ - #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) /* Diagnostic functions */ @@ -92,8 +78,16 @@ /* Amount of memory in kilobytes, if it isn't set assume enough */ static unsigned long mem_k = 0xFFFFFFFF; -extern char input_data[]; -extern int input_len; +/* Variables in our header */ +extern unsigned long input_addr; +extern unsigned long input_len; +extern unsigned long output_overhang; +extern unsigned long kernel_memsz; +extern unsigned long kernel_filesz; + +/* External symbols */ +extern unsigned char move_routine_end[], move_routine_start[]; +extern unsigned char _end[]; static long bytes_out = 0; static uch *output_data; @@ -108,18 +102,15 @@ static void puts(const char *); -extern int end; -static long free_mem_ptr = (long)&end; -static long free_mem_end_ptr; - -/* Decompressor constants */ #define HEAP_SIZE 0x003000 +static unsigned char heap[HEAP_SIZE]; static unsigned long move_routine; -extern unsigned char move_routine_end[], move_routine_start[]; +static long free_mem_ptr = (unsigned long)&heap[0]; +static long free_mem_end_ptr = (unsigned long)&heap[HEAP_SIZE]; static unsigned int low_buffer_end, low_buffer_size; static int high_loaded =0; -static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; +static uch *high_buffer_start; static char *vidmem = (char *)0xb8000; static int vidport; @@ -167,7 +158,7 @@ { int i; - memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); + memmove ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) vidmem[i] = ' '; } @@ -228,39 +219,14 @@ cols = real_mode->screen.info.orig_video_cols; } -static void* memset(void* s, int c, size_t n) -{ - int i; - char *ss = (char*)s; - - for (i=0;i<n;i++) ss[i] = c; - return s; -} - -static void* memcpy(void* __dest, __const void* __src, - size_t __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++) d[i] = s[i]; - return __dest; -} - /* =========================================================================== * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed. */ static int fill_inbuf(void) { - if (insize != 0) { - error("ran out of input data\n"); - } - - inbuf = input_data; - insize = input_len; - inptr = 1; - return inbuf[0]; + error("ran out of input data\n"); + return 0; } /* =========================================================================== @@ -324,14 +290,20 @@ long * a; } stack_start = { & user_stack [STACK_SIZE] }; +static char command_line[COMMAND_LINE_SIZE]; + extern struct initial_regs32 initial_regs; extern __u32 kernel_start; -static void setup_normal_output_buffer(void) +static void setup_normal_buffers(void) { - if (mem_k < 2048) error("Less than 2MB of memory.\n"); - output_data = (char *)0x100000; /* Points to 1M */ - free_mem_end_ptr = (long)real_mode; + /* Input buffers */ + inbuf = (uch *)input_addr; + insize = input_len; + inptr = 0; + + /* Output buffers */ + output_data = (char *)HIGH_BASE; /* Points to 1M */ } struct moveparams { @@ -339,25 +311,43 @@ uch *high_buffer_start; int hcount; }; -static void setup_output_buffer_if_we_run_high(struct moveparams *mv) +static void setup_buffers_if_we_run_high(struct moveparams *mv) { - high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); + unsigned long high_compressed_start; + /* Ouput buffers */ + high_buffer_start = _end; move_routine = LOW_BASE; - if (mem_k < (4*1024)) error("Less than 4MB of memory.\n"); mv->low_buffer_start = output_data = (char *)move_routine + (move_routine_end - move_routine_start); low_buffer_end = ((unsigned int)real_mode > LOW_MAX ? LOW_MAX : (unsigned int)real_mode) & ~0xfff; low_buffer_size = low_buffer_end - (unsigned long)mv->low_buffer_start; high_loaded = 1; - free_mem_end_ptr = (long)high_buffer_start; - if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) { - high_buffer_start = (uch *)(0x100000 + low_buffer_size); + if ( (HIGH_BASE + low_buffer_size) > ((ulg)high_buffer_start)) { + high_buffer_start = (uch *)(HIGH_BASE + low_buffer_size); mv->hcount = 0; /* say: we need not to move high_buffer */ } else mv->hcount = -1; mv->high_buffer_start = high_buffer_start; if ((ulg)output_data >= low_buffer_end) output_data=high_buffer_start; + + /* Input buffers */ + inptr = 0; + insize = input_len; + high_compressed_start = (ulg)high_buffer_start; + high_compressed_start -=low_buffer_size; + high_compressed_start += kernel_filesz + output_overhang; + high_compressed_start -= insize; + if (high_compressed_start > input_addr) { + inbuf = (uch *)high_compressed_start; + } else { + inbuf = (uch *)input_addr; + } + /* Move the compressed data to a location where the + * decompressed data can overwrite it but will not + * before it is used. + */ + memmove(inbuf, (void *)input_addr, insize); } static void close_output_buffer_if_we_run_high(struct moveparams *mv) @@ -372,6 +362,69 @@ } } +static void relocate_realmode(void) +{ + unsigned long high_addr; + unsigned long new_real_mode, new_cmdline; + int cmdline_len; + char *cmdline; + + /* Compute the highest address we can actually use */ + if (initial_regs.ebp == ENTRY16) { + high_addr = real_mode->base_mem_k << 10; + /* To be safe enforce the 640K barrier */ + if (high_addr > LOW_MAX) { + high_addr = LOW_MAX; + } + } + else { + high_addr = real_mode->real_base + real_mode->real_memsz; + } + /* To allow a maximal sized decompression buffer + * we need to move the command line, and the real mode + * buffer out of the way. + */ + /* Find the command line and get it out of the way */ + cmdline = 0; + if (real_mode->cmd_line_ptr) { + cmdline = (char *)(real_mode->cmd_line_ptr); + } + else if (real_mode->screen.overlap.cl_magic == CL_MAGIC_VALUE) { + cmdline = (char *)real_mode + real_mode->screen.overlap.cl_offset; + } + cmdline_len = 0; + if (cmdline) { + while(cmdline_len < COMMAND_LINE_SIZE) { + cmdline_len++; + if (cmdline[cmdline_len -1] == '\0') + break; + } + memmove(command_line, cmdline, cmdline_len); + command_line[cmdline_len -1] = '\0'; + } + /* relocate the real mode code and the command line */ + new_real_mode = (high_addr - real_mode->real_filesz - DEF_HEAP_SIZE); + new_real_mode -= cmdline_len; + new_real_mode &= ~15; + new_cmdline = new_real_mode + real_mode->real_filesz + DEF_HEAP_SIZE; + memmove((void *)new_real_mode, real_mode, real_mode->real_filesz); + memmove((void *)new_cmdline, cmdline, cmdline_len); + + /* Note the new real_mode address */ + real_mode = (struct boot_params *)new_real_mode; + *((__u32 *)&initial_regs.esi) = new_real_mode; + /* Note the change in heap size */ + real_mode->heap_end_ptr = (new_real_mode + + real_mode->real_filesz + DEF_HEAP_SIZE - 0x200) & 0xffff; + /* Note the new command line address */ + if (real_mode->cmd_line_ptr) { + real_mode->cmd_line_ptr = new_cmdline; + } + if (real_mode->screen.overlap.cl_magic == CL_MAGIC_VALUE) { + real_mode->screen.overlap.cl_offset = + new_cmdline - (unsigned long)real_mode; + } +} asmlinkage unsigned long decompress_kernel(struct moveparams *mv) { @@ -393,9 +446,14 @@ #endif mem_k += 1024; } - - if (free_mem_ptr < HIGH_BASE) setup_normal_output_buffer(); - else setup_output_buffer_if_we_run_high(mv); + if (real_mode) { + relocate_realmode(); + } + if ((mem_k << 10) < HIGH_BASE + kernel_memsz) { + error("Too little memory\n"); + } + if (free_mem_ptr < HIGH_BASE) setup_normal_buffers(); + else setup_buffers_if_we_run_high(mv); makecrc(); puts("Uncompressing Linux... "); diff -uNr linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/vmlinuz.lds linux-2.5.12.boot.footprint/arch/i386/boot/compressed/vmlinuz.lds --- linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/compressed/vmlinuz.lds Wed Dec 31 17:00:00 1969 +++ linux-2.5.12.boot.footprint/arch/i386/boot/compressed/vmlinuz.lds Wed May 1 09:40:06 2002 @@ -0,0 +1,29 @@ +/* ld script to make compressed i386 Linux kernel + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(startup_32) +SECTIONS +{ + . = 0x1000; + _text = .; /* Text and read-only data */ + .text : { *(.text) } = 0x9090 + _etext = .; /* End of text section */ + .rodata : { *(.rodata) *(.rodata.*) } + .data : { + *(.data) + + } + _edata = .; /* End of data section */ + .bss _edata : { *(.bss) } + _end = .; + .input _edata : { + input_data = . ; + *(.input) + input_data_end = . ; + } + input_data_len = input_data_end - input_data; + input_data_shift = _end - _edata; + + /DISCARD/ : { *(*) } +} diff -uNr linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/setup.S linux-2.5.12.boot.footprint/arch/i386/boot/setup.S --- linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/setup.S Wed May 1 09:39:47 2002 +++ linux-2.5.12.boot.footprint/arch/i386/boot/setup.S Wed May 1 09:40:06 2002 @@ -109,6 +109,8 @@ # flags, unused bits must be zero (RFU) bit within loadflags loadflags: LOADED_HIGH = 1 # If set, the kernel is loaded high +STAY_PUT = 0x40 # If set, the loader doesn't expect + # us to relocate anything CAN_USE_HEAP = 0x80 # If set, the loader also has set # heap_end_ptr to tell how much # space behind setup.S can be used for @@ -165,7 +167,11 @@ # The highest safe address for # the contents of an initrd -# variables private to setup.S (not for bootloaders) +# variables private to the kernel (not for bootloaders) +pad2: .long 0 +real_base: .long REAL_BASE # Location of real mode kernel +real_memsz: # Memory usage of real mode kernel + .long (_esetup_heap - _setup) + DELTA_BOOTSECT real_filesz: # Datasize of the real mode kernel .long (_esetup - _setup) + DELTA_BOOTSECT trampoline: call start_of_setup @@ -300,6 +306,15 @@ #endif /* __BIG_KERNEL__ */ loader_ok: +# Get base memory size +# The size in kilobytes is returned in %ax +# There shouldn't be any subfunctions but just +# in case we clear eax and ecx + xorl %eax, %eax + xorl %ecx, %ecx + int $0x12 + movw %ax, (0x1e4) + # Get memory size (extended mem, kB) xorl %eax, %eax @@ -607,12 +622,13 @@ # then we load the segment descriptors movw %cs, %ax # aka SETUPSEG movw %ax, %ds - + # Check whether we need to be downward compatible with version <=201 +# We don't relocate if STAY_PUT is specified or we have a 202 cmd_line + testb $STAY_PUT, loadflags + jnz end_move_self cmpl $0, cmd_line_ptr jne end_move_self # loader uses version >=202 features - cmpb $0x20, type_of_loader - je end_move_self # bootsect loader, we know of it # Boot loader doesnt support boot protocol version 2.02. # If we have our code not at 0x90000, we need to move it there now. @@ -860,6 +876,7 @@ jnz bootsect_second movb $0x20, %cs:type_of_loader + orb $STAY_PUT, %cs:loadflags movw %es, %ax shrw $4, %ax movb %ah, %cs:bootsect_src_base+2 diff -uNr linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/tools/build.c linux-2.5.12.boot.footprint/arch/i386/boot/tools/build.c --- linux-2.5.12.boot.clean_32bit_entries/arch/i386/boot/tools/build.c Mon Jul 2 14:56:40 2001 +++ linux-2.5.12.boot.footprint/arch/i386/boot/tools/build.c Wed May 1 09:40:06 2002 @@ -28,6 +28,9 @@ #include <string.h> #include <stdlib.h> #include <stdarg.h> +#include <stdint.h> +#include <byteswap.h> +#include <endian.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/sysmacros.h> @@ -45,7 +48,140 @@ /* Minimal number of setup sectors (see also bootsect.S) */ #define SETUP_SECTS 4 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(x) x +#define cpu_to_le32(x) x +#define cpu_to_le64(x) x +#define le16_to_cpu(x) x +#define le32_to_cpu(x) x +#define le64_to_cpu(x) x +#else +#define cpu_to_le16(x) bswap_16(x) +#define cpu_to_le32(x) bswap_32(x) +#define cpu_to_le64(x) bswap_64(x) +#define le16_to_cpu(x) bswap_16(x) +#define le32_to_cpu(x) bswap_32(x) +#define le64_to_cpu(x) bswap_64(x) +#endif + +#define OF(args) args +#define STATIC static + /* and a power of two */ + +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#define memzero(s, n) memset ((s), 0, (n)) + + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +static long bytes_out = 0; + +#define get_byte() (inptr<insize?inbuf[inptr++]:(die("missing input data\n"),0)) +#define error(m) die(m) +static void flush_window(void); +#define gzip_mark(x) +#define gzip_release(x) + +static void die(const char * str, ...); + +#include "../../../../lib/inflate.c" + +struct zkernel_header { + uint8_t jump[4]; + uint32_t input_addr; + uint32_t input_len; + uint32_t output_overhang; + uint32_t kernel_base; + uint32_t kernel_memsz; + uint32_t kernel_filesz; + uint32_t unzip_memsz; + uint32_t unzip_filesz; +}; + +static struct overhang_info { + size_t overhang; + size_t output_bytes; +} oh; +static void flush_window(void) +{ + size_t input_bytes_left; + size_t output_bytes_left; + size_t overhang; + unsigned long lcrc = crc; + unsigned i; + + /* Flush the window */ + for(i = 0; i < outcnt; i++) { + unsigned char ch; + ch = window[i]; + lcrc = crc_32_tab[((int)lcrc ^ ch) & 0xff] ^ (lcrc >> 8); + } + crc = lcrc; + bytes_out += outcnt; + outcnt = 0; + + input_bytes_left = insize - inptr; + output_bytes_left = oh.output_bytes - bytes_out; + + overhang = 0; + if (input_bytes_left > output_bytes_left) { + overhang = input_bytes_left - output_bytes_left; + } + if (overhang > oh.overhang) { + oh.overhang = overhang; + } +} +static size_t compute_unzip_overhang(unsigned char *data, size_t data_size) +{ + struct zkernel_header *zhdr; + size_t result_size; + size_t offset; + + + /* Set up the input buffer */ + zhdr = (struct zkernel_header *)data; + offset = le32_to_cpu(zhdr->input_addr) - HIGH_BASE; + inbuf = data + offset; + insize = le32_to_cpu(zhdr->input_len); + if (insize != data_size - offset) + die("Compressed kernel sizes(%d,%d) do not match!\n", + insize, data_size - offset); + result_size = le32_to_cpu(*(uint32_t *)(inbuf + insize - 4)); + inptr = 0; + + /* Setup the overhang computation */ + oh.overhang = 0; + oh.output_bytes = result_size; + + makecrc(); + gunzip(); + + zhdr->output_overhang = cpu_to_le32(oh.overhang); + zhdr->kernel_memsz = cpu_to_le32(result_size); + zhdr->kernel_filesz = cpu_to_le32(result_size); + return oh.overhang; +} + + + byte buf[1024]; +byte *bigbuf; int fd; int is_big_kernel; @@ -157,21 +293,36 @@ if (sys_size > 0xefff) fprintf(stderr,"warning: kernel is too big for standalone boot " "from floppy\n"); + bigbuf = malloc(sz); + if (!bigbuf) + die("Out of memory\n"); while (sz > 0) { - int l, n; + int off, n; - l = (sz > sizeof(buf)) ? sizeof(buf) : sz; - if ((n=read(fd, buf, l)) != l) { + off = sb.st_size - sz; + if ((n=read(fd, bigbuf +off, sz)) <= 0) { if (n < 0) die("Error reading %s: %m", argv[3]); else die("%s: Unexpected EOF", argv[3]); } - if (write(1, buf, l) != l) - die("Write failed"); - sz -= l; + sz -= n; } close(fd); + compute_unzip_overhang(bigbuf, sb.st_size); + sz = sb.st_size; + while(sz > 0) { + int off, n; + + off = sb.st_size - sz; + if ((n=write(1, bigbuf+off, sz)) <= 0) { + if (n < 0) + die("Error writing %s: %m", "<stdout>"); + else + die("%s: Unexpected EOF", "<stdout>"); + } + sz -= n; + } if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */ die("Output: seek failed"); diff -uNr linux-2.5.12.boot.clean_32bit_entries/include/asm-i386/boot_param.h linux-2.5.12.boot.footprint/include/asm-i386/boot_param.h --- linux-2.5.12.boot.clean_32bit_entries/include/asm-i386/boot_param.h Wed May 1 09:39:48 2002 +++ linux-2.5.12.boot.footprint/include/asm-i386/boot_param.h Wed May 1 09:40:06 2002 @@ -37,7 +37,8 @@ struct drive_info_struct drive_info; /* 0x80 */ struct sys_desc_table sys_desc_table; /* 0xa0 */ __u32 alt_mem_k; /* 0x1e0 */ - __u8 reserved5[4]; /* 0x1e4 */ + __u16 base_mem_k; /* 0x1e4 */ + __u8 reserved5[2]; /* 0x1e6 */ __u8 e820_map_nr; /* 0x1e8 */ __u8 reserved6[8]; /* 0x1e9 */ __u8 setup_sects; /* 0x1f1 */ @@ -83,8 +84,11 @@ /* 2.03+ */ __u32 ramdisk_max; /* 0x22c */ /* Below this point for internal kernel use only */ - __u32 real_filesz; /* 0x230 */ - __u8 reserved15[0x2d0 - 0x234]; /* 0x234 */ + __u32 pad2; /* 0x230 */ + __u32 real_base; /* 0x234 */ + __u32 real_memsz; /* 0x238 */ + __u32 real_filesz; /* 0x23c */ + __u8 reserved15[0x2d0 - 0x240]; /* 0x240 */ struct e820entry e820_map[E820MAX]; /* 0x2d0 */ /* 0x550 */ } __attribute__((packed)); ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, build beancounting 8/11 2002-05-02 15:05 ` [PATCH 2.5.12] x86 Boot enhancements, footprint reduction 7/11 Eric W. Biederman @ 2002-05-02 15:07 ` Eric W. Biederman 2002-05-02 15:11 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 Eric W. Biederman 0 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 15:07 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This patch reorganizes the build of the x86 boot image so that we preserve enough information to accurately track how much memory will be used. Eric diff -uNr linux-2.5.12.boot.footprint/Makefile linux-2.5.12.boot.build/Makefile --- linux-2.5.12.boot.footprint/Makefile Tue Apr 30 22:55:20 2002 +++ linux-2.5.12.boot.build/Makefile Wed May 1 09:40:42 2002 @@ -93,15 +93,6 @@ AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) # -# ROOT_DEV specifies the default root-device when making the image. -# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case -# the default of FLOPPY is used by 'build'. -# This is i386 specific. -# - -export ROOT_DEV = CURRENT - -# # If you want to preset the SVGA mode, uncomment the next line and # set SVGA_MODE to whatever number you want. # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/Makefile linux-2.5.12.boot.build/arch/i386/boot/Makefile --- linux-2.5.12.boot.footprint/arch/i386/boot/Makefile Sun Aug 5 14:13:19 2001 +++ linux-2.5.12.boot.build/arch/i386/boot/Makefile Wed May 1 09:40:42 2002 @@ -12,13 +12,11 @@ $(TOPDIR)/include/linux/autoconf.h \ $(TOPDIR)/include/asm/boot.h -zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build - $(OBJCOPY) compressed/vmlinux compressed/vmlinux.out - tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage - -bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build - $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out - tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage +zImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux realmode compressed/vmlinux + tools/build $(TOPDIR)/vmlinux realmode compressed/vmlinux zImage + +bzImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux + tools/build -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzImage compressed/vmlinux: $(TOPDIR)/vmlinux @$(MAKE) -C compressed vmlinux @@ -39,49 +37,43 @@ install: $(CONFIGURE) $(BOOTIMAGE) sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)" -tools/build: tools/build.c +tools/build: tools/build.c $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(TOPDIR)/include/asm-i386/boot.h $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include -bootsect: bootsect.o - $(LD) -Ttext 0x0 -s --oformat binary -o $@ $< - bootsect.o: bootsect.s $(AS) -o $@ $< bootsect.s: bootsect.S Makefile $(BOOT_INCL) $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bbootsect: bbootsect.o - $(LD) -Ttext 0x0 -s --oformat binary $< -o $@ - bbootsect.o: bbootsect.s $(AS) -o $@ $< bbootsect.s: bootsect.S Makefile $(BOOT_INCL) $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -setup: setup.o - $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< - setup.o: setup.s $(AS) -o $@ $< setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bsetup: bsetup.o - $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< - bsetup.o: bsetup.s $(AS) -o $@ $< bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ +realmode: bootsect.o setup.o + $(LD) -T realmode.lds -o $@ $^ + +brealmode: bbootsect.o bsetup.o + $(LD) -T realmode.lds -o $@ $^ + dep: clean: rm -f tools/build - rm -f setup bootsect zImage compressed/vmlinux.out - rm -f bsetup bbootsect bzImage compressed/bvmlinux.out + rm -f realmode zImage + rm -f brealmode bzImage @$(MAKE) -C compressed clean diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/bootsect.S linux-2.5.12.boot.build/arch/i386/boot/bootsect.S --- linux-2.5.12.boot.footprint/arch/i386/boot/bootsect.S Sun Mar 10 20:07:02 2002 +++ linux-2.5.12.boot.build/arch/i386/boot/bootsect.S Wed May 1 09:40:42 2002 @@ -54,7 +54,7 @@ #endif .code16 -.text +.section ".bootsect", "ax", @progbits .global _start _start: diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/realmode.lds linux-2.5.12.boot.build/arch/i386/boot/realmode.lds --- linux-2.5.12.boot.footprint/arch/i386/boot/realmode.lds Wed Dec 31 17:00:00 1969 +++ linux-2.5.12.boot.build/arch/i386/boot/realmode.lds Wed May 1 09:40:42 2002 @@ -0,0 +1,18 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +ENTRY(_start) +OUTPUT_ARCH(i386) +SECTIONS +{ + .bootsect 0 : AT(0x10000) { + *(.bootsect) + } + .setup 0 : AT(LOADADDR(.bootsect) + SIZEOF(.bootsect)) { + *(.setup) + } + .setup.heap SIZEOF(.setup) : AT(LOADADDR(.setup) + SIZEOF(.setup)) { + *(.setup.heap) + } + /DISCARD/ : { + *(*) + } +} diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/setup.S linux-2.5.12.boot.build/arch/i386/boot/setup.S --- linux-2.5.12.boot.footprint/arch/i386/boot/setup.S Wed May 1 09:40:06 2002 +++ linux-2.5.12.boot.build/arch/i386/boot/setup.S Wed May 1 09:40:42 2002 @@ -83,7 +83,7 @@ .code16 .globl _setup, _esetup -.text +.section ".setup", "ax", @progbits _setup: start: @@ -174,6 +174,9 @@ .long (_esetup_heap - _setup) + DELTA_BOOTSECT real_filesz: # Datasize of the real mode kernel .long (_esetup - _setup) + DELTA_BOOTSECT +kern_base: .long KERNEL_START # Kernel load address +kern_memsz: .long 0x00000000 # Kernel memory usage +kern_filesz: .long 0x00000000 # Kernel datasize trampoline: call start_of_setup # Don't let the E820 map overlap code . = (E820MAP - DELTA_BOOTSECT) + (E820MAX * E820ENTRY_SIZE) diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/tools/build.c linux-2.5.12.boot.build/arch/i386/boot/tools/build.c --- linux-2.5.12.boot.footprint/arch/i386/boot/tools/build.c Wed May 1 09:40:06 2002 +++ linux-2.5.12.boot.build/arch/i386/boot/tools/build.c Wed May 1 09:40:42 2002 @@ -1,19 +1,24 @@ + /* * $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1997 Martin Mares + * Copyright (C) 2002 Eric Biederman + * */ /* * This file builds a disk-image from three different files: * - * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest - * - setup: 8086 machine code, sets up system parm + * - vmlinux: kernel before compression + * - realmode: composed of: + * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest + * - setup: 8086 machine code, sets up system parm * - system: 80386 code for actual system * * It does some checking that all files are of the correct type, and - * just writes the result to stdout, removing headers and padding to + * just writes the result, removing headers and padding to * the right amount. It also writes some system data to stderr. */ @@ -22,26 +27,29 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 * Cross compiling fixes by Gertjan van Wingerde, July 1996 * Rewritten by Martin Mares, April 1997 + * Rewriten by Eric Biederman to remove the need for objcopy and + * to stop losing information. 29 Mary 2002 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdarg.h> +#include <stddef.h> #include <stdint.h> #include <byteswap.h> #include <endian.h> #include <sys/types.h> #include <sys/stat.h> -#include <sys/sysmacros.h> #include <unistd.h> #include <fcntl.h> +#include <errno.h> +#include <elf.h> +/* To stay in sync with the kernel we must include these headers */ +#include <linux/version.h> +#include <linux/compile.h> #include <asm/boot.h> -typedef unsigned char byte; -typedef unsigned short word; -typedef unsigned long u32; - #define DEFAULT_MAJOR_ROOT 0 #define DEFAULT_MINOR_ROOT 0 @@ -64,6 +72,84 @@ #define le64_to_cpu(x) bswap_64(x) #endif + +/* Input segments */ +#define IKERN 0 +#define IREAL 1 +#define IZKERN 2 +#define ISEGS 3 + +/* Segments of the output file */ +#define OREAL 0 +#define OKERN 1 +#define OBSS1 2 +#define OBSS2 3 +#define OSEGS 4 + +struct file_seg +{ + size_t mem_addr; + size_t mem_size; + size_t data_size; + off_t file_offset; + size_t entry; + unsigned char *data; +}; + +struct boot_params { + uint8_t reserved1[0x1f1]; /* 0x000 */ + uint8_t setup_sects; /* 0x1f1 */ + uint16_t mount_root_rdonly; /* 0x1f2 */ + uint16_t syssize; /* 0x1f4 */ + uint16_t swapdev; /* 0x1f6 */ + uint16_t ramdisk_flags; /* 0x1f8 */ +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 + uint16_t vid_mode; /* 0x1fa */ + uint16_t root_dev; /* 0x1fc */ + uint8_t reserved9[1]; /* 0x1fe */ + uint8_t aux_device_info; /* 0x1ff */ + /* 2.00+ */ + uint8_t jump[2]; /* 0x200 */ + uint8_t header_magic[4]; /* 0x202 */ + uint16_t version; /* 0x206 */ + uint8_t reserved11[8]; /* 0x208 */ + uint8_t type_of_loader; /* 0x210 */ +#define LOADER_LILO 0x00 +#define LOADER_LOADLIN 0x10 +#define LOADER_BOOTSECT_LOADER 0x20 +#define LOADER_SYSLINUX 0x30 +#define LOADER_ETHERBOOT 0x40 +#define LOADER_UNKNOWN 0xFF + uint8_t loadflags; /* 0x211 */ +#define LOADFLAG_LOADED_HIGH 1 +#define LOADFLAG_STAY_PUT 0x40 +#define LOADFLAG_CAN_USE_HEAP 0x80 + uint8_t reserved12[2]; /* 0x212 */ + uint32_t code32_start; /* 0x214 */ + uint32_t initrd_start; /* 0x218 */ + uint32_t initrd_size; /* 0x21c */ + uint8_t reserved13[4]; /* 0x220 */ + /* 2.01+ */ + uint16_t heap_end_ptr; /* 0x224 */ + uint8_t reserved14[2]; /* 0x226 */ + /* 2.02+ */ + uint32_t cmd_line_ptr; /* 0x228 */ + /* 2.03+ */ + uint32_t ramdisk_max; /* 0x22c */ + /* 2.04+ */ + uint16_t entry32_off; /* 0x230 */ + uint16_t internal_cmdline_off; /* 0x232 */ + uint32_t real_base; /* 0x240 */ + uint32_t real_memsz; /* 0x244 */ + uint32_t real_filesz; /* 0x248 */ + uint32_t kern_base; /* 0x24C */ + uint32_t kern_memsz; /* 0x250 */ + uint32_t kern_filesz; /* 0x254 */ + /* 0x258 */ +}; + #define OF(args) args #define STATIC static /* and a power of two */ @@ -103,6 +189,7 @@ #include "../../../../lib/inflate.c" struct zkernel_header { + /* 2.04+ */ uint8_t jump[4]; uint32_t input_addr; uint32_t input_len; @@ -147,22 +234,28 @@ oh.overhang = overhang; } } -static size_t compute_unzip_overhang(unsigned char *data, size_t data_size) +static size_t compute_unzip_overhang(struct file_seg *iseg) { struct zkernel_header *zhdr; + unsigned char *data; + size_t data_size; size_t result_size; size_t offset; - /* Set up the input buffer */ + data = iseg[IZKERN].data; + data_size = iseg[IZKERN].data_size; zhdr = (struct zkernel_header *)data; - offset = le32_to_cpu(zhdr->input_addr) - HIGH_BASE; + offset = le32_to_cpu(zhdr->input_addr) - iseg[IZKERN].mem_addr; inbuf = data + offset; insize = le32_to_cpu(zhdr->input_len); if (insize != data_size - offset) die("Compressed kernel sizes(%d,%d) do not match!\n", insize, data_size - offset); result_size = le32_to_cpu(*(uint32_t *)(inbuf + insize - 4)); + if (result_size != iseg[IKERN].data_size) + die("Uncompressed kernel sizes(%d,%d) do not match!\n", + result_size, iseg[IKERN].data_size); inptr = 0; /* Setup the overhang computation */ @@ -172,20 +265,10 @@ makecrc(); gunzip(); - zhdr->output_overhang = cpu_to_le32(oh.overhang); - zhdr->kernel_memsz = cpu_to_le32(result_size); - zhdr->kernel_filesz = cpu_to_le32(result_size); return oh.overhang; } - - -byte buf[1024]; -byte *bigbuf; -int fd; -int is_big_kernel; - -void die(const char * str, ...) +static void die(const char * str, ...) { va_list args; va_start(args, str); @@ -194,147 +277,430 @@ exit(1); } -void file_open(const char *name) +static int checked_open(const char *pathname, int flags, mode_t mode) { - if ((fd = open(name, O_RDONLY, 0)) < 0) - die("Unable to open `%s': %m", name); + int result; + result = open(pathname, flags, mode); + if (result < 0) { + die("Cannot open %s : %s", + pathname, + strerror(errno)); + } + return result; } -void usage(void) +static void checked_read(int fd, void *buf, size_t count, const char *pathname) { - die("Usage: build [-b] bootsect setup system [rootdev] [> image]"); + ssize_t result; + result = read(fd, buf, count); + if (result != count) { + die("Cannot read %d bytes from %s: %s", + count, + pathname, + strerror(errno)); + } } -int main(int argc, char ** argv) +static void checked_write(int fd, void *buf, size_t count, const char *pathname) { - unsigned int i, c, sz, setup_sectors; - u32 sys_size; - byte major_root, minor_root; - struct stat sb; - - if (argc > 2 && !strcmp(argv[1], "-b")) - { - is_big_kernel = 1; - argc--, argv++; - } - if ((argc < 4) || (argc > 5)) - usage(); - if (argc > 4) { - if (!strcmp(argv[4], "CURRENT")) { - if (stat("/", &sb)) { - perror("/"); - die("Couldn't stat /"); + ssize_t result; + result = write(fd, buf, count); + if (result != count) { + die("Cannot write %d bytes from %s: %s", + count, + pathname, + strerror(errno)); + } +} + +static off_t checked_lseek(int fd, off_t offset, int whence, const char *pathname) +{ + off_t result; + result = lseek(fd, offset, whence); + if (result == (off_t)-1) { + die("lseek failed on %s: %s", + pathname, strerror(errno)); + } + return result; +} + +static void *checked_malloc(size_t size) +{ + void *result; + result = malloc(size); + if (result == 0) { + die("malloc of %d bytes failed: %s", + size, strerror(errno)); + } + return result; +} + +static void check_ehdr(Elf32_Ehdr *ehdr, char *name) +{ + /* Do some basic to ensure it is an ELF image */ + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { + die("%s is not an ELF binary", name); + } + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { + die("%s is not a 32bit ELF object", name); + } + if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { + die("%s does not have little endian data", name); + } + if ((ehdr->e_ident[EI_VERSION] != EV_CURRENT) || + ehdr->e_version != EV_CURRENT) { + die("%s has invalid ELF version", name); + } + if (ehdr->e_type != ET_EXEC) { + die("%s is not an ELF executable", name); + } + if (ehdr->e_machine != EM_386) { + die("%s is not for x86", name); + } + if ((ehdr->e_phoff == 0) || (ehdr->e_phnum == 0)) { + die("%s has no program header", name); + } + if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) { + die("%s has invalid program header size", name); + } +} + +static Elf32_Phdr *read_sorted_phdr(char *name, int fd, + Elf32_Ehdr *ehdr, struct file_seg *seg) +{ + int i, j; + Elf32_Phdr *phdr, *plow, *phigh; + size_t phdr_size; + seg->mem_addr = 0; + seg->mem_size = 0; + seg->data_size = 0; + seg->file_offset = 0; + seg->entry = ehdr->e_entry; + seg->data = 0; + + phdr_size = ehdr->e_phnum * sizeof(*phdr); + phdr = checked_malloc(phdr_size); + checked_lseek(fd, ehdr->e_phoff, SEEK_SET, name); + checked_read(fd, phdr, phdr_size, name); + + plow = 0; + phigh = 0; + /* Do an insertion sort on the program headers */ + for(i = 0; i < ehdr->e_phnum; i++) { + Elf32_Phdr *least; + least = phdr +i; + for(j = i+1; j < ehdr->e_phnum; j++) { + if (phdr[j].p_type != PT_LOAD) { + continue; } - major_root = major(sb.st_dev); - minor_root = minor(sb.st_dev); - } else if (strcmp(argv[4], "FLOPPY")) { - if (stat(argv[4], &sb)) { - perror(argv[4]); - die("Couldn't stat root device."); + if ((least->p_type != PT_LOAD) || + (phdr[j].p_paddr < least->p_paddr)) { + least = phdr + j; } - major_root = major(sb.st_rdev); - minor_root = minor(sb.st_rdev); - } else { - major_root = 0; - minor_root = 0; } - } else { - major_root = DEFAULT_MAJOR_ROOT; - minor_root = DEFAULT_MINOR_ROOT; + if (least != phdr +i) { + Elf32_Phdr tmp; + tmp = phdr[i]; + phdr[i] = *least; + *least = tmp; + } + } + plow = phdr; + phigh = 0; + for(i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + break; + phigh = phdr +i; + } + if (phigh) { + size_t start, middle, end; + start = plow->p_paddr; + middle = phigh->p_paddr + phigh->p_filesz; + end = phigh->p_paddr + phigh->p_memsz; + seg->mem_addr = start; + seg->mem_size = end - start; + seg->data_size = middle - start; } - fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + return phdr; + +} - file_open(argv[1]); - i = read(fd, buf, sizeof(buf)); - fprintf(stderr,"Boot sector %d bytes.\n",i); - if (i != 512) - die("Boot block must be exactly 512 bytes"); - if (buf[510] != 0x55 || buf[511] != 0xaa) - die("Boot block hasn't got boot flag (0xAA55)"); - buf[508] = minor_root; - buf[509] = major_root; - if (write(1, buf, 512) != 512) - die("Write call failed"); - close (fd); - - file_open(argv[2]); /* Copy the setup code */ - for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c ) - if (write(1, buf, c) != c) - die("Write call failed"); - if (c != 0) - die("read-error on `setup'"); - close (fd); - - setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */ - /* for compatibility with ancient versions of LILO. */ - if (setup_sectors < SETUP_SECTS) - setup_sectors = SETUP_SECTS; - fprintf(stderr, "Setup is %d bytes.\n", i); - memset(buf, 0, sizeof(buf)); - while (i < setup_sectors * 512) { - c = setup_sectors * 512 - i; - if (c > sizeof(buf)) - c = sizeof(buf); - if (write(1, buf, c) != c) - die("Write call failed"); - i += c; - } - - file_open(argv[3]); - if (fstat (fd, &sb)) - die("Unable to stat `%s': %m", argv[3]); - sz = sb.st_size; - fprintf (stderr, "System is %d kB\n", sz/1024); - sys_size = (sz + 15) / 16; - /* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */ - if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE)) - die("System is too big. Try using %smodules.", - is_big_kernel ? "" : "bzImage or "); - if (sys_size > 0xefff) - fprintf(stderr,"warning: kernel is too big for standalone boot " - "from floppy\n"); - bigbuf = malloc(sz); - if (!bigbuf) - die("Out of memory\n"); - while (sz > 0) { - int off, n; - - off = sb.st_size - sz; - if ((n=read(fd, bigbuf +off, sz)) <= 0) { - if (n < 0) - die("Error reading %s: %m", argv[3]); - else - die("%s: Unexpected EOF", argv[3]); - } - sz -= n; +static void get_elf_sizes(char *name, size_t pstart, struct file_seg *sizes) +{ + int fd; + Elf32_Ehdr ehdr; + Elf32_Phdr *phdr; + fd = checked_open(name, O_RDONLY, 0); + checked_read(fd, &ehdr, sizeof(ehdr), name); + check_ehdr(&ehdr, name); + + phdr = read_sorted_phdr(name, fd, &ehdr, sizes); + if (sizes->mem_addr != pstart) { + die("Low PHDR in %s not at 0x%08x", name, pstart); } + + free(phdr); close(fd); - compute_unzip_overhang(bigbuf, sb.st_size); - sz = sb.st_size; - while(sz > 0) { - int off, n; - - off = sb.st_size - sz; - if ((n=write(1, bigbuf+off, sz)) <= 0) { - if (n < 0) - die("Error writing %s: %m", "<stdout>"); - else - die("%s: Unexpected EOF", "<stdout>"); + return; +} + +static void read_elf(char *name, size_t pstart, struct file_seg *seg) +{ + int src_fd; + Elf32_Ehdr ehdr; + Elf32_Phdr *phdr; + size_t last_paddr; + size_t loc; + int i; + + src_fd = checked_open(name, O_RDONLY, 0); + checked_read(src_fd, &ehdr, sizeof(ehdr), name); + check_ehdr(&ehdr, name); + + phdr = read_sorted_phdr(name, src_fd, &ehdr, seg); + if (seg->mem_addr != pstart) { + die("Low PHDR in %s not at 0x%08x", name, pstart); + } + + last_paddr = phdr[0].p_paddr; + seg->data = checked_malloc(seg->data_size); + loc = 0; + for(i = 0; i < ehdr.e_phnum; i++) { + size_t size; + if (phdr[i].p_type != PT_LOAD) { + break; + } + if (last_paddr != phdr[i].p_paddr) { + size = phdr[i].p_paddr - last_paddr; + memset(seg->data + loc, 0, size); + loc += size; } - sz -= n; + last_paddr = phdr[i].p_paddr + phdr[i].p_filesz; + + size = phdr[i].p_filesz; + checked_lseek(src_fd, phdr[i].p_offset, SEEK_SET, name); + checked_read(src_fd, seg->data + loc, size, name); + loc += size; } + free(phdr); + close(src_fd); + return; +} - if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */ - die("Output: seek failed"); - buf[0] = setup_sectors; - if (write(1, buf, 1) != 1) - die("Write of setup sector count failed"); - if (lseek(1, 500, SEEK_SET) != 500) - die("Output: seek failed"); - buf[0] = (sys_size & 0xff); - buf[1] = ((sys_size >> 8) & 0xff); - if (write(1, buf, 2) != 2) - die("Write of image length failed"); +struct image_info { + int is_big_kernel; + size_t entry32; + size_t setup_sectors; + size_t sys_size; + size_t root_dev; + size_t unzip_overhang; + struct boot_params *param; + struct zkernel_header *zhdr; +}; - return 0; /* Everything is OK */ +static void update_image( + struct file_seg *iseg, struct file_seg *oseg, struct image_info *info) +{ + struct boot_params *param = info->param; + struct zkernel_header *zhdr = info->zhdr; + info->setup_sectors &= 0xff; + info->sys_size &= 0xffff; + info->root_dev &= 0xffff; + param->setup_sects = info->setup_sectors; + param->syssize = cpu_to_le16(info->sys_size); + param->root_dev = cpu_to_le16(info->root_dev); + param->real_base = cpu_to_le32(oseg[OREAL].mem_addr); + param->real_memsz = cpu_to_le32(oseg[OREAL].mem_size); + param->real_filesz = cpu_to_le32(oseg[OREAL].data_size); + param->kern_base = cpu_to_le32(oseg[OKERN].mem_addr); + param->kern_memsz = cpu_to_le32(oseg[OKERN].mem_size); + param->kern_filesz = cpu_to_le32(oseg[OKERN].data_size); + zhdr->output_overhang = cpu_to_le32(info->unzip_overhang); + zhdr->kernel_memsz = cpu_to_le32(iseg[IKERN].mem_size); + zhdr->kernel_filesz = cpu_to_le32(iseg[IKERN].data_size); +} + +static void usage(void) +{ + die("Usage: build [-b] vmlinux realmode compressed/vmlinux image"); +} + +int main(int argc, char ** argv) +{ + char *kernel; + char *realmode; + char *zkernel; + char *image; + int image_fd; + size_t major_root, minor_root; + size_t zkernel_base; + struct image_info info; + struct file_seg iseg[ISEGS]; + struct file_seg oseg[OSEGS]; + struct stat st; + int i; + + memset(iseg, 0, sizeof(iseg)); + memset(oseg, 0, sizeof(oseg)); + memset(&info, 0, sizeof(info)); + info.is_big_kernel = 0; + if (argc > 2 && (strcmp(argv[1], "-b") == 0)) { + info.is_big_kernel = 1; + argc--; + argv++; + } + if (argc != 5) { + usage(); + } + kernel = argv[1]; + realmode = argv[2]; + zkernel = argv[3]; + image = argv[4]; + + /* Compute the current root device */ + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + if (stat("/", &st) == 0) { + major_root = major(st.st_dev); + minor_root = minor(st.st_dev); + } + major_root &= 0xff; + minor_root &= 0xff; + info.root_dev = (major_root << 8) | minor_root; + printf("Root device is (%d, %d)\n", major_root, minor_root); + + /* Read in the file information */ + zkernel_base = info.is_big_kernel? HIGH_BASE : LOW_BASE; + get_elf_sizes(kernel, HIGH_BASE, &iseg[IKERN]); + read_elf(realmode, REAL_BASE, &iseg[IREAL]); + read_elf(zkernel, zkernel_base, &iseg[IZKERN]); + + oseg[OREAL] = iseg[IREAL]; + oseg[OKERN] = iseg[IZKERN]; + + info.param = (struct boot_params *)oseg[OREAL].data; + info.zhdr = (struct zkernel_header *)oseg[OKERN].data; + info.unzip_overhang = compute_unzip_overhang(iseg); + + /* Compute the memory usage when the compressed data + * and the BSS stop overlapping. + */ + oseg[OKERN].mem_size = oseg[OKERN].data_size + + (le32_to_cpu(info.zhdr->unzip_memsz) - + le32_to_cpu(info.zhdr->unzip_filesz)); + if (!info.is_big_kernel) { + /* zImage */ + size_t kern_end; + /* zImages are wacky, they load at 64K but then + * setup.S relocates them down to 4K. + */ + /* Check the decompression address and ensure we + * have enough space, to decompress. + */ + oseg[OREAL].mem_addr = DEF_INITSEG << 4; + kern_end = oseg[OKERN].mem_addr + oseg[OKERN].mem_size; + kern_end = (kern_end + 15) & ~15; + if (kern_end > oseg[OREAL].mem_addr) { + die("System is to big. Try using bzImage or modules"); + } + + /* Describe the initial hole */ + oseg[OBSS1].mem_addr = oseg[OKERN].mem_addr; + oseg[OBSS1].data_size = 0; + oseg[OBSS1].mem_size = (DEF_SYSSEG << 4) - oseg[OBSS1].mem_addr; + + /* Check the load time address and verify we + * have enough space to load. + */ + oseg[OKERN].mem_addr = DEF_SYSSEG << 4; + kern_end = oseg[OKERN].mem_addr + oseg[OKERN].data_size; + kern_end = (kern_end + 15) & ~15; + if (kern_end > oseg[OREAL].mem_addr) { + die("System is to big. Try using bzImage or modules"); + } + + /* Describe where the kernel actually runs */ + oseg[OBSS2].mem_addr = HIGH_BASE; + oseg[OBSS2].mem_size = iseg[IKERN].mem_size; + oseg[OBSS2].data_size = 0; + } else { + /* bzImage */ + size_t unzip_bufsz; + + /* Compute the bzImage decompressor memory size */ + unzip_bufsz = iseg[IKERN].data_size + info.unzip_overhang; + if (unzip_bufsz > oseg[OKERN].mem_size) { + oseg[OKERN].mem_size = unzip_bufsz; + } + + /* Compute how much real memory we need */ + oseg[OREAL].mem_size += + ((le32_to_cpu(info.zhdr->unzip_memsz) - + oseg[OKERN].mem_addr) + 0xfff) & ~0xfff; + oseg[OREAL].mem_size += COMMAND_LINE_SIZE; + if (oseg[OREAL].mem_size > REAL_MAX - REAL_BASE) { + die("Kernel requires %d bytes low memory %d available!\n", + oseg[OREAL].mem_size, + REAL_MAX - REAL_BASE); + } + /* See if the loaded kernel uses more memory */ + if (iseg[IKERN].mem_size > oseg[OKERN].mem_size) { + oseg[OKERN].mem_size = iseg[IKERN].mem_size; + } + } + + /* Compute the file offsets */ + info.setup_sectors = (oseg[OREAL].data_size - 512 + 511)/512; + if (info.setup_sectors < SETUP_SECTS) + info.setup_sectors = SETUP_SECTS; + + oseg[OKERN].file_offset = oseg[OREAL].file_offset + (info.setup_sectors +1)*512; + + /* Check and print the values to write back. */ + info.entry32 = oseg[OREAL].mem_addr + + le32_to_cpu(info.param->entry32_off); + printf("Boot sector is 512 bytes\n"); + printf("Setup is %d bytes\n", oseg[OREAL].data_size - 512); + + info.sys_size = (oseg[OKERN].data_size + 15)/16; + if ((iseg[IKERN].mem_addr + iseg[IKERN].mem_size) + >= INITIAL_PAGE_TABLE_SIZE) { + die("System is to big. Try using modules."); + } + if (info.sys_size > 0xefff) { + fprintf(stderr, "warning: kernel is too big for standalone boot " + "from floppy\n"); + } + printf("System is %d KB\n", (info.sys_size*16)/1024); + printf("entry32: 0x%x\n", info.entry32); + printf("[real] base: %08x filesz %5d B memsz= %5d KB\n", + oseg[OREAL].mem_addr, + oseg[OREAL].data_size, + oseg[OREAL].mem_size/1024); + printf("[kern] base: %08x filesz %5d KB memsz= %5d KB\n", + oseg[OKERN].mem_addr, + oseg[OKERN].data_size/1024, + oseg[OKERN].mem_size/1024); + printf("[bss1] base: %08x filesz %5d KB memsz= %5d KB\n", + oseg[OBSS1].mem_addr, + oseg[OBSS1].data_size/1024, + oseg[OBSS1].mem_size/1024); + printf("[bss2] base: %08x filesz %5d KB memsz= %5d KB\n", + oseg[OBSS2].mem_addr, + oseg[OBSS2].data_size/1024, + oseg[OBSS2].mem_size/1024); + + /* Write the values back */ + update_image(iseg, oseg, &info); + + /* Write destination file */ + image_fd = checked_open(image, O_RDWR | O_CREAT | O_TRUNC, 0666); + for(i = 0; i < OSEGS; i++) { + if (oseg[i].data_size == 0) + continue; + checked_lseek(image_fd, oseg[i].file_offset, SEEK_SET, image); + checked_write(image_fd, oseg[i].data, oseg[i].data_size, image); + } + close(image_fd); + return 0; } diff -uNr linux-2.5.12.boot.footprint/arch/x86_64/boot/Makefile linux-2.5.12.boot.build/arch/x86_64/boot/Makefile --- linux-2.5.12.boot.footprint/arch/x86_64/boot/Makefile Sun Mar 10 20:08:39 2002 +++ linux-2.5.12.boot.build/arch/x86_64/boot/Makefile Wed May 1 09:40:42 2002 @@ -14,11 +14,11 @@ zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build $(OBJCOPY) compressed/vmlinux compressed/vmlinux.out - tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage + tools/build bootsect setup compressed/vmlinux.out CURRENT > zImage bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out - tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage + tools/build -b bbootsect bsetup compressed/bvmlinux.out CURRENT > bzImage bzImage-padded: bzImage dd if=/dev/zero bs=1k count=70 >> bzImage diff -uNr linux-2.5.12.boot.footprint/include/asm-i386/boot_param.h linux-2.5.12.boot.build/include/asm-i386/boot_param.h --- linux-2.5.12.boot.footprint/include/asm-i386/boot_param.h Wed May 1 09:40:06 2002 +++ linux-2.5.12.boot.build/include/asm-i386/boot_param.h Wed May 1 09:40:42 2002 @@ -88,7 +88,10 @@ __u32 real_base; /* 0x234 */ __u32 real_memsz; /* 0x238 */ __u32 real_filesz; /* 0x23c */ - __u8 reserved15[0x2d0 - 0x240]; /* 0x240 */ + __u32 kern_base; /* 0x240 */ + __u32 kern_memsz; /* 0x244 */ + __u32 kern_filesz; /* 0x248 */ + __u8 reserved15[0x2d0 - 0x24c]; /* 0x24c */ struct e820entry e820_map[E820MAX]; /* 0x2d0 */ /* 0x550 */ } __attribute__((packed)); ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 2002-05-02 15:07 ` [PATCH 2.5.12] x86 Boot enhancements, build beancounting 8/11 Eric W. Biederman @ 2002-05-02 15:11 ` Eric W. Biederman 2002-05-02 15:13 ` [PATCH 2.5.12] x86 Boot enhancements, LinuxBIOS support 10/11 Eric W. Biederman ` (2 more replies) 0 siblings, 3 replies; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 15:11 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This patch revs the x86 boot protocol, making the bean counting information, and the 32bit entry point available, to bootloaders that need it. Eric diff -uNr linux-2.5.12.boot.build/Documentation/i386/boot.txt linux-2.5.12.boot.proto/Documentation/i386/boot.txt --- linux-2.5.12.boot.build/Documentation/i386/boot.txt Sun Mar 10 20:05:16 2002 +++ linux-2.5.12.boot.proto/Documentation/i386/boot.txt Wed May 1 09:41:19 2002 @@ -4,6 +4,9 @@ H. Peter Anvin <hpa@zytor.com> Last update 2002-01-01 + Eric Biederman <ebiederm@xmission.com> + Last update 28 April 2002 + On the i386 platform, the Linux kernel uses a rather complicated boot convention. This has evolved partially due to historical aspects, as well as the desire in the early days to have the kernel itself be a @@ -35,6 +38,14 @@ initrd address available to the bootloader. +Protocol 2.04: (Kernel 2.5.x) + - Decompression in place (smaller load footpribnt) + The overhead is now 72KB below 1MB && 8 bytes above 1MB + - 32bit entry point support + - Exported the load time memory usage. + - zImage now has a larger memory footprint than bzImage. + should we just kill zImage? + **** MEMORY LAYOUT The traditional memory map for the kernel loader, used for Image or @@ -100,34 +111,42 @@ The header looks like: -Offset Proto Name Meaning +Offset Proto Name Meaning /Size -01F1/1 ALL setup_sects The size of the setup in sectors -01F2/2 ALL root_flags If set, the root is mounted readonly -01F4/2 ALL syssize DO NOT USE - for bootsect.S use only -01F6/2 ALL swap_dev DO NOT USE - obsolete -01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only -01FA/2 ALL vid_mode Video mode control -01FC/2 ALL root_dev Default root device number -01FE/2 ALL boot_flag 0xAA55 magic number -0200/2 2.00+ jump Jump instruction -0202/4 2.00+ header Magic signature "HdrS" -0206/2 2.00+ version Boot protocol version supported -0208/4 2.00+ realmode_swtch Boot loader hook (see below) -020C/2 2.00+ start_sys The load-low segment (0x1000) (obsolete) -020E/2 2.00+ kernel_version Pointer to kernel version string -0210/1 2.00+ type_of_loader Boot loader identifier -0211/1 2.00+ loadflags Boot protocol option flags -0212/2 2.00+ setup_move_size Move to high memory size (used with hooks) -0214/4 2.00+ code32_start Boot loader hook (see below) -0218/4 2.00+ ramdisk_image initrd load address (set by boot loader) -021C/4 2.00+ ramdisk_size initrd size (set by boot loader) -0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only -0224/2 2.01+ heap_end_ptr Free memory after setup end -0226/2 N/A pad1 Unused -0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line -022C/4 2.03+ initrd_addr_max Highest legal initrd address +01F1/1 ALL setup_sects The size of the setup in sectors +01F2/2 ALL root_flags If set, the root is mounted readonly +01F4/2 ALL syssize DO NOT USE - for bootsect.S use only +01F6/2 ALL swap_dev DO NOT USE - obsolete +01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only +01FA/2 ALL vid_mode Video mode control +01FC/2 ALL root_dev Default root device number +01FE/2 ALL boot_flag 0xAA55 magic number +0200/2 2.00+ jump Jump instruction +0202/4 2.00+ header_magic Magic signature "HdrS" +0206/2 2.00+ protocol_version Boot protocol version supported +0208/4 2.00+ realmode_swtch Boot loader hook (see below) +020C/2 2.00+ start_sys_seg Segment the zImage kernel was loaded at (0x1000) (obsolete) +020E/2 2.00+ kernel_version Pointer to kernel version string +0210/1 2.00+ type_of_loader Boot loader identifier +0211/1 2.00+ loadflags Boot protocol option flags +0212/2 2.00+ setup_move_size Move to high memory size (used with hooks) +0214/4 2.00+ code32_start Boot loader hook (see below) +0218/4 2.00+ initrd_start initrd load address (set by boot loader) +021C/4 2.00+ initrd_size initrd size (set by boot loader) +0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only +0224/2 2.01+ heap_end_ptr Free memory after setup end +0226/2 N/A pad1 Unused +0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line +022C/4 2.03+ ramdisk_max Highest legal initrd address +0230/2 2.04+ entry32_off offset of 32bit entry point +0230/2 2.04+ internal_cmdline_off offset of compiled in command line +0234/4 2.04+ real_base Default load address of real mode code +0238/4 2.04+ real_memsz Memory used @ real_base +023C/4 2.04+ real_filesz Amount of data loaded @ real_base +0240/4 2.04+ kern_base Kernel decompressor load address +0244/4 2.04+ kern_memsz Memory used @ kern_base +0248/4 2.04+ kern_filesz Amount of data loaeded @ kern_base For backwards compatibility, if the setup_sects field contains 0, the real value is 4. @@ -180,8 +199,14 @@ loadflags, heap_end_ptr: If the protocol version is 2.01 or higher, enter the offset limit of the setup heap into heap_end_ptr and set the - 0x80 bit (CAN_USE_HEAP) of loadflags. heap_end_ptr appears to - be relative to the start of setup (offset 0x0200). + 0x80 bit (CAN_USE_HEAP) of loadflags. heap_end_ptr is + relative to the start of setup (offset 0x0200). + + If the protocol version is 2.04 or higher set the 0x40 bit + (STAY_PUT). This explictly tells the real mode code that you + don't expect it to relocate itself to 0x90000. No earlier + protocols versions look at this bit so it is safe to set it + unconditionally. setup_move_size: When using protocol 2.00 or 2.01, if the real mode @@ -190,17 +215,20 @@ additional data (such as the kernel command line) moved in addition to the real-mode kernel itself. - ramdisk_image, ramdisk_size: + initrd_start, initrd_size: If your boot loader has loaded an initial ramdisk (initrd), - set ramdisk_image to the 32-bit pointer to the ramdisk data - and the ramdisk_size to the size of the ramdisk data. + set initrd_start to the 32-bit pointer to the ramdisk data + and the initrd_size to the size of the ramdisk data. The initrd should typically be located as high in memory as possible, as it may otherwise get overwritten by the early kernel initialization sequence. However, it must never be - located above the address specified in the initrd_addr_max + located above the address specified in the ramdisk_max field. The initrd should be at least 4K page aligned. + With boot protocol 2.04 and above the initrd can be loaded + as low as kern_base + kern_memsz. + cmd_line_ptr: If the protocol version is 2.02 or higher, this is a 32-bit pointer to the kernel command line. The kernel command line @@ -248,6 +276,11 @@ covered by setup_move_size, so you may need to adjust this field. +If the protocol version is 2.04 or higher a compiled in command line +may be present. If this is the case the passed command line is +appended onto the tail of the compiled command line. Assuming +there is room. + **** SAMPLE BOOT CONFIGURATION @@ -269,8 +302,8 @@ if ( protocol >= 0x0200 ) { type_of_loader = <type code>; if ( loading_initrd ) { - ramdisk_image = <initrd_address>; - ramdisk_size = <initrd_size>; + initrd_start = <initrd_address>; + initrd_size = <initrd_size>; } if ( protocol >= 0x0201 ) { heap_end_ptr = 0x9000 - 0x200; @@ -436,3 +469,176 @@ After completing your hook, you should jump to the address that was in this field before your boot loader overwrote it. + + +**** THE COMPRESSED KERNEL HEADER + +As of boot protocol version 2.04 a header has been added to the +compressed data, to reduce information loss. Most bootloaders +should never need to look at these fields. + +Offset Proto Name Meaning +/Size + +0000/4 2.04+ jump Jump Instruction +0004/4 2.04+ input_addr Load address of compressed data +0008/4 2.04+ input_len Length of compressed data +000C/4 2.04+ output_overhang Extra bytes needed for inplace decompression +0010/4 2.04+ kernel_base Kernel load address +0014/4 2.04+ kernel_filesz Memory usage @ kernel_base +0018/4 2.04+ kernel_memsz Data size @ kernel_base +001C/4 2.04+ unzip_filesz Decompressor code/data size +0020/4 2.04+ unzip_memsz Decompressor code memory usage + +**** DETAILED DESCRIPTION OF FIELDS + + entry32_off: + The unsigned offset of the 32bit entry point from the real + mode kernel. For boot protocols 2.03 or earlier, this field is + not present, and there is no 32bit entry point. + + The 32bit entry point is a mechanism for entering the kernel + without doing 16bit PC BIOS calls. Very useful for systems + with alternative firmware implementations. + + A bootloader using the 32bit entry point should verify that + there are real_memsz bytes available at real_base (real_base + remains relocatable in bzImages). And that there kern_memsz + bytes available at kern_base. For zImages you should also + verify that there are kernel_memsz bytes available at + kernel_base. + + Verifing there is enough memory for the kernel to load is + necessary for using the 32bit entry point, and suggested for + the 16bit entry point. In the case of the 32bit entry point + the kernel has no ability to talk to whatever weird firmware you + have until it is fully loaded. + + The 32bit entry point makes the following assumptions. You + are calling it protected mode. Paging is disabled. All + segment registers are loaded with a 32bit segment with a base + of 0, and a limit of 0xFFFFFFFF (limitless). Either %esp == 0 + and you are using the default real_base or %esp points to a + stack large enough to hold at least 12 new bytes of data. + + + internal_cmdline_off: + The offset of the null terminated compiled in command line + from the real mode kernel. For boot protocols 2.03 or + earlier this field is not present, and there is no built in + command line. The memory from internal_cmdline_off to + real_filesz is reserved for the compiled in command_line. An + external utility may modify this command line. + + To change the maximum size of the compiled in command line several + variables need to be modified. real_filesz to indicate the + new maximum size. setup_sects to indicate if the number of + sectors needed for the realmode kernel changes. + + A heap is maintained between real_filesz and real_memsz/heap_end_ptr. + Increasing the size of the heap is not a problem, decreasing + it is. So when changing the real_filesz, real_memsz and + heap_end_ptr should also be changed. + + input_addr/input_len: + The kernel is loaded into memory in compressed form. + input_addr is the location where the compressed data is + loaded, and input_len is the count of how many bytes of + compressed data there are. + + These two variables allow an external program to inspect a + bzImage and find the compressed data. This is mostly of use + to build.c as it computes output_overhang but other programs + may find it useful as well. + + output_overhang: + Most decompression algorithms may transformed into near + in-place algorithms by simply overlapping the compressed data + and the decompressed data buffers. For a particular + decompression algorithm then the question becomes how much + overlap is safe. More practically how much must the + compressed data stick out from the end of the decompressed + data buffer for this technique to work. + + output_overhang is that amount the compressed data buffer + must extend beyond the decompressed data buffer for + decompression in place to work for the linux kernel. + + build.c is responsible for computing this number. For + gzip typically this number is 8 (file length and checksum). + But in pathological cases it may be worse. + + real_base, real_memsz, real_filesz, + kern_base, kern_memsz, kern_filesz, + kernel_base, kernel_memsz, kernel_filesz, + unzip_memsz, unzip_filesz, + + Up to this point building a zImage or a bzImage has been a + very lossy process. The introduction of these variables + attempts to rectify that situation. They document exactly + which pieces of memory, the kernel uses during the boot + process, and they indicate exactly how large the various data + segments of the kernel are. It is now possible to create a + lossless transformation to and from a static ELF executable. + + Program segments are described with 3 variables. The base + address where the segment is loaded in memory. The file size + which records the amount of data in the input file that is + loaded into memory. The memory size which is greater than or + equal to the file size and records how much memory this + program segment consumes. + + base +-----------+ + | code/data | + filesz +-----------+ + | bss | + memsz +-----------+ + + The real program segment (real_base, real_filesz, real_memsz) + describes the memory usage of the real mode code from 4KB to + 640KB. The real code segment and the command line must be + located somewhere in this range. + + The compressed kernel segment (kern_base, kern_filesz, + kern_memsz) describes the memory usage of the compressed + kernel. For a zImage this is memory below 1MB for a bzImage + this is memory starting at 1MB. + + For bzImages it is sufficient to look at the real program + segment, and the compressed kernel segment to get the entire + boottime memory usage of the kernel. real_memsz is increased + to also document the decompressors real memory usage, and the + kern_memsz value is increased to document the decompressed + kernels memory usage. + + You can look at heap_end_ptr to get the actual memory + footprint of the real mode segment. Just the decompressors + memory footprint is kern_base + kernel_filesz + + output_overhang, if unzip_memsz bytes are available of real + memory, and kern_base + kernel_filesz + output_overhang + + unzip_memsz bytes otherwise. + + The decompressed kernel segment (kernel_base, kernel_filesz, + kernel_memsz) describes the memory usage of the decompresed + kernel (essentially vmlinux). + + The decompressor segment (load_address, unzip_filesz, unzip_memsz) + describes the memory usage of the kernel decompressor, + not counting the compressed data. + + The real program segment describes memory in the range + 4KB (0x1000) to 640KB (0xa0000) that the real mode kernel + uses. real_base may be moved lower or higher in memory if + there is a memory conflict with another address. When doing + so the following considerations should apply. + + For a zImage the range [real_base, real_base + + real_memsz) should not overlap the range [ kern_base, + kern_base + kern_memsz]. + + Ensure that the range [real_base, real_base + + real_memsz) is within the range [ 0x1000, 0xa0000). + + With this information it becomes safe to statically relocate + the real mode kernel as well as to dynamically relocate the + real_mode kernel. diff -uNr linux-2.5.12.boot.build/arch/i386/Config.help linux-2.5.12.boot.proto/arch/i386/Config.help --- linux-2.5.12.boot.build/arch/i386/Config.help Mon Apr 29 00:17:11 2002 +++ linux-2.5.12.boot.proto/arch/i386/Config.help Wed May 1 09:41:19 2002 @@ -803,6 +803,12 @@ a work-around for a number of buggy BIOSes. Switch this option on if your computer crashes instead of powering off properly. +CONFIG_CMDLINE + Generally it is best to pass command line parameters via the + bootloader but there are times it is convinient not to do this. + This allows you to hard code a default kernel command line, whatever + the bootloader passes will be appended to it. + CONFIG_X86_MCE Machine Check Exception support allows the processor to notify the kernel if it detects a problem (e.g. overheating, component failure). diff -uNr linux-2.5.12.boot.build/arch/i386/boot/realmode.lds linux-2.5.12.boot.proto/arch/i386/boot/realmode.lds --- linux-2.5.12.boot.build/arch/i386/boot/realmode.lds Wed May 1 09:40:42 2002 +++ linux-2.5.12.boot.proto/arch/i386/boot/realmode.lds Wed May 1 09:41:19 2002 @@ -1,5 +1,5 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -ENTRY(_start) +ENTRY(entry32) OUTPUT_ARCH(i386) SECTIONS { diff -uNr linux-2.5.12.boot.build/arch/i386/boot/setup.S linux-2.5.12.boot.proto/arch/i386/boot/setup.S --- linux-2.5.12.boot.build/arch/i386/boot/setup.S Wed May 1 09:40:42 2002 +++ linux-2.5.12.boot.proto/arch/i386/boot/setup.S Wed May 1 09:41:19 2002 @@ -45,6 +45,12 @@ * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes * by Robert Schwebel, December 2001 <robert@schwebel.de> * + * Update boot protocol to version 2.04 + * - Add support for a compiled in command line. + * - Add support for a 32bit kernel entry point + * - Stop information loss when bzImage is created + * Eric Biederman 29 March 2002 <ebiederm@xmission.com> + * */ #include <linux/config.h> @@ -91,12 +97,12 @@ # This is the setup header, and it must start at %cs:2 (old 0x9020:2) - .ascii "HdrS" # header signature - .word 0x0203 # header version number (>= 0x0105) +header_magic: .ascii "HdrS" # header signature +version: .word 0x0204 # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) realmode_swtch: .word 0, 0 # default_switch, SETUPSEG start_sys_seg: .word SYSSEG - .word kernel_version # pointing to kernel version string +kernel_version: .word kversion_str # pointing to kernel version string # above section of header is compatible # with loadlin-1.5 (header v1.5). Don't # change it. @@ -132,15 +138,15 @@ code32_start: .long KERNEL_START # here loaders can put a different # start address for 32-bit code. -ramdisk_image: .long 0 # address of loaded ramdisk image +initrd_start: .long 0 # address of loaded ramdisk image # Here the loader puts the 32-bit # address where it loaded the image. # This only will be read by the kernel. -ramdisk_size: .long 0 # its size in bytes +initrd_size: .long 0 # its size in bytes bootsect_kludge: - .word bootsect_helper, SETUPSEG + .word bootsect_helper, SETUPSEG heap_end_ptr: .word _esetup_heap # (Header version 0x0201 or later) # space from here (exclusive) down to @@ -148,7 +154,7 @@ # for local heap purposes. pad1: .word 0 -cmd_line_ptr: .long 0 # (Header version 0x0202 or later) +cmd_line_ptr: .long 0 # (Header version 0x0202 or later) # If nonzero, a 32-bit pointer # to the kernel command line. # The command line should be @@ -163,12 +169,17 @@ # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) +ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd -# variables private to the kernel (not for bootloaders) -pad2: .long 0 +entry32_off: .word entry32 - _setup + DELTA_BOOTSECT + # offset of the 32bit entry point + # relative to the start of + # the real mode kernel + +internal_cmdline_off: # offset of compiled in command line + .word internal_command_line - _setup + DELTA_BOOTSECT real_base: .long REAL_BASE # Location of real mode kernel real_memsz: # Memory usage of real mode kernel .long (_esetup_heap - _setup) + DELTA_BOOTSECT @@ -177,6 +188,17 @@ kern_base: .long KERNEL_START # Kernel load address kern_memsz: .long 0x00000000 # Kernel memory usage kern_filesz: .long 0x00000000 # Kernel datasize +# variables private to the kernel (not for bootloaders) +entry32_used: .long 0x00000000 +entry32_16_off: .long protected_to_real - _setup + DELTA_BOOTSECT +eax: .long 0x00000000 +ebx: .long 0x00000000 +ecx: .long 0x00000000 +edx: .long 0x00000000 +esi: .long 0x00000000 +edi: .long 0x00000000 +esp: .long 0x00000000 +ebp: .long 0x00000000 trampoline: call start_of_setup # Don't let the E820 map overlap code . = (E820MAP - DELTA_BOOTSECT) + (E820MAX * E820ENTRY_SIZE) @@ -852,7 +874,7 @@ .word __SETUP_CS # Here's a bunch of information about your current kernel.. -kernel_version: .ascii UTS_RELEASE +kversion_str: .ascii UTS_RELEASE .ascii " (" .ascii LINUX_COMPILE_BY .ascii "@" @@ -1042,29 +1064,175 @@ outb %al,$0x80 ret + .code32 + .globl entry32 +entry32: + testl %esp, %esp + jnz 1f + /* If there isn't a valid stack pointer assume + * we are loaded at our default address and put + * a temporary stack a _esetup_heap. + */ + movl %esp, (REAL_BASE + _esetup_heap - _setup - 4) + movl $(REAL_BASE + _esetup_heap - _setup - 4), %esp + jmp 2f +1: pushl %esp +2: pushl %esi + call 3f +3: popl %esi + subl $(3b - _setup), %esi + movl %eax, eax - _setup(%esi) + movl %ebx, ebx - _setup(%esi) + movl %ebx, ebx - _setup(%esi) + movl %ecx, ecx - _setup(%esi) + movl %edx, edx - _setup(%esi) + popl %eax + movl %eax, esi - _setup(%esi) + movl %edi, edi - _setup(%esi) + movl %ebp, ebp - _setup(%esi) + popl %esp + movl %esp, esp - _setup(%esi) + + /* Magic to indicate 32bit entry */ + movl $ENTRY32, %ebp + movl %ebp, entry32_used - _setup(%esi) + + /* Pointer to real mode code */ + subl $(DELTA_INITSEG << 4), %esi + + /* Start address for 32-bit code */ + movl $KERNEL_START, %ebx + jmpl *%ebx + +protected_to_real: + cli + /* Get pointer to start */ + call 1f +1: popl %esi + subl $(1b - _setup), %esi + + /* Fixup my real mode segment */ + movl %esi, %eax + shrl $4, %eax + movw %ax, 2 + realptr - _setup(%esi) + + /* Compute the gdt fixup */ + movl %esi, %eax + shll $16, %eax # Base low + + movl %esi, %ebx + shrl $16, %ebx + andl $0xff, %ebx + + movl %esi, %edx + andl $0xff000000, %edx + orl %edx, %ebx # Base high + + /* Fixup the gdt */ + andl $0x0000ffff, (gdt - _setup + __SETUP_REAL_CS)(%esi) + orl %eax, (gdt - _setup + __SETUP_REAL_CS)(%esi) + andl $0x00ffff00, (gdt - _setup + __SETUP_REAL_CS + 4)(%esi) + orl %ebx, (gdt - _setup + __SETUP_REAL_CS + 4)(%esi) + andl $0x0000ffff, (gdt - _setup + __SETUP_REAL_DS)(%esi) + orl %eax, (gdt - _setup + __SETUP_REAL_DS)(%esi) + andl $0x00ffff00, (gdt - _setup + __SETUP_REAL_DS + 4)(%esi) + orl %ebx, (gdt - _setup + __SETUP_REAL_DS + 4)(%esi) + + /* Fixup gdt_48 */ + leal gdt - _setup(%esi), %eax # Compute gdt_base + movl %eax, gdt_48 +2 - _setup(%esi) # Store gdt_base + + /* Setup the classic BIOS interrupt table at 0x0 */ + lidt idt_real - _setup(%esi) + + /* Load 16bit segments we can use */ + lgdt gdt_48 - _setup(%esi) + + /* Don't disable the a20 line, (this shouldn't be required) */ + + /* Load 16bit data segments, to ensure the segment limits are set */ + movl $__SETUP_REAL_DS, %ebx + movl %ebx, %ds + movl %ebx, %es + movl %ebx, %ss + movl %ebx, %fs + movl %ebx, %gs + + /* switch to 16bit mode */ + ljmp $__SETUP_REAL_CS, $1f - _setup +1: + .code16 + /* Disable Paging and protected mode */ + /* clear the PG & PE bits of CR0 */ + movl %cr0,%eax + andl $~((1 << 31)|(1<<0)),%eax + movl %eax,%cr0 + + /* make intersegment jmp to flush the processor pipeline + * and reload %cs:%eip (to clear upper 16 bits of %eip). + */ + ljmp *(realptr - _setup) +2: + /* we are in real mode now + * set up the real mode segment registers : %ds, %ss, %es, %gs, %fs + */ + movw %cs, %ax + /* Put the data segments in INITSEG */ + subw $DELTA_INITSEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + /* Put the stack ss:sp at the end of the heap */ + movw %cs, %ax + movw %cs:heap_end_ptr, %bx + movw %ax, %ss + movw %bx, %sp + jmp start + +realptr: + .word 2b - _setup + .word 0x0000 + # Descriptor tables gdt: .word 0, 0, 0, 0 # dummy .word 0, 0, 0, 0 # unused - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0xFFFF # 32bit 4GB - (0x100000*0x1000 = 4GB) .word 0 # base address = 0 - .word 0x9A00 # code read/exec - .word 0x00CF # granularity = 4096, 386 + .byte 0x00, 0x9B # code read/exec/accessed + .byte 0xCF, 0x00 # granularity = 4096, 386 # (+5th nibble of limit) - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0xFFFF # 32bit 4GB - (0x100000*0x1000 = 4GB) .word 0 # base address = 0 - .word 0x9200 # data read/write - .word 0x00CF # granularity = 4096, 386 + .byte 0x00, 0x93 # data read/write/accessed + .byte 0xCF, 0x00 # granularity = 4096, 386 # (+5th nibble of limit) + + .word 0xFFFF # 16bit 64KB - (0x10000*1 = 64KB) + .word 0 # base address = SETUPSEG + .byte 0x00, 0x9b # code read/exec/accessed + .byte 0x00, 0x00 # granularity = bytes + + + .word 0xFFFF # 16bit 64KB - (0x10000*1 = 64KB) + .word 0 # base address = SETUPSEG + .byte 0x00, 0x93 # data read/write/accessed + .byte 0x00, 0x00 # granularity = bytes +gdt_end: + idt_48: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L -gdt_48: - .word 0x8000 # gdt limit=2048, - # 256 GDT entries +idt_real: + .word 0x400 - 1 # idt limit ( 256 entries) + .word 0, 0 # idt base = 0L + +gdt_48: + .word gdt_end - gdt - 1 # gdt limit .word 0, 0 # gdt base (filled in later) # Include video setup & detection code @@ -1077,7 +1245,8 @@ # After this point, there is some free space which is used by the video mode # handling code to store the temporary mode table (not used by the kernel). - +internal_command_line: + .asciz CONFIG_CMDLINE _esetup: .section ".setup.heap", "a", @nobits _setup_heap: diff -uNr linux-2.5.12.boot.build/arch/i386/config.in linux-2.5.12.boot.proto/arch/i386/config.in --- linux-2.5.12.boot.build/arch/i386/config.in Mon Apr 29 00:17:11 2002 +++ linux-2.5.12.boot.proto/arch/i386/config.in Wed May 1 09:41:19 2002 @@ -282,6 +282,7 @@ bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi +string 'Initial kernel command line' CONFIG_CMDLINE "" endmenu source drivers/mtd/Config.in diff -uNr linux-2.5.12.boot.build/arch/i386/kernel/setup.c linux-2.5.12.boot.proto/arch/i386/kernel/setup.c --- linux-2.5.12.boot.build/arch/i386/kernel/setup.c Wed May 1 09:39:48 2002 +++ linux-2.5.12.boot.proto/arch/i386/kernel/setup.c Wed May 1 09:41:19 2002 @@ -103,6 +103,7 @@ #include <linux/pci_ids.h> #include <linux/seq_file.h> #include <linux/console.h> +#include <linux/smp_lock.h> #include <asm/processor.h> #include <asm/mtrr.h> #include <asm/uaccess.h> @@ -668,34 +669,38 @@ screen_info.orig_video_points = 16; } -static void read_entry16_params(struct boot_params *params) +static void read_entry32_params(struct boot_params *params) { char *cmdline; + int cmdline_off; /* - * These values are set up by the setup-routine at boot-time + * These values are set a compile time or set by the bootloader */ ROOT_DEV = to_kdev_t(params->root_dev); - drive_info = params->drive_info; - screen_info = params->screen.info; - apm_info.bios = params->apm_bios_info; - if( params->sys_desc_table.length != 0 ) { - MCA_bus = params->sys_desc_table.table[3] &0x2; - machine_id = params->sys_desc_table.table[0]; - machine_submodel_id = params->sys_desc_table.table[1]; - BIOS_revision = params->sys_desc_table.table[2]; - } - aux_device_present = params->aux_device_info; + + if (!params->mount_root_rdonly) + root_mountflags &= ~MS_RDONLY; #ifdef CONFIG_BLK_DEV_RAM rd_image_start = params->ramdisk_flags & RAMDISK_IMAGE_START_MASK; rd_prompt = ((params->ramdisk_flags & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((params->ramdisk_flags & RAMDISK_LOAD_FLAG) != 0); #endif - setup_memory_region(params); - if (!params->mount_root_rdonly) - root_mountflags &= ~MS_RDONLY; + /* The compiled in command line */ + cmdline = (char *)params; + cmdline += params->internal_cmdline_off; + strncpy(command_line, cmdline, COMMAND_LINE_SIZE); + command_line[COMMAND_LINE_SIZE -1] = '\0'; + cmdline_off = strlen(command_line); + + /* Add a spece between command lines */ + if (cmdline_off && (cmdline_off < COMMAND_LINE_SIZE) && + (command_line[cmdline_off -1] != ' ')) { + command_line[cmdline_off++] = ' '; + } + /* The bootloader passed command line */ cmdline = ""; if (params->cmd_line_ptr) { /* New command line protocol */ @@ -704,7 +709,7 @@ else if (params->screen.overlap.cl_magic == CL_MAGIC_VALUE) { cmdline = (char *)params + params->screen.overlap.cl_offset; } - memcpy(command_line, cmdline, COMMAND_LINE_SIZE); + memcpy(command_line + cmdline_off, cmdline, COMMAND_LINE_SIZE - cmdline_off); command_line[COMMAND_LINE_SIZE -1] = '\0'; #ifdef CONFIG_BLK_DEV_INITRD @@ -715,22 +720,74 @@ } #endif } + +static void read_entry16_params(struct boot_params *params) +{ + /* + * These values are set up by the setup-routine at boot-time + */ + drive_info = params->drive_info; + screen_info = params->screen.info; + apm_info.bios = params->apm_bios_info; + if( params->sys_desc_table.length != 0 ) { + MCA_bus = params->sys_desc_table.table[3] &0x2; + machine_id = params->sys_desc_table.table[0]; + machine_submodel_id = params->sys_desc_table.table[1]; + BIOS_revision = params->sys_desc_table.table[2]; + } + aux_device_present = params->aux_device_info; + + setup_memory_region(params); +} + +static void call_entry16(struct boot_params *params) +{ + extern void (startup_32)(void); + void (*entry32_16)(void); + entry32_16 = (void (*)(void))(initial_regs.esi + params->entry32_16_off); + /* Disable advanced boot time hooks */ + params->code32_start = __pa(&startup_32); + params->realmode_swtch[0] = 0; + params->realmode_swtch[1] = 0; + /* Don't have the realmode code self relocate */ + params->loadflags |= LOADFLAG_STAY_PUT; + unlock_kernel(); + entry32_16(); + +} static void parse_params(char **cmdline_p) { struct boot_params *params; - int entry16; + int entry16, entry32; params = (struct boot_params *)initial_regs.esi; entry16 = initial_regs.ebp == ENTRY16; + entry32 = (initial_regs.ebp == ENTRY32) && (params->entry32_used); init_settings(); + /* Get compiled in and bootloader parameters */ + if (entry16 || entry32) { + read_entry32_params(params); + } + + /* Get parameters from the 16bit BIOS */ if (entry16) { read_entry16_params(params); } /* Read user specified params */ parse_mem_cmdline(cmdline_p); + + if ((e820.nr_map == 0) && entry32) { + /* If we came in via the 32bit entry point and don't + * have a memory size we need help. + * So go out and come back in the 16bit entry point. + */ + printk(KERN_INFO + "No memory size information so reentering 16bit mode\n"); + call_entry16(params); + } if (e820.nr_map == 0) { panic("Unknown memory size\n"); diff -uNr linux-2.5.12.boot.build/include/asm-i386/boot_param.h linux-2.5.12.boot.proto/include/asm-i386/boot_param.h --- linux-2.5.12.boot.build/include/asm-i386/boot_param.h Wed May 1 09:40:42 2002 +++ linux-2.5.12.boot.proto/include/asm-i386/boot_param.h Wed May 1 09:41:19 2002 @@ -83,15 +83,20 @@ __u32 cmd_line_ptr; /* 0x228 */ /* 2.03+ */ __u32 ramdisk_max; /* 0x22c */ - /* Below this point for internal kernel use only */ - __u32 pad2; /* 0x230 */ + /* 2.04+ */ + __u16 entry32_off; /* 0x230 */ + __u16 internal_cmdline_off; /* 0x232 */ __u32 real_base; /* 0x234 */ __u32 real_memsz; /* 0x238 */ __u32 real_filesz; /* 0x23c */ __u32 kern_base; /* 0x240 */ __u32 kern_memsz; /* 0x244 */ __u32 kern_filesz; /* 0x248 */ - __u8 reserved15[0x2d0 - 0x24c]; /* 0x24c */ + /* Below this point for internal kernel use only */ + __u32 entry32_used; /* 0x24c */ + __u32 entry32_16_off; /* 0x250 */ + struct initial_regs32 regs; /* 0x254 */ + __u8 reserved15[0x2d0 - 0x274]; /* 0x274 */ struct e820entry e820_map[E820MAX]; /* 0x2d0 */ /* 0x550 */ } __attribute__((packed)); ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, LinuxBIOS support 10/11 2002-05-02 15:11 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 Eric W. Biederman @ 2002-05-02 15:13 ` Eric W. Biederman 2002-05-02 15:15 ` [PATCH 2.5.12] x86 Boot enhancements, bzElf support 11/11 Eric W. Biederman 2002-05-02 20:39 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 H. Peter Anvin 2002-05-02 20:45 ` H. Peter Anvin 2 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 15:13 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This patch adds support for LinuxBIOS. Eric diff -uNr linux-2.5.12.boot.proto/arch/i386/Config.help linux-2.5.12.boot.linuxbios/arch/i386/Config.help --- linux-2.5.12.boot.proto/arch/i386/Config.help Wed May 1 09:41:19 2002 +++ linux-2.5.12.boot.linuxbios/arch/i386/Config.help Wed May 1 09:41:27 2002 @@ -803,6 +803,22 @@ a work-around for a number of buggy BIOSes. Switch this option on if your computer crashes instead of powering off properly. +LinuxBIOS support +CONFIG_LINUXBIOS + LinuxBIOS is an alternative GPL'd firmware initially for x86 + compatible machines. LinuxBIOS attempts to be a simple and as fast + as possible, and is initially optimized for linux. The interface to + the OS is a table at the beginning of memory. Which should make the + inevitable firmware bugs easier to work around, as should the source + code :) A goal of this table is to provide enough information so + that any OS but especially linux does not need to have motherboard + specific knowledge. + + This first release only provides LinuxBIOS detection (by detecting + it's table) and memory size detection. + + For more information on LinuxBIOS see http://www.linuxbios.org + CONFIG_CMDLINE Generally it is best to pass command line parameters via the bootloader but there are times it is convinient not to do this. diff -uNr linux-2.5.12.boot.proto/arch/i386/config.in linux-2.5.12.boot.linuxbios/arch/i386/config.in --- linux-2.5.12.boot.proto/arch/i386/config.in Wed May 1 09:41:19 2002 +++ linux-2.5.12.boot.linuxbios/arch/i386/config.in Wed May 1 09:41:27 2002 @@ -206,6 +206,7 @@ fi fi +bool 'LinuxBIOS support' CONFIG_LINUXBIOS endmenu mainmenu_option next_comment diff -uNr linux-2.5.12.boot.proto/arch/i386/defconfig linux-2.5.12.boot.linuxbios/arch/i386/defconfig --- linux-2.5.12.boot.proto/arch/i386/defconfig Tue Apr 30 22:55:21 2002 +++ linux-2.5.12.boot.linuxbios/arch/i386/defconfig Wed May 1 09:41:27 2002 @@ -119,6 +119,7 @@ CONFIG_BINFMT_MISC=y CONFIG_PM=y # CONFIG_APM is not set +# CONFIG_LINUXBIOS is not set # # Memory Technology Devices (MTD) diff -uNr linux-2.5.12.boot.proto/arch/i386/kernel/Makefile linux-2.5.12.boot.linuxbios/arch/i386/kernel/Makefile --- linux-2.5.12.boot.proto/arch/i386/kernel/Makefile Tue Apr 16 11:10:43 2002 +++ linux-2.5.12.boot.linuxbios/arch/i386/kernel/Makefile Wed May 1 09:41:27 2002 @@ -42,6 +42,7 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o +obj-$(CONFIG_LINUXBIOS) += linuxbios.o ifdef CONFIG_VISWS obj-y += setup-visws.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o diff -uNr linux-2.5.12.boot.proto/arch/i386/kernel/linuxbios.c linux-2.5.12.boot.linuxbios/arch/i386/kernel/linuxbios.c --- linux-2.5.12.boot.proto/arch/i386/kernel/linuxbios.c Wed Dec 31 17:00:00 1969 +++ linux-2.5.12.boot.linuxbios/arch/i386/kernel/linuxbios.c Wed May 1 09:41:27 2002 @@ -0,0 +1,103 @@ +#include <linux/kernel.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <net/checksum.h> +#include <asm/linuxbios.h> +#include <asm/e820.h> +#include "linuxbios_tables.h" + +#define for_each_lbrec(head, rec) \ + for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \ + (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \ + (rec->size >= 1) && \ + ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \ + rec = (struct lb_record *)(((char *)rec) + rec->size)) + + +static int __init count_lb_records(struct lb_header *head) +{ + struct lb_record *rec; + int count; + count = 0; + for_each_lbrec(head, rec) { + count++; + } + return count; +} + +static struct lb_header * __init __find_lb_table(unsigned long start, unsigned long end) +{ + unsigned long addr; + /* For now be stupid.... */ + for(addr = start; addr < end; addr += 16) { + struct lb_header *head = phys_to_virt(addr); + struct lb_record *recs = phys_to_virt(addr + sizeof(*head)); + if (memcmp(head->signature, "LBIO", 4) != 0) + continue; + if (head->header_bytes != sizeof(*head)) + continue; + if (ip_compute_csum((unsigned char *)head, sizeof(*head)) != 0) + continue; + if (ip_compute_csum((unsigned char *)recs, head->table_bytes) + != head->table_checksum) + continue; + if (count_lb_records(head) != head->table_entries) + continue; + printk(KERN_DEBUG "Found LinuxBIOS table at: %p\n", head); + return head; + }; + return 0; +} + +static struct lb_header * __init find_lb_table(void) +{ + struct lb_header *head; + head = 0; + if (!head) { + /* First try at address 0 */ + head = __find_lb_table(0x00000, 0x1000); + } + if (!head) { + /* Then try at address 0xf0000 */ + head = __find_lb_table(0xf0000, 0x100000); + } + return head; +} + +void __init read_linuxbios_params(void) +{ + struct lb_header *head; + struct lb_record *rec; + struct lb_memory *mem; + int i, entries; + head = find_lb_table(); + if (!head) { + return; + } + mem = 0; + for_each_lbrec(head, rec) { + if (rec->tag == LB_TAG_MEMORY) { + mem = (struct lb_memory *)rec; + break; + } + } + if (!mem) { + return; + } + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + if (entries == 0) + return; + e820.nr_map = 0; + for(i = 0; i < entries; i++) { + unsigned long long start; + unsigned long long size; + unsigned long type; + start = mem->map[i].start; + size = mem->map[i].size; + type = (mem->map[i].type == LB_MEM_RAM)?E820_RAM: E820_RESERVED; + add_memory_region(start, size, type); + } + print_memory_map("LinuxBIOS"); + return; +} + diff -uNr linux-2.5.12.boot.proto/arch/i386/kernel/linuxbios_tables.h linux-2.5.12.boot.linuxbios/arch/i386/kernel/linuxbios_tables.h --- linux-2.5.12.boot.proto/arch/i386/kernel/linuxbios_tables.h Wed Dec 31 17:00:00 1969 +++ linux-2.5.12.boot.linuxbios/arch/i386/kernel/linuxbios_tables.h Wed May 1 09:41:27 2002 @@ -0,0 +1,82 @@ +#ifndef LINUXBIOS_TABLES_H +#define LINUXBIOS_TABLES_H + +#include <linux/types.h> + +/* The linuxbios table information is for conveying information + * from the firmware to the loaded OS image. Primarily this + * is expected to be information that cannot be discovered by + * other means, such as quering the hardware directly. + * + * All of the information should be Position Independent Data. + * That is it should be safe to relocated any of the information + * without it's meaning/correctnes changing. For table that + * can reasonably be used on multiple architectures the data + * size should be fixed. This should ease the transition between + * 32 bit and 64 bit architectures etc. + * + * The completeness test for the information in this table is: + * - Can all of the hardware be detected? + * - Are the per motherboard constants available? + * - Is there enough to allow a kernel to run that was written before + * a particular motherboard is constructed? (Assuming the kernel + * has drivers for all of the hardware but it does not have + * assumptions on how the hardware is connected together). + * + * With this test it should be straight forward to determine if a + * table entry is required or not. This should remove much of the + * long term compatibility burden as table entries which are + * irrelevant or have been replaced by better alternatives may be + * dropped. Of course it is polite and expidite to include extra + * table entries and be backwards compatible, but it is not required. + */ + + +struct lb_header +{ + uint8_t signature[4]; /* LBIO */ + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +}; + +/* Every entry in the boot enviroment list will correspond to a boot + * info record. Encoding both type and size. The type is obviously + * so you can tell what it is. The size allows you to skip that + * boot enviroment record if you don't know what it easy. This allows + * forward compatibility with records not yet defined. + */ +struct lb_record { + uint32_t tag; /* tag ID */ + uint32_t size; /* size of record (in bytes) */ +}; + +#define LB_TAG_UNUSED 0x0000 + +#define LB_TAG_MEMORY 0x0001 + +struct lb_memory_range { + uint64_t start; + uint64_t size; + uint32_t type; +#define LB_MEM_RAM 1 +#define LB_MEM_RESERVED 2 + +}; + +struct lb_memory { + uint32_t tag; + uint32_t size; + struct lb_memory_range map[0]; +}; + +#define LB_TAG_HWRPB 0x0002 +struct lb_hwrpb { + uint32_t tag; + uint32_t size; + uint64_t hwrpb; +}; + +#endif /* LINUXBIOS_TABLES_H */ diff -uNr linux-2.5.12.boot.proto/arch/i386/kernel/setup.c linux-2.5.12.boot.linuxbios/arch/i386/kernel/setup.c --- linux-2.5.12.boot.proto/arch/i386/kernel/setup.c Wed May 1 09:41:19 2002 +++ linux-2.5.12.boot.linuxbios/arch/i386/kernel/setup.c Wed May 1 09:41:27 2002 @@ -119,6 +119,7 @@ #include <asm/mmu_context.h> #include <asm/boot.h> #include <asm/boot_param.h> +#include <asm/linuxbios.h> /* * Machine setup.. @@ -265,7 +266,7 @@ } } -static void __init add_memory_region(unsigned long long start, +void __init add_memory_region(unsigned long long start, unsigned long long size, int type) { int x = e820.nr_map; @@ -283,7 +284,7 @@ #define E820_DEBUG 1 -static void __init print_memory_map(char *who) +void __init print_memory_map(char *who) { int i; @@ -775,6 +776,9 @@ if (entry16) { read_entry16_params(params); } + + /* Attempt to get the LinuxBIOS parameters */ + read_linuxbios_params(); /* Read user specified params */ parse_mem_cmdline(cmdline_p); diff -uNr linux-2.5.12.boot.proto/include/asm-i386/e820.h linux-2.5.12.boot.linuxbios/include/asm-i386/e820.h --- linux-2.5.12.boot.proto/include/asm-i386/e820.h Wed May 1 09:39:11 2002 +++ linux-2.5.12.boot.linuxbios/include/asm-i386/e820.h Wed May 1 09:41:27 2002 @@ -36,6 +36,9 @@ }; extern struct e820map e820; +extern void add_memory_region(unsigned long long start, + unsigned long long size, int type); +extern void print_memory_map(char *who); #endif/*!__ASSEMBLY__*/ #endif/*__E820_HEADER*/ diff -uNr linux-2.5.12.boot.proto/include/asm-i386/linuxbios.h linux-2.5.12.boot.linuxbios/include/asm-i386/linuxbios.h --- linux-2.5.12.boot.proto/include/asm-i386/linuxbios.h Wed Dec 31 17:00:00 1969 +++ linux-2.5.12.boot.linuxbios/include/asm-i386/linuxbios.h Wed May 1 09:41:27 2002 @@ -0,0 +1,10 @@ +#ifndef __ASMi386_LINUXBIOS_H +#define __ASMi386_LINUXBIOS_H + +#ifdef CONFIG_LINUXBIOS +void read_linuxbios_params(void); +#else +#define read_linuxbios_params() +#endif /* CONFIG_LINUXBIOS */ + +#endif ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2.5.12] x86 Boot enhancements, bzElf support 11/11 2002-05-02 15:13 ` [PATCH 2.5.12] x86 Boot enhancements, LinuxBIOS support 10/11 Eric W. Biederman @ 2002-05-02 15:15 ` Eric W. Biederman 2002-05-02 20:45 ` H. Peter Anvin 0 siblings, 1 reply; 20+ messages in thread From: Eric W. Biederman @ 2002-05-02 15:15 UTC (permalink / raw) To: Linus Torvalds, Dave Jones; +Cc: linux-kernel Please apply, This patch allows a bzELF image to be built instead of a bzImage. A bzELF is just a bzImage represented in the ELF file format. The transform from bzELF to bzImage is 1-1. Eric diff -uNr linux-2.5.12.boot.linuxbios/arch/i386/Makefile linux-2.5.12.boot.elf/arch/i386/Makefile --- linux-2.5.12.boot.linuxbios/arch/i386/Makefile Wed May 1 09:38:47 2002 +++ linux-2.5.12.boot.elf/arch/i386/Makefile Wed May 1 09:41:44 2002 @@ -119,6 +119,9 @@ bzImage: vmlinux @$(MAKEBOOT) bzImage +bzElf: vmlinux + @$(MAKEBOOT) bzElf + compressed: zImage zlilo: vmlinux diff -uNr linux-2.5.12.boot.linuxbios/arch/i386/boot/Makefile linux-2.5.12.boot.elf/arch/i386/boot/Makefile --- linux-2.5.12.boot.linuxbios/arch/i386/boot/Makefile Wed May 1 09:40:42 2002 +++ linux-2.5.12.boot.elf/arch/i386/boot/Makefile Wed May 1 09:41:44 2002 @@ -18,6 +18,9 @@ bzImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux tools/build -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzImage +bzElf: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux + tools/build -e -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzElf + compressed/vmlinux: $(TOPDIR)/vmlinux @$(MAKE) -C compressed vmlinux @@ -75,5 +78,5 @@ clean: rm -f tools/build rm -f realmode zImage - rm -f brealmode bzImage + rm -f brealmode bzImage bzElf @$(MAKE) -C compressed clean diff -uNr linux-2.5.12.boot.linuxbios/arch/i386/boot/tools/build.c linux-2.5.12.boot.elf/arch/i386/boot/tools/build.c --- linux-2.5.12.boot.linuxbios/arch/i386/boot/tools/build.c Wed May 1 09:40:42 2002 +++ linux-2.5.12.boot.elf/arch/i386/boot/tools/build.c Wed May 1 09:41:44 2002 @@ -80,11 +80,12 @@ #define ISEGS 3 /* Segments of the output file */ -#define OREAL 0 -#define OKERN 1 -#define OBSS1 2 -#define OBSS2 3 -#define OSEGS 4 +#define OEHDR 0 +#define OREAL 1 +#define OKERN 2 +#define OBSS1 3 +#define OBSS2 4 +#define OSEGS 5 struct file_seg { @@ -96,6 +97,37 @@ unsigned char *data; }; +/* Kernel version */ +#define LINUX_KERNEL_VERSION \ + UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") " UTS_VERSION + +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef uint64_t Elf_Xword; + +typedef struct +{ + Elf_Word n_namesz; /* Length of the note's name. */ + Elf_Word n_descsz; /* Length of the note's descriptor. */ + Elf_Word n_type; /* Type of the note. */ +} Elf_Nhdr; + +typedef struct +{ + Elf_Word n_paddr; + Elf_Word n_size; +} Elf_Pdesc; + +/* Elf image notes for booting... The name for all of these is ELFBoot */ + +#define EIN_NOTE_NAME "ELFBoot" +#define EIN_PROGRAM_NAME 0x00000001 +/* The program in this ELF file */ +#define EIN_PROGRAM_VERSION 0x00000002 +/* The version of the program in this ELF file */ +#define EIN_PROGRAM_CHECKSUM 0x00000003 +/* ip style checksum of the memory image. */ + struct boot_params { uint8_t reserved1[0x1f1]; /* 0x000 */ uint8_t setup_sects; /* 0x1f1 */ @@ -335,6 +367,76 @@ return result; } +static unsigned long compute_ip_checksum(void *addr, unsigned long length) +{ + uint16_t *ptr; + unsigned long sum; + unsigned long len; + unsigned long laddr; + /* compute an ip style checksum */ + laddr = (unsigned long )addr; + sum = 0; + if (laddr & 1) { + uint16_t buffer; + unsigned char *ptr; + /* copy the first byte into a 2 byte buffer. + * This way automatically handles the endian question + * of which byte (low or high) the last byte goes in. + */ + buffer = 0; + ptr = addr; + memcpy(&buffer, ptr, 1); + sum += buffer; + if (sum > 0xFFFF) + sum -= 0xFFFF; + length -= 1; + addr = ptr +1; + } + len = length >> 1; + ptr = addr; + while (len--) { + sum += *(ptr++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + addr = ptr; + if (length & 1) { + uint16_t buffer; + unsigned char *ptr; + /* copy the last byte into a 2 byte buffer. + * This way automatically handles the endian question + * of which byte (low or high) the last byte goes in. + */ + buffer = 0; + ptr = addr; + memcpy(&buffer, ptr, 1); + sum += buffer; + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return (~sum) & 0xFFFF; + +} + +static unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new) +{ + unsigned long checksum; + sum = ~sum & 0xFFFF; + new = ~new & 0xFFFF; + if (offset & 1) { + /* byte swap the sum if it came from an odd offset + * since the computation is endian independant this + * works. + */ + new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); + } + checksum = sum + new; + if (checksum > 0xFFFF) { + checksum -= 0xFFFF; + } + return (~checksum) & 0xFFFF; +} + static void check_ehdr(Elf32_Ehdr *ehdr, char *name) { /* Do some basic to ensure it is an ELF image */ @@ -489,6 +591,7 @@ struct image_info { int is_big_kernel; + int is_elf; size_t entry32; size_t setup_sectors; size_t sys_size; @@ -518,11 +621,114 @@ zhdr->output_overhang = cpu_to_le32(info->unzip_overhang); zhdr->kernel_memsz = cpu_to_le32(iseg[IKERN].mem_size); zhdr->kernel_filesz = cpu_to_le32(iseg[IKERN].data_size); + if (info->is_elf) { + /* For ELF images we don't expect the header to be relocated */ + param->loadflags |= cpu_to_le32(LOADFLAG_STAY_PUT); + param->type_of_loader = LOADER_UNKNOWN; + } +} + +struct elf_header { + Elf32_Ehdr ehdr; + Elf32_Phdr phdr[OSEGS - (OEHDR + 1)]; + Elf_Nhdr program_name_hdr; + uint8_t program_name_name[8]; + uint8_t program_name_desc[8]; + Elf_Nhdr program_version_hdr; + uint8_t program_version_name[8]; + uint8_t program_version_desc[(sizeof(LINUX_KERNEL_VERSION) + 3) & ~3]; + Elf_Nhdr program_checksum_hdr; + uint8_t program_checksum_name[8]; + uint16_t program_checksum; + uint16_t program_checksum_pad; +} __attribute__((packed)); + +static void build_elf_header(struct file_seg *seg, struct image_info *info) +{ + struct elf_header *hdr; + size_t checksum, bytes; + size_t offset, size; + int i; + hdr = checked_malloc(sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + memcpy(hdr->ehdr.e_ident, ELFMAG, 4); + hdr->ehdr.e_ident[EI_CLASS] = ELFCLASS32; + hdr->ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + hdr->ehdr.e_ident[EI_VERSION] = EV_CURRENT; + hdr->ehdr.e_type = cpu_to_le16(ET_EXEC); + hdr->ehdr.e_machine = cpu_to_le16(EM_386); + hdr->ehdr.e_version = cpu_to_le32(EV_CURRENT); + hdr->ehdr.e_entry = cpu_to_le32(info->entry32); + hdr->ehdr.e_phoff = cpu_to_le32(offsetof(struct elf_header, phdr)); + hdr->ehdr.e_shoff = cpu_to_le32(0); + hdr->ehdr.e_flags = cpu_to_le16(0); + hdr->ehdr.e_ehsize = cpu_to_le16(sizeof(hdr->ehdr)); + hdr->ehdr.e_phentsize = cpu_to_le16(sizeof(hdr->phdr[0])); + hdr->ehdr.e_phnum = cpu_to_le16(sizeof(hdr->phdr)/sizeof(hdr->phdr[0])); + hdr->ehdr.e_shentsize = cpu_to_le16(0); + hdr->ehdr.e_shnum = cpu_to_le16(0); + hdr->ehdr.e_shstrndx = cpu_to_le16(0); + + offset = offsetof(struct elf_header, program_name_hdr); + size = sizeof(*hdr) - offset; + hdr->phdr[0].p_type = cpu_to_le32(PT_NOTE); + hdr->phdr[0].p_offset = cpu_to_le32(offset); + hdr->phdr[0].p_vaddr = cpu_to_le32(0); + hdr->phdr[0].p_paddr = cpu_to_le32(0); + hdr->phdr[0].p_filesz = cpu_to_le32(size); + hdr->phdr[0].p_memsz = cpu_to_le32(size); + hdr->phdr[0].p_flags = cpu_to_le32(0); + hdr->phdr[0].p_align = cpu_to_le32(0); + + for(i = OEHDR +1; i < OSEGS; i++) { + hdr->phdr[i].p_type = cpu_to_le32(PT_NULL); + if (seg[i].mem_size == 0) + continue; + hdr->phdr[i].p_type = cpu_to_le32(PT_LOAD); + hdr->phdr[i].p_offset = cpu_to_le32(seg[i].file_offset); + hdr->phdr[i].p_vaddr = cpu_to_le32(seg[i].mem_addr); + hdr->phdr[i].p_paddr = cpu_to_le32(seg[i].mem_addr); + hdr->phdr[i].p_filesz = cpu_to_le32(seg[i].data_size); + hdr->phdr[i].p_memsz = cpu_to_le32(seg[i].mem_size); + hdr->phdr[i].p_flags = cpu_to_le32(0); + hdr->phdr[i].p_align = cpu_to_le32(0); + } + + hdr->program_name_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1); + hdr->program_name_hdr.n_descsz = cpu_to_le32(strlen("Linux") +1); + hdr->program_name_hdr.n_type = cpu_to_le32(EIN_PROGRAM_NAME); + strcpy(hdr->program_name_name, EIN_NOTE_NAME); + strcpy(hdr->program_name_desc, "Linux"); + + hdr->program_version_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1); + hdr->program_version_hdr.n_descsz = cpu_to_le32(strlen(LINUX_KERNEL_VERSION)+1); + hdr->program_version_hdr.n_type = cpu_to_le32(EIN_PROGRAM_VERSION); + strcpy(hdr->program_version_name, EIN_NOTE_NAME); + strcpy(hdr->program_version_desc, LINUX_KERNEL_VERSION); + + hdr->program_checksum_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1); + hdr->program_checksum_hdr.n_descsz = cpu_to_le32(2); + hdr->program_checksum_hdr.n_type = cpu_to_le32(EIN_PROGRAM_CHECKSUM); + strcpy(hdr->program_checksum_name, EIN_NOTE_NAME); + hdr->program_checksum = cpu_to_le16(0); /* This is written later */ + + /* Compute the image checksum, this covers everything except the + * ELF notes. + */ + bytes = sizeof(hdr->ehdr) + sizeof(hdr->phdr); + checksum = compute_ip_checksum(hdr, bytes); + for(i = 1; i < 4; i++) { + checksum = add_ip_checksums(bytes, checksum, + compute_ip_checksum(seg[i].data, seg[i].data_size)); + bytes += seg[i].mem_size; + } + hdr->program_checksum = cpu_to_le16(checksum); + seg[OEHDR].data = (unsigned char *)hdr; } static void usage(void) { - die("Usage: build [-b] vmlinux realmode compressed/vmlinux image"); + die("Usage: build [-e] [-b] vmlinux realmode compressed/vmlinux image"); } int main(int argc, char ** argv) @@ -544,6 +750,12 @@ memset(oseg, 0, sizeof(oseg)); memset(&info, 0, sizeof(info)); info.is_big_kernel = 0; + info.is_elf = 0; + if (argc > 2 && (strcmp(argv[1], "-e") == 0)) { + info.is_elf = 1; + argc--; + argv++; + } if (argc > 2 && (strcmp(argv[1], "-b") == 0)) { info.is_big_kernel = 1; argc--; @@ -626,7 +838,7 @@ } else { /* bzImage */ size_t unzip_bufsz; - + /* Compute the bzImage decompressor memory size */ unzip_bufsz = iseg[IKERN].data_size + info.unzip_overhang; if (unzip_bufsz > oseg[OKERN].mem_size) { @@ -653,7 +865,15 @@ info.setup_sectors = (oseg[OREAL].data_size - 512 + 511)/512; if (info.setup_sectors < SETUP_SECTS) info.setup_sectors = SETUP_SECTS; + if (info.is_elf) { + oseg[OEHDR].data_size = sizeof(struct elf_header); + } + /* Note: for ELF images I don't have to make OREAL + * info.setup_sectors long, but it makes the conversion back + * to a bzImage just a trivial header removal. + */ + oseg[OREAL].file_offset = oseg[OEHDR].file_offset + oseg[OEHDR].data_size; oseg[OKERN].file_offset = oseg[OREAL].file_offset + (info.setup_sectors +1)*512; /* Check and print the values to write back. */ @@ -692,6 +912,10 @@ /* Write the values back */ update_image(iseg, oseg, &info); + if (info.is_elf) { + build_elf_header(oseg, &info); + printf("elf_header_size=%d\n", oseg[OEHDR].data_size); + } /* Write destination file */ image_fd = checked_open(image, O_RDWR | O_CREAT | O_TRUNC, 0666); ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, bzElf support 11/11 2002-05-02 15:15 ` [PATCH 2.5.12] x86 Boot enhancements, bzElf support 11/11 Eric W. Biederman @ 2002-05-02 20:45 ` H. Peter Anvin 0 siblings, 0 replies; 20+ messages in thread From: H. Peter Anvin @ 2002-05-02 20:45 UTC (permalink / raw) To: linux-kernel Followup to: <m1sn5awpg2.fsf_-_@frodo.biederman.org> By author: ebiederm@xmission.com (Eric W. Biederman) In newsgroup: linux.dev.kernel > > Please apply, > > This patch allows a bzELF image to be built instead of a bzImage. > A bzELF is just a bzImage represented in the ELF file format. The transform > from bzELF to bzImage is 1-1. > ... thus adding another binary format for no gain. -hpa -- <hpa@transmeta.com> at work, <hpa@zytor.com> in private! "Unix gives you enough rope to shoot yourself in the foot." http://www.zytor.com/~hpa/puzzle.txt <amsp@zytor.com> ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 2002-05-02 15:11 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 Eric W. Biederman 2002-05-02 15:13 ` [PATCH 2.5.12] x86 Boot enhancements, LinuxBIOS support 10/11 Eric W. Biederman @ 2002-05-02 20:39 ` H. Peter Anvin 2002-05-02 20:45 ` H. Peter Anvin 2 siblings, 0 replies; 20+ messages in thread From: H. Peter Anvin @ 2002-05-02 20:39 UTC (permalink / raw) To: linux-kernel Followup to: <m11ycuy48d.fsf_-_@frodo.biederman.org> By author: ebiederm@xmission.com (Eric W. Biederman) In newsgroup: linux.dev.kernel > +0200/2 2.00+ jump Jump instruction I would like to make it an explicit part of the protocol that the jump instruction must jump to the first byte following the header. It can therefore be used to determine the end of the header. -hpa -- <hpa@transmeta.com> at work, <hpa@zytor.com> in private! "Unix gives you enough rope to shoot yourself in the foot." http://www.zytor.com/~hpa/puzzle.txt <amsp@zytor.com> ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 2002-05-02 15:11 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 Eric W. Biederman 2002-05-02 15:13 ` [PATCH 2.5.12] x86 Boot enhancements, LinuxBIOS support 10/11 Eric W. Biederman 2002-05-02 20:39 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 H. Peter Anvin @ 2002-05-02 20:45 ` H. Peter Anvin 2 siblings, 0 replies; 20+ messages in thread From: H. Peter Anvin @ 2002-05-02 20:45 UTC (permalink / raw) To: linux-kernel Followup to: <m11ycuy48d.fsf_-_@frodo.biederman.org> By author: ebiederm@xmission.com (Eric W. Biederman) In newsgroup: linux.dev.kernel > > For backwards compatibility, if the setup_sects field contains 0, the > real value is 4. > @@ -180,8 +199,14 @@ > loadflags, heap_end_ptr: > If the protocol version is 2.01 or higher, enter the > offset limit of the setup heap into heap_end_ptr and set the > - 0x80 bit (CAN_USE_HEAP) of loadflags. heap_end_ptr appears to > - be relative to the start of setup (offset 0x0200). > + 0x80 bit (CAN_USE_HEAP) of loadflags. heap_end_ptr is > + relative to the start of setup (offset 0x0200). > + > + If the protocol version is 2.04 or higher set the 0x40 bit > + (STAY_PUT). This explictly tells the real mode code that you > + don't expect it to relocate itself to 0x90000. No earlier > + protocols versions look at this bit so it is safe to set it > + unconditionally. > Hang on here... this is bullsh*t. The real-mode code should not be relocated if the cmd_line_ptr field is set. If you don't want to pass a command line, set cmd_line_ptr to an empty string "". There should be no need for an additional protocol here; in fact, having two protocols only means the boot loader has to do both, in effect, so what's the point?!? > + With boot protocol 2.04 and above the initrd can be loaded > + as low as kern_base + kern_memsz. It's still a bad idea, for several reasons: a) Adds to the number of configurations that have to be tested, for absolutely no good reason. b) It may be OK for the Linux kernel proper, but it is *NOT* acceptable for some other programs that use the Linux boot protocol. -hpa -- <hpa@transmeta.com> at work, <hpa@zytor.com> in private! "Unix gives you enough rope to shoot yourself in the foot." http://www.zytor.com/~hpa/puzzle.txt <amsp@zytor.com> ^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2002-05-06 20:20 UTC | newest] Thread overview: 20+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2002-05-02 14:42 [PATCH 2.5.12] x86 Boot enhancements, boot params 1/11 Eric W. Biederman 2002-04-27 2:56 ` Pavel Machek 2002-05-06 10:13 ` Eric W. Biederman 2002-05-06 15:19 ` Pavel Machek 2002-05-06 17:55 ` Eric W. Biederman 2002-05-06 20:20 ` Pavel Machek 2002-05-02 14:45 ` [PATCH 2.5.12] x86 Boot enhancements, linker fixes 2/11 Eric W. Biederman 2002-05-02 14:48 ` [PATCH 2.5.12] x86 Boot enhancements, bzImage/zImage code differentiation 3/11 Eric W. Biederman 2002-05-02 14:51 ` [PATCH 2.5.12] x86 Boot enhancements, constants 4/11 Eric W. Biederman 2002-05-02 14:55 ` [PATCH 2.5.12] x86 Boot enhancements, heap 5/11 Eric W. Biederman 2002-05-02 15:00 ` [PATCH 2.5.12] x86 Boot enhancements, 32bit entries 6/11 Eric W. Biederman 2002-04-27 4:53 ` Pavel Machek 2002-05-02 15:05 ` [PATCH 2.5.12] x86 Boot enhancements, footprint reduction 7/11 Eric W. Biederman 2002-05-02 15:07 ` [PATCH 2.5.12] x86 Boot enhancements, build beancounting 8/11 Eric W. Biederman 2002-05-02 15:11 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 Eric W. Biederman 2002-05-02 15:13 ` [PATCH 2.5.12] x86 Boot enhancements, LinuxBIOS support 10/11 Eric W. Biederman 2002-05-02 15:15 ` [PATCH 2.5.12] x86 Boot enhancements, bzElf support 11/11 Eric W. Biederman 2002-05-02 20:45 ` H. Peter Anvin 2002-05-02 20:39 ` [PATCH 2.5.12] x86 Boot enhancements, boot protocol 2.04 9/11 H. Peter Anvin 2002-05-02 20:45 ` H. Peter Anvin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox