File: /usr/src/linux/arch/ia64/boot/bootloader.c
1 /*
2 * arch/ia64/boot/bootloader.c
3 *
4 * Loads an ELF kernel.
5 *
6 * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
7 * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
8 * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
9 *
10 * 01/07/99 S.Eranian modified to pass command line arguments to kernel
11 */
12 #include <linux/config.h>
13 #include <linux/elf.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16
17 #include <asm/elf.h>
18 #include <asm/pal.h>
19 #include <asm/pgtable.h>
20 #include <asm/sal.h>
21 #include <asm/system.h>
22
23 /* Simulator system calls: */
24
25 #define SSC_CONSOLE_INIT 20
26 #define SSC_GETCHAR 21
27 #define SSC_PUTCHAR 31
28 #define SSC_OPEN 50
29 #define SSC_CLOSE 51
30 #define SSC_READ 52
31 #define SSC_WRITE 53
32 #define SSC_GET_COMPLETION 54
33 #define SSC_WAIT_COMPLETION 55
34 #define SSC_CONNECT_INTERRUPT 58
35 #define SSC_GENERATE_INTERRUPT 59
36 #define SSC_SET_PERIODIC_INTERRUPT 60
37 #define SSC_GET_RTC 65
38 #define SSC_EXIT 66
39 #define SSC_LOAD_SYMBOLS 69
40 #define SSC_GET_TOD 74
41
42 #define SSC_GET_ARGS 75
43
44 struct disk_req {
45 unsigned long addr;
46 unsigned len;
47 };
48
49 struct disk_stat {
50 int fd;
51 unsigned count;
52 };
53
54 #include "../kernel/fw-emu.c"
55
56 static void
57 cons_write (const char *buf)
58 {
59 unsigned long ch;
60
61 while ((ch = *buf++) != '\0') {
62 ssc(ch, 0, 0, 0, SSC_PUTCHAR);
63 if (ch == '\n')
64 ssc('\r', 0, 0, 0, SSC_PUTCHAR);
65 }
66 }
67
68 #define MAX_ARGS 32
69
70 void
71 _start (void)
72 {
73 static char stack[16384] __attribute__ ((aligned (16)));
74 static char mem[4096];
75 static char buffer[1024];
76 unsigned long off;
77 int fd, i;
78 struct disk_req req;
79 struct disk_stat stat;
80 struct elfhdr *elf;
81 struct elf_phdr *elf_phdr; /* program header */
82 unsigned long e_entry, e_phoff, e_phnum;
83 register struct ia64_boot_param *bp;
84 char *kpath, *args;
85 long arglen = 0;
86
87 asm volatile ("movl gp=__gp;;" ::: "memory");
88 asm volatile ("mov sp=%0" :: "r"(stack) : "memory");
89 asm volatile ("bsw.1;;");
90
91 ssc(0, 0, 0, 0, SSC_CONSOLE_INIT);
92
93 /*
94 * S.Eranian: extract the commandline argument from the simulator
95 *
96 * The expected format is as follows:
97 *
98 * kernelname args...
99 *
100 * Both are optional but you can't have the second one without the first.
101 */
102 arglen = ssc((long) buffer, 0, 0, 0, SSC_GET_ARGS);
103
104 kpath = "vmlinux";
105 args = buffer;
106 if (arglen > 0) {
107 kpath = buffer;
108 while (*args != ' ' && *args != '\0')
109 ++args, --arglen;
110 if (*args == ' ')
111 *args++ = '\0', --arglen;
112 }
113
114 if (arglen <= 0) {
115 args = "";
116 arglen = 1;
117 }
118
119 fd = ssc((long) kpath, 1, 0, 0, SSC_OPEN);
120
121 if (fd < 0) {
122 cons_write(kpath);
123 cons_write(": file not found, reboot now\n");
124 for(;;);
125 }
126 stat.fd = fd;
127 off = 0;
128
129 req.len = sizeof(mem);
130 req.addr = (long) mem;
131 ssc(fd, 1, (long) &req, off, SSC_READ);
132 ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION);
133
134 elf = (struct elfhdr *) mem;
135 if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) != 0) {
136 cons_write("not an ELF file\n");
137 return;
138 }
139 if (elf->e_type != ET_EXEC) {
140 cons_write("not an ELF executable\n");
141 return;
142 }
143 if (!elf_check_arch(elf)) {
144 cons_write("kernel not for this processor\n");
145 return;
146 }
147
148 e_entry = elf->e_entry;
149 e_phnum = elf->e_phnum;
150 e_phoff = elf->e_phoff;
151
152 cons_write("loading ");
153 cons_write(kpath);
154 cons_write("...\n");
155
156 for (i = 0; i < e_phnum; ++i) {
157 req.len = sizeof(*elf_phdr);
158 req.addr = (long) mem;
159 ssc(fd, 1, (long) &req, e_phoff, SSC_READ);
160 ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION);
161 if (stat.count != sizeof(*elf_phdr)) {
162 cons_write("failed to read phdr\n");
163 return;
164 }
165 e_phoff += sizeof(*elf_phdr);
166
167 elf_phdr = (struct elf_phdr *) mem;
168
169 if (elf_phdr->p_type != PT_LOAD)
170 continue;
171
172 req.len = elf_phdr->p_filesz;
173 req.addr = __pa(elf_phdr->p_vaddr);
174 ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ);
175 ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION);
176 memset((char *)__pa(elf_phdr->p_vaddr) + elf_phdr->p_filesz, 0,
177 elf_phdr->p_memsz - elf_phdr->p_filesz);
178 }
179 ssc(fd, 0, 0, 0, SSC_CLOSE);
180
181 cons_write("starting kernel...\n");
182
183 /* fake an I/O base address: */
184 asm volatile ("mov ar.k0=%0" :: "r"(0xffffc000000UL));
185
186 bp = sys_fw_init(args, arglen);
187
188 ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS);
189
190 asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0"
191 :: "b"(e_entry), "r"(bp), "r"(__pa(&stack)));
192
193 cons_write("kernel returned!\n");
194 ssc(-1, 0, 0, 0, SSC_EXIT);
195 }
196