use the correct size depending on wordsize.
[AROS.git] / arch / all-hosted / bootstrap / bootstrap.c
blob4989306212fb5d55d009c809ed0eb0b50e241a9c
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <ctype.h>
7 #include <dirent.h>
8 #include <errno.h>
9 #include <limits.h>
10 #include <locale.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h>
17 #ifndef _WIN32
18 #include <unistd.h>
19 #endif
21 /* These macros are defined in both UNIX and AROS headers. Get rid of warnings. */
22 #undef __pure
23 #undef __const
24 #undef __pure2
25 #undef __deprecated
27 #include <aros/kernel.h>
28 #include <aros/multiboot.h>
29 #include <exec/execbase.h>
30 #include <utility/tagitem.h>
32 #include <elfloader.h>
33 #include <runtime.h>
35 #include "bootstrap.h"
36 #include "elf_io.h"
37 #include "filesystem.h"
38 #include "kickstart.h"
39 #include "log.h"
40 #include "memory.h"
41 #include "support.h"
42 #include "shutdown.h"
44 #ifndef PATH_MAX
45 #define PATH_MAX _MAX_PATH
46 #endif
48 #define D(x)
50 #define LOWMEMSIZE (512 * 1024 * 1024)
52 /* These macros are defined in both UNIX and AROS headers. Get rid of warnings. */
53 #undef __pure
54 #undef __const
55 #undef __pure2
56 #undef __deprecated
58 extern void *HostIFace;
60 /*
61 * External libgcc routine which eventually clears instruction cache.
62 * It is equivalent to gcc's __builtin___clear_cache(char *, char*)
64 extern void __clear_cache(char *begin, char *end);
66 char bootstrapdir[PATH_MAX];
67 char *KernelArgs = NULL;
68 char *SystemVersion = NULL;
69 char buf[BUFFER_SIZE];
71 #if (__WORDSIZE != 64)
72 static struct mb_mmap MemoryMap[1] =
73 #else
74 static struct mb_mmap MemoryMap[2] =
75 #endif
78 sizeof(struct mb_mmap) - 4,
81 #if (__WORDSIZE != 64)
84 #endif
85 MMAP_TYPE_RAM
87 #if (__WORDSIZE == 64)
88 , {
89 sizeof(struct mb_mmap) - 4,
92 MMAP_TYPE_RAM
94 #endif
97 /* gdb can pick up kickstart segments from here */
98 static struct ELF_ModuleInfo *Debug_KickList = NULL;
100 static const char version[] = "$VER: AROS Hosted bootstrap v1.0 (" ADATE ")";
102 /* Kernel message */
103 static struct TagItem km[] =
105 {KRN_KernelLowest , 0 },
106 {KRN_KernelHighest, 0 },
107 {KRN_KernelBss , 0 },
108 {KRN_BootLoader , 0 },
109 {KRN_DebugInfo , 0 },
110 {KRN_HostInterface, 0 },
111 {KRN_MMAPAddress , 0 },
112 {KRN_MMAPLength , sizeof(struct mb_mmap)},
113 {KRN_CmdLine , 0 },
114 {TAG_DONE , 0 }
117 /* Global SysBase */
118 struct ExecBase *SysBase;
120 static char *GetConfigArg(char *str, char *option)
122 size_t l = strlen(option);
124 /* First check option name */
125 if (strncasecmp(str, option, l))
126 return NULL;
128 /* Skip option name */
129 str += l;
131 /* First character must be space */
132 if (!isspace(*str++))
133 return NULL;
134 /* Skip the rest of spaces */
135 while(isspace(*str))
136 str++;
138 return str;
141 char *join_string(int argc, char **argv)
143 char *str, *s;
144 int j;
145 int x = 0;
147 for (j = 0; j < argc; j++)
148 x += (strlen(argv[j]) + 1);
149 D(fprintf(stderr, "[Bootstrap] Allocating %u bytes for string\n", x));
150 str = malloc(x);
151 if (str) {
152 s = str;
153 for (j = 0; j < argc; j++) {
154 strcpy(s, argv[j]);
155 s += strlen(s);
156 *s++ = ' ';
158 s[-1] = 0;
159 D(fprintf(stderr, "[Bootstrap] Joined line: %s\n", str));
161 return str;
164 int bootstrap(int argc, char ** argv)
166 int i = 1;
167 unsigned int memSize = 64;
168 int def_memSize = 1;
169 char *config = DefaultConfig;
170 FILE *file;
171 kernel_entry_fun_t kernel_entry;
172 void *ro_addr, *rw_addr, *__bss_track;
173 unsigned long ro_size, rw_size, bss_size;
175 D(fprintf(stderr, "[Bootstrap] Started\n"));
178 * This makes national characters to be output properly into
179 * the debug log under Windows
181 setlocale(LC_ALL, "");
182 if (!getcwd(bootstrapdir, sizeof(bootstrapdir)))
184 DisplayError("Failed to get current working directory!");
185 return -1;
187 SaveArgs(argv);
189 while (i < argc) {
190 if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
191 printf ("Hosted AROS bootstrap\n"
192 "usage: %s [options] [kernel arguments]\n"
193 "Available options:\n"
194 " -h show this page\n"
195 " -m <size> allocate <size> Megabytes of memory for AROS\n"
196 " (default is 64MB)\n"
197 " -c <file> read configuration from <file>\n"
198 " (default is %s)\n"
199 " --help same as '-h'\n"
200 " --memsize <size> same as '-m <size>'\n"
201 " --config <file> same as '-c'\n"
202 "\n"
203 "Please report bugs to the AROS development team. http://www.aros.org/\n", argv[0], DefaultConfig);
204 return 0;
205 } else if (!strcmp(argv[i], "--memsize") || !strcmp(argv[i], "-m")) {
206 memSize = atoi(argv[++i]);
207 def_memSize = 0;
208 i++;
209 } else if (!strcmp(argv[i], "--config") || !strcmp(argv[i], "-c")) {
210 config = argv[++i];
211 i++;
212 } else
213 break;
215 D(fprintf(stderr, "[Bootstrap] %u argument%s processed\n", i, i==1 ? "" : "s"));
217 if (i < argc) {
218 KernelArgs = join_string(argc - i, &argv[i]);
219 D(fprintf(stderr, "[Bootstrap] Kernel arguments: %s\n", KernelArgs));
222 SystemVersion = getosversion(&version[6]);
223 D(fprintf(stderr, "[Bootstrap] OS version: %s\n", SystemVersion));
225 if (SetRootDirectory())
227 DisplayError("Failed to locate root directory!");
228 return -1;
231 D(fprintf(stderr, "[Bootstrap] Opening configuration file %s\n", config));
232 file = fopen(config, "r");
233 if (!file)
235 DisplayError("Failed to load configuration file %s!", config);
236 return -1;
239 /* Parse the configuration file */
240 while (fgets(buf, sizeof(buf), file)) {
241 char *c = strchr(buf, '\r');
243 if (!c)
244 c = strchr(buf, '\n');
245 if (c)
246 *c = 0;
248 c = GetConfigArg(buf, "module");
249 if (c) {
250 AddKernelFile(c);
251 continue;
254 /* Command line argument overrides this */
255 if (def_memSize) {
256 c = GetConfigArg(buf, "memory");
257 if (c) {
258 memSize = atoi(c);
259 continue;
263 c = GetConfigArg(buf, "logfile");
264 if (c)
266 i = SetLog(c);
267 if (i)
269 DisplayError("Failed to redirect debug output to %s", c);
270 return i;
272 fprintf(stderr, "----\n"); /* Separation marker */
275 c = GetConfigArg(buf, "arguments");
276 if (c)
278 /* If we already have some arguments, append our line to them */
279 if (KernelArgs)
281 char *parts[] = {KernelArgs, c};
282 char *args = join_string(2, parts);
284 if (args)
286 free(KernelArgs);
287 KernelArgs = args;
290 else
292 /* Otherwise just copy the line */
293 i = strlen(c);
294 if (i)
296 i++;
297 KernelArgs = malloc(i);
298 memcpy(KernelArgs, c, i);
303 fclose(file);
305 D(fprintf(stderr, "[Bootstrap] Allocating %iMB of RAM for AROS\n",memSize));
307 #if (__WORDSIZE == 64)
308 if ((memSize << 20) > LOWMEMSIZE)
310 MemoryMap[1].len = (memSize << 20) - LOWMEMSIZE;
311 MemoryMap[1].addr = (IPTR)AllocateRAM((size_t)MemoryMap[1].len);
312 if (!MemoryMap[1].addr) {
313 int err = errno;
314 DisplayError("[Bootstrap] Failed to allocate %iMB of 'High' RAM for AROS: %08x %s\n", memSize, err, strerror(err));
315 return -1;
317 fprintf(stderr, "[Bootstrap] RAM memory block allocated: %p - %p (%llu bytes)\n",
318 (void *)(IPTR)MemoryMap[1].addr, (void *)(IPTR)MemoryMap[1].addr + MemoryMap[1].len, (unsigned long long)MemoryMap[1].len);
320 memSize = (LOWMEMSIZE >> 20);
321 km[7].ti_Data += sizeof(struct mb_mmap);
323 #endif
324 MemoryMap[0].len = memSize << 20;
325 MemoryMap[0].addr = (IPTR)AllocateRAM32((size_t)MemoryMap[0].len);
327 if (!MemoryMap[0].addr) {
328 int err = errno;
329 DisplayError("[Bootstrap] Failed to allocate %iMB of RAM for AROS: %08x %s\n", memSize, err, strerror(err));
330 return -1;
332 fprintf(stderr, "[Bootstrap] RAM memory block allocated: %p - %p (",
333 (void *)(IPTR)MemoryMap[0].addr, (void *)(IPTR)MemoryMap[0].addr + MemoryMap[0].len;
334 #if (__WORDSIZE == 64)
335 fprintf(stderr, "%llu bytes)\n", (unsigned long long)MemoryMap[0].len);
336 #else
337 fprintf(stderr, "%u bytes)\n", MemoryMap[0].len);
338 #endif
340 if (!GetKernelSize(FirstELF, &ro_size, &rw_size, &bss_size))
341 return -1;
343 ro_addr = AllocateRO(ro_size);
344 D(fprintf(stderr, "[Bootstrap] Kickstart ROM area: %p\n", ro_addr));
345 if (!ro_addr)
347 DisplayError("Failed to allocate %u bytes for the kickstart!", ro_size);
348 return -1;
351 rw_addr = AllocateRW(rw_size);
352 D(fprintf(stderr, "[Bootstrap] Kickstart data area: %p\n", rw_addr));
353 if (!rw_addr)
355 DisplayError("Failed to allocate %u bytes for the kickstart!", rw_size);
356 return -1;
359 __bss_track = AllocateRO(bss_size);
360 D(fprintf(stderr, "[Bootstrap] Kickstart BSS array: %p\n", __bss_track));
361 if (!__bss_track)
363 DisplayError("Failed to allocate %u bytes for the kickstart!", bss_size);
364 return -1;
367 if (!LoadKernel(FirstELF, ro_addr, rw_addr, __bss_track, (uintptr_t)&SysBase, NULL, &kernel_entry, &Debug_KickList))
368 return -1;
370 D(fprintf(stderr, "[Bootstrap] Read-only %p - %p, Read-write %p - %p, Entry %p, Debug info %p\n",
371 ro_addr, ro_addr + ro_size - 1, rw_addr, rw_addr + rw_size - 1, kernel_entry, Debug_KickList));
373 FreeKernelList();
375 D(fprintf(stderr, "[Bootstrap] Sealing kernel code memory\n"));
376 if (SetRO(ro_addr, ro_size))
378 DisplayError("Failed to set kernel memory permissions");
379 return -1;
383 km[0].ti_Data = (IPTR)ro_addr;
384 km[1].ti_Data = (IPTR)ro_addr + ro_size - 1;
385 km[2].ti_Data = (IPTR)__bss_track;
386 km[3].ti_Data = (IPTR)SystemVersion;
387 km[4].ti_Data = (IPTR)Debug_KickList;
388 km[5].ti_Data = (IPTR)HostIFace;
389 km[6].ti_Data = (IPTR)&MemoryMap;
390 /* km[7] is statically filled in */
391 if (KernelArgs)
392 km[8].ti_Data = (IPTR)KernelArgs;
393 else
394 km[8].ti_Tag = TAG_DONE;
396 /* Flush instruction cache */
397 __clear_cache((char *)ro_addr, (char *)ro_addr + ro_size);
399 #ifdef DEBUG_CODE
400 /* This is a quickly hacked up sanity test which was used during iOS port development */
401 if (ro_size > 256)
402 ro_size = 256;
404 fprintf(stderr, "[Bootstrap] Dumping %u bytes of code at %p\n", ro_size, ro_addr);
405 for (i = 0; i < ro_size;)
407 if (i % 8 == 0)
408 fprintf(stderr, "%p ", ro_addr + i);
409 fprintf(stderr, "%02X ", ((unsigned char *)ro_addr)[i++]);
410 if (i % 8 == 0)
411 fprintf(stderr, "\n");
413 fprintf(stderr, "\n");
414 #endif
416 i = kick(kernel_entry, km);
418 return i;