1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
|
#include "stdint.h"
#include "limits.h"
#include <stdarg.h>
#include "elf.h"
#include "elf_boot.h"
#include "convert.h"
/* NOTE be very careful with static variables. No relocations are
* being performed so static variables with initialized pointers will
* point to the wrong locations, unless this file is loaded at just
* the right location.
*/
/* Data and functions in head.S */
extern void uart_tx_byte(int c);
static void putchar(int c)
{
if (c == '\n') {
putchar('\r');
}
#if 0
uart_tx_byte(c);
#endif
}
#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_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 h;
int ncase;
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 > 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);
}
void *memcpy(void *vdest, void *vsrc, size_t size)
{
unsigned char *dest = vdest, *src = vsrc;
size_t i;
for(i = 0; i < size; i++) {
*dest++ = *src++;
}
return dest;
}
int memcmp(void *vs1, void *vs2, size_t size)
{
unsigned char *s1 =vs1, *s2=vs2;
size_t i;
for(i = 0; i < size; i++, s1++, s2++) {
if (*s1 != *s2)
return *s1 - *s2;
}
return 0;
}
void strappend(char *dest, const char *src, size_t max)
{
size_t len, i;
/* Walk to the end of the destination string */
for(len = 0; len < max; len++) {
if (dest[len] == '\0')
break;
}
/* Walk through the source string and append it */
for(i = 0; (i + len) < max; i++) {
if (src[i] == '\0')
break;
dest[len + i] = src[i];
}
len = len + i;
/* Now null terminate the string */
if (len >= max) {
len = max -1;
}
dest[len] = '\0';
}
static struct ia64_boot_param {
uint64_t command_line; /* physical address of command line arguments */
uint64_t efi_systab; /* physical address of EFI system table */
uint64_t efi_memmap; /* physical address of EFI memory map */
uint64_t efi_memmap_size; /* size of EFI memory map */
uint64_t efi_memdesc_size; /* size of an EFI memory map descriptor */
uint32_t efi_memdesc_version; /* memory descriptor version */
struct {
uint16_t num_cols; /* number of columns on console output device */
uint16_t num_rows; /* number of rows on console output device */
uint16_t orig_x; /* cursor's x position */
uint16_t orig_y; /* cursor's y position */
} console_info;
uint64_t fpswa; /* physical address of the fpswa interface */
uint64_t initrd_start;
uint64_t initrd_size;
} bp = { 0, 0, 0, 0, 0, 0, { 80, 24, 0, 0 }, 0, 0, 0 };
static void append_command_line(char *arg)
{
strappend((char *)bp.command_line, " ", CMDLINE_MAX);
strappend((char *)bp.command_line, arg, CMDLINE_MAX);
}
static void convert_ia64_boot_params(struct ia64_boot_param *orig_bp)
{
/* Copy the parameters I have no clue about */
bp.efi_systab = orig_bp->efi_systab;
bp.efi_memmap = orig_bp->efi_memmap;
bp.efi_memmap_size = orig_bp->efi_memmap_size;
bp.efi_memdesc_size = orig_bp->efi_memdesc_size;
bp.efi_memdesc_version = orig_bp->efi_memdesc_version;
bp.console_info.num_cols = orig_bp->console_info.num_cols;
bp.console_info.num_rows = orig_bp->console_info.num_rows;
bp.console_info.orig_x = orig_bp->console_info.orig_x;
bp.console_info.orig_y = orig_bp->console_info.orig_y;
bp.fpswa = orig_bp->fpswa;
/* If a ramdisk was supplied and I didn't original have one,
* use it.
*/
if (orig_bp->initrd_size && (!bp.initrd_size)) {
bp.initrd_start = orig_bp->initrd_start;
bp.initrd_size = orig_bp->initrd_size;
}
/* If a command line was supplied append it */
if (orig_bp->command_line) {
append_command_line((char *)(orig_bp->command_line));
}
}
static void convert_bhdr_params(Elf_Bhdr *bhdr)
{
unsigned char *note, *end;
char *ldr_name, *ldr_version, *firmware;
ldr_name = ldr_version = firmware = 0;
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 0
printf("n_type: %x n_name(%d): n_desc(%d): \n",
hdr->n_type, hdr->n_namesz, hdr->n_descsz);
#endif
if (hdr->n_namesz == 0) {
switch(hdr->n_type) {
case EBN_FIRMWARE_TYPE:
firmware = n_desc;
break;
case EBN_BOOTLOADER_NAME:
ldr_name = n_desc;
break;
case EBN_BOOTLOADER_VERSION:
ldr_version = n_desc;
break;
case EBN_COMMAND_LINE:
append_command_line(n_desc);
break;
}
}
else if ((hdr->n_namesz == 10) &&
(memcmp(n_name, "Etherboot", 10) == 0)) {
switch(hdr->n_type) {
case EB_IA64_SYSTAB:
{
uint64_t *systabp = (void *)n_desc;
bp.efi_systab = *systabp;
break;
}
case EB_IA64_FPSWA:
{
uint64_t *fpswap = (void *)n_desc;
bp.fpswa = *fpswap;
break;
}
case EB_IA64_CONINFO:
memcpy(&bp.console_info, n_desc, sizeof(bp.console_info));
break;
case EB_IA64_MEMMAP:
{
struct efi_mem_map {
uint64_t map_size;
uint64_t map_key;
uint64_t descriptor_size;
uint64_t descriptor_version;
uint8_t map[40];
} *map = (void *)n_desc;
bp.efi_memmap = (uint64_t)&map->map;
bp.efi_memmap_size = map->map_size;
bp.efi_memdesc_size = map->descriptor_size;
bp.efi_memdesc_version = map->descriptor_version;
break;
}
}
}
note = next;
}
if (ldr_name && ldr_version) {
printf("Loader: %s version: %s\n",
ldr_name, ldr_version);
}
if (firmware) {
printf("Firmware: %s\n",
firmware);
}
}
void *convert_params(unsigned long arg1, unsigned long r28,
struct image_parameters *params)
{
struct ia64_boot_param *orig_bp;
Elf_Bhdr *bhdr = (Elf_Bhdr*)arg1;
/* handle the options I can easily deal with */
bp.command_line = (unsigned long)¶ms->cmdline;
bp.initrd_start = params->initrd_start;
bp.initrd_size = params->initrd_size;
orig_bp = (struct ia64_boot_param *)r28;
if (bhdr->b_signature == 0x0E1FB007) {
convert_bhdr_params(bhdr);
}
else {
convert_ia64_boot_params(orig_bp);
}
return &bp;
}
|