while others dislike them being extra commits, let's clean them up once and for all for the existing code. If it's ugly, let it only be ugly once :-) Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5507 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
		
			
				
	
	
		
			1563 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1563 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdarg.h>
 | |
| #include <limits.h>
 | |
| #include "arch/io.h"
 | |
| #include "stdint.h"
 | |
| #include "uniform_boot.h"
 | |
| #include "linuxbios_tables.h"
 | |
| #include "elf_boot.h"
 | |
| #include "convert.h"
 | |
| #define STACK_SIZE (4096)
 | |
| 
 | |
| #define __unused __attribute__ ((unused))
 | |
| 
 | |
| long user_stack [STACK_SIZE] = { 0 };
 | |
| 
 | |
| unsigned long * stack_start = & user_stack[STACK_SIZE];
 | |
| 
 | |
| /* FIXME expand on drive_info_)struct... */
 | |
| struct drive_info_struct {
 | |
| 	uint8_t dummy[32];
 | |
| };
 | |
| struct sys_desc_table {
 | |
| 	uint16_t length;
 | |
| 	uint8_t  table[318];
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * These are set up by the setup-routine at boot-time:
 | |
|  */
 | |
| 
 | |
| struct screen_info {
 | |
| 	uint8_t  orig_x;		/* 0x00 */
 | |
| 	uint8_t  orig_y;		/* 0x01 */
 | |
| 	uint16_t dontuse1;		/* 0x02 -- EXT_MEM_K sits here */
 | |
| 	uint16_t orig_video_page;	/* 0x04 */
 | |
| 	uint8_t  orig_video_mode;	/* 0x06 */
 | |
| 	uint8_t  orig_video_cols;	/* 0x07 */
 | |
| 	uint16_t unused2;		/* 0x08 */
 | |
| 	uint16_t orig_video_ega_bx;	/* 0x0a */
 | |
| 	uint16_t unused3;		/* 0x0c */
 | |
| 	uint8_t	 orig_video_lines;	/* 0x0e */
 | |
| 	uint8_t	 orig_video_isVGA;	/* 0x0f */
 | |
| 	uint16_t orig_video_points;	/* 0x10 */
 | |
| 
 | |
| 	/* VESA graphic mode -- linear frame buffer */
 | |
| 	uint16_t lfb_width;		/* 0x12 */
 | |
| 	uint16_t lfb_height;		/* 0x14 */
 | |
| 	uint16_t lfb_depth;		/* 0x16 */
 | |
| 	uint32_t lfb_base;		/* 0x18 */
 | |
| 	uint32_t lfb_size;		/* 0x1c */
 | |
| 	uint16_t dontuse2, dontuse3;	/* 0x20 -- CL_MAGIC and CL_OFFSET here */
 | |
| 	uint16_t lfb_linelength;	/* 0x24 */
 | |
| 	uint8_t	 red_size;		/* 0x26 */
 | |
| 	uint8_t	 red_pos;		/* 0x27 */
 | |
| 	uint8_t	 green_size;		/* 0x28 */
 | |
| 	uint8_t	 green_pos;		/* 0x29 */
 | |
| 	uint8_t	 blue_size;		/* 0x2a */
 | |
| 	uint8_t	 blue_pos;		/* 0x2b */
 | |
| 	uint8_t	 rsvd_size;		/* 0x2c */
 | |
| 	uint8_t	 rsvd_pos;		/* 0x2d */
 | |
| 	uint16_t vesapm_seg;		/* 0x2e */
 | |
| 	uint16_t vesapm_off;		/* 0x30 */
 | |
| 	uint16_t pages;			/* 0x32 */
 | |
| };
 | |
| 
 | |
| 
 | |
| #define PAGE_SIZE 4096
 | |
| 
 | |
| 
 | |
| #define E820MAP	0x2d0		/* our map */
 | |
| #define E820MAX	32		/* number of entries in E820MAP */
 | |
| #define E820NR	0x1e8		/* # entries in E820MAP */
 | |
| 
 | |
| 
 | |
| struct e820entry {
 | |
| 	unsigned long long addr;	/* start of memory segment */
 | |
| 	unsigned long long size;	/* size of memory segment */
 | |
| 	unsigned long type;		/* type of memory segment */
 | |
| #define E820_RAM	1
 | |
| #define E820_RESERVED	2
 | |
| #define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */
 | |
| #define E820_NVS	4
 | |
| };
 | |
| 
 | |
| struct e820map {
 | |
|     int nr_map;
 | |
| 	struct e820entry map[E820MAX];
 | |
| };
 | |
| 
 | |
| 
 | |
| struct apm_bios_info {
 | |
| 	uint16_t version;       /* 0x40 */
 | |
| 	uint16_t cseg;		/* 0x42 */
 | |
| 	uint32_t offset;	/* 0x44 */
 | |
| 	uint16_t cseg_16;	/* 0x48 */
 | |
| 	uint16_t dseg;		/* 0x4a */
 | |
| 	uint16_t flags;		/* 0x4c */
 | |
| 	uint16_t cseg_len;	/* 0x4e */
 | |
| 	uint16_t cseg_16_len;	/* 0x50 */
 | |
| 	uint16_t dseg_len;	/* 0x52 */
 | |
| 	uint8_t  reserved[44];	/* 0x54 */
 | |
| };
 | |
| 
 | |
| 
 | |
| struct parameters {
 | |
| 	uint8_t  orig_x;			/* 0x00 */
 | |
| 	uint8_t  orig_y;			/* 0x01 */
 | |
| 	uint16_t ext_mem_k;			/* 0x02 -- EXT_MEM_K sits here */
 | |
| 	uint16_t orig_video_page;		/* 0x04 */
 | |
| 	uint8_t  orig_video_mode;		/* 0x06 */
 | |
| 	uint8_t  orig_video_cols;		/* 0x07 */
 | |
| 	uint16_t unused2;			/* 0x08 */
 | |
| 	uint16_t orig_video_ega_bx;		/* 0x0a */
 | |
| 	uint16_t unused3;			/* 0x0c */
 | |
| 	uint8_t	 orig_video_lines;		/* 0x0e */
 | |
| 	uint8_t	 orig_video_isVGA;		/* 0x0f */
 | |
| 	uint16_t orig_video_points;		/* 0x10 */
 | |
| 
 | |
| 	/* VESA graphic mode -- linear frame buffer */
 | |
| 	uint16_t lfb_width;			/* 0x12 */
 | |
| 	uint16_t lfb_height;			/* 0x14 */
 | |
| 	uint16_t lfb_depth;			/* 0x16 */
 | |
| 	uint32_t lfb_base;			/* 0x18 */
 | |
| 	uint32_t lfb_size;			/* 0x1c */
 | |
| 	uint16_t cl_magic;			/* 0x20 */
 | |
| #define CL_MAGIC_VALUE 0xA33F
 | |
| 	uint16_t cl_offset;			/* 0x22 */
 | |
| 	uint16_t lfb_linelength;		/* 0x24 */
 | |
| 	uint8_t	 red_size;			/* 0x26 */
 | |
| 	uint8_t	 red_pos;			/* 0x27 */
 | |
| 	uint8_t	 green_size;			/* 0x28 */
 | |
| 	uint8_t	 green_pos;			/* 0x29 */
 | |
| 	uint8_t	 blue_size;			/* 0x2a */
 | |
| 	uint8_t	 blue_pos;			/* 0x2b */
 | |
| 	uint8_t	 rsvd_size;			/* 0x2c */
 | |
| 	uint8_t	 rsvd_pos;			/* 0x2d */
 | |
| 	uint16_t vesapm_seg;			/* 0x2e */
 | |
| 	uint16_t vesapm_off;			/* 0x30 */
 | |
| 	uint16_t pages;				/* 0x32 */
 | |
| 	uint8_t  reserved4[12];			/* 0x34 -- 0x3f reserved for future expansion */
 | |
| 
 | |
| 	struct apm_bios_info apm_bios_info;	/* 0x40 */
 | |
| 	struct drive_info_struct drive_info;	/* 0x80 */
 | |
| 	struct sys_desc_table sys_desc_table;	/* 0xa0 */
 | |
| 	uint32_t alt_mem_k;			/* 0x1e0 */
 | |
| 	uint8_t  reserved5[4];			/* 0x1e4 */
 | |
| 	uint8_t  e820_map_nr;			/* 0x1e8 */
 | |
| 	uint8_t  reserved6[9];			/* 0x1e9 */
 | |
| 	uint16_t mount_root_rdonly;		/* 0x1f2 */
 | |
| 	uint8_t  reserved7[4];			/* 0x1f4 */
 | |
| 	uint16_t ramdisk_flags;			/* 0x1f8 */
 | |
| #define RAMDISK_IMAGE_START_MASK  	0x07FF
 | |
| #define RAMDISK_PROMPT_FLAG		0x8000
 | |
| #define RAMDISK_LOAD_FLAG		0x4000
 | |
| 	uint8_t  reserved8[2];			/* 0x1fa */
 | |
| 	uint16_t orig_root_dev;			/* 0x1fc */
 | |
| 	uint8_t  reserved9[1];			/* 0x1fe */
 | |
| 	uint8_t  aux_device_info;		/* 0x1ff */
 | |
| 	uint8_t  reserved10[2];			/* 0x200 */
 | |
| 	uint8_t  param_block_signature[4];	/* 0x202 */
 | |
| 	uint16_t param_block_version;		/* 0x206 */
 | |
| 	uint8_t  reserved11[8];			/* 0x208 */
 | |
| 	uint8_t  loader_type;			/* 0x210 */
 | |
| #define LOADER_TYPE_LOADLIN         1
 | |
| #define LOADER_TYPE_BOOTSECT_LOADER 2
 | |
| #define LOADER_TYPE_SYSLINUX        3
 | |
| #define LOADER_TYPE_ETHERBOOT       4
 | |
| #define LOADER_TYPE_KERNEL          5
 | |
| 	uint8_t  loader_flags;			/* 0x211 */
 | |
| 	uint8_t  reserved12[2];			/* 0x212 */
 | |
| 	uint32_t kernel_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 initrd_addr_max;               /* 0x22c */
 | |
| 	uint8_t  reserved15[0x2d0 - 0x230];     /* 0x230 */
 | |
| 
 | |
| 	struct e820entry e820_map[E820MAX];	/* 0x2d0 */
 | |
| 	uint8_t  reserved16[688];		/* 0x550 */
 | |
| #define COMMAND_LINE_SIZE 256
 | |
| 	uint8_t  command_line[COMMAND_LINE_SIZE]; /* 0x800 */
 | |
| 	uint8_t  reserved17[1792];		/* 0x900 - 0x1000 */
 | |
| };
 | |
| 
 | |
| /* Keep track of which information I need to acquire. */
 | |
| struct param_info {
 | |
| 	unsigned type;
 | |
| 	void *data;
 | |
| 	Elf_Bhdr *param;
 | |
| 	struct image_parameters *image;
 | |
| 	struct parameters *real_mode;
 | |
| 	/* bootloader type */
 | |
| 	int has_multiboot;
 | |
| 	int has_uniform_boot;
 | |
| 	int has_elf_boot;
 | |
| 	/* firmware type */
 | |
| 	int has_pcbios;
 | |
| 	int has_linuxbios;
 | |
| 	struct lb_header *lb_table;
 | |
| 	/* machine information needed */
 | |
| 	int need_mem_sizes;
 | |
| };
 | |
| /*
 | |
|  * This is set up by the setup-routine at boot-time
 | |
|  */
 | |
| 
 | |
| 
 | |
| #undef memcmp
 | |
| #undef memset
 | |
| #undef memcpy
 | |
| #define memzero(s, n)     memset ((s), 0, (n))
 | |
| 
 | |
| 
 | |
| /* FIXME handle systems with large EBDA's */
 | |
| static struct parameters *faked_real_mode = (void *)REAL_MODE_DATA_LOC;
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Output
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| /* Base Address */
 | |
| #define TTYS0 0x3f8
 | |
| #define TTYS0_LSR (TTYS0+0x05)
 | |
| #define TTYS0_TBR (TTYS0+0x00)
 | |
| 
 | |
| static void ttys0_tx_byte(unsigned byte)
 | |
| {
 | |
| 	/* Wait until I can send a byte */
 | |
| 	while((inb(TTYS0_LSR) & 0x20) == 0)
 | |
| 		;
 | |
| 	outb(byte, TTYS0_TBR);
 | |
| 	/* Wait until the byte is transmitted */
 | |
| 	while(!(inb(TTYS0_LSR) & 0x40))
 | |
| 		;
 | |
| }
 | |
| static void put_char_serial(int c)
 | |
| {
 | |
| 	if (c == '\n') {
 | |
| 		ttys0_tx_byte('\r');
 | |
| 	}
 | |
| 	ttys0_tx_byte(c);
 | |
| }
 | |
| 
 | |
| static void putchar(int c)
 | |
| {
 | |
| #if 0
 | |
| 	put_char_video(c);
 | |
| #endif
 | |
| 	put_char_serial(c);
 | |
| }
 | |
| 
 | |
| #define LONG_LONG_SHIFT  ((int)((sizeof(unsigned long long)*CHAR_BIT) - 4))
 | |
| #define LONG_SHIFT  ((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
 | |
| #define INT_SHIFT   ((int)((sizeof(unsigned int)*CHAR_BIT) - 4))
 | |
| #define SHRT_SHIFT  ((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
 | |
| #define CHAR_SHIFT  ((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
 | |
| 
 | |
| /**************************************************************************
 | |
| PRINTF and friends
 | |
| 
 | |
| 	Formats:
 | |
| 		%x	- 4 bytes int (8 hex digits, lower case)
 | |
| 		%X	- 4 bytes int (8 hex digits, upper case)
 | |
| 		%lx     - 8 bytes long (16 hex digits, lower case)
 | |
| 		%lX     - 8 bytes long (16 hex digits, upper case)
 | |
| 		%hx	- 2 bytes int (4 hex digits, lower case)
 | |
| 		%hX	- 2 bytes int (4 hex digits, upper case)
 | |
| 		%hhx	- 1 byte int (2 hex digits, lower case)
 | |
| 		%hhX	- 1 byte int (2 hex digits, upper case)
 | |
| 			- optional # prefixes 0x or 0X
 | |
| 		%d	- decimal int
 | |
| 		%c	- char
 | |
| 		%s	- string
 | |
| 	Note: width specification not supported
 | |
| **************************************************************************/
 | |
| static void printf(const char *fmt, ...)
 | |
| {
 | |
| 	va_list args;
 | |
| 	char *p;
 | |
| 	va_start(args, fmt);
 | |
| 	for ( ; *fmt != '\0'; ++fmt) {
 | |
| 		if (*fmt != '%') {
 | |
| 			putchar(*fmt);
 | |
| 			continue;
 | |
| 		}
 | |
| 		if (*++fmt == 's') {
 | |
| 			for(p = va_arg(args, char *); *p != '\0'; p++)
 | |
| 				putchar(*p);
 | |
| 		}
 | |
| 		else {	/* Length of item is bounded */
 | |
| 			char tmp[40], *q = tmp;
 | |
| 			int shift = INT_SHIFT;
 | |
| 			if (*fmt == 'L') {
 | |
| 				shift = LONG_LONG_SHIFT;
 | |
| 				fmt++;
 | |
| 			}
 | |
| 			else if (*fmt == 'l') {
 | |
| 				shift = LONG_SHIFT;
 | |
| 				fmt++;
 | |
| 			}
 | |
| 			else if (*fmt == 'h') {
 | |
| 				shift = SHRT_SHIFT;
 | |
| 				fmt++;
 | |
| 				if (*fmt == 'h') {
 | |
| 					shift = CHAR_SHIFT;
 | |
| 					fmt++;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			/*
 | |
| 			 * Before each format q points to tmp buffer
 | |
| 			 * After each format q points past end of item
 | |
| 			 */
 | |
| 			if ((*fmt | 0x20) == 'x') {
 | |
| 				/* With x86 gcc, sizeof(long) == sizeof(int) */
 | |
| 				unsigned long long h;
 | |
| 				int ncase;
 | |
| 				if (shift > LONG_SHIFT) {
 | |
| 					h = va_arg(args, unsigned long long);
 | |
| 				}
 | |
| 				else if (shift > INT_SHIFT) {
 | |
| 					h = va_arg(args, unsigned long);
 | |
| 				} else {
 | |
| 					h = va_arg(args, unsigned int);
 | |
| 				}
 | |
| 				ncase = (*fmt & 0x20);
 | |
| 				for ( ; shift >= 0; shift -= 4)
 | |
| 					*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
 | |
| 			}
 | |
| 			else if (*fmt == 'd') {
 | |
| 				char *r;
 | |
| 				long i;
 | |
| 				if (shift > LONG_SHIFT) {
 | |
| 					i = va_arg(args, long long);
 | |
| 				}
 | |
| 				else if (shift > INT_SHIFT) {
 | |
| 					i = va_arg(args, long);
 | |
| 				} else {
 | |
| 					i = va_arg(args, int);
 | |
| 				}
 | |
| 				if (i < 0) {
 | |
| 					*q++ = '-';
 | |
| 					i = -i;
 | |
| 				}
 | |
| 				p = q;		/* save beginning of digits */
 | |
| 				do {
 | |
| 					*q++ = '0' + (i % 10);
 | |
| 					i /= 10;
 | |
| 				} while (i);
 | |
| 				/* reverse digits, stop in middle */
 | |
| 				r = q;		/* don't alter q */
 | |
| 				while (--r > p) {
 | |
| 					i = *r;
 | |
| 					*r = *p;
 | |
| 					*p++ = i;
 | |
| 				}
 | |
| 			}
 | |
| 			else if (*fmt == 'c')
 | |
| 				*q++ = va_arg(args, int);
 | |
| 			else
 | |
| 				*q++ = *fmt;
 | |
| 			/* now output the saved string */
 | |
| 			for (p = tmp; p < q; ++p)
 | |
| 				putchar(*p);
 | |
| 		}
 | |
| 	}
 | |
| 	va_end(args);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * String Functions
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| 
 | |
| size_t strnlen(const char *s, size_t max)
 | |
| {
 | |
| 	size_t len = 0;
 | |
| 	while(len < max && *s) {
 | |
| 		len++;
 | |
| 		s++;
 | |
| 	}
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| void* memset(void* s, int c, size_t n)
 | |
| {
 | |
| 	size_t i;
 | |
| 	char *ss = (char*)s;
 | |
| 
 | |
| 	for (i=0;i<n;i++) ss[i] = c;
 | |
| 	return s;
 | |
| }
 | |
| 
 | |
| void* memcpy(void *dest, const void *src, size_t len)
 | |
| {
 | |
| 	size_t i;
 | |
| 	unsigned char *d;
 | |
| 	const unsigned char *s;
 | |
| 	d = dest;
 | |
| 	s = src;
 | |
| 
 | |
| 	for (i=0; i < len; i++)
 | |
| 		d[i] = s[i];
 | |
| 
 | |
| 	return dest;
 | |
| }
 | |
| 
 | |
| int memcmp(void *src1, void *src2, size_t len)
 | |
| {
 | |
| 	unsigned char *s1, *s2;
 | |
| 	size_t i;
 | |
| 	s1 = src1;
 | |
| 	s2 = src2;
 | |
| 	for(i = 0; i < len; i++) {
 | |
| 		if (*s1 != *s2) {
 | |
| 			return *s2 - *s1;
 | |
| 		}
 | |
| 	}
 | |
| 	return 0;
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Checksum functions
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| 
 | |
| static unsigned long checksum_partial(unsigned long sum,
 | |
| 	void *addr, unsigned long length)
 | |
| {
 | |
| 	uint8_t *ptr;
 | |
| 	volatile union {
 | |
| 		uint8_t  byte[2];
 | |
| 		uint16_t word;
 | |
| 	} value;
 | |
| 	unsigned long i;
 | |
| 	/* In the most straight forward way possible,
 | |
| 	 * compute an ip style checksum.
 | |
| 	 */
 | |
| 	sum = 0;
 | |
| 	ptr = addr;
 | |
| 	for(i = 0; i < length; i++) {
 | |
| 		unsigned long value;
 | |
| 		value = ptr[i];
 | |
| 		if (i & 1) {
 | |
| 			value <<= 8;
 | |
| 		}
 | |
| 		/* Add the new value */
 | |
| 		sum += value;
 | |
| 		/* Wrap around the carry */
 | |
| 		if (sum > 0xFFFF) {
 | |
| 			sum = (sum + (sum >> 16)) & 0xFFFF;
 | |
| 		}
 | |
| 	}
 | |
| 	value.byte[0] = sum & 0xff;
 | |
| 	value.byte[1] = (sum >> 8) & 0xff;
 | |
| 	return value.word & 0xFFFF;
 | |
| 
 | |
| }
 | |
| 
 | |
| static unsigned long checksum_final(unsigned long partial)
 | |
| {
 | |
| 	return (~partial) & 0xFFFF;
 | |
| }
 | |
| 
 | |
| static unsigned long compute_checksum(void *vaddr, unsigned long length)
 | |
| {
 | |
| 	return checksum_final(checksum_partial(0, vaddr, length));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Helper functions
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| 
 | |
| void append_command_line(struct parameters *real_mode, char *arg, int arg_bytes)
 | |
| {
 | |
| 	int len, max;
 | |
| 	char *dest;
 | |
| 	/* skip over what has already been set */
 | |
| 	len = strnlen(real_mode->command_line, sizeof(real_mode->command_line));
 | |
| 	dest = real_mode->command_line + len;
 | |
| 	max = sizeof(real_mode->command_line) - 1;
 | |
| 	if (max < 1) {
 | |
| 		/* No room to append anything :( */
 | |
| 		return;
 | |
| 	}
 | |
| 	/* Add a space in between strings */
 | |
| 	*dest++ = ' ';
 | |
| 	/* Append the added command line */
 | |
| 	max = sizeof(real_mode->command_line) - 1;
 | |
| 	if (max > arg_bytes) {
 | |
| 		max = arg_bytes;
 | |
| 	}
 | |
| 	len = strnlen(arg, max);
 | |
| 	memcpy(dest, arg, len);
 | |
| 	dest += len;
 | |
| 	/* Null terminate the string */
 | |
| 	*dest++ = '\0';
 | |
| }
 | |
| 
 | |
| static void set_memsize_k(struct parameters *real_mode, unsigned long mem_k)
 | |
| {
 | |
| 	/* ALT_MEM_K maxes out at 4GB */
 | |
| 	if (mem_k > 0x3fffff) {
 | |
| 		mem_k = 0x3fffff;
 | |
| 	}
 | |
| 	if (mem_k > (real_mode->alt_mem_k + (1 << 10))) {
 | |
| 		/* Use our memory size less 1M */
 | |
| 		real_mode->alt_mem_k = mem_k - (1 << 10);
 | |
| 		real_mode->ext_mem_k = mem_k - (1 << 10);
 | |
| 		if ((mem_k - (1 << 10)) > 0xFFFF) {
 | |
| 			real_mode->ext_mem_k = 0xFC00; /* 64 M */
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void add_e820_map(struct parameters *real_mode,
 | |
| 	unsigned long long addr, unsigned long long size,
 | |
| 	unsigned long type)
 | |
| {
 | |
| 	unsigned long long high;
 | |
| 	unsigned long mem_k;
 | |
| 	int i;
 | |
| 	i = real_mode->e820_map_nr;
 | |
| 	if (i < E820MAX) {
 | |
| 		real_mode->e820_map[i].addr = addr;
 | |
| 		real_mode->e820_map[i].size = size;
 | |
| 		real_mode->e820_map[i].type = type;
 | |
| 		real_mode->e820_map_nr++;
 | |
| 	}
 | |
| 	/* policy I assume that for the legacy memory
 | |
| 	 * variables memory is contiguous.
 | |
| 	 */
 | |
| 	if (type == E820_RAM) {
 | |
| 		high = addr + size;
 | |
| 		if (high >= 0x40000000000ULL) {
 | |
| 			mem_k = 0xFFFFFFFF;
 | |
| 		} else {
 | |
| 			mem_k = high >> 10;
 | |
| 		}
 | |
| 		set_memsize_k(real_mode, mem_k);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Multiboot
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| #define MULTI_MEM_DEBUG 0
 | |
| #if MULTI_MEM_DEBUG
 | |
| #define multi_puts(x) printf("%s", x)
 | |
| #define multi_put_hex(x) printf("%x", x)
 | |
| #define multi_put_lhex(x) printf("%Lx", x)
 | |
| #else
 | |
| #define multi_puts(x)
 | |
| #define multi_put_hex(x)
 | |
| #define multi_put_lhex(x)
 | |
| #endif /* MULTI_MEM_DEBUG */
 | |
| 
 | |
| /* Multiboot Specification */
 | |
| struct multiboot_mods {
 | |
| 	unsigned mod_start;
 | |
| 	unsigned mod_end;
 | |
| 	unsigned char *string;
 | |
| 	unsigned reserved;
 | |
| };
 | |
| 
 | |
| struct memory_segment {
 | |
| 	unsigned long long addr;
 | |
| 	unsigned long long size;
 | |
| 	unsigned type;
 | |
| };
 | |
| 
 | |
| struct multiboot_info {
 | |
|         unsigned flags;
 | |
| #define MULTIBOOT_MEM_VALID       0x01
 | |
| #define MULTIBOOT_BOOT_DEV_VALID  0x02
 | |
| #define MULTIBOOT_CMDLINE_VALID   0x04
 | |
| #define MULTIBOOT_MODS_VALID      0x08
 | |
| #define MULTIBOOT_AOUT_SYMS_VALID 0x10
 | |
| #define MULTIBOOT_ELF_SYMS_VALID  0x20
 | |
| #define MULTIBOOT_MMAP_VALID      0x40
 | |
| 	unsigned mem_lower;
 | |
| 	unsigned mem_upper;
 | |
| 	unsigned char boot_device[4];
 | |
| 	void *command_line;
 | |
| 	unsigned mods_count;
 | |
| 	struct multiboot_mods *mods_addr;
 | |
| 	unsigned syms_num;
 | |
| 	unsigned syms_size;
 | |
| 	unsigned syms_addr;
 | |
| 	unsigned syms_shndx;
 | |
| 	unsigned mmap_length;
 | |
| 	struct memory_segment *mmap_addr;
 | |
| };
 | |
| 
 | |
| #define MULTIBOOT_MAX_COMMAND_LINE 0xFFFFFFFF
 | |
| 
 | |
| static void convert_multiboot_memmap(
 | |
| 	struct parameters *real_mode,
 | |
| 	struct multiboot_info *info)
 | |
| {
 | |
| 	unsigned size;
 | |
| 	unsigned *size_addr;
 | |
| #define next_seg(seg, size) ((struct memory_segment *)((char *)(seg) + (size)))
 | |
| 	struct memory_segment *seg, *end;
 | |
| 
 | |
| 	seg = info->mmap_addr;
 | |
| 	end  = (void *)(((char *)seg) + info->mmap_length);
 | |
| 	size_addr = (unsigned *)(((char *)seg) - 4);
 | |
| 	size = *size_addr;
 | |
| 	multi_puts("mmap_addr: "); multi_put_hex((unsigned)info->mmap_addr); multi_puts("\n");
 | |
| 	multi_puts("mmap_length: "); multi_put_hex(info->mmap_length); multi_puts("\n");
 | |
| 	multi_puts("size_addr: "); multi_put_hex((unsigned)size_addr); multi_puts("\n");
 | |
| 	multi_puts("size: "); multi_put_hex(size); multi_puts("\n");
 | |
| 	multi_puts("end: "); multi_put_hex((unsigned)end); multi_puts("\n");
 | |
| 	for(seg = info->mmap_addr; (seg < end); seg = next_seg(seg,size)) {
 | |
| 		multi_puts("multi-mem: ");
 | |
| 		multi_put_lhex(seg->size);
 | |
| 		multi_puts(" @ ");
 | |
| 		multi_put_lhex(seg->addr);
 | |
| 		multi_puts(" (");
 | |
| 		switch(seg->type) {
 | |
| 		case E820_RAM:
 | |
| 			multi_puts("ram");
 | |
| 			break;
 | |
| 		case E820_ACPI:
 | |
| 			multi_puts("ACPI data");
 | |
| 			break;
 | |
| 		case E820_NVS:
 | |
| 			multi_puts("ACPI NVS");
 | |
| 			break;
 | |
| 		case E820_RESERVED:
 | |
| 		default:
 | |
| 			multi_puts("reserved");
 | |
| 			break;
 | |
| 		}
 | |
| 		multi_puts(")\n");
 | |
| 		add_e820_map(real_mode, seg->addr, seg->size, seg->type);
 | |
| 	}
 | |
| #undef next_seg
 | |
| }
 | |
| 
 | |
| static void convert_multiboot(
 | |
| 	struct param_info *info, struct multiboot_info *mb_info)
 | |
| {
 | |
| 	if (info->need_mem_sizes && (mb_info->flags & MULTIBOOT_MEM_VALID)) {
 | |
| 		/* info->memory is short 1M */
 | |
| 		set_memsize_k(info->real_mode, mb_info->mem_upper + (1 << 10));
 | |
| 	}
 | |
| 	if (mb_info->flags & MULTIBOOT_CMDLINE_VALID) {
 | |
| 		append_command_line(info->real_mode, mb_info->command_line,
 | |
| 			MULTIBOOT_MAX_COMMAND_LINE);
 | |
| 	}
 | |
| 	if (info->need_mem_sizes && (mb_info->flags & MULTIBOOT_MMAP_VALID)) {
 | |
| 		convert_multiboot_memmap(info->real_mode, mb_info);
 | |
| 	}
 | |
| 	if (mb_info->flags & (MULTIBOOT_MEM_VALID | MULTIBOOT_MMAP_VALID)) {
 | |
| 		info->need_mem_sizes = 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Uniform Boot Environment
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| #define UBE_MEM_DEBUG 0
 | |
| #if UBE_MEM_DEBUG
 | |
| #define ube_puts(x) printf("%s", x)
 | |
| #define ube_put_hex(x) printf("%x", x)
 | |
| #define ube_put_lhex(x) printf("%Lx", x)
 | |
| #else
 | |
| #define ube_puts(x)
 | |
| #define ube_put_hex(x)
 | |
| #define ube_put_lhex(x)
 | |
| #endif /* UBE_MEM_DEBUG */
 | |
| static void convert_uniform_boot_memory(
 | |
| 	struct parameters *real_mode, struct ube_memory *mem)
 | |
| {
 | |
| 	int i;
 | |
| 	int entries;
 | |
| 	unsigned long mem_k;
 | |
| 	mem_k = 0;
 | |
| 	entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
 | |
| 	for(i = 0; (i < entries) && (i < E820MAX); i++) {
 | |
| 		unsigned long type;
 | |
| 		ube_puts("ube-mem: ");
 | |
| 		ube_put_lhex(mem->map[i].size);
 | |
| 		ube_puts(" @ ");
 | |
| 		ube_put_lhex(mem->map[i].start);
 | |
| 		ube_puts(" (");
 | |
| 		switch(mem->map[i].type) {
 | |
| 		case UBE_MEM_RAM:
 | |
| 			type = E820_RAM;
 | |
| 			ube_puts("ram");
 | |
| 			break;
 | |
| 		case UBE_MEM_ACPI:
 | |
| 			type = E820_ACPI;
 | |
| 			ube_puts("ACPI data");
 | |
| 			break;
 | |
| 		case UBE_MEM_NVS:
 | |
| 			type = E820_NVS;
 | |
| 			ube_puts("ACPI NVS");
 | |
| 			break;
 | |
| 		case UBE_MEM_RESERVED:
 | |
| 		default:
 | |
| 			type = E820_RESERVED;
 | |
| 			ube_puts("reserved");
 | |
| 			break;
 | |
| 		}
 | |
| 		ube_puts(")\n");
 | |
| 		add_e820_map(real_mode,
 | |
| 			mem->map[i].start, mem->map[i].size, type);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void convert_uniform_boot(struct param_info *info,
 | |
| 	struct uniform_boot_header *header)
 | |
| {
 | |
| 	/* Uniform boot environment */
 | |
| 	unsigned long env_bytes;
 | |
| 	char *env;
 | |
| 	if (header->arg_bytes) {
 | |
| 		append_command_line(info->real_mode, (void *)(header->arg), header->arg_bytes);
 | |
| 	}
 | |
| 	env = (void *)(header->env);
 | |
| 	env_bytes = header->env_bytes;
 | |
| 	while(env_bytes) {
 | |
| 		struct ube_record *record;
 | |
| 		record = (void *)env;
 | |
| 		if (record->tag == UBE_TAG_MEMORY) {
 | |
| 			if (info->need_mem_sizes) {
 | |
| 				convert_uniform_boot_memory(info->real_mode, (void *)record);
 | |
| 				info->need_mem_sizes = 0;
 | |
| 			}
 | |
| 		}
 | |
| 		env += record->size;
 | |
| 		env_bytes -= record->size;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Hardware
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| /* we're getting screwed again and again by this problem of the 8259.
 | |
|  * so we're going to leave this lying around for inclusion into
 | |
|  * crt0.S on an as-needed basis.
 | |
|  * well, that went ok, I hope. Now we have to reprogram the interrupts :-(
 | |
|  * we put them right after the intel-reserved hardware interrupts, at
 | |
|  * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
 | |
|  * messed this up with the original PC, and they haven't been able to
 | |
|  * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
 | |
|  * which is used for the internal hardware interrupts as well. We just
 | |
|  * have to reprogram the 8259's, and it isn't fun.
 | |
|  */
 | |
| 
 | |
| static void setup_i8259(void)
 | |
| {
 | |
| 	outb(0x11, 0x20);		/*! initialization sequence to 8259A-1*/
 | |
| 	outb(0x11, 0xA0);		/*! and to 8259A-2*/
 | |
| 
 | |
| 	outb(0x20, 0x21);		/*! start of hardware int's (0x20)*/
 | |
| 	outb(0x28, 0xA1);		/*! start of hardware int's 2 (0x28)*/
 | |
| 
 | |
| 	outb(0x04, 0x21);		/*! 8259-1 is master*/
 | |
| 	outb(0x02, 0xA1);		/*! 8259-2 is slave*/
 | |
| 
 | |
| 	outb(0x01, 0x21);		/*! 8086 mode for both*/
 | |
| 	outb(0x01, 0xA1);
 | |
| 
 | |
| 	outb(0xFF, 0xA1);		/*! mask off all interrupts for now*/
 | |
| 	outb(0xFB, 0x21);		/*! mask all irq's but irq2 which is cascaded*/
 | |
| }
 | |
| 
 | |
| static void hardware_setup(struct param_info *info __unused)
 | |
| {
 | |
| 	/* Disable nmi */
 | |
| 	outb(0x80, 0x70);
 | |
| 
 | |
| 	/* Make sure any coprocessor is properly reset.. */
 | |
| 	outb(0, 0xf0);
 | |
| 	outb(0, 0xf1);
 | |
| 
 | |
| 	setup_i8259();
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * ELF Boot loader
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| static int count_elf_notes(Elf_Bhdr *bhdr)
 | |
| {
 | |
| 	unsigned char *note, *end;
 | |
| 	int count;
 | |
| 	count = 0;
 | |
| 	note = ((char *)bhdr) + sizeof(*bhdr);
 | |
| 	end = ((char *)bhdr) + bhdr->b_size;
 | |
| #if 0
 | |
| 	printf("count_elf_notes %lx\n", (unsigned long)bhdr);
 | |
| #endif
 | |
| 	while (note < end) {
 | |
| 		Elf_Nhdr *hdr;
 | |
| 		unsigned char *n_name, *n_desc, *next;
 | |
| 		hdr = (Elf_Nhdr *)note;
 | |
| 		n_name = note + sizeof(*hdr);
 | |
| 		n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
 | |
| 		next = n_desc + ((hdr->n_descsz + 3) & ~3);
 | |
| #if 0
 | |
| 		printf("elf_note = %lx\n", (unsigned long)note);
 | |
| 		printf("elf_namesz = %x\n", hdr->n_namesz);
 | |
| 		printf("elf_descsz = %x\n", hdr->n_descsz);
 | |
| 		printf("elf_type   = %x\n", hdr->n_type);
 | |
| 		printf("elf_name = %lx\n", (unsigned long)n_name);
 | |
| 		printf("elf_desc = %lx\n", (unsigned long)n_desc);
 | |
| #endif
 | |
| 		if (next > end)
 | |
| 			break;
 | |
| 		count++;
 | |
| 		note = next;
 | |
| 	}
 | |
| 	return count;
 | |
| }
 | |
| 
 | |
| static Elf_Nhdr *find_elf_note(Elf_Bhdr *bhdr,
 | |
| 	Elf_Word namesz, unsigned char *name, Elf_Word type)
 | |
| {
 | |
| 	unsigned char *note, *end;
 | |
| 	note = ((char *)bhdr) + sizeof(*bhdr);
 | |
| 	end = ((char *)bhdr) + bhdr->b_size;
 | |
| 	while(note < end) {
 | |
| 		Elf_Nhdr *hdr;
 | |
| 		unsigned char *n_name, *n_desc, *next;
 | |
| 		hdr = (Elf_Nhdr *)note;
 | |
| 		n_name = note + sizeof(*hdr);
 | |
| 		n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
 | |
| 		next = n_desc + ((hdr->n_descsz + 3) & ~3);
 | |
| 		if (next > end)
 | |
| 			break;
 | |
| 		if ((hdr->n_type == type) &&
 | |
| 			(hdr->n_namesz == namesz) &&
 | |
| 			(memcmp(n_name, name, namesz) == 0)) {
 | |
| 			return hdr;
 | |
| 		}
 | |
| 		note = next;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void convert_elf_command_line(struct param_info *info,
 | |
| 	Elf_Word descsz, unsigned char *desc)
 | |
| {
 | |
| 	append_command_line(info->real_mode, desc, descsz);
 | |
| }
 | |
| 
 | |
| struct {
 | |
| 	Elf_Word namesz;
 | |
| 	unsigned char *name;
 | |
| 	Elf_Word type;
 | |
| 	void (*convert)(struct param_info *info, Elf_Word descsz, unsigned char *desc);
 | |
| } elf_notes[] =
 | |
| {
 | |
| 	{ 0, "", EBN_COMMAND_LINE, convert_elf_command_line },
 | |
| };
 | |
| 
 | |
| static void convert_elf_boot(struct param_info *info, Elf_Bhdr *bhdr)
 | |
| {
 | |
| 	unsigned char *note, *end;
 | |
| 	note = ((char *)bhdr) + sizeof(*bhdr);
 | |
| 	end = ((char *)bhdr) + bhdr->b_size;
 | |
| 	while(note < end) {
 | |
| 		Elf_Nhdr *hdr;
 | |
| 		unsigned char *n_name, *n_desc, *next;
 | |
| 		size_t i;
 | |
| 		hdr = (Elf_Nhdr *)note;
 | |
| 		n_name = note + sizeof(*hdr);
 | |
| 		n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
 | |
| 		next = n_desc + ((hdr->n_descsz + 3) & ~3);
 | |
| 		if (next > end)
 | |
| 			break;
 | |
| 		for(i = 0; i < sizeof(elf_notes)/sizeof(elf_notes[0]); i++) {
 | |
| 			if ((hdr->n_type == elf_notes[i].type) &&
 | |
| 				(hdr->n_namesz == elf_notes[i].namesz) &&
 | |
| 				(memcmp(n_name, elf_notes[i].name, elf_notes[i].namesz) == 0)) {
 | |
| 				elf_notes[i].convert(info, hdr->n_descsz, n_desc);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		note = next;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * LinuxBIOS
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| #define LB_MEM_DEBUG 0
 | |
| #if LB_MEM_DEBUG
 | |
| #define lb_puts(x) printf("%s", x)
 | |
| #define lb_put_hex(x) printf("%x", x)
 | |
| #define lb_put_lhex(x) printf("%Lx", x)
 | |
| #else
 | |
| #define lb_puts(x)
 | |
| #define lb_put_hex(x)
 | |
| #define lb_put_lhex(x)
 | |
| #endif /* LB_MEM_DEBUG */
 | |
| 
 | |
| static unsigned count_lb_records(void *start, unsigned long length)
 | |
| {
 | |
| 	struct lb_record *rec;
 | |
| 	void *end;
 | |
| 	unsigned count;
 | |
| 	count = 0;
 | |
| 	end = ((char *)start) + length;
 | |
| 	for(rec = start; ((void *)rec < end) &&
 | |
| 		(rec->size <= (unsigned long)(end - (void *)rec));
 | |
| 		rec = (void *)(((char *)rec) + rec->size)) {
 | |
| 		count++;
 | |
| 	}
 | |
| 	return count;
 | |
| }
 | |
| 
 | |
| static struct lb_header *__find_lb_table(void *start, void *end)
 | |
| {
 | |
| 	unsigned char *ptr;
 | |
| 	/* For now be stupid.... */
 | |
| 	for(ptr = start; (void *)ptr < end; ptr += 16) {
 | |
| 		struct lb_header *head = (void *)ptr;
 | |
| 		if ((head->signature[0] == 'L') &&
 | |
| 			(head->signature[1] == 'B') &&
 | |
| 			(head->signature[2] == 'I') &&
 | |
| 			(head->signature[3] == 'O') &&
 | |
| 			(head->header_bytes == sizeof(*head)) &&
 | |
| 			(compute_checksum(head, sizeof(*head)) == 0) &&
 | |
| 			(compute_checksum(ptr + sizeof(*head), head->table_bytes) ==
 | |
| 				head->table_checksum) &&
 | |
| 			(count_lb_records(ptr + sizeof(*head), head->table_bytes) ==
 | |
| 				head->table_entries)
 | |
| 			) {
 | |
| 			return head;
 | |
| 		}
 | |
| 	};
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int find_lb_table(struct param_info *info)
 | |
| {
 | |
| 	struct lb_header *head;
 | |
| 	head = 0;
 | |
| 	if (!head) {
 | |
| 		/* First try at address 0 */
 | |
| 		head = __find_lb_table((void *)0x00000, (void *)0x1000);
 | |
| 	}
 | |
| 	if (!head) {
 | |
| 		/* Then try at address 0xf0000 */
 | |
| 		head = __find_lb_table((void *)0xf0000, (void *)0x100000);
 | |
| 	}
 | |
| 	if (head) {
 | |
| 		struct lb_forward *forward = (struct lb_forward *)(((char *)head) + head->header_bytes);
 | |
| 		if (forward->tag == LB_TAG_FORWARD) {
 | |
| 			head = __find_lb_table(forward->forward,
 | |
| 					forward->forward + 0x1000);
 | |
| 		}
 | |
| 	}
 | |
| 	if (head) {
 | |
| 		info->has_linuxbios = 1;
 | |
| 		info->lb_table = head;
 | |
| 		return 1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void convert_lb_memory(struct param_info *info, struct lb_memory *mem)
 | |
| {
 | |
| 	int i;
 | |
| 	int entries;
 | |
| 	entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
 | |
| 	for(i = 0; (i < entries) && (i < E820MAX); i++) {
 | |
| 		unsigned long type;
 | |
| 		unsigned long long end;
 | |
| 		end = mem->map[i].start + mem->map[i].size;
 | |
| 		lb_puts("lb-mem: ");
 | |
| 		lb_put_lhex(mem->map[i].start);
 | |
| 		lb_puts(" - ");
 | |
| 		lb_put_lhex(end);
 | |
| 		lb_puts(" (");
 | |
| 		switch(mem->map[i].type) {
 | |
| 		case LB_MEM_RAM:
 | |
| 			type = E820_RAM;
 | |
| 			lb_puts("ram");
 | |
| 			break;
 | |
| 		default:
 | |
| 			type = E820_RESERVED;
 | |
| 			lb_puts("reserved");
 | |
| 			break;
 | |
| 		}
 | |
| 		lb_puts(")\n");
 | |
| 		add_e820_map(info->real_mode,
 | |
| 			mem->map[i].start, mem->map[i].size, type);
 | |
| 	}
 | |
| 	info->need_mem_sizes = 0;
 | |
| }
 | |
| 
 | |
| static void query_lb_values(struct param_info *info)
 | |
| {
 | |
| 	struct lb_header *head;
 | |
| 	struct lb_record *rec;
 | |
| 	void *start, *end;
 | |
| 	head = info->lb_table;
 | |
| 	start = ((unsigned char *)head) + sizeof(*head);
 | |
| 	end = ((char *)start) + head->table_bytes;
 | |
| 	for(rec = start; ((void *)rec < end) &&
 | |
| 		(rec->size <= (unsigned long)(end - (void *)rec));
 | |
| 		rec = (void *)(((char *)rec) + rec->size)) {
 | |
| 		switch(rec->tag) {
 | |
| 		case LB_TAG_MEMORY:
 | |
| 		{
 | |
| 			struct lb_memory *mem;
 | |
| 			mem = (struct lb_memory *) rec;
 | |
| 			convert_lb_memory(info, mem);
 | |
| 			break;
 | |
| 		}
 | |
| 		default:
 | |
| 			break;
 | |
| 		};
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * PCBIOS
 | |
|  * =============================================================================
 | |
|  */
 | |
| #define PC_MEM_DEBUG 0
 | |
| #if PC_MEM_DEBUG
 | |
| #define pc_puts(x) printf("%s", x)
 | |
| #define pc_put_hex(x) printf("%x", x)
 | |
| #define pc_put_lhex(x) printf("%Lx", x)
 | |
| #else
 | |
| #define pc_puts(x)
 | |
| #define pc_put_hex(x)
 | |
| #define pc_put_lhex(x)
 | |
| #endif /* PC_MEM_DEBUG */
 | |
| 
 | |
| /* functions for querying the pcbios */
 | |
| extern void noop(void); /* for testing purposes only */
 | |
| extern int meme820(struct e820entry *buf, int count);
 | |
| extern unsigned int meme801(void);
 | |
| extern unsigned short mem88(void);
 | |
| extern unsigned short basememsize(void);
 | |
| 
 | |
| struct meminfo {
 | |
| 	int map_count;
 | |
| 	struct e820entry map[E820MAX];
 | |
| };
 | |
| 
 | |
| static struct meminfo meminfo;
 | |
| static void get_meminfo(struct param_info *info)
 | |
| {
 | |
| 	int i;
 | |
| 	pc_puts("getting meminfo...\n");
 | |
| 	meminfo.map_count = meme820(meminfo.map, E820MAX);
 | |
| 	pc_puts("got meminfo count="); pc_put_hex(meminfo.map_count); pc_puts("\n");
 | |
| 	for(i = 0; i < meminfo.map_count; i++) {
 | |
| 		unsigned long long end;
 | |
| 		struct e820entry *seg = meminfo.map + i;
 | |
| 		end = seg->addr + seg->size;
 | |
| 		pc_puts("BIOS-e820: ");
 | |
| 		pc_put_lhex(seg->addr);
 | |
| 		pc_puts(" - ");
 | |
| 		pc_put_lhex(end);
 | |
| 		pc_puts(" (");
 | |
| 		switch(seg->type) {
 | |
| 		case E820_RAM:
 | |
| 			pc_puts("ram");
 | |
| 			info->need_mem_sizes = 0;
 | |
| 			break;
 | |
| 		case E820_ACPI:
 | |
| 			pc_puts("ACPI data");
 | |
| 			break;
 | |
| 		case E820_NVS:
 | |
| 			pc_puts("ACPI NVS");
 | |
| 			break;
 | |
| 		case E820_RESERVED:
 | |
| 		default:
 | |
| 			pc_puts("reserved");
 | |
| 			break;
 | |
| 		}
 | |
| 		pc_puts(")\n");
 | |
| 		add_e820_map(info->real_mode,
 | |
| 			seg->addr, seg->size, seg->type);
 | |
| 	}
 | |
| 	info->real_mode->alt_mem_k = meme801();
 | |
| 	info->real_mode->ext_mem_k = mem88();
 | |
| 	if (info->real_mode->alt_mem_k || info->real_mode->ext_mem_k) {
 | |
| 		info->need_mem_sizes = 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void query_pcbios_values(struct param_info *info)
 | |
| {
 | |
| 	get_meminfo(info);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Bootloaders
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| 
 | |
| static void query_bootloader_param_class(struct param_info *info)
 | |
| {
 | |
| 	int has_bootloader_type = 0;
 | |
| 	Elf_Bhdr *hdr = 0;
 | |
| 	if (!has_bootloader_type && (info->type == 0x2BADB002)) {
 | |
| 		/* Orignal multiboot specification */
 | |
| 		info->has_multiboot = 1;
 | |
| 		has_bootloader_type = 1;
 | |
| 	}
 | |
| 	if (!has_bootloader_type && (info->type == 0x0A11B007)) {
 | |
| 		/* Uniform boot proposal */
 | |
| 		unsigned long checksum;
 | |
| 		struct uniform_boot_header *header;
 | |
| 		header = info->data;
 | |
| 		checksum = compute_checksum(header, header->header_bytes);
 | |
| 		if (checksum == 0) {
 | |
| 			info->has_uniform_boot = 1;
 | |
| 			has_bootloader_type = 1;
 | |
| 		} else{
 | |
| 			printf("Bad uniform boot header checksum!\n");
 | |
| 		}
 | |
| 	}
 | |
| 	if (info->type == ELF_BHDR_MAGIC) {
 | |
| 		hdr = info->data;
 | |
| 	}
 | |
| 	if (info->param && (info->param->b_signature == ELF_BHDR_MAGIC)) {
 | |
| 		hdr = info->param;
 | |
| 	}
 | |
| 	if (!has_bootloader_type && hdr) {
 | |
| 		/* Good ELF boot proposal... */
 | |
| 		unsigned long checksum;
 | |
| 		int count;
 | |
| 		checksum = 0;
 | |
| 		if (hdr->b_checksum != 0) {
 | |
| 			checksum = compute_checksum(hdr, hdr->b_size);
 | |
| 		}
 | |
| 		count = count_elf_notes(hdr);
 | |
| 		if ((hdr->b_signature == ELF_BHDR_MAGIC) &&
 | |
| 			(checksum == 0) &&
 | |
| 			hdr->b_records == count) {
 | |
| 			info->has_elf_boot = 1;
 | |
| 			info->param = hdr;
 | |
| 			has_bootloader_type = 1;
 | |
| 		}
 | |
| 		else {
 | |
| 			printf("Bad ELF parameter table!\n");
 | |
| 			printf("   checksum = %x\n", checksum);
 | |
| 			printf("      count = %x\n", count);
 | |
| 			printf("        hdr = %x\n", (unsigned long)hdr);
 | |
| 			printf("     b_size = %x\n", hdr->b_size);
 | |
| 			printf("b_signature = %x\n", hdr->b_signature);
 | |
| 			printf("  b_records = %x\n", hdr->b_records);
 | |
| 		}
 | |
| 	}
 | |
| 	if (!has_bootloader_type) {
 | |
| 		printf("Unknown bootloader class!\n");
 | |
| 		printf("type=%x\n", info->type);
 | |
| 		printf("data=%x\n", (unsigned)info->data);
 | |
| 		printf("param=%x\n", (unsigned)info->param);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void query_bootloader_values(struct param_info *info)
 | |
| {
 | |
| 	if (info->has_multiboot) {
 | |
| 		convert_multiboot(info, info->data);
 | |
| 	}
 | |
| 	else if (info->has_uniform_boot) {
 | |
| 		convert_uniform_boot(info, info->data);
 | |
| 	}
 | |
| 	else if (info->has_elf_boot) {
 | |
| 		convert_elf_boot(info, info->param);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Firmware
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| static int bootloader_query_firmware_class(struct param_info *info)
 | |
| {
 | |
| 	Elf_Nhdr *hdr;
 | |
| 	unsigned char *note, *n_name, *n_desc;
 | |
| 	int detected_firmware_type;
 | |
| 	if (!info->has_elf_boot) {
 | |
| 		/* Only the elf boot tables gives us a firmware type */
 | |
| 		return 0;
 | |
| 	}
 | |
| 	detected_firmware_type = 0;
 | |
| 	n_desc = 0;
 | |
| 
 | |
| 	hdr = find_elf_note(info->param, 0, 0, EBN_FIRMWARE_TYPE);
 | |
| 	if (!hdr) {
 | |
| 		/* If I'm not explicitly told the firmware type
 | |
| 		 * do my best to guess it for myself.
 | |
| 		 */
 | |
| 		detected_firmware_type = 0;
 | |
| 	} else {
 | |
| 		note = (char *)hdr;
 | |
| 		n_name = note + sizeof(*hdr);
 | |
| 		n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
 | |
| 	}
 | |
| 	if (!detected_firmware_type && hdr &&
 | |
| 		(hdr->n_descsz == 7) &&
 | |
| 		(memcmp(n_desc, "PCBIOS", 7) == 0)) {
 | |
| 		info->has_pcbios = 1;
 | |
| 		detected_firmware_type = 1;
 | |
| 	}
 | |
| 	if (!detected_firmware_type && hdr &&
 | |
| 		(hdr->n_descsz == 10) &&
 | |
| 		(memcmp(n_desc, "LinuxBIOS", 10) == 0)) {
 | |
| 		/* Don't believe I'm linuxBIOS unless I can
 | |
| 		 * find the linuxBIOS table..
 | |
| 		 */
 | |
| 		detected_firmware_type = find_lb_table(info);
 | |
| 	}
 | |
| 	if (!detected_firmware_type && hdr &&
 | |
| 		(hdr->n_descsz == 0)) {
 | |
| 		/* No firmware is present */
 | |
| 		detected_firmware_type = 1;
 | |
| 	}
 | |
| 	if (!detected_firmware_type && hdr &&
 | |
| 		(hdr->n_descsz == 1) &&
 | |
| 		(memcmp(n_desc, "", 1) == 0)) {
 | |
| 		/* No firmware is present */
 | |
| 		detected_firmware_type = 1;
 | |
| 	}
 | |
| 	if (!detected_firmware_type && hdr) {
 | |
| 		printf("Unknown firmware type: %s\n", n_desc);
 | |
| 	}
 | |
| 	return detected_firmware_type;
 | |
| }
 | |
| 
 | |
| static void query_firmware_class(struct param_info *info)
 | |
| {
 | |
| 	int detected_firmware_type = 0;
 | |
| 
 | |
| 	/* First say I have no firmware at all... */
 | |
| 	info->has_pcbios = 0;
 | |
| 	info->has_linuxbios = 0;
 | |
| 
 | |
| 	/* See if the bootloader has told us what
 | |
| 	 * kind of firmware we are running on.
 | |
| 	 */
 | |
| 	detected_firmware_type = bootloader_query_firmware_class(info);
 | |
| 
 | |
| 	/* See if we can detect linuxbios. */
 | |
| 	if (!detected_firmware_type) {
 | |
| 		detected_firmware_type = find_lb_table(info);
 | |
| 	}
 | |
| 
 | |
| 	if (!detected_firmware_type) {
 | |
| 		/* if all else fails assume a standard pcbios... */
 | |
| 		info->has_pcbios = 1;
 | |
| 	}
 | |
| 
 | |
| 	/* Now print out the firmware type... */
 | |
| 	printf("Firmware type:");
 | |
| 	if (info->has_linuxbios) {
 | |
| 		printf(" LinuxBIOS");
 | |
| 	}
 | |
| 	if (info->has_pcbios) {
 | |
| 		printf(" PCBIOS");
 | |
| 	}
 | |
| 	printf("\n");
 | |
| }
 | |
| 
 | |
| static void query_firmware_values(struct param_info *info)
 | |
| {
 | |
| 	if (info->has_linuxbios) {
 | |
| 		query_lb_values(info);
 | |
| 	}
 | |
| 	if (info->has_pcbios) {
 | |
| 		query_pcbios_values(info);
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Debug
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| #if 0
 | |
| static void print_offsets(void)
 | |
| {
 | |
| 	struct parameters *real_mode = 0;
 | |
| 	printf("print_offsets\n");
 | |
| 
 | |
| 	printf("orig_x               =%x\n", (uint32_t)&real_mode->orig_x);
 | |
| 	printf("orig_y               =%x\n", (uint32_t)&real_mode->orig_y);
 | |
| 	printf("ext_mem_k            =%x\n", (uint32_t)&real_mode->ext_mem_k);
 | |
| 	printf("orig_video_page      =%x\n", (uint32_t)&real_mode->orig_video_page);
 | |
| 	printf("orig_video_mode      =%x\n", (uint32_t)&real_mode->orig_video_mode);
 | |
| 	printf("orig_video_cols      =%x\n", (uint32_t)&real_mode->orig_video_cols);
 | |
| 	printf("unused2              =%x\n", (uint32_t)&real_mode->unused2);
 | |
| 	printf("orig_video_ega_bx    =%x\n", (uint32_t)&real_mode->orig_video_ega_bx);
 | |
| 	printf("unused3              =%x\n", (uint32_t)&real_mode->unused3);
 | |
| 	printf("orig_video_lines     =%x\n", (uint32_t)&real_mode->orig_video_lines);
 | |
| 	printf("orig_video_isVGA     =%x\n", (uint32_t)&real_mode->orig_video_isVGA);
 | |
| 	printf("orig_video_points    =%x\n", (uint32_t)&real_mode->orig_video_points);
 | |
| 	printf("lfb_width            =%x\n", (uint32_t)&real_mode->lfb_width);
 | |
| 	printf("lfb_height           =%x\n", (uint32_t)&real_mode->lfb_height);
 | |
| 	printf("lfb_depth            =%x\n", (uint32_t)&real_mode->lfb_depth);
 | |
| 	printf("lfb_base             =%x\n", (uint32_t)&real_mode->lfb_base);
 | |
| 	printf("lfb_size             =%x\n", (uint32_t)&real_mode->lfb_size);
 | |
| 	printf("cl_magic             =%x\n", (uint32_t)&real_mode->cl_magic);
 | |
| 	printf("cl_offset            =%x\n", (uint32_t)&real_mode->cl_offset);
 | |
| 	printf("lfb_linelength       =%x\n", (uint32_t)&real_mode->lfb_linelength);
 | |
| 	printf("red_size             =%x\n", (uint32_t)&real_mode->red_size);
 | |
| 	printf("red_pos              =%x\n", (uint32_t)&real_mode->red_pos);
 | |
| 	printf("green_size           =%x\n", (uint32_t)&real_mode->green_size);
 | |
| 	printf("green_pos            =%x\n", (uint32_t)&real_mode->green_pos);
 | |
| 	printf("blue_size            =%x\n", (uint32_t)&real_mode->blue_size);
 | |
| 	printf("blue_pos             =%x\n", (uint32_t)&real_mode->blue_pos);
 | |
| 	printf("rsvd_size            =%x\n", (uint32_t)&real_mode->rsvd_size);
 | |
| 	printf("rsvd_pos             =%x\n", (uint32_t)&real_mode->rsvd_pos);
 | |
| 	printf("vesapm_seg           =%x\n", (uint32_t)&real_mode->vesapm_seg);
 | |
| 	printf("vesapm_off           =%x\n", (uint32_t)&real_mode->vesapm_off);
 | |
| 	printf("pages                =%x\n", (uint32_t)&real_mode->pages);
 | |
| 	printf("reserved4            =%x\n", (uint32_t)&real_mode->reserved4);
 | |
| 	printf("apm_bios_info        =%x\n", (uint32_t)&real_mode->apm_bios_info);
 | |
| 	printf("drive_info           =%x\n", (uint32_t)&real_mode->drive_info);
 | |
| 	printf("sys_desc_table       =%x\n", (uint32_t)&real_mode->sys_desc_table);
 | |
| 	printf("alt_mem_k            =%x\n", (uint32_t)&real_mode->alt_mem_k);
 | |
| 	printf("reserved5            =%x\n", (uint32_t)&real_mode->reserved5);
 | |
| 	printf("e820_map_nr          =%x\n", (uint32_t)&real_mode->e820_map_nr);
 | |
| 	printf("reserved6            =%x\n", (uint32_t)&real_mode->reserved6);
 | |
| 	printf("mount_root_rdonly    =%x\n", (uint32_t)&real_mode->mount_root_rdonly);
 | |
| 	printf("reserved7            =%x\n", (uint32_t)&real_mode->reserved7);
 | |
| 	printf("ramdisk_flags        =%x\n", (uint32_t)&real_mode->ramdisk_flags);
 | |
| 	printf("reserved8            =%x\n", (uint32_t)&real_mode->reserved8);
 | |
| 	printf("orig_root_dev        =%x\n", (uint32_t)&real_mode->orig_root_dev);
 | |
| 	printf("reserved9            =%x\n", (uint32_t)&real_mode->reserved9);
 | |
| 	printf("aux_device_info      =%x\n", (uint32_t)&real_mode->aux_device_info);
 | |
| 	printf("reserved10           =%x\n", (uint32_t)&real_mode->reserved10);
 | |
| 	printf("param_block_signature=%x\n", (uint32_t)&real_mode->param_block_signature);
 | |
| 	printf("param_block_version  =%x\n", (uint32_t)&real_mode->param_block_version);
 | |
| 	printf("reserved11           =%x\n", (uint32_t)&real_mode->reserved11);
 | |
| 	printf("loader_type          =%x\n", (uint32_t)&real_mode->loader_type);
 | |
| 	printf("loader_flags         =%x\n", (uint32_t)&real_mode->loader_flags);
 | |
| 	printf("reserved12           =%x\n", (uint32_t)&real_mode->reserved12);
 | |
| 	printf("kernel_start         =%x\n", (uint32_t)&real_mode->kernel_start);
 | |
| 	printf("initrd_start         =%x\n", (uint32_t)&real_mode->initrd_start);
 | |
| 	printf("initrd_size          =%x\n", (uint32_t)&real_mode->initrd_size);
 | |
| 	printf("reserved13           =%x\n", (uint32_t)&real_mode->reserved13);
 | |
| 	printf("e820_map             =%x\n", (uint32_t)&real_mode->e820_map);
 | |
| 	printf("reserved16           =%x\n", (uint32_t)&real_mode->reserved16);
 | |
| 	printf("command_line         =%x\n", (uint32_t)&real_mode->command_line);
 | |
| 	printf("reserved17           =%x\n", (uint32_t)&real_mode->reserved17);
 | |
| }
 | |
| 
 | |
| static void print_linux_params(struct param_info *info)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	printf("print_linux_params\n");
 | |
| 	/* Default screen size */
 | |
| 	printf("orig_x           =%x\n", info->real_mode->orig_x);
 | |
| 	printf("orig_y           =%x\n", info->real_mode->orig_y);
 | |
| 	printf("orig_video_page  =%x\n", info->real_mode->orig_video_page);
 | |
| 	printf("orig_video_mode  =%x\n", info->real_mode->orig_video_mode);
 | |
| 	printf("orig_video_cols  =%x\n", info->real_mode->orig_video_cols);
 | |
| 	printf("orig_video_lines =%x\n", info->real_mode->orig_video_lines);
 | |
| 	printf("orig_video_ega_bx=%x\n", info->real_mode->orig_video_ega_bx);
 | |
| 	printf("orig_video_isVGA =%x\n", info->real_mode->orig_video_isVGA);
 | |
| 	printf("orig_video_points=%x\n", info->real_mode->orig_video_points);
 | |
| 
 | |
| 
 | |
| 	/* System descriptor table... */
 | |
| 	printf("sys_dest_table_len=%x\n", info->real_mode->sys_desc_table.length);
 | |
| 
 | |
| 	/* Memory sizes */
 | |
| 	printf("ext_mem_k        =%x\n", info->real_mode->ext_mem_k);
 | |
| 	printf("alt_mem_k        =%x\n", info->real_mode->alt_mem_k);
 | |
| 	printf("e820_map_nr      =%x\n", info->real_mode->e820_map_nr);
 | |
| 	for(i = 0; i < E820MAX; i++) {
 | |
| 		printf("addr[%x]         =%Lx\n",
 | |
| 			i,  info->real_mode->e820_map[i].addr);
 | |
| 		printf("size[%x]         =%Lx\n",
 | |
| 			i, info->real_mode->e820_map[i].size);
 | |
| 		printf("type[%x]         =%Lx\n",
 | |
| 			i, info->real_mode->e820_map[i].type);
 | |
| 	}
 | |
| 	printf("mount_root_rdonly=%x\n", info->real_mode->mount_root_rdonly);
 | |
| 	printf("ramdisk_flags    =%x\n", info->real_mode->ramdisk_flags);
 | |
| 	printf("orig_root_dev    =%x\n", info->real_mode->orig_root_dev);
 | |
| 	printf("aux_device_info  =%x\n", info->real_mode->aux_device_info);
 | |
| 	printf("param_block_signature=%x\n", *((uint32_t *)info->real_mode->param_block_signature));
 | |
| 	printf("loader_type      =%x\n", info->real_mode->loader_type);
 | |
| 	printf("loader_flags     =%x\n", info->real_mode->loader_flags);
 | |
| 	printf("initrd_start     =%x\n", info->real_mode->initrd_start);
 | |
| 	printf("initrd_size      =%x\n", info->real_mode->initrd_size);
 | |
| 
 | |
| 	/* Where I'm putting the command line */
 | |
| 	printf("cl_magic         =%x\n", info->real_mode->cl_magic);
 | |
| 	printf("cl_offset        =%x\n", info->real_mode->cl_offset);
 | |
| 
 | |
| 	/* Now print the command line */
 | |
| 	printf("command_line     =%s\n", info->real_mode->command_line);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * main
 | |
|  * =============================================================================
 | |
|  */
 | |
| 
 | |
| void initialize_linux_params(struct param_info *info)
 | |
| {
 | |
| 	int len;
 | |
| 	/* First the defaults */
 | |
| 	memset(info->real_mode, 0, PAGE_SIZE);
 | |
| 
 | |
| 	/* Default screen size */
 | |
| 	info->real_mode->orig_x = 0;
 | |
| 	info->real_mode->orig_y = 25;
 | |
| 	info->real_mode->orig_video_page = 0;
 | |
| 	info->real_mode->orig_video_mode = 0;
 | |
| 	info->real_mode->orig_video_cols = 80;
 | |
| 	info->real_mode->orig_video_lines = 25;
 | |
| 	info->real_mode->orig_video_ega_bx = 0;
 | |
| 	info->real_mode->orig_video_isVGA = 1;
 | |
| 	info->real_mode->orig_video_points = 16;
 | |
| 
 | |
| 	/* Fill this in later */
 | |
| 	info->real_mode->ext_mem_k = 0;
 | |
| 
 | |
| 	/* Fill in later... */
 | |
| 	info->real_mode->e820_map_nr = 0;
 | |
| 
 | |
| 	/* Where I'm putting the command line */
 | |
| 	info->real_mode->cl_magic = CL_MAGIC_VALUE;
 | |
| 	info->real_mode->cl_offset = 2048;
 | |
| 
 | |
| 	info->real_mode->cmd_line_ptr = info->real_mode->cl_offset + (unsigned long) info->real_mode;
 | |
| 
 | |
| 	/* Now set the command line */
 | |
| 	len = strnlen(info->image->cmdline, sizeof(info->real_mode->command_line) -1);
 | |
| 	memcpy(info->real_mode->command_line, info->image->cmdline, len);
 | |
| 	info->real_mode->command_line[len] = '\0';
 | |
| 
 | |
| 	/* from the bios initially */
 | |
| 	memset(&info->real_mode->apm_bios_info, 0, sizeof(info->real_mode->apm_bios_info));
 | |
| 
 | |
| 	memset(&info->real_mode->drive_info, 0, sizeof(info->real_mode->drive_info));
 | |
| 
 | |
| 	/* forget it for now... */
 | |
| 	info->real_mode->sys_desc_table.length = 0;
 | |
| 
 | |
| 	/* Fill this in later */
 | |
| 	info->real_mode->alt_mem_k = 0;
 | |
| 	info->real_mode->ext_mem_k = 0;
 | |
| 
 | |
| 	/* default yes: this can be overridden on the command line */
 | |
| 	info->real_mode->mount_root_rdonly = 0xFFFF;
 | |
| 
 | |
| 	/* old ramdisk options, These really should be command line
 | |
| 	 * things...
 | |
| 	 */
 | |
| 	info->real_mode->ramdisk_flags = info->image->ramdisk_flags;
 | |
| 
 | |
| 	/* default to /dev/hda.
 | |
| 	 * Override this on the command line if necessary
 | |
| 	 */
 | |
| 	info->real_mode->orig_root_dev = info->image->root_dev;
 | |
| 
 | |
| 	/* Originally from the bios? */
 | |
| 	info->real_mode->aux_device_info = 0;
 | |
| 
 | |
| 	/* Boot block magic */
 | |
| 	memcpy(info->real_mode->param_block_signature, "HdrS", 4);
 | |
| 	info->real_mode->param_block_version = 0x0201;
 | |
| 
 | |
| 	/* Say I'm a kernel boot loader */
 | |
| 	info->real_mode->loader_type = (LOADER_TYPE_KERNEL << 4) + 0 /* version */;
 | |
| 
 | |
| 	/* No loader flags */
 | |
| 	info->real_mode->loader_flags = 0;
 | |
| 
 | |
| 	/* Ramdisk address and size ... */
 | |
| 	info->real_mode->initrd_start = 0;
 | |
| 	info->real_mode->initrd_size = 0;
 | |
| 	if (info->image->initrd_size) {
 | |
| 		info->real_mode->initrd_start = info->image->initrd_start;
 | |
| 		info->real_mode->initrd_size = info->image->initrd_size;
 | |
| 	}
 | |
| 
 | |
| 	/* Now remember those things that I need */
 | |
| 	info->need_mem_sizes = 1;
 | |
| }
 | |
| 
 | |
| void *convert_params(unsigned type, void *data, void *param, void *image)
 | |
| {
 | |
| 	struct param_info info;
 | |
| #if 0
 | |
| 	printf("hello world\n");
 | |
| #endif
 | |
| 	info.real_mode = faked_real_mode;
 | |
| 	info.type  = type;
 | |
| 	info.data  = data;
 | |
| 	info.param = param;
 | |
| 	info.image = image;
 | |
| 	initialize_linux_params(&info);
 | |
| 	query_bootloader_param_class(&info);
 | |
| 	query_firmware_class(&info);
 | |
| 	query_firmware_values(&info);
 | |
| 	query_bootloader_values(&info);
 | |
| 
 | |
| 	/* Do the hardware setup that linux might forget... */
 | |
| 	hardware_setup(&info);
 | |
| 
 | |
| 	/* Print some debugging information */
 | |
| #if 0
 | |
| 	printf("EXT_MEM_K=%x\n", info.real_mode->ext_mem_k);
 | |
| 	printf("ALT_MEM_K=%x\n", info.real_mode->alt_mem_k);
 | |
| #endif
 | |
| #if 0
 | |
| 	print_offsets();
 | |
| 	print_linux_params(&info);
 | |
| #endif
 | |
| #if 0
 | |
| 	printf("info.real_mode = 0x%x\n", info.real_mode );
 | |
| 	printf("Jumping to Linux\n");
 | |
| #endif
 | |
| 	return info.real_mode;
 | |
| }
 | |
| 
 |