Included header with kprintf() declaration to prevent problems with building hosted...
[cake.git] / arch / all-linux / exec / init.c
blobe823dbcebe9bc75b422e8e5ea93a594fe6794194
1 /*
2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Linux init code for emulated (Unix) systems.
6 Lang: english
7 */
10 #include <exec/types.h>
11 #include <exec/memory.h>
12 #include <exec/memheaderext.h>
13 #include <exec/resident.h>
14 #include <exec/execbase.h>
16 #include <proto/exec.h>
17 #include <aros/debug.h>
19 #if (AROS_BIG_ENDIAN == 0)
20 #define SWAP(x) ((((ULONG)x >> 24) & 0x000000ff) |\
21 (((ULONG)x >> 8 ) & 0x0000ff00) |\
22 (((ULONG)x << 8 ) & 0x00ff0000) |\
23 (((ULONG)x << 24) & 0xff000000) )
24 #else
25 #define SWAP(x) x
26 #endif
28 #define _XOPEN_SOURCE 600L /* for posix_memalign */
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <string.h>
33 #define __USE_MISC /* for MAP_ANON */
34 #include <sys/mman.h>
35 #include <sys/termios.h>
37 #include "../../../rom/exec/memory.h" /* From $(TOP)/rom/exec */
39 extern const struct Resident
40 Expansion_ROMTag,
41 Exec_resident,
42 Utility_ROMTag,
43 Aros_ROMTag,
44 /* BOOPSI_resident,*/
45 OOP_ROMTag,
46 HIDDCl_ROMTag,
47 UXIO_ROMTag,
48 HostLib_ROMTag,
49 Graphics_ROMTag,
50 Layers_ROMTag,
51 Timer_ROMTag,
52 Battclock_ROMTag,
53 Keyboard_ROMTag,
54 Gameport_ROMTag,
55 Keymap_ROMTag,
56 Input_ROMTag,
57 Intuition_ROMTag,
58 LinuxFB_ROMTag,
59 Cybergraphics_ROMTag,
60 Console_ROMTag,
61 #if ENABLE_DBUS == 1
62 Dbus_ROMTag,
63 #endif
64 Mathffp_ROMTag,
65 Mathieeesingbas_ROMTag,
66 Workbench_ROMTag,
67 Dos_ROMTag,
68 LDDemon_resident,
69 emul_handler_ROMTag,
70 Packet_ROMTag,
71 UXSer_ROMTag,
72 UXPar_ROMTag,
73 boot_resident,
74 Con_ROMTag,
75 Nil_ROMTag,
76 Ram_ROMTag,
77 PCI_ROMTag,
78 PCILx_ROMTag;
81 /* This list MUST be in the correct order (priority). */
82 static const struct Resident *romtagList[] =
84 &Expansion_ROMTag, /* SingleTask, 110 */
85 &Exec_resident, /* SingleTask, 105 */
86 &Utility_ROMTag, /* ColdStart, 103 */
87 &Aros_ROMTag, /* ColdStart, 102 */
88 &Mathieeesingbas_ROMTag, /* ColdStart, 101 */
89 #if 0
90 &BOOPSI_resident, /* ColdStart, 95 */
91 #endif
92 &OOP_ROMTag, /* ColdStart, 94 */
93 &HIDDCl_ROMTag, /* ColdStart, 92 */
94 &UXIO_ROMTag, /* ColdStart, 91 */
95 &HostLib_ROMTag, /* ColdStart, 91 */
96 #if defined(__i386__) || defined(__x86_64__)
97 &PCI_ROMTag, /* ColdStart, 90 */
98 // &PCILx_ROMTag, /* ColdStart, 89 */
99 #endif
100 &Graphics_ROMTag, /* ColdStart, 65 */
101 &Layers_ROMTag, /* ColdStart, 60 */
102 &Timer_ROMTag, /* ColdStart, 50 */
103 &Battclock_ROMTag, /* ColdStart, 45 */
104 &Keyboard_ROMTag, /* ColdStart, 44 */
105 &Gameport_ROMTag, /* ColdStart, 43 */
106 &Keymap_ROMTag, /* ColdStart, 40 */
107 &Input_ROMTag, /* ColdStart, 30 */
108 &Intuition_ROMTag, /* ColdStart, 10 */
109 &LinuxFB_ROMTag, /* ColdStart, 9 */
110 &Cybergraphics_ROMTag, /* ColdStart, 8 */
111 &Console_ROMTag, /* ColdStart, 5 */
112 #if ENABLE_DBUS == 1
113 &Dbus_ROMTag, /* ColdStart, 0 */
114 #endif
115 &emul_handler_ROMTag, /* ColdStart, 0 */
116 &Packet_ROMTag, /* ColdStart, 0 */
117 &UXSer_ROMTag, /* ColdStart, 0 */
118 &UXPar_ROMTag, /* ColdStart, 0 */
119 &Workbench_ROMTag, /* ColdStart, -120 */
120 &Mathffp_ROMTag, /* ColdStart, -120 */
123 NOTE: You must not put anything between these two; the code
124 which initialized boot_resident will directly call
125 Dos_resident and anything between the two will be skipped.
127 &boot_resident, /* ColdStart, -50 */
128 &Dos_ROMTag, /* None, -120 */
129 &LDDemon_resident, /* AfterDOS, -125 */
130 &Con_ROMTag, /* AfterDOS, -126 */
131 &Nil_ROMTag, /* AfterDOS, -127 */
132 &Ram_ROMTag, /* AfterDOS, -128 */
133 // &Partition_ROMTag,
135 NULL
138 /* So we can examine the memory */
139 static struct MemHeaderExt mhe;
140 struct MemHeader *mh = &mhe.mhe_MemHeader;
141 UBYTE *memory, *space;
142 int memSize = 32;
144 extern void InitCore(void);
145 extern struct ExecBase *PrepareExecBase(struct MemHeader *mh);
147 extern APTR __libc_malloc(size_t);
148 extern VOID __libc_free(APTR);
149 extern APTR __libc_calloc(size_t, size_t);
150 extern APTR __libc_realloc(APTR mem, size_t newsize);
153 static int memnest;
154 #define MEMLOCK Forbid();
155 #define MEMUNLOCK Permit();
157 static APTR myAlloc(struct MemHeaderExt *mhe, ULONG size, ULONG *flags)
159 APTR ret;
161 if (flags && (*flags & MEMF_CLEAR))
162 ret = __libc_calloc(1, size);
163 else
164 ret = __libc_malloc(size);
166 if (ret)
168 if (flags) *flags &= ~MEMF_CLEAR;
169 mhe->mhe_MemHeader.mh_Free -= size;
172 return ret;
175 static VOID myFree(struct MemHeaderExt *mhe, APTR mem, ULONG size)
177 mhe->mhe_MemHeader.mh_Free += size;
179 return __libc_free(mem);
182 static ULONG myAvail(struct MemHeaderExt *mhe, ULONG flags)
184 if (flags & MEMF_TOTAL)
185 return memSize << 20;
187 return mhe->mhe_MemHeader.mh_Free;
190 BOOL use_hostmem = FALSE;
192 APTR malloc(size_t size)
194 APTR retval;
196 if (use_hostmem)
197 return AllocVec(size, MEMF_ANY);
199 //kprintf("malloc %s\n", FindTask(0)->tc_Node.ln_Name);
200 MEMLOCK
202 memnest++;
203 if (memnest > 1) kprintf("==== NESTING in malloc %d %s\n", memnest, FindTask(0)->tc_Node.ln_Name);
205 retval = __libc_malloc(size);
207 memnest--;
209 MEMUNLOCK
211 return retval;
214 VOID free(APTR mem)
216 if (use_hostmem)
217 return FreeVec(mem);
219 MEMLOCK
220 memnest++;
221 if (memnest > 1) kprintf("==== NESTING in free %d\n", memnest);
223 __libc_free(mem);
224 memnest--;
225 MEMUNLOCK
228 APTR calloc(size_t n, size_t size)
230 APTR retval;
232 if (use_hostmem)
233 return AllocVec(size * n, MEMF_CLEAR);
235 MEMLOCK
236 memnest++;
237 if (memnest > 1) kprintf("==== NESTING in calloc %d\n", memnest);
239 retval = __libc_calloc(n, size);
241 memnest--;
242 MEMUNLOCK
244 return retval;
248 static APTR ReAllocVec(APTR old, size_t size, ULONG flags)
250 APTR new = AllocVec(size, flags);
252 if (new)
254 if (old)
256 ULONG oldsize = *(ULONG *)((char *)old - AROS_ALIGN(sizeof(ULONG)));
258 memcpy(new, old, oldsize > size ? size : oldsize);
259 FreeVec(old);
261 old = new;
264 return old;
267 APTR realloc(APTR mem, size_t size)
269 APTR retval;
271 if (use_hostmem)
272 return ReAllocVec(mem, size, MEMF_ANY);
274 MEMLOCK
275 memnest++;
276 if (memnest > 1) kprintf("==== NESTING in realloc %d\n", memnest);
278 retval = __libc_realloc(mem, size);
280 memnest--;
281 MEMUNLOCK
283 return retval;
287 This is where AROS is first called by whatever system loaded it,
288 either some kind of boot loader, or a "parent" operating system.
290 For boot loaded $(ARCH), you don't need to define main() like this,
291 you can have it anyway your bootloader likes.
294 extern char _start, _end;
296 int main(int argc, char **argv)
298 /* Well, if you want you can take in command line arguments here,
299 but that is not necessary, or perhaps rather complex...
301 eg: say you wished to allow people to specify the root directory
302 arosshell --rootdir /usr/local/AROS --memsize 4
304 For an example, you could ask how much memory you want for the
305 system, chip/fast whatever...
308 struct ExecBase *SysBase;
309 struct termios t;
310 int psize = 0;
311 int i = 0, x;
312 int ticrate = 100;
313 BOOL mapSysBase = FALSE;
314 BOOL _use_hostmem = FALSE;
316 while (i < argc)
318 if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
320 printf
322 "AROS for Linux\n"
323 "usage: %s [options]\n"
324 " -h show this page\n"
325 " -m <size> allocate <size> Megabytes of memory for AROS\n"
326 " -M allows programs to read SysBase from Address $4; SysBase is\n"
327 " found there in big endian format\n"
328 " -t <value> timer ticks per second. Must be Multiple of 50; max value\n"
329 " working on 2.4 kernels is 100; on 2.6 kernels it is 1000;\n"
330 " default is 100.\n"
331 " --help same as '-h'\n"
332 " --memsize <size> same as '-m <size>'\n"
333 " --mapsysbase same as '-M'\n"
334 " --tickrate <value> same as '-t <value>'\n"
335 " --hostmem Let AROS use the host operating system's facilities to\n"
336 " manage memory, rather than the AROS' builtin ones.\n"
337 "\n"
338 "Please report bugs to the AROS development team. http://www.aros.org/\n",
339 argv[0]
341 return 0;
343 else
344 if (!strcmp(argv[i], "--memsize") || !strcmp(argv[i], "-m"))
346 i++;
347 x = 0;
348 memSize = 0;
349 while ((argv[i])[x] >= '0' && (argv[i])[x] <= '9')
351 memSize = memSize * 10 + (argv[i])[x] - '0';
352 x++;
354 i++;
356 else
357 if (!strcmp(argv[i], "--mapsysbase") || !strcmp(argv[i], "-M"))
359 mapSysBase = TRUE;
360 i++;
362 else
363 if (!strcmp(argv[i], "--ticrate") || !strcmp(argv[i], "-t"))
365 i++;
366 x = 0;
367 ticrate = 0;
368 while ((argv[i])[x] >= '0' && (argv[i])[x] <= '9')
370 ticrate = ticrate * 10 + (argv[i])[x] - '0';
371 x++;
373 i++;
375 else
376 if (!strcmp(argv[i], "--hostmem"))
378 _use_hostmem = TRUE;
379 i++;
381 else
382 i++;
386 First up, set up the memory.
388 If your memory starts at 0 (I think Linux does, FreeBSD doesn't),
389 then you can allocate 4K at that address, and do whatever you want
390 to make that invalid to trap NULL dereference errors.
394 #if defined(__linux__) && defined(__mc68000__)
396 if (TRUE == mapSysBase)
398 psize = getpagesize();
399 space = mmap((APTR)0, (memSize << 20), PROT_READ|PROT_WRITE,
400 MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
401 if (space != (UBYTE *)-1)
403 int size = psize/sizeof(ULONG);
404 memory = (UBYTE *)((IPTR)space + psize);
405 while(--size)
406 ((ULONG *)space)[size] = 0xDEADBEEF;
408 else
410 perror("mmap");
411 exit(20);
414 else
416 #else
418 if (!_use_hostmem)
420 /* We allocate memSize megabytes */
421 #ifdef __x86_64__
422 /* Allocate AROS memory in the first 2GB on x86-64 machines,
423 * otherwise relocations won't work correctly */
424 memory = mmap((APTR)0, (memSize << 20), PROT_READ|PROT_WRITE,
425 MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, -1, 0);
426 if( memory == (UBYTE *)-1 )
427 #else
428 if( posix_memalign(&memory, getpagesize(), (memSize << 20)) != 0 )
429 #endif
431 /*fprintf(stderr, "Cannot allocate any memory!\n");*/
432 exit(20);
434 /* Make whole AROS memory area executable */
435 if (mprotect(memory, memSize << 20, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
436 perror("mprotect failed");
438 else
440 /* The host system is going to allocate memory through AROS,
441 allocate some more memory for it. */
442 memSize += 8;
445 #endif
447 /* Prepare the first mem header */
448 mh->mh_Node.ln_Type = NT_MEMORY;
449 mh->mh_Node.ln_Name = "chip memory";
450 mh->mh_Node.ln_Pri = -5;
451 mh->mh_Attributes = MEMF_CHIP | MEMF_PUBLIC | MEMF_LOCAL |
452 MEMF_24BITDMA | MEMF_KICK;
454 if (_use_hostmem)
456 mh->mh_Attributes |= MEMF_MANAGED;
457 mh->mh_First = NULL;
458 mh->mh_Lower = (char *)&_end + 1;
459 mh->mh_Upper = (APTR)(~(IPTR)0 / 2); /* Should use getrlimit here. */
460 mh->mh_Free = memSize << 20;
462 ((struct MemHeaderExt *)mh)->mhe_Alloc = myAlloc;
463 ((struct MemHeaderExt *)mh)->mhe_Free = myFree;
464 ((struct MemHeaderExt *)mh)->mhe_Avail = myAvail;
466 else
468 mh->mh_First = (struct MemChunk *)memory;
469 mh->mh_First->mc_Next = NULL;
470 mh->mh_First->mc_Bytes = (memSize << 20) - psize;
472 mh->mh_Lower = mh->mh_First;
473 mh->mh_Upper = (APTR)(memory + (memSize << 20) - psize);
474 mh->mh_Free = mh->mh_First->mc_Bytes;
478 This will prepare enough of ExecBase to allow us to
479 call functions, it will also set up the memory list.
481 SysBase = PrepareExecBase(mh);
482 SysBase->PowerSupplyFrequency = ticrate / SysBase->VBlankFrequency;
484 use_hostmem = _use_hostmem;
486 /* ROM memory header. This special memory header covers all ROM code and data sections
487 * so that TypeOfMem() will not return 0 for addresses pointing into the kernel.
489 if ((mh = (struct MemHeader *)AllocMem(sizeof(struct MemHeader), MEMF_PUBLIC)))
491 /* These symbols are provided by the linker on most platforms */
492 mh->mh_Node.ln_Type = NT_MEMORY;
493 mh->mh_Node.ln_Name = "rom memory";
494 mh->mh_Node.ln_Pri = -128;
495 mh->mh_Attributes = MEMF_KICK;
496 mh->mh_First = NULL;
497 mh->mh_Lower = (APTR)&_start;
498 mh->mh_Upper = (APTR)&_end;
499 mh->mh_Free = 0; /* Never allocate from this chunk! */
500 Forbid();
501 Enqueue(&SysBase->MemList, &mh->mh_Node);
503 /* Ok, lets start up the kernel, we are probably using the UNIX
504 kernel, or a variant of that (see config/unix).
506 InitCore();
508 /* On Linux/m68k where we can run old Amiga binaries, we should
509 put SysBase at location 4. On other systems, DON'T DO THIS.
512 #if defined(__linux__) && defined(__mc68000__)
514 if (TRUE == mapSysBase)
516 *(APTR *)4 = (APTR)SWAP(SysBase);
517 if (mprotect((APTR)0, psize, PROT_READ))
519 perror("mprotect");
520 exit(10);
524 #endif
526 /* We might also be interested in using the BS key instead of the
527 delete key, this will do that
529 #if 0 /* !defined(__x86_64__) */
530 tcgetattr(0, &t);
531 t.c_cc[VERASE] = '\b';
532 #ifndef TCSASOFT
533 # define TCSASOFT 0
534 #endif
535 tcsetattr(0, TCSANOW|TCSASOFT, &t);
536 #endif
537 /* There is nothing more system dependant to set up,
538 so lets start that ball rolling...
540 The InitCode() call should never return in a working system.
542 SysBase->ResModules = romtagList;
543 InitCode(RTF_SINGLETASK, 0);
544 fprintf(stderr,"Returned from InitCode()\n");
545 return 1;