Re-enabled use of AROS.Boot file due to lack of general enthusiasm for
[tangerine.git] / arch / all-linux / exec / init.c
blob47cea81702c0c3851b5fd8e6c3b38384d4952b41
1 /*
2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Linux init code for emulated (Unix) systems.
6 Lang: english
7 */
9 #define DEBUG 0
11 #define _XOPEN_SOURCE 600L /* for posix_memalign */
13 #include <exec/types.h>
14 #include <exec/memory.h>
15 #include <exec/memheaderext.h>
16 #include <exec/resident.h>
17 #include <exec/execbase.h>
19 #include <proto/exec.h>
20 #include <aros/debug.h>
22 #if (AROS_BIG_ENDIAN == 0)
23 #define SWAP(x) ((((ULONG)x >> 24) & 0x000000ff) |\
24 (((ULONG)x >> 8 ) & 0x0000ff00) |\
25 (((ULONG)x << 8 ) & 0x00ff0000) |\
26 (((ULONG)x << 24) & 0xff000000) )
27 #else
28 #define SWAP(x) x
29 #endif
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <string.h>
35 #define __USE_MISC /* for MAP_ANON */
36 #include <sys/mman.h>
37 #include <sys/termios.h>
38 #include <sys/utsname.h>
40 #include "../../../rom/exec/memory.h" /* From $(TOP)/rom/exec */
42 extern const struct Resident
43 Expansion_ROMTag,
44 Exec_resident,
45 Utility_ROMTag,
46 Aros_ROMTag,
47 Bootloader_ROMTag,
48 /* BOOPSI_resident,*/
49 OOP_ROMTag,
50 HIDDCl_ROMTag,
51 UXIO_ROMTag,
52 HostLib_ROMTag,
53 Graphics_ROMTag,
54 Layers_ROMTag,
55 Timer_ROMTag,
56 Battclock_ROMTag,
57 Keyboard_ROMTag,
58 Gameport_ROMTag,
59 Keymap_ROMTag,
60 Input_ROMTag,
61 Intuition_ROMTag,
62 LinuxFB_ROMTag,
63 Cybergraphics_ROMTag,
64 Console_ROMTag,
65 #if ENABLE_DBUS == 1
66 Dbus_ROMTag,
67 #endif
68 Mathffp_ROMTag,
69 Mathieeesingbas_ROMTag,
70 Workbench_ROMTag,
71 Dos_ROMTag,
72 LDDemon_resident,
73 emul_handler_ROMTag,
74 Packet_ROMTag,
75 UXSer_ROMTag,
76 UXPar_ROMTag,
77 boot_resident,
78 Con_ROMTag,
79 Nil_ROMTag,
80 Ram_ROMTag,
81 PCI_ROMTag,
82 PCILx_ROMTag,
83 Dosboot_ROMTag,
84 GFX_ROMTag,
85 #if ENABLE_X11 == 1
86 X11Cl_ROMTag,
87 #endif
88 Bootmenu_ROMTag;
90 /* This list MUST be in the correct order (priority). */
91 static const struct Resident *romtagList[] =
93 &Expansion_ROMTag, /* SingleTask, 110 */
94 &Exec_resident, /* SingleTask, 105 */
95 &Utility_ROMTag, /* ColdStart, 103 */
96 &Aros_ROMTag, /* ColdStart, 102 */
97 &Mathieeesingbas_ROMTag, /* ColdStart, 101 */
98 &Bootloader_ROMTag, /* ColdStart, 100 */
99 #if 0
100 &BOOPSI_resident, /* ColdStart, 95 */
101 #endif
102 &OOP_ROMTag, /* ColdStart, 94 */
103 &HIDDCl_ROMTag, /* ColdStart, 92 */
104 &UXIO_ROMTag, /* ColdStart, 91 */
105 &HostLib_ROMTag, /* ColdStart, 91 */
106 #if defined(__i386__) || defined(__x86_64__)
107 &PCI_ROMTag, /* ColdStart, 90 */
108 // &PCILx_ROMTag, /* ColdStart, 89 */
109 #endif
110 &Graphics_ROMTag, /* ColdStart, 65 */
111 &Layers_ROMTag, /* ColdStart, 60 */
112 &Timer_ROMTag, /* ColdStart, 50 */
113 &Battclock_ROMTag, /* ColdStart, 45 */
114 &Keyboard_ROMTag, /* ColdStart, 44 */
115 &Gameport_ROMTag, /* ColdStart, 43 */
116 &Keymap_ROMTag, /* ColdStart, 40 */
117 &Input_ROMTag, /* ColdStart, 30 */
118 &Intuition_ROMTag, /* ColdStart, 10 */
119 &GFX_ROMTag, /* ColdStart, 10 */
120 /* This driver now causes segmentation fault and trashes the
121 display. Probably previously it failed to initialize because
122 its superclass was not initialized. Now everything is OK.
123 I've looked at the code, it creates input task during
124 resident initialization, not during driver instantiation.
125 I guess this causes some weird conflicts with running X server.
126 Disabled for now, needs to be seriously rewritten.
127 Pavel Fedin <sonic.amiga@gmail.com>
128 &LinuxFB_ROMTag,*/ /* ColdStart, 9 */
129 #if ENABLE_X11 == 1
130 &X11Cl_ROMTag, /* ColdStart, 9 */
131 #endif
132 &Cybergraphics_ROMTag, /* ColdStart, 8 */
133 &Console_ROMTag, /* ColdStart, 5 */
134 #if ENABLE_DBUS == 1
135 &Dbus_ROMTag, /* ColdStart, 0 */
136 #endif
137 &emul_handler_ROMTag, /* ColdStart, 0 */
138 &UXSer_ROMTag, /* ColdStart, 0 */
139 &UXPar_ROMTag, /* ColdStart, 0 */
140 &Workbench_ROMTag, /* ColdStart, -120 */
141 &Mathffp_ROMTag, /* ColdStart, -120 */
144 NOTE: You must not put anything between these two; the code
145 which initialized boot_resident will directly call
146 Dos_resident and anything between the two will be skipped.
148 &boot_resident, /* ColdStart, -50 */
149 &Dos_ROMTag, /* None, -120 */
150 &LDDemon_resident, /* AfterDOS, -123 */
151 &Con_ROMTag, /* AfterDOS, -124 */
152 &Packet_ROMTag, /* AfterDOS, -124 */
153 &Nil_ROMTag, /* AfterDOS, -125 */
154 &Ram_ROMTag, /* AfterDOS, -125 */
155 // &Partition_ROMTag,
156 &Bootmenu_ROMTag, /* AfterDOS, -127 */
157 &Dosboot_ROMTag, /* AfterDOS, -128 */
158 NULL
161 /* So we can examine the memory */
162 static struct MemHeaderExt mhe;
163 struct MemHeader *mh = &mhe.mhe_MemHeader;
164 UBYTE *memory, *space;
165 int memSize = 32;
167 extern void InitCore(void);
168 extern struct ExecBase *PrepareExecBase(struct MemHeader *mh);
170 extern APTR __libc_malloc(size_t);
171 extern VOID __libc_free(APTR);
172 extern APTR __libc_calloc(size_t, size_t);
173 extern APTR __libc_realloc(APTR mem, size_t newsize);
176 static int memnest;
177 #define MEMLOCK Forbid();
178 #define MEMUNLOCK Permit();
180 static APTR myAlloc(struct MemHeaderExt *mhe, ULONG size, ULONG *flags)
182 APTR ret;
184 if (flags && (*flags & MEMF_CLEAR))
185 ret = __libc_calloc(1, size);
186 else
187 ret = __libc_malloc(size);
189 if (ret)
191 if (flags) *flags &= ~MEMF_CLEAR;
192 mhe->mhe_MemHeader.mh_Free -= size;
195 return ret;
198 static VOID myFree(struct MemHeaderExt *mhe, APTR mem, ULONG size)
200 mhe->mhe_MemHeader.mh_Free += size;
202 return __libc_free(mem);
205 static ULONG myAvail(struct MemHeaderExt *mhe, ULONG flags)
207 if (flags & MEMF_TOTAL)
208 return memSize << 20;
210 return mhe->mhe_MemHeader.mh_Free;
213 BOOL use_hostmem = FALSE;
215 APTR malloc(size_t size)
217 APTR retval;
219 if (use_hostmem)
220 return AllocVec(size, MEMF_ANY);
222 //kprintf("malloc %s\n", FindTask(0)->tc_Node.ln_Name);
223 MEMLOCK
225 memnest++;
226 if (memnest > 1) kprintf("==== NESTING in malloc %d %s\n", memnest, FindTask(0)->tc_Node.ln_Name);
228 retval = __libc_malloc(size);
230 memnest--;
232 MEMUNLOCK
234 return retval;
237 VOID free(APTR mem)
239 if (use_hostmem)
240 return FreeVec(mem);
242 MEMLOCK
243 memnest++;
244 if (memnest > 1) kprintf("==== NESTING in free %d\n", memnest);
246 __libc_free(mem);
247 memnest--;
248 MEMUNLOCK
251 APTR calloc(size_t n, size_t size)
253 APTR retval;
255 if (use_hostmem)
256 return AllocVec(size * n, MEMF_CLEAR);
258 MEMLOCK
259 memnest++;
260 if (memnest > 1) kprintf("==== NESTING in calloc %d\n", memnest);
262 retval = __libc_calloc(n, size);
264 memnest--;
265 MEMUNLOCK
267 return retval;
271 static APTR ReAllocVec(APTR old, size_t size, ULONG flags)
273 APTR new = AllocVec(size, flags);
275 if (new)
277 if (old)
279 ULONG oldsize = *(ULONG *)((char *)old - AROS_ALIGN(sizeof(ULONG)));
281 memcpy(new, old, oldsize > size ? size : oldsize);
282 FreeVec(old);
284 old = new;
287 return old;
290 APTR realloc(APTR mem, size_t size)
292 APTR retval;
294 if (use_hostmem)
295 return ReAllocVec(mem, size, MEMF_ANY);
297 MEMLOCK
298 memnest++;
299 if (memnest > 1) kprintf("==== NESTING in realloc %d\n", memnest);
301 retval = __libc_realloc(mem, size);
303 memnest--;
304 MEMUNLOCK
306 return retval;
309 char *join_string(int argc, char **argv)
311 char *str, *s;
312 int j;
313 int x = 0;
315 for (j = 0; j < argc; j++)
316 x += (strlen(argv[j]) + 1);
317 D(printf("[Init] Allocating %lu bytes for string\n", x));
318 str = __libc_malloc(x);
319 if (str) {
320 s = str;
321 for (j = 0; j < argc; j++) {
322 strcpy(s, argv[j]);
323 s += strlen(s);
324 *s++ = ' ';
326 s[-1] = 0;
327 D(printf("[Init] Joined line: %s\n", str));
329 return str;
333 This is where AROS is first called by whatever system loaded it,
334 either some kind of boot loader, or a "parent" operating system.
336 For boot loaded $(ARCH), you don't need to define main() like this,
337 you can have it anyway your bootloader likes.
340 extern char _start, _end;
341 char *BootLoader_Name = NULL;
342 char *Kernel_Args = NULL;
343 char **Kernel_ArgV;
345 int main(int argc, char **argv)
347 struct ExecBase *SysBase;
348 int psize = 0;
349 int i = 1, x;
350 struct utsname sysinfo;
351 char *nameparts[4];
352 int ticrate = 100;
353 BOOL mapSysBase = FALSE;
354 BOOL _use_hostmem = FALSE;
356 while (i < argc)
358 if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
360 printf
362 "AROS for Linux\n"
363 "usage: %s [options] [kernel arguments]\n"
364 "Availible options:\n"
365 " -h show this page\n"
366 " -m <size> allocate <size> Megabytes of memory for AROS\n"
367 " -M allows programs to read SysBase from Address $4; SysBase is\n"
368 " found there in big endian format\n"
369 " -t <value> timer ticks per second. Must be Multiple of 50; max value\n"
370 " working on 2.4 kernels is 100; on 2.6 kernels it is 1000;\n"
371 " default is 100.\n"
372 " --help same as '-h'\n"
373 " --memsize <size> same as '-m <size>'\n"
374 " --mapsysbase same as '-M'\n"
375 " --tickrate <value> same as '-t <value>'\n"
376 " --hostmem Let AROS use the host operating system's facilities to\n"
377 " manage memory, rather than the AROS' builtin ones.\n"
378 "\n"
379 "Please report bugs to the AROS development team. http://www.aros.org/\n",
380 argv[0]
382 return 0;
384 else if (!strcmp(argv[i], "--memsize") || !strcmp(argv[i], "-m"))
386 i++;
387 x = 0;
388 memSize = 0;
389 while ((argv[i])[x] >= '0' && (argv[i])[x] <= '9')
391 memSize = memSize * 10 + (argv[i])[x] - '0';
392 x++;
394 i++;
396 else if (!strcmp(argv[i], "--mapsysbase") || !strcmp(argv[i], "-M"))
398 mapSysBase = TRUE;
399 i++;
401 else if (!strcmp(argv[i], "--ticrate") || !strcmp(argv[i], "-t"))
403 i++;
404 x = 0;
405 ticrate = 0;
406 while ((argv[i])[x] >= '0' && (argv[i])[x] <= '9')
408 ticrate = ticrate * 10 + (argv[i])[x] - '0';
409 x++;
411 i++;
413 else if (!strcmp(argv[i], "--hostmem"))
415 _use_hostmem = TRUE;
416 i++;
418 else
419 break;
422 if (i < argc)
423 Kernel_Args = join_string(argc - i, &argv[i]);
425 uname(&sysinfo);
426 nameparts[0] = sysinfo.sysname;
427 nameparts[1] = sysinfo.machine;
428 nameparts[2] = sysinfo.release;
429 nameparts[3] = sysinfo.version;
430 BootLoader_Name = join_string(4, nameparts);
431 Kernel_ArgV = argv;
434 First up, set up the memory.
436 If your memory starts at 0 (I think Linux does, FreeBSD doesn't),
437 then you can allocate 4K at that address, and do whatever you want
438 to make that invalid to trap NULL dereference errors.
442 #if defined(__linux__) && defined(__mc68000__)
444 if (TRUE == mapSysBase)
446 psize = getpagesize();
447 space = mmap((APTR)0, (memSize << 20), PROT_READ|PROT_WRITE,
448 MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
449 if (space != (UBYTE *)-1)
451 int size = psize/sizeof(ULONG);
452 memory = (UBYTE *)((IPTR)space + psize);
453 while(--size)
454 ((ULONG *)space)[size] = 0xDEADBEEF;
456 else
458 perror("mmap");
459 exit(20);
462 else
464 #else
466 if (!_use_hostmem)
468 /* We allocate memSize megabytes */
469 #ifdef __x86_64__
470 /* Allocate AROS memory in the first 2GB on x86-64 machines,
471 * otherwise relocations won't work correctly */
472 memory = mmap((APTR)0, (memSize << 20), PROT_READ|PROT_WRITE,
473 MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, -1, 0);
474 if( memory == (UBYTE *)-1 )
475 #else
476 if( posix_memalign(&memory, getpagesize(), (memSize << 20)) != 0 )
477 #endif
479 /*fprintf(stderr, "Cannot allocate any memory!\n");*/
480 exit(20);
482 /* Make whole AROS memory area executable */
483 if (mprotect(memory, memSize << 20, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
484 perror("mprotect failed");
486 else
488 /* The host system is going to allocate memory through AROS,
489 allocate some more memory for it. */
490 memSize += 8;
493 #endif
495 /* Prepare the first mem header */
496 mh->mh_Node.ln_Type = NT_MEMORY;
497 mh->mh_Node.ln_Name = "chip memory";
498 mh->mh_Node.ln_Pri = -5;
499 mh->mh_Attributes = MEMF_CHIP | MEMF_PUBLIC | MEMF_LOCAL |
500 MEMF_24BITDMA | MEMF_KICK;
502 if (_use_hostmem)
504 mh->mh_Attributes |= MEMF_MANAGED;
505 mh->mh_First = NULL;
506 mh->mh_Lower = (char *)&_end + 1;
507 mh->mh_Upper = (APTR)(~(IPTR)0 / 2); /* Should use getrlimit here. */
508 mh->mh_Free = memSize << 20;
510 ((struct MemHeaderExt *)mh)->mhe_Alloc = myAlloc;
511 ((struct MemHeaderExt *)mh)->mhe_Free = myFree;
512 ((struct MemHeaderExt *)mh)->mhe_Avail = myAvail;
514 else
516 mh->mh_First = (struct MemChunk *)memory;
517 mh->mh_First->mc_Next = NULL;
518 mh->mh_First->mc_Bytes = (memSize << 20) - psize;
520 mh->mh_Lower = mh->mh_First;
521 mh->mh_Upper = (APTR)(memory + (memSize << 20) - psize);
522 mh->mh_Free = mh->mh_First->mc_Bytes;
526 This will prepare enough of ExecBase to allow us to
527 call functions, it will also set up the memory list.
529 SysBase = PrepareExecBase(mh);
530 SysBase->PowerSupplyFrequency = ticrate / SysBase->VBlankFrequency;
532 use_hostmem = _use_hostmem;
534 /* ROM memory header. This special memory header covers all ROM code and data sections
535 * so that TypeOfMem() will not return 0 for addresses pointing into the kernel.
537 if ((mh = (struct MemHeader *)AllocMem(sizeof(struct MemHeader), MEMF_PUBLIC)))
539 /* These symbols are provided by the linker on most platforms */
540 mh->mh_Node.ln_Type = NT_MEMORY;
541 mh->mh_Node.ln_Name = "rom memory";
542 mh->mh_Node.ln_Pri = -128;
543 mh->mh_Attributes = MEMF_KICK;
544 mh->mh_First = NULL;
545 mh->mh_Lower = (APTR)&_start;
546 mh->mh_Upper = (APTR)&_end;
547 mh->mh_Free = 0; /* Never allocate from this chunk! */
548 Forbid();
549 Enqueue(&SysBase->MemList, &mh->mh_Node);
551 /* Ok, lets start up the kernel, we are probably using the UNIX
552 kernel, or a variant of that (see config/unix).
554 InitCore();
556 /* On Linux/m68k where we can run old Amiga binaries, we should
557 put SysBase at location 4. On other systems, DON'T DO THIS.
560 #if defined(__linux__) && defined(__mc68000__)
562 if (TRUE == mapSysBase)
564 *(APTR *)4 = (APTR)SWAP(SysBase);
565 if (mprotect((APTR)0, psize, PROT_READ))
567 perror("mprotect");
568 exit(10);
572 #endif
574 /* We might also be interested in using the BS key instead of the
575 delete key, this will do that
577 #if 0 /* !defined(__x86_64__) */
578 tcgetattr(0, &t);
579 t.c_cc[VERASE] = '\b';
580 #ifndef TCSASOFT
581 # define TCSASOFT 0
582 #endif
583 tcsetattr(0, TCSANOW|TCSASOFT, &t);
584 #endif
585 /* There is nothing more system dependant to set up,
586 so lets start that ball rolling...
588 The InitCode() call should never return in a working system.
590 SysBase->ResModules = romtagList;
591 InitCode(RTF_SINGLETASK, 0);
592 fprintf(stderr,"Returned from InitCode()\n");
593 return 1;