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 memreg1
[] = {0, mm_bootmem_size
};
45 u64 memreg2
[] = {mm_highmem_addr
, mm_highmem_size
};
47 res
= fdt_open_into(dt_blob_start
, __devtree
, DT_BUFSIZE
);
49 fatal("fdt_open_into() failed");
51 node
= fdt_path_offset(__devtree
, "/chosen");
53 fatal("/chosen node not found in devtree");
55 res
= fdt_setprop(__devtree
, node
, "bootargs", bootargs
, strlen(bootargs
)+1);
57 fatal("couldn't set chosen.bootargs property");
59 if (initrd_start
&& initrd_size
)
62 start
= mm_addr_to_kernel(initrd_start
);
63 res
= fdt_setprop(__devtree
, node
, "linux,initrd-start", &start
, sizeof(start
));
65 fatal("couldn't set chosen.linux,initrd-start property");
67 end
= mm_addr_to_kernel(initrd_start
+ initrd_size
);
68 res
= fdt_setprop(__devtree
, node
, "linux,initrd-end", &end
, sizeof(end
));
70 fatal("couldn't set chosen.linux,initrd-end property");
72 res
= fdt_add_mem_rsv(__devtree
, start
, initrd_size
);
74 fatal("couldn't add reservation for the initrd");
77 node
= fdt_path_offset(__devtree
, "/memory");
79 fatal("/memory node not found in devtree");
81 res
= fdt_setprop(__devtree
, node
, "reg", memreg1
, sizeof(memreg1
));
83 fatal("couldn't set memory.reg property");
85 res
= fdt_setprop(__devtree
, node
, "sony,lv1-highmem", memreg2
, sizeof(memreg2
));
87 fatal("couldn't set memory.sony,lv1-highmem property");
89 res
= fdt_add_mem_rsv(__devtree
, (u64
)__devtree
, DT_BUFSIZE
);
91 fatal("couldn't add reservation for the devtree");
93 res
= fdt_pack(__devtree
);
95 fatal("fdt_pack() failed");
97 printf("Device tree prepared\n");
100 static void vecmemclr(u64 dest
, u64 size
)
103 if (size
&& dest
< VECSIZE
) {
109 memset((void*)dest
, 0, size
);
110 sync_before_exec((void*)dest
, size
);
113 static void vecmemcpy(u64 dest
, const void *src
, u64 size
)
117 if (size
&& dest
< VECSIZE
) {
118 if (end
<= VECSIZE
) {
119 memcpy(vec_buf
+dest
, p
, size
);
122 memcpy(vec_buf
+dest
, p
, VECSIZE
-dest
);
128 memcpy((void*)dest
, p
, size
);
129 sync_before_exec((void*)dest
, size
);
132 int kernel_load(const u8
*addr
, u32 len
)
134 memset(vec_buf
, 0, sizeof(vec_buf
));
136 if (len
< sizeof(Elf64_Ehdr
))
139 Elf64_Ehdr
*ehdr
= (Elf64_Ehdr
*) addr
;
141 if (memcmp("\x7F" "ELF\x02\x02\x01", ehdr
->e_ident
, 7)) {
142 printf("load_elf_kernel: invalid ELF header 0x%02x 0x%02x 0x%02x 0x%02x\n",
143 ehdr
->e_ident
[0], ehdr
->e_ident
[1],
144 ehdr
->e_ident
[2], ehdr
->e_ident
[3]);
148 if (ehdr
->e_phoff
== 0 || ehdr
->e_phnum
== 0) {
149 printf("load_elf_kernel: ELF has no program headers\n");
153 int count
= ehdr
->e_phnum
;
154 if (len
< ehdr
->e_phoff
+ count
* sizeof(Elf64_Phdr
)) {
155 printf("load_elf_kernel: image too short for phdrs\n");
159 Elf64_Phdr
*phdr
= (Elf64_Phdr
*) &addr
[ehdr
->e_phoff
];
162 if (phdr
->p_type
!= PT_LOAD
) {
163 printf("load_elf_kernel: skipping PHDR of type %d\n", phdr
->p_type
);
165 if ((phdr
->p_paddr
+phdr
->p_memsz
) > ADDR_LIMIT
) {
166 printf("PHDR out of bounds [0x%lx...0x%lx]\n",
167 phdr
->p_paddr
, phdr
->p_paddr
+ phdr
->p_memsz
);
171 printf("load_elf_kernel: LOAD 0x%lx @0x%lx [0x%lx/0x%lx]\n", phdr
->p_offset
,
172 phdr
->p_paddr
, phdr
->p_filesz
, phdr
->p_memsz
);
174 vecmemclr(phdr
->p_paddr
, phdr
->p_memsz
);
175 vecmemcpy(phdr
->p_paddr
, &addr
[phdr
->p_offset
],
181 ehdr
->e_entry
&= 0x3ffffffffffffffful
;
183 entry
[0] = (void*)ehdr
->e_entry
;
185 printf("load_elf_kernel: kernel loaded, entry at 0x%lx\n", ehdr
->e_entry
);
190 void kernel_build_cmdline(const char *parameters
, const char *root
)
195 strlcat(bootargs
, "root=", MAX_CMDLINE_SIZE
);
196 strlcat(bootargs
, root
, MAX_CMDLINE_SIZE
);
197 strlcat(bootargs
, " ", MAX_CMDLINE_SIZE
);
201 strlcat(bootargs
, parameters
, MAX_CMDLINE_SIZE
);
203 printf("Kernel command line: '%s'\n", bootargs
);
206 void kernel_set_initrd(void *start
, size_t size
)
208 printf("Initrd at %p/0x%lx: %ld bytes (%ldKiB)\n", start
, \
209 mm_addr_to_kernel(start
), size
, size
/1024);
211 initrd_start
= start
;
215 void kernel_launch(void)
218 printf("Relocating vectors...\n");
219 memcpy((void*)0, vec_buf
, VECSIZE
);
220 sync_before_exec((void*)0, VECSIZE
);
221 printf("Letting thread1 run loose...\n");
222 _thread1_vector
= 0x60; /* this is __secondary_hold in Linux */
223 _thread1_release
= 1;
224 printf("Taking the plunge...\n");
226 ((kernel_entry
)entry
)(__devtree
, entry
[0], NULL
);