blob: fb1d76506d9aebd7dafde1cc1851f4b826899cd2 [file] [log] [blame]
/*
* bootstub 32 bit entry setting routings
*
* Copyright (C) 2008-2010 Intel Corporation.
* Author: Alek Du <alek.du@intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "types.h"
#include "bootstub.h"
#include "bootparam.h"
#include "spi-uart.h"
#include "sfi.h"
#define bs_printk(x) { if (! *(int *)SPI_UART_SUPPRESSION) bs_spi_printk(x);}
extern int no_uart_used;
static void *memcpy(void *dest, const void *src, size_t count)
{
char *tmp = dest;
const char *s = src;
size_t _count = count / 4;
while (_count--) {
*(long *)tmp = *(long *)s;
tmp += 4;
s += 4;
}
count %= 4;
while (count--)
*tmp++ = *s++;
return dest;
}
static void *memset(void *s, unsigned char c, size_t count)
{
char *xs = s;
size_t _count = count / 4;
unsigned long _c = c << 24 | c << 16 | c << 8 | c;
while (_count--) {
*(long *)xs = _c;
xs += 4;
}
count %= 4;
while (count--)
*xs++ = c;
return s;
}
static size_t strnlen(const char *s, size_t maxlen)
{
const char *es = s;
while (*es && maxlen) {
es++;
maxlen--;
}
return (es - s);
}
static void setup_boot_params(struct boot_params *bp, struct setup_header *sh)
{
u8 *initramfs;
int nr_entries;
memset(bp, 0, sizeof (struct boot_params));
bp->screen_info.orig_video_mode = 0;
bp->screen_info.orig_video_lines = 0;
bp->screen_info.orig_video_cols = 0;
bp->alt_mem_k = 128*1024; // hard coded 128M mem here, since SFI will override it
memcpy(&bp->hdr, sh, sizeof (struct setup_header));
bp->hdr.cmd_line_ptr = CMDLINE_OFFSET;
bp->hdr.cmdline_size = strnlen((const char *)CMDLINE_OFFSET, CMDLINE_SIZE);
bp->hdr.type_of_loader = 0xff; //bootstub is unknown bootloader for kernel :)
bp->hdr.ramdisk_size = *(u32 *)INITRD_SIZE_OFFSET;
bp->hdr.ramdisk_image = (bp->alt_mem_k*1024 - bp->hdr.ramdisk_size) & 0xFFFFF000;
bp->hdr.hardware_subarch = X86_SUBARCH_MRST;
initramfs = (u8 *)BZIMAGE_OFFSET + *(u32 *)BZIMAGE_SIZE_OFFSET;
if (*initramfs) {
bs_printk("Relocating initramfs to high memory ...\n");
memcpy((u8*)bp->hdr.ramdisk_image, initramfs, bp->hdr.ramdisk_size);
} else {
bs_printk("Won't relocate initramfs, are you in SLE?\n");
}
if (mid_identify_cpu() == MID_CPU_CHIP_VALLEYVIEW2) {
nr_entries = get_e820_by_bios(bp->e820_map);
bp->e820_entries = (nr_entries > 0) ? nr_entries : 0;
} else {
sfi_setup_e820(bp);
}
}
static int get_32bit_entry(unsigned char *ptr)
{
while (1){
if (*(u32 *)ptr == SETUP_SIGNATURE && *(u32 *)(ptr+4) == 0)
break;
ptr++;
}
ptr+=4;
return (((unsigned int)ptr+511)/512)*512;
}
static inline void cpuid(u32 op, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
{
*eax = op;
*ecx = 0;
asm volatile("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
enum cpuid_regs {
CR_EAX = 0,
CR_ECX,
CR_EDX,
CR_EBX
};
int mid_identify_cpu(void)
{
u32 regs[4];
cpuid(1, &regs[CR_EAX], &regs[CR_EBX], &regs[CR_ECX], &regs[CR_EDX]);
switch ( regs[CR_EAX] & CPUID_MASK ) {
case PENWELL_FAMILY:
return MID_CPU_CHIP_PENWELL;
case CLOVERVIEW_FAMILY:
return MID_CPU_CHIP_CLOVERVIEW;
case VALLEYVIEW2_FAMILY:
return MID_CPU_CHIP_VALLEYVIEW2;
default:
return MID_CPU_CHIP_OTHER;
}
}
static void setup_spi(void)
{
if (!(*(int *)SPI_TYPE)) {
switch ( mid_identify_cpu() ) {
case MID_CPU_CHIP_PENWELL:
*(int *)SPI_TYPE = SPI_1;
bs_printk("PNW detected\n");
break;
case MID_CPU_CHIP_CLOVERVIEW:
*(int *)SPI_TYPE = SPI_1;
bs_printk("CLV detected\n");
break;
case MID_CPU_CHIP_VALLEYVIEW2:
case MID_CPU_CHIP_OTHER:
default:
no_uart_used = 1;
}
}
}
int bootstub(void)
{
setup_spi();
bs_printk("Bootstub Version: 1.3 ...\n");
setup_boot_params((struct boot_params *)BOOT_PARAMS_OFFSET,
(struct setup_header *)SETUP_HEADER_OFFSET);
bs_printk("Jump to kernel 32bit entry ...\n");
return get_32bit_entry((unsigned char *)BZIMAGE_OFFSET);
}