aboutsummaryrefslogtreecommitdiff
path: root/linuxboot.c
blob: 51bfba3f1873a1fd94bca606502f9b1b5c7544b8 (plain)
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
#include "bios.h"
#include "ioport.h"
#include "fw_cfg.h"

static void *_fw_cfg_read_blob(int faddr, int fsize, int fdata)
{
	void *addr;
	int length;

	fw_cfg_select(faddr);
	addr = (void *)fw_cfg_readl_le();
	fw_cfg_select(fsize);
	length = fw_cfg_readl_le();
	fw_cfg_select(fdata);
	fw_cfg_read(addr, length);
	return addr;
}

/* BX = address of data block
 * DX = cmdline_addr-setup_addr-16
 */
asm("pm16_boot_linux:"
	    ".code16;"
	    "mov $0, %eax; mov %eax, %cr0;"
	    "ljmpl $0xf000, $(1f - 0xf0000); 1:"
	    "mov %bx, %ds; mov %bx, %es;"
	    "mov %bx, %fs; mov %bx, %gs; mov %bx, %ss;"
	    "mov %dx, %sp;"
	    "add $0x20, %bx; pushw %bx;"    // push CS
	    "xor %eax, %eax; pushw %ax;"    // push IP
	    "xor %ebx, %ebx;"
	    "xor %ecx, %ecx;"
	    "xor %edx, %edx;"
	    "xor %edi, %edi;"
	    "xor %ebp, %ebp;"
	    "lret;"
	    ".code32");

void boot_linux(void)
{
	void *setup_addr, *cmdline_addr;

#define fw_cfg_read_blob(f) \
	_fw_cfg_read_blob(f##_ADDR, f##_SIZE, f##_DATA)

	setup_addr = fw_cfg_read_blob(FW_CFG_SETUP);
	cmdline_addr = fw_cfg_read_blob(FW_CFG_CMDLINE);
	fw_cfg_read_blob(FW_CFG_INITRD);
	fw_cfg_read_blob(FW_CFG_KERNEL);

	asm volatile(
	    "ljmp $0x18, $pm16_boot_linux - 0xf0000"
	    : :
	    "b" (((uintptr_t) setup_addr) >> 4),
	    "d" (cmdline_addr - setup_addr - 16));
        panic();
}