make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / all-linux / exec / init.c
blob09a9d3f83195de85162f5a17ba1eb804d0c3b24d
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>
18 #if (AROS_BIG_ENDIAN == 0)
19 #define SWAP(x) ((((ULONG)x >> 24) & 0x000000ff) |\
20 (((ULONG)x >> 8 ) & 0x0000ff00) |\
21 (((ULONG)x << 8 ) & 0x00ff0000) |\
22 (((ULONG)x << 24) & 0xff000000) )
23 #else
24 #define SWAP(x) x
25 #endif
27 #define _XOPEN_SOURCE 600L /* for posix_memalign */
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <string.h>
32 #define __USE_MISC /* for MAP_ANON */
33 #include <sys/mman.h>
34 #include <sys/termios.h>
36 #include "../../../rom/exec/memory.h" /* From $(TOP)/rom/exec */
38 extern const struct Resident
39 Expansion_ROMTag,
40 Exec_resident,
41 Utility_ROMTag,
42 Aros_ROMTag,
43 /* BOOPSI_resident,*/
44 OOP_ROMTag,
45 HIDDCl_ROMTag,
46 UXIO_ROMTag,
47 HostLib_ROMTag,
48 Graphics_ROMTag,
49 Layers_ROMTag,
50 Timer_ROMTag,
51 Battclock_ROMTag,
52 Keyboard_ROMTag,
53 Gameport_ROMTag,
54 Keymap_ROMTag,
55 Input_ROMTag,
56 Intuition_ROMTag,
57 LinuxFB_ROMTag,
58 Cybergraphics_ROMTag,
59 Console_ROMTag,
60 #if ENABLE_DBUS == 1
61 Dbus_ROMTag,
62 #endif
63 Mathffp_ROMTag,
64 Mathieeesingbas_ROMTag,
65 Workbench_ROMTag,
66 Dos_ROMTag,
67 LDDemon_resident,
68 emul_handler_ROMTag,
69 Packet_ROMTag,
70 UXSer_ROMTag,
71 UXPar_ROMTag,
72 boot_resident,
73 Con_ROMTag,
74 Nil_ROMTag,
75 Ram_ROMTag,
76 PCI_ROMTag,
77 PCILx_ROMTag;
80 /* This list MUST be in the correct order (priority). */
81 static const struct Resident *romtagList[] =
83 &Expansion_ROMTag, /* SingleTask, 110 */
84 &Exec_resident, /* SingleTask, 105 */
85 &Utility_ROMTag, /* ColdStart, 103 */
86 &Aros_ROMTag, /* ColdStart, 102 */
87 &Mathieeesingbas_ROMTag, /* ColdStart, 101 */
88 #if 0
89 &BOOPSI_resident, /* ColdStart, 95 */
90 #endif
91 &OOP_ROMTag, /* ColdStart, 94 */
92 &HIDDCl_ROMTag, /* ColdStart, 92 */
93 &UXIO_ROMTag, /* ColdStart, 91 */
94 &HostLib_ROMTag, /* ColdStart, 91 */
95 #if defined(__i386__) || defined(__x86_64__)
96 &PCI_ROMTag, /* ColdStart, 90 */
97 // &PCILx_ROMTag, /* ColdStart, 89 */
98 #endif
99 &Graphics_ROMTag, /* ColdStart, 65 */
100 &Layers_ROMTag, /* ColdStart, 60 */
101 &Timer_ROMTag, /* ColdStart, 50 */
102 &Battclock_ROMTag, /* ColdStart, 45 */
103 &Keyboard_ROMTag, /* ColdStart, 44 */
104 &Gameport_ROMTag, /* ColdStart, 43 */
105 &Keymap_ROMTag, /* ColdStart, 40 */
106 &Input_ROMTag, /* ColdStart, 30 */
107 &Intuition_ROMTag, /* ColdStart, 10 */
108 &LinuxFB_ROMTag, /* ColdStart, 9 */
109 &Cybergraphics_ROMTag, /* ColdStart, 8 */
110 &Console_ROMTag, /* ColdStart, 5 */
111 #if ENABLE_DBUS == 1
112 &Dbus_ROMTag, /* ColdStart, 0 */
113 #endif
114 &emul_handler_ROMTag, /* ColdStart, 0 */
115 &Packet_ROMTag, /* ColdStart, 0 */
116 &UXSer_ROMTag, /* ColdStart, 0 */
117 &UXPar_ROMTag, /* ColdStart, 0 */
118 &Workbench_ROMTag, /* ColdStart, -120 */
119 &Mathffp_ROMTag, /* ColdStart, -120 */
122 NOTE: You must not put anything between these two; the code
123 which initialized boot_resident will directly call
124 Dos_resident and anything between the two will be skipped.
126 &boot_resident, /* ColdStart, -50 */
127 &Dos_ROMTag, /* None, -120 */
128 &LDDemon_resident, /* AfterDOS, -125 */
129 &Con_ROMTag, /* AfterDOS, -126 */
130 &Nil_ROMTag, /* AfterDOS, -127 */
131 &Ram_ROMTag, /* AfterDOS, -128 */
132 // &Partition_ROMTag,
134 NULL
137 /* So we can examine the memory */
138 static struct MemHeaderExt mhe;
139 struct MemHeader *mh = &mhe.mhe_MemHeader;
140 UBYTE *memory, *space;
141 int memSize = 32;
143 extern void InitCore(void);
144 extern struct ExecBase *PrepareExecBase(struct MemHeader *mh);
146 extern APTR __libc_malloc(size_t);
147 extern VOID __libc_free(APTR);
148 extern APTR __libc_calloc(size_t, size_t);
149 extern APTR __libc_realloc(APTR mem, size_t newsize);
152 static APTR myAlloc(struct MemHeaderExt *mhe, ULONG size, ULONG *flags)
154 APTR ret;
156 if (flags && (*flags & MEMF_CLEAR))
157 ret = __libc_calloc(1, size);
158 else
159 ret = __libc_malloc(size);
161 if (ret)
163 if (flags) *flags &= ~MEMF_CLEAR;
164 mhe->mhe_MemHeader.mh_Free -= size;
167 return ret;
170 static VOID myFree(struct MemHeaderExt *mhe, APTR mem, ULONG size)
172 mhe->mhe_MemHeader.mh_Free += size;
174 return __libc_free(mem);
177 static ULONG myAvail(struct MemHeaderExt *mhe, ULONG flags)
179 if (flags & MEMF_TOTAL)
180 return memSize << 20;
182 return mhe->mhe_MemHeader.mh_Free;
185 BOOL use_hostmem = FALSE;
187 APTR malloc(size_t size)
189 if (use_hostmem)
190 return AllocVec(size, MEMF_ANY);
192 return __libc_malloc(size);
195 VOID free(APTR mem)
197 if (use_hostmem)
198 return FreeVec(mem);
200 return __libc_free(mem);
203 APTR calloc(size_t n, size_t size)
205 if (use_hostmem)
206 return AllocVec(size * n, MEMF_CLEAR);
208 return __libc_calloc(n, size);
212 static APTR ReAllocVec(APTR old, size_t size, ULONG flags)
214 APTR new = AllocVec(size, flags);
216 if (new)
218 ULONG oldsize = *(ULONG *)((char *)old - AROS_ALIGN(sizeof(ULONG)));
220 memcpy(new, old, oldsize > size ? size : oldsize);
221 FreeVec(old);
222 old = new;
225 return old;
228 APTR realloc(APTR mem, size_t size)
230 if (use_hostmem)
231 return ReAllocVec(mem, size, MEMF_ANY);
233 return __libc_realloc(mem, size);
237 This is where AROS is first called by whatever system loaded it,
238 either some kind of boot loader, or a "parent" operating system.
240 For boot loaded $(ARCH), you don't need to define main() like this,
241 you can have it anyway your bootloader likes.
244 extern char _start, _end;
246 int main(int argc, char **argv)
248 /* Well, if you want you can take in command line arguments here,
249 but that is not necessary, or perhaps rather complex...
251 eg: say you wished to allow people to specify the root directory
252 arosshell --rootdir /usr/local/AROS --memsize 4
254 For an example, you could ask how much memory you want for the
255 system, chip/fast whatever...
258 struct ExecBase *SysBase;
259 struct termios t;
260 int psize = 0;
261 int i = 0, x;
262 int ticrate = 100;
263 BOOL mapSysBase = FALSE;
264 BOOL _use_hostmem = FALSE;
266 while (i < argc)
268 if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
270 printf
272 "AROS for Linux\n"
273 "usage: %s [options]\n"
274 " -h show this page\n"
275 " -m <size> allocate <size> Megabytes of memory for AROS\n"
276 " -M allows programs to read SysBase from Address $4; SysBase is\n"
277 " found there in big endian format\n"
278 " -t <value> timer ticks per second. Must be Multiple of 50; max value\n"
279 " working on 2.4 kernels is 100; on 2.6 kernels it is 1000;\n"
280 " default is 100.\n"
281 " --help same as '-h'\n"
282 " --memsize <size> same as '-m <size>'\n"
283 " --mapsysbase same as '-M'\n"
284 " --tickrate <value> same as '-t <value>'\n"
285 " --hostmem Let AROS use the host operating system's facilities to\n"
286 " manage memory, rather than the AROS' builtin ones.\n"
287 "\n"
288 "Please report bugs to the AROS development team. http://www.aros.org/\n",
289 argv[0]
291 return 0;
293 else
294 if (!strcmp(argv[i], "--memsize") || !strcmp(argv[i], "-m"))
296 i++;
297 x = 0;
298 memSize = 0;
299 while ((argv[i])[x] >= '0' && (argv[i])[x] <= '9')
301 memSize = memSize * 10 + (argv[i])[x] - '0';
302 x++;
304 i++;
306 else
307 if (!strcmp(argv[i], "--mapsysbase") || !strcmp(argv[i], "-M"))
309 mapSysBase = TRUE;
310 i++;
312 else
313 if (!strcmp(argv[i], "--ticrate") || !strcmp(argv[i], "-t"))
315 i++;
316 x = 0;
317 ticrate = 0;
318 while ((argv[i])[x] >= '0' && (argv[i])[x] <= '9')
320 ticrate = ticrate * 10 + (argv[i])[x] - '0';
321 x++;
323 i++;
325 else
326 if (!strcmp(argv[i], "--hostmem"))
328 _use_hostmem = TRUE;
329 i++;
331 else
332 i++;
336 First up, set up the memory.
338 If your memory starts at 0 (I think Linux does, FreeBSD doesn't),
339 then you can allocate 4K at that address, and do whatever you want
340 to make that invalid to trap NULL dereference errors.
344 #if defined(__linux__) && defined(__mc68000__)
346 if (TRUE == mapSysBase)
348 psize = getpagesize();
349 space = mmap((APTR)0, (memSize << 20), PROT_READ|PROT_WRITE,
350 MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
351 if (space != (UBYTE *)-1)
353 int size = psize/sizeof(ULONG);
354 memory = (UBYTE *)((IPTR)space + psize);
355 while(--size)
356 ((ULONG *)space)[size] = 0xDEADBEEF;
358 else
360 perror("mmap");
361 exit(20);
364 else
366 #else
368 if (!_use_hostmem)
370 /* We allocate memSize megabytes */
371 #ifdef __x86_64__
372 /* Allocate AROS memory in the first 2GB on x86-64 machines,
373 * otherwise relocations won't work correctly */
374 memory = mmap((APTR)0, (memSize << 20), PROT_READ|PROT_WRITE,
375 MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, -1, 0);
376 if( memory == (UBYTE *)-1 )
377 #else
378 if( posix_memalign(&memory, getpagesize(), (memSize << 20)) != 0 )
379 #endif
381 /*fprintf(stderr, "Cannot allocate any memory!\n");*/
382 exit(20);
384 /* Make whole AROS memory area executable */
385 if (mprotect(memory, memSize << 20, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
386 perror("mprotect failed");
388 else
390 /* The host system is going to allocate memory through AROS,
391 allocate some more memory for it. */
392 memSize += 8;
395 #endif
397 /* Prepare the first mem header */
398 mh->mh_Node.ln_Type = NT_MEMORY;
399 mh->mh_Node.ln_Name = "chip memory";
400 mh->mh_Node.ln_Pri = -5;
401 mh->mh_Attributes = MEMF_CHIP | MEMF_PUBLIC | MEMF_LOCAL |
402 MEMF_24BITDMA | MEMF_KICK;
404 if (_use_hostmem)
406 mh->mh_Attributes |= MEMF_MANAGED;
407 mh->mh_First = NULL;
408 mh->mh_Lower = (char *)&_end + 1;
409 mh->mh_Upper = (APTR)(~(IPTR)0 / 2); /* Should use getrlimit here. */
410 mh->mh_Free = memSize << 20;
412 ((struct MemHeaderExt *)mh)->mhe_Alloc = myAlloc;
413 ((struct MemHeaderExt *)mh)->mhe_Free = myFree;
414 ((struct MemHeaderExt *)mh)->mhe_Avail = myAvail;
416 else
418 mh->mh_First = (struct MemChunk *)memory;
419 mh->mh_First->mc_Next = NULL;
420 mh->mh_First->mc_Bytes = (memSize << 20) - psize;
422 mh->mh_Lower = mh->mh_First;
423 mh->mh_Upper = (APTR)(memory + (memSize << 20) - psize);
424 mh->mh_Free = mh->mh_First->mc_Bytes;
428 This will prepare enough of ExecBase to allow us to
429 call functions, it will also set up the memory list.
431 SysBase = PrepareExecBase(mh);
432 SysBase->PowerSupplyFrequency = ticrate / SysBase->VBlankFrequency;
434 use_hostmem = _use_hostmem;
436 /* ROM memory header. This special memory header covers all ROM code and data sections
437 * so that TypeOfMem() will not return 0 for addresses pointing into the kernel.
439 if ((mh = (struct MemHeader *)AllocMem(sizeof(struct MemHeader), MEMF_PUBLIC)))
441 /* These symbols are provided by the linker on most platforms */
442 mh->mh_Node.ln_Type = NT_MEMORY;
443 mh->mh_Node.ln_Name = "rom memory";
444 mh->mh_Node.ln_Pri = -128;
445 mh->mh_Attributes = MEMF_KICK;
446 mh->mh_First = NULL;
447 mh->mh_Lower = (APTR)&_start;
448 mh->mh_Upper = (APTR)&_end;
449 mh->mh_Free = 0; /* Never allocate from this chunk! */
450 Forbid();
451 Enqueue(&SysBase->MemList, &mh->mh_Node);
453 /* Ok, lets start up the kernel, we are probably using the UNIX
454 kernel, or a variant of that (see config/unix).
456 InitCore();
458 /* On Linux/m68k where we can run old Amiga binaries, we should
459 put SysBase at location 4. On other systems, DON'T DO THIS.
462 #if defined(__linux__) && defined(__mc68000__)
464 if (TRUE == mapSysBase)
466 *(APTR *)4 = (APTR)SWAP(SysBase);
467 if (mprotect((APTR)0, psize, PROT_READ))
469 perror("mprotect");
470 exit(10);
474 #endif
476 /* We might also be interested in using the BS key instead of the
477 delete key, this will do that
479 #if 0 /* !defined(__x86_64__) */
480 tcgetattr(0, &t);
481 t.c_cc[VERASE] = '\b';
482 #ifndef TCSASOFT
483 # define TCSASOFT 0
484 #endif
485 tcsetattr(0, TCSANOW|TCSASOFT, &t);
486 #endif
487 /* There is nothing more system dependant to set up,
488 so lets start that ball rolling...
490 The InitCode() call should never return in a working system.
492 SysBase->ResModules = romtagList;
493 InitCode(RTF_SINGLETASK, 0);
494 fprintf(stderr,"Returned from InitCode()\n");
495 return 1;