1 /* device.c - lv1 device functions
3 Copyright (C) 2010-2011 Hector Martin "marcan" <hector@marcansoft.com>
5 This code is licensed to you under the terms of the GNU GPL, version 2;
6 see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
19 static u8 vec_buf
[VECSIZE
];
21 #define DT_BUFSIZE 65536
24 extern char __devtree
[];
25 extern char dt_blob_start
[];
27 #define ADDR_LIMIT ((u64)__base)
29 static char bootargs
[MAX_CMDLINE_SIZE
];
31 static u64
*entry
[3] = {NULL
,NULL
,NULL
}; // function descriptor for the kernel entrypoint
33 typedef void (*kernel_entry
)(void *devtree
, void *self
, void *null
);
35 extern volatile u64 _thread1_release
;
36 extern volatile u64 _thread1_vector
;
38 static u8
*initrd_start
= NULL
;
39 static size_t initrd_size
= 0;
41 static void devtree_prepare(void)
44 u64 memreg
[] = {0, mm_bootmem_size
};
46 res
= fdt_open_into(dt_blob_start
, __devtree
, DT_BUFSIZE
);
48 fatal("fdt_open_into() failed");
50 node
= fdt_path_offset(__devtree
, "/chosen");
52 fatal("/chosen node not found in devtree");
54 res
= fdt_setprop(__devtree
, node
, "bootargs", bootargs
, strlen(bootargs
)+1);
56 fatal("couldn't set chosen.bootargs property");
58 if (initrd_start
&& initrd_size
)
61 start
= mm_addr_to_kernel(initrd_start
);
62 res
= fdt_setprop(__devtree
, node
, "linux,initrd-start", &start
, sizeof(start
));
64 fatal("couldn't set chosen.linux,initrd-start property");
66 end
= mm_addr_to_kernel(initrd_start
+ initrd_size
);
67 res
= fdt_setprop(__devtree
, node
, "linux,initrd-end", &end
, sizeof(end
));
69 fatal("couldn't set chosen.linux,initrd-end property");
71 res
= fdt_add_mem_rsv(__devtree
, start
, initrd_size
);
73 fatal("couldn't add reservation for the initrd");
76 node
= fdt_path_offset(__devtree
, "/memory");
78 fatal("/memory node not found in devtree");
80 res
= fdt_setprop(__devtree
, node
, "reg", memreg
, sizeof(memreg
));
82 fatal("couldn't set memory.reg property");
84 res
= fdt_add_mem_rsv(__devtree
, (u64
)__devtree
, DT_BUFSIZE
);
86 fatal("couldn't add reservation for the devtree");
88 res
= fdt_pack(__devtree
);
90 fatal("fdt_pack() failed");
92 printf("Device tree prepared\n");
95 static void vecmemcpy(u64 dest
, const void *src
, u64 size
)
99 if (size
&& dest
< VECSIZE
) {
100 if (end
<= VECSIZE
) {
101 memcpy(vec_buf
+dest
, p
, size
);
104 memcpy(vec_buf
+dest
, p
, VECSIZE
-dest
);
110 memcpy((void*)dest
, p
, size
);
111 sync_before_exec((void*)dest
, size
);
114 int kernel_load_elf64(const u8
*addr
, u32 len
)
116 if (len
< sizeof(Elf64_Ehdr
))
119 Elf64_Ehdr
*ehdr
= (Elf64_Ehdr
*) addr
;
121 if (ehdr
->e_phoff
== 0 || ehdr
->e_phnum
== 0) {
122 printf("load_elf_kernel: ELF has no program headers\n");
126 int count
= ehdr
->e_phnum
;
127 if (len
< ehdr
->e_phoff
+ count
* sizeof(Elf64_Phdr
)) {
128 printf("load_elf_kernel: image too short for phdrs\n");
132 Elf64_Phdr
*phdr
= (Elf64_Phdr
*) &addr
[ehdr
->e_phoff
];
135 if (phdr
->p_type
!= PT_LOAD
) {
136 printf("load_elf_kernel: skipping PHDR of type %d\n", phdr
->p_type
);
138 if ((phdr
->p_paddr
+phdr
->p_filesz
) > ADDR_LIMIT
) {
139 printf("PHDR out of bounds [0x%lx...0x%lx] 0x%lx\n",
140 phdr
->p_paddr
, phdr
->p_paddr
+ phdr
->p_filesz
,
145 printf("load_elf_kernel: LOAD 0x%lx @0x%lx [0x%lx/0x%lx]\n", phdr
->p_offset
,
146 phdr
->p_paddr
, phdr
->p_filesz
, phdr
->p_memsz
);
148 vecmemcpy(phdr
->p_paddr
, &addr
[phdr
->p_offset
],
154 ehdr
->e_entry
&= 0x3ffffffffffffffful
;
156 entry
[0] = (void*)ehdr
->e_entry
;
158 printf("load_elf_kernel: kernel loaded, entry at 0x%lx\n", ehdr
->e_entry
);
163 int kernel_load_elf32(const u8
*addr
, u32 len
)
165 if (len
< sizeof(Elf32_Ehdr
)) {
166 printf("file smaller than Elf32_Ehdr\n");
170 Elf32_Ehdr
*ehdr
= (Elf32_Ehdr
*) addr
;
172 if (ehdr
->e_ehsize
!= sizeof(Elf32_Ehdr
)) {
173 printf("sizeof Elf32_Ehdr mismatch\n");
177 if (ehdr
->e_phoff
== 0 || ehdr
->e_phnum
== 0) {
178 printf("load_elf_kernel: ELF has no program headers\n");
182 int count
= ehdr
->e_phnum
;
183 if (len
< ehdr
->e_phoff
+ count
* sizeof(Elf32_Phdr
)) {
184 printf("load_elf_kernel: image too short for phdrs\n");
188 Elf32_Phdr
*phdr
= (Elf32_Phdr
*) &addr
[ehdr
->e_phoff
];
191 if (phdr
->p_type
!= PT_LOAD
) {
192 printf("load_elf_kernel: skipping PHDR of type %d\n", phdr
->p_type
);
194 if ((phdr
->p_paddr
+phdr
->p_filesz
) > ADDR_LIMIT
) {
195 printf("PHDR out of bounds [0x%x...0x%x] 0x%lx\n",
196 phdr
->p_paddr
, phdr
->p_paddr
+ phdr
->p_filesz
,
201 printf("load_elf_kernel: LOAD 0x%x @0x%x [0x%x/0x%x]\n", phdr
->p_offset
,
202 phdr
->p_paddr
, phdr
->p_filesz
, phdr
->p_memsz
);
204 vecmemcpy(phdr
->p_paddr
, &addr
[phdr
->p_offset
],
210 ehdr
->e_entry
&= 0x3ffffffffffffffful
;
212 entry
[0] = (void*)(u64
)ehdr
->e_entry
;
214 printf("load_elf_kernel: kernel loaded, entry at 0x%x\n", ehdr
->e_entry
);
219 int kernel_load(const u8
*addr
, u32 len
)
221 memset(vec_buf
, 0, sizeof(vec_buf
));
223 if (len
< EI_NIDENT
) {
224 printf("kernel too short\n");
228 if (!memcmp("\x7F" "ELF\x02\x02\x01", addr
, 7)) {
229 printf("ELF64 kernel detected\n");
230 return kernel_load_elf64(addr
, len
);
233 if (!memcmp("\x7F" "ELF\x01\x02\x01", addr
, 7)) {
234 printf("ELF32 kernel detected\n");
235 return kernel_load_elf32(addr
, len
);
238 printf("invalid ELF header %02x %02x %02x %02x %02x %02x %02x\n",
239 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5], addr
[6]);
243 void kernel_build_cmdline(const char *parameters
, const char *root
)
248 strlcat(bootargs
, "root=", MAX_CMDLINE_SIZE
);
249 strlcat(bootargs
, root
, MAX_CMDLINE_SIZE
);
250 strlcat(bootargs
, " ", MAX_CMDLINE_SIZE
);
254 strlcat(bootargs
, parameters
, MAX_CMDLINE_SIZE
);
256 printf("Kernel command line: '%s'\n", bootargs
);
259 void kernel_set_initrd(void *start
, size_t size
)
261 printf("Initrd at %p/0x%lx: %ld bytes (%ldKiB)\n", start
, \
262 mm_addr_to_kernel(start
), size
, size
/1024);
264 initrd_start
= start
;
268 void kernel_launch(void)
272 if (initrd_start
&& initrd_size
)
273 mm_set_highmem_repo_info();
275 mm_shutdown_highmem();
277 printf("Relocating vectors...\n");
278 memcpy((void*)0, vec_buf
, VECSIZE
);
279 sync_before_exec((void*)0, VECSIZE
);
280 printf("Letting thread1 run loose...\n");
281 _thread1_vector
= (u64
)entry
[0] + 0x60; /* this is __secondary_hold */
282 _thread1_release
= 1;
283 printf("Taking the plunge...\n");
285 ((kernel_entry
)entry
)(__devtree
, entry
[0], NULL
);