After this has been brought up many times before, rename src/arch/i386 to
[coreboot.git] / src / arch / x86 / boot / boot.c
1 #include <console/console.h>
2 #include <ip_checksum.h>
3 #include <boot/elf.h>
4 #include <boot/elf_boot.h>
5 #include <string.h>
6 #include <cpu/x86/multiboot.h>
7
8
9 #ifndef CMD_LINE
10 #define CMD_LINE ""
11 #endif
12
13
14
15 #define UPSZ(X) ((sizeof(X) + 3) &~3)
16
17 static struct {
18         Elf_Bhdr hdr;
19         Elf_Nhdr ft_hdr;
20         unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)];
21         Elf_Nhdr bl_hdr;
22         unsigned char bl_desc[UPSZ(BOOTLOADER)];
23         Elf_Nhdr blv_hdr;
24         unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
25         Elf_Nhdr cmd_hdr;
26         unsigned char cmd_desc[UPSZ(CMD_LINE)];
27 } elf_boot_notes = {
28         .hdr = {
29                 .b_signature = 0x0E1FB007,
30                 .b_size = sizeof(elf_boot_notes),
31                 .b_checksum = 0,
32                 .b_records = 4,
33         },
34         .ft_hdr = {
35                 .n_namesz = 0,
36                 .n_descsz = sizeof(FIRMWARE_TYPE),
37                 .n_type = EBN_FIRMWARE_TYPE,
38         },
39         .ft_desc = FIRMWARE_TYPE,
40         .bl_hdr = {
41                 .n_namesz = 0,
42                 .n_descsz = sizeof(BOOTLOADER),
43                 .n_type = EBN_BOOTLOADER_NAME,
44         },
45         .bl_desc = BOOTLOADER,
46         .blv_hdr = {
47                 .n_namesz = 0,
48                 .n_descsz = sizeof(BOOTLOADER_VERSION),
49                 .n_type = EBN_BOOTLOADER_VERSION,
50         },
51         .blv_desc = BOOTLOADER_VERSION,
52         .cmd_hdr = {
53                 .n_namesz = 0,
54                 .n_descsz = sizeof(CMD_LINE),
55                 .n_type = EBN_COMMAND_LINE,
56         },
57         .cmd_desc = CMD_LINE,
58 };
59
60
61 int elf_check_arch(Elf_ehdr *ehdr)
62 {
63         return (
64                 ((ehdr->e_machine == EM_386) || (ehdr->e_machine == EM_486)) &&
65                 (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
66                 (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
67                 );
68
69 }
70
71 void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long size)
72 {
73         extern unsigned char _ram_seg, _eram_seg;
74         unsigned long lb_start, lb_size;
75         unsigned long adjust, adjusted_boot_notes;
76
77         elf_boot_notes.hdr.b_checksum =
78                 compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes));
79
80         lb_start = (unsigned long)&_ram_seg;
81         lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
82         adjust = buffer +  size - lb_start;
83
84         adjusted_boot_notes = (unsigned long)&elf_boot_notes;
85         adjusted_boot_notes += adjust;
86
87         printk(BIOS_SPEW, "entry    = 0x%08lx\n", (unsigned long)entry);
88         printk(BIOS_SPEW, "lb_start = 0x%08lx\n", lb_start);
89         printk(BIOS_SPEW, "lb_size  = 0x%08lx\n", lb_size);
90         printk(BIOS_SPEW, "adjust   = 0x%08lx\n", adjust);
91         printk(BIOS_SPEW, "buffer   = 0x%08lx\n", buffer);
92         printk(BIOS_SPEW, "     elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes);
93         printk(BIOS_SPEW, "adjusted_boot_notes = 0x%08lx\n", adjusted_boot_notes);
94
95         /* Jump to kernel */
96         __asm__ __volatile__(
97                 "       cld     \n\t"
98                 /* Save the callee save registers... */
99                 "       pushl   %%esi\n\t"
100                 "       pushl   %%edi\n\t"
101                 "       pushl   %%ebx\n\t"
102                 /* Save the parameters I was passed */
103                 "       pushl   $0\n\t" /* 20 adjust */
104                 "       pushl   %0\n\t" /* 16 lb_start */
105                 "       pushl   %1\n\t" /* 12 buffer */
106                 "       pushl   %2\n\t" /*  8 lb_size */
107                 "       pushl   %3\n\t" /*  4 entry */
108                 "       pushl   %4\n\t" /*  0 elf_boot_notes */
109                 /* Compute the adjustment */
110                 "       xorl    %%eax, %%eax\n\t"
111                 "       subl    16(%%esp), %%eax\n\t"
112                 "       addl    12(%%esp), %%eax\n\t"
113                 "       addl     8(%%esp), %%eax\n\t"
114                 "       movl    %%eax, 20(%%esp)\n\t"
115                 /* Place a copy of coreboot in its new location */
116                 /* Move ``longs'' the coreboot size is 4 byte aligned */
117                 "       movl    12(%%esp), %%edi\n\t"
118                 "       addl     8(%%esp), %%edi\n\t"
119                 "       movl    16(%%esp), %%esi\n\t"
120                 "       movl     8(%%esp), %%ecx\n\n"
121                 "       shrl    $2, %%ecx\n\t"
122                 "       rep     movsl\n\t"
123
124                 /* Adjust the stack pointer to point into the new coreboot image */
125                 "       addl    20(%%esp), %%esp\n\t"
126                 /* Adjust the instruction pointer to point into the new coreboot image */
127                 "       movl    $1f, %%eax\n\t"
128                 "       addl    20(%%esp), %%eax\n\t"
129                 "       jmp     *%%eax\n\t"
130                 "1:     \n\t"
131
132                 /* Copy the coreboot bounce buffer over coreboot */
133                 /* Move ``longs'' the coreboot size is 4 byte aligned */
134                 "       movl    16(%%esp), %%edi\n\t"
135                 "       movl    12(%%esp), %%esi\n\t"
136                 "       movl     8(%%esp), %%ecx\n\t"
137                 "       shrl    $2, %%ecx\n\t"
138                 "       rep     movsl\n\t"
139
140                 /* Now jump to the loaded image */
141                 "       movl    %5, %%eax\n\t"
142                 "       movl     0(%%esp), %%ebx\n\t"
143                 "       call    *4(%%esp)\n\t"
144
145                 /* The loaded image returned? */
146                 "       cli     \n\t"
147                 "       cld     \n\t"
148
149                 /* Copy the saved copy of coreboot where coreboot runs */
150                 /* Move ``longs'' the coreboot size is 4 byte aligned */
151                 "       movl    16(%%esp), %%edi\n\t"
152                 "       movl    12(%%esp), %%esi\n\t"
153                 "       addl     8(%%esp), %%esi\n\t"
154                 "       movl     8(%%esp), %%ecx\n\t"
155                 "       shrl    $2, %%ecx\n\t"
156                 "       rep     movsl\n\t"
157
158                 /* Adjust the stack pointer to point into the old coreboot image */
159                 "       subl    20(%%esp), %%esp\n\t"
160
161                 /* Adjust the instruction pointer to point into the old coreboot image */
162                 "       movl    $1f, %%eax\n\t"
163                 "       subl    20(%%esp), %%eax\n\t"
164                 "       jmp     *%%eax\n\t"
165                 "1:     \n\t"
166
167                 /* Drop the parameters I was passed */
168                 "       addl    $24, %%esp\n\t"
169
170                 /* Restore the callee save registers */
171                 "       popl    %%ebx\n\t"
172                 "       popl    %%edi\n\t"
173                 "       popl    %%esi\n\t"
174
175                 ::
176                 "ri" (lb_start), "ri" (buffer), "ri" (lb_size),
177                 "ri" (entry),
178 #if CONFIG_MULTIBOOT
179                 "ri"(mbi), "ri" (MB_MAGIC2)
180 #else
181                 "ri"(adjusted_boot_notes), "ri" (0x0E1FB007)
182 #endif
183                 );
184 }
185
186