added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / i386-pc / exec / exec_init.c
blob2feef2d91c1fbb362a1ec78df88f5e25b31e0a81
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Early bootup section
6 Lang: english
7 */
9 /*
10 AROS MemoryMap:
12 First 4KB of RAM (page 0x0000-0x0FFF) are READ ONLY!
14 +------------+-----------+-------------------------------------------------+
15 | address | length | description |
16 +------------+-----------+-------------------------------------------------+
17 | System page. Read only! Addresses undefined here are not allowed!!!! |
18 +------------------------+-------------------------------------------------+
19 | 0x00000004 | 0x0000004 | ExecBase pointer. |
20 | 0x00000020 | 0x0000020 | CPU information |
21 | 0x00000040 | 0x0000068 | TSS structure. Do not use! |
22 | 0x000000a8 | 0x0000004 | INT server! cached_irq_mask |
23 | 0x000000ac | 0x0000004 | INT server! io_apic_irqs |
24 | 0x00000100 | 0x0000800 | 256 interrupt vectors |
25 | 0x00000900 | 0x0000040 | Global Descriptor Table |<---- needs changed! - must have space for GDT x No CPUs (NicJA)
26 | 0x00000940 | 0x0000001 | INT server! softblock |
27 | 0x00000a00 | 0x0000200 | INT server! irq_desc[] |
28 +------------+-----------+-------------------------------------------------+
29 | 0x00001000 | 0x0001000 | MultiBoot information |
30 | 0x00002000 | ......... | System RAM |
31 | .......... | ......... | Temporary stack frame for bootup process |
32 ......0x0009e000 0x0001000 SMP Trampoline (NicJA)
33 | 0x000a0000 | 0x0060000 | Data reserved for BIOS, VGA and some MMIO cards |
34 ......0x000f7070 ACPI<-
35 1MB| 0x00100000 | ......... | AROS KERNEL |
36 | .......... | ......... | System RAM divided into DMA and rest. |
37 +------------+-----------+-------------------------------------------------+
38 0fef7f80
39 WARNING!
41 AROS Kernel will not be placed in first 1MB of ram anymore. Instead it
42 will be either somewhere in DMA memory (eg at 2nd MByte), at the end of
43 available memory or placed at Virtual address. Don't trust its position.
45 When ROM module called from loader, the ExecBase should be cleared.
47 This file has been completely rewritten from assembler source!
51 #include <exec/resident.h>
52 #include <exec/types.h>
53 #include <exec/nodes.h>
54 #include <exec/execbase.h>
55 #include <exec/memory.h>
56 #include <hardware/intbits.h>
57 #include <asm/segments.h>
58 #include <asm/linkage.h>
59 #include <asm/ptrace.h>
60 #include <dos/dosextens.h>
62 #include <aros/arossupportbase.h>
63 #include <aros/asmcall.h>
64 #include <aros/config.h>
66 #ifndef DEBUG
67 # define DEBUG 1
68 #endif
70 #include <aros/debug.h>
71 #include <aros/multiboot.h>
73 #include <hardware/custom.h>
75 #include <proto/exec.h>
77 #include <stddef.h>
78 #include <stdio.h>
79 #include <string.h>
81 #include LC_LIBDEFS_FILE
83 #include "etask.h"
84 #include "exec_util.h"
85 #include "traps.h"
86 #include "vesa.h"
88 #define SMP_SUPPORT 0
90 #if SMP_SUPPORT
91 extern void prepare_primary_cpu(struct ExecBase *SysBase); /* FUNCTION FROM "cpu.resource"!!!!!!! */
92 #endif
94 /* As long as we don't have CPU detection routine, assume FPU to be present */
96 #define ASSUME_FPU 1
99 * Some macro definitions. __text will place given structure in .text section.
100 * __no_ret will force function type to be no-return function. __packed will
101 * force any structure to be non-aligned (we don't need alignment in native
102 * AROS).
105 #define __text __attribute__((section(".text")))
106 #define __no_ret __attribute__((noreturn))
107 #define __packed __attribute__((packed))
109 #define rdcr(reg) \
110 ({ long val; asm volatile("mov %%" #reg ",%0":"=r"(val)); val; })
112 #define wrcr(reg, val) \
113 do { asm volatile("mov %0,%%" #reg::"r"(val)); } while(0)
115 #define cpuid(num, eax, ebx, ecx, edx) \
116 do { asm volatile("cpuid":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx):"a"(num)); } while(0)
120 * Some declarations
122 void exec_init() __no_ret; /* init NEVER returns */
123 void exec_cinit() __no_ret; /* c-style init NEVER returns */
124 int exec_check_base();
125 void exec_DefaultTrap();
126 void exec_DefaultTaskExit();
127 //void exec_CheckCPU();
128 int exec_RamCheck_fast();
129 int exec_RamCheck_dma();
130 unsigned char setupVesa(struct multiboot *mbinfo);
133 asmlinkage void Exec_SystemCall(struct pt_regs);
134 ULONG **exec_RomTagScanner();
135 void irqSetup(void);
137 extern const UBYTE LIBEND __text; /* Somewhere in library */
138 extern ULONG _edata,_end; /* They are standard for ELF */
139 extern const APTR LIBFUNCTABLE[] __text;
141 extern struct Library * PrepareAROSSupportBase (void);
142 extern ULONG SoftIntDispatch();
143 extern void Exec_SerialRawIOInit();
144 extern void Exec_SerialRawPutChar(UBYTE chr);
146 extern void Exec_Switch_FPU();
147 extern void Exec_PrepareContext_FPU();
148 extern void Exec_Dispatch_FPU();
150 extern void Exec_Switch_SSE();
151 extern void Exec_PrepareContext_SSE();
152 extern void Exec_Dispatch_SSE();
154 extern ULONG Exec_MakeFunctions(APTR, APTR, APTR, APTR);
156 AROS_UFP5S(void, IntServer,
157 AROS_UFPA(ULONG, intMask, D0),
158 AROS_UFPA(struct Custom *, custom, A0),
159 AROS_UFPA(struct List *, intList, A1),
160 AROS_UFPA(APTR, intCode, A5),
161 AROS_UFPA(struct ExecBase *, SysBase, A6));
163 #undef memcpy
164 #define memcpy(_d, _s, _len) \
166 int len = _len; \
167 while (len) \
169 ((char *)_d)[len-1] = ((char *)_s)[len-1];\
170 len--; \
175 /* Temporary information */
177 #if 1
179 void clr();
180 void scr_RawPutChars(char *, int);
182 char tab[127];
184 #ifdef rkprintf
185 # undef rkprintf
186 #endif
187 #define rkprintf(x...) scr_RawPutChars(tab, snprintf(tab,126, x))
189 #else
191 #define clr() /* eps */
192 #define rkprintf(x...) /* eps */
194 #endif
197 * Make SysBase global. This way we will have no problems with all crapy modules
198 * which rely on global SysBase. They will get what they want - they will access
199 * it :)
202 asm( ".globl aros_intern\n\t"
203 ".globl SysBase \n\t"
204 ".set aros_intern,0\n\t"
205 ".set SysBase,4 ");
208 * Here the history starts. We are already in flat, 32bit mode. All protections
209 * are off, CPU is working in Supervisor level (CPL0). This state can be emu-
210 * lated by ColdReboot() routine as it may freely use Supervisor()
212 * kernel_startup can be executed only from CPL0 without vmm. Interrupts should
213 * be disabled.
215 * Note that kernel_startup is declared as entry symbol for output ELF file.
218 asm( ".globl kernel_startup \n\t"
219 ".type kernel_startup,@function\n"
220 "kernel_startup: jmp exec_init");
222 const char exec_core[] __text = "Native/CORE v2.0.1";
225 * First, we will define exec.library (global) to make it usable outside this
226 * file.
228 const char exec_name[] __text = "exec.library";
230 /* Now ID string as it will be used in a minute in resident structure. */
231 const char exec_idstring[] __text = "$VER: exec 41.11 (16.12.2000)\r\n";
233 /* We would need also version and revision fields placed somewhere here. */
234 const short exec_Version __text = 41;
235 const short exec_Revision __text = 11;
238 * The RomTag structure. It has to be placed inside .text block as there will
239 * be no public RomTagList. In future we may change RTC_MATCHWORD to be machine
240 * specific.
242 const struct Resident Exec_resident __text=
244 RTC_MATCHWORD, /* Magic value used to find resident */
245 &Exec_resident, /* Points to Resident itself */
246 &LIBEND, /* Where could we find next Resident? */
247 0, /* There are no flags!! */
248 41, /* Version */
249 NT_LIBRARY, /* Type */
250 126, /* Very high startup priority. */
251 (char *)exec_name, /* Pointer to name string */
252 (char *)exec_idstring, /* Ditto */
253 exec_init /* Library initializer (for exec this value is irrelevant since we've jumped there at the begining to bring the system up */
256 struct view { unsigned char sign; unsigned char attr; };
259 * Init the exec.library and as well whole system. This routine has to prepare
260 * all needed structures, GDT and IDT tables, TSS structure and many other.
262 * We have to use asm creature because there is no stack at the moment
264 asm("\nexec_init: \n\t"
265 "movl $0x93000,%esp\n\t" /* Start with setting up a temporary stack */
266 "pushl %ebx \n\t" /* Then store the MultiBoot info pointer */
267 "pushl %eax \n\t" /* Store multiboot magic cookie */
268 "pushl $0x0 \n\t" /* And fake a C code call */
270 "cld \n\t" /* At the startup it's very important */
271 "cli \n\t" /* to lock all interrupts. Both on the */
272 "movb $-1,%al \n\t" /* CPU side and hardware side. We don't */
273 "outb %al,$0x21 \n\t" /* have proper structures in RAM yet. */
274 "outb %al,$0xa1 \n\n\t"
276 "jmp exec_cinit"); /* Jump to C function :))) */
279 * This routine is used by kernel to change all colors on the screen according
280 * to R,G,B values passed here
282 void exec_SetColors(char r, char g, char b)
284 int i;
285 short reg = 0x3c8; /* IO reg to control PEL */
287 asm("movb $0,%%al\n\t" /* Start with color 0 */
288 "outb %%al,%w0\n\t"
289 : /* no output */
290 : "Nd"(reg));
292 reg++; /* Here we have to put R, G, B */
294 for (i=0; i<256; i++) /* Set whole palette */
296 asm("outb %b0,%w1"::"a"(r),"Nd"(reg));
297 asm("outb %b0,%w1"::"a"(g),"Nd"(reg));
298 asm("outb %b0,%w1"::"a"(b),"Nd"(reg));
299 asm("nop \n\t"
300 "nop \n\t"
301 "nop \n\t"
302 "nop");
307 * Mixed stuff used to control TSS/GDT/IDT stuff. This is strictly machine
308 * specific
311 asm(".globl TSS\n\t" /* Make this three global in case one would */
312 ".globl SSP\n\t" /* decide to use them directly */
313 ".globl EIP\n\t"
314 ".set TSS, 0x00000040\n\t" /* See Memory Map at the top of the file */
315 ".set SSP, 0x00000044\n\t"
316 ".set EIP, 0x00000060");
319 * Two defines used to keep control over interrupt server
322 asm(".globl cached_irq_mask\n\t"
323 ".globl io_apic_irqs\n\t"
324 ".globl softblock\n\t"
325 ".globl irq_desc\n\t"
326 ".set cached_irq_mask, 0x000000a8\n\t"
327 ".set io_apic_irqs, 0x000000ac\n\t"
328 ".set softblock, 0x00000940\n\t"
329 ".set irq_desc, 0x00000a00");
332 * TaskStateStructure, defined only in matter of making life (setup)
333 * more human-readable
335 struct _tss {
336 ULONG link, /* link to previous task - UNUSED */
337 ssp, /* Supervisor Stack Pointer */
338 ssp_seg, /* SSP descriptor */
339 t0,t1, /* Stack for CPL1 code - USE IN FUTURE */
340 t2,t3, /* Stack for CPL2 code - UNUSED */
341 cr3, /* used in paging */
342 eip, /* Instruction pointer */
343 eflags, /* Flags for given task */
344 r0,r1,r2,r3, /* 8 general purpouse registers */
345 r4,r5,r6,r7,
346 es,cs,ss,ds,fs,gs, /* segment descriptors */
347 ldt; /* LocalDescriptorTable - UNUSED */
348 UWORD trap,iomap; /* trap flag and iomap pointer */
352 * Nice macro used for setting given gate to specified type.
353 * dpl is used to control access of this gate - setting to something
354 * lower than 3 makes gate impossible to use from User Mode
356 #define set_gate(gate_addr,type,dpl,addr) \
357 do { \
358 int __d0, __d1; \
359 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
360 "movw %4,%%dx\n\t" \
361 "movl %%eax,%0\n\t" \
362 "movl %%edx,%1" \
363 :"=m" (*((long *) (gate_addr))), \
364 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
365 :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
366 "3" ((char *) (addr)),"2" (KERNEL_CS << 16)); \
367 } while (0)
369 /* Empty interrupt. Used for short while */
370 void exec_DummyInt();
371 asm("\nexec_DummyInt: iret");
374 * RO copy of GlobalDescriptorTable. It's easyier to copy this table than
375 * to generate completely new one
377 const struct {UWORD l1, l2, l3, l4;}
378 GDT_Table[] __text = {
379 { 0x0000, 0x0000, 0x0000, 0x0000 },
380 { 0xffff, 0x0000, 0x9a00, 0x00cf },
381 { 0xffff, 0x0000, 0x9200, 0x00cf },
382 { 0xffff, 0x0000, 0xfa00, 0x00cf },
383 { 0xffff, 0x0000, 0xf200, 0x00cf },
384 { 0x0000, 0x0000, 0x0000, 0x0000 },
385 { 0x0067, 0x0040, 0x8900, 0x0000 },
386 { 0x0000, 0x0000, 0x0000, 0x0000 }};
388 /* Two magic registers pointing to Global Descriptor Table and Interrupt
389 * Descriptor Table */
390 const struct
392 UWORD l1 __packed;
393 ULONG l3 __packed;
395 GDT_reg __text = {0x3f, 0x900},
396 IDT_reg __text = {0x7ff, 0x100};
398 const char exec_chipname[] __text = "Chip Memory";
399 const char exec_fastname[] __text = "Fast Memory";
402 * C/ASM mixed initialization routine. Here the real game begins...
404 void exec_cinit(unsigned long magic, unsigned long addr)
406 struct ExecBase *ExecBase;
407 struct multiboot *mbinfo;
408 struct arosmb *arosmb;
410 ULONG locmem, extmem;
412 APTR KickMemPtr,
413 KickTagPtr,
414 KickCheckSum;
416 struct _tss *tss = (struct _tss *)0x40; /* Dummy pointer making life easier */
417 long long *idt = (long long *)0x100; /* Ditto */
419 int i; /* Whatever? Counter? Erm... */
421 // exec_SetColors(0x10,0x10,0x10); /* Set screen to almost black */
423 /* Check whether we have .bss block */
424 if ((int)&_end - (int)&_edata)
427 * Damn! We have to GET RID OF THIS!!! But now the only thing I can do
428 * is clearing it. GRUB have done it already but we have to repeat that
429 * (it may NEED that as it might be ColdReboot())
431 bzero(&_edata,(int)&_end-(int)&_edata);
434 clr();
435 rkprintf("AROS - The AROS Research OS\nCompiled %s\n\n",__DATE__);
437 /* MultiBoot
438 * This messy bit here will store away useful information we receive from
439 * the bootloader. It will happen when we are loaded, and not on when we
440 * are here from ColdReboot().
441 * This is just the first stage of it. Later this information will be extracted
442 * by bootloader.resource, but we do this here anyway. Both to keep the info
443 * safe, and also since we will use some of it in here.
445 arosmb = (struct arosmb *)0x1000;
446 if (magic == 0x2badb002)
448 mbinfo = (struct multiboot *)addr;
449 if (mbinfo->flags & MB_FLAGS_CMDLINE)
450 arosmb->vbe_palette_width = setupVesa(mbinfo);
451 rkprintf("Copying multiboot information into storage\n");
452 arosmb->magic = MBRAM_VALID;
453 arosmb->flags = 0L;
454 if (mbinfo->flags & MB_FLAGS_MEM)
456 arosmb->flags |= MB_FLAGS_MEM;
457 arosmb->mem_lower = mbinfo->mem_lower;
458 arosmb->mem_upper = mbinfo->mem_upper;
460 if (mbinfo->flags & MB_FLAGS_LDRNAME)
462 arosmb->flags |= MB_FLAGS_LDRNAME;
463 snprintf(arosmb->ldrname,29,"%s",mbinfo->loader_name);
465 if (mbinfo->flags & MB_FLAGS_CMDLINE)
467 arosmb->flags |= MB_FLAGS_CMDLINE;
468 snprintf(arosmb->cmdline,199,"%s",mbinfo->cmdline);
470 if (mbinfo->flags & MB_FLAGS_MMAP)
472 arosmb->flags |= MB_FLAGS_MMAP;
473 arosmb->mmap_addr = (struct mb_mmap *)((ULONG)(0x1000 + sizeof(struct arosmb)));
474 arosmb->mmap_len = mbinfo->mmap_length;
475 memcpy((void *)arosmb->mmap_addr,(void *)mbinfo->mmap_addr,mbinfo->mmap_length);
477 if (mbinfo->flags & MB_FLAGS_DRIVES)
479 if (mbinfo->drives_length > 0)
481 arosmb->flags |= MB_FLAGS_DRIVES;
482 arosmb->drives_addr = ((ULONG)(arosmb->mmap_addr + arosmb->mmap_len));
483 arosmb->drives_len = mbinfo->drives_length;
484 memcpy((void *)arosmb->drives_addr,(void *)mbinfo->drives_addr,mbinfo->drives_length);
487 if (mbinfo->flags & MB_FLAGS_GFX)
489 arosmb->flags |= MB_FLAGS_GFX;
490 arosmb->vbe_mode = mbinfo->vbe_mode;
491 memcpy((void *)&arosmb->vmi,(void *)mbinfo->vbe_mode_info,sizeof(struct vbe_mode));
492 memcpy((void *)&arosmb->vci,(void *)mbinfo->vbe_control_info,sizeof(struct vbe_controller));
495 rkprintf("Done\n");
497 #warning "TODO: WE MUST PARSE THE BIOS MEMORY MAP HERE AND PROTECT NECESSARY STRUCTS (i.e ACPI stores its data in the last few meg of physical ram..)"
499 rkprintf("Clearing system area...");
502 * Well, if we all in clearing moode, then it's the best occasion to clear
503 * some areas in AROS private 4KB ram area. Hmmm. If there would occur any
504 * interrupt at this moment, AROS would be really dead as it is going to
505 * destroy its private stuff (which is really needed to make CPU operate
506 * properly)
508 bzero((void *)8, 4096-8);
511 * Feel better? Now! Quick. We will have to build new tables for our CPU to
512 * make it work nicely.
514 tss->ssp = 0x00090000; /* temporary Supervisor Stack Pointer */
515 tss->ssp_seg = KERNEL_DS; /* SSP segment descriptor */
516 tss->cs = USER_CS;
517 tss->ds = USER_DS;
518 tss->es = USER_DS;
519 tss->ss = USER_DS;
520 tss->iomap = 104;
522 /* Restore IDT structure. */
523 for (i=0; i<256; i++)
525 /* Feed all vectors with dummy interrupt */
526 set_gate(idt + i, 14, 0, exec_DummyInt);
530 * Fix Global Descriptor Table. Because I'm too lazy I'll just copy one from
531 * here. I've already prepared such a nice one :)
533 memcpy((void *)0x900, &GDT_Table, 64);
536 * As we prepared all necessary stuff, we can hopefully load GDT and LDT
537 * into CPU. We may also play a bit with TSS
539 asm("lgdt %0\n\t"
540 "lidt %1"
542 :"m"(GDT_reg),"m"(IDT_reg));
544 asm("mov %0,%%ds\n\t" /* Now it's high time to set segment */
545 "mov %0,%%es\n\t" /* registers (segment descriptors). */
546 "mov %0,%%ss\n\t" /* AROS uses only %CS %SS %DS and %ES */
547 "mov %1,%%fs\n\t" /* %FS and %GS are set to 0 so we can */
548 "mov %1,%%gs" /* generate GP if someone uses them. */
550 :"a"(KERNEL_DS),"b"(0));
552 asm("ltr %%ax"::"ax"(0x30));
554 rkprintf("OK\nSystem restored\n");
557 * Wew have to do some stuff from setup.S due to remove of it.
559 * Remap IRQs. We really HAVE TO do that because IBM did it in a very bad
560 * way - they've ignored what Intel said about interrupts. See intel manual
561 * for further information.
562 * For now all irq's are placed in range 0x20 - 0x30 as vectors 0x00 - 0x1f
563 * are reserved by Intel
565 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x11),"i"(0x20)); /* Initialization sequence for 8259A-1 */
566 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x11),"i"(0xa0)); /* Initialization sequence for 8259A-2 */
567 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x20),"i"(0x21)); /* IRQs at 0x20 - 0x27 */
568 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x28),"i"(0xa1)); /* IRQs at 0x28 - 0x2f */
569 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x04),"i"(0x21)); /* 8259A-1 is master */
570 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x02),"i"(0xa1)); /* 8259A-2 is slave */
571 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x01),"i"(0x21)); /* 8086 mode for both */
572 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0x01),"i"(0xa1));
573 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0xff),"i"(0x21)); /* Enable cascade int */
574 asm("outb %b0,%b1\n\tcall delay"::"a"((char)0xff),"i"(0xa1)); /* Mask all interrupts */
576 rkprintf("Interrupts redirected\n");
579 * Check for valid ExecBase. This is quite important part, because this way
580 * we may determine whether to clear and reconfigure memory or whether we
581 * already know everything and may continue further initialisation.
583 if (!exec_check_base())
585 ULONG negsize = 0; /* size of vector table */
586 void **fp = LIBFUNCTABLE; /* pointer to a function in the table */
588 rkprintf("Reallocating ExecBase...");
590 * If we managed to reach this point, it means that there was no ExecBase in
591 * the memory. That means that we have to calculate amount of memory available.
593 * We will guess ExecBase pointer by taking the lowest possible address and
594 * substrating from it the offset of lowet vector used by Exec. This way the ExecBase
595 * Will be placed in the lowes address possible with fitting all functions :)
598 /* Calculate the size of the vector table */
599 while (*fp++ != (VOID *) -1) negsize += LIB_VECTSIZE;
601 ExecBase = (struct ExecBase *) 0x00002000; /* Got ExecBase at the lowest possible addr */
602 ExecBase += negsize; /* Substract lowest vector so jumpable would fit */
604 /* Check whether we have some FAST memory,
605 * If not, then use calculated ExecBase */
606 if ((extmem = exec_RamCheck_fast(arosmb)))
608 rkprintf("%x Fastmem\n",extmem);
609 /* We have found some FAST memory. Let's use it for ExecBase */
610 ExecBase = (struct ExecBase *) 0x01000000;
611 ExecBase += negsize;
613 /* Now we will clear FAST memory. */
614 /* Disabled due to taking to much time on P4 machines */
615 rkprintf("Clearing FastMem...");
617 /************* NICJA - Fix this code so that only unused meory is flushed, and protect certain ares - ie acpi */
619 /* Ogun - Disable cruddy attempt to save ACPI data for now */
620 //bzero((void *)0x01000000, extmem - 0x01000000 - 0x500000);
621 bzero((void *)0x01000000, extmem - 0x01000000);
625 * Now, the FAST memory is cleared, the ExecBase is reserved. We have only to
626 * determine how much CHIP memory do we have.
629 locmem = exec_RamCheck_dma(arosmb);
630 rkprintf("%x Chipmem\n",locmem);
632 rkprintf("OK\nExecBase=%p\n", ExecBase);
634 /* Clear chip ram. Do it carefully as we have kernel somewhere in chip! */
637 * NOTE:
638 * We will leave area 0x90000 - 0xa0000 uncleared as there is
639 * temporary system stack!
641 rkprintf("Clearing ChipMem...\n");
643 bzero((void *)0x2000, 0x90000-0x2000);
644 bzero(&_end, locmem -(ULONG)&_end);
646 else
648 ExecBase = *(struct ExecBase **)4UL;
650 locmem = ExecBase->MaxLocMem;
651 extmem = (ULONG)ExecBase->MaxExtMem;
653 rkprintf("Got old ExecBase = %p\n",ExecBase);
656 * We happend to be here with local ExecBase properly set as well as
657 * local locmem and extmem
660 // exec_SetColors(0x20,0x20,0x20);
662 /* Store this values as they may point to interesting stuff */
663 KickMemPtr = ExecBase->KickMemPtr;
664 KickTagPtr = ExecBase->KickTagPtr;
665 KickCheckSum = ExecBase->KickCheckSum;
667 rkprintf("Clearing ExecBase\n");
669 /* How about clearing most of ExecBase structure? */
670 bzero(&ExecBase->IntVects[0], sizeof(struct ExecBase) - offsetof(struct ExecBase, IntVects[0]));
672 ExecBase->KickMemPtr = KickMemPtr;
673 ExecBase->KickTagPtr = KickTagPtr;
674 ExecBase->KickCheckSum = KickCheckSum;
677 * Now everything is prepared to store ExecBase at the location 4UL and set
678 * it complement in ExecBase structure
681 rkprintf("Initializing library...");
683 *(struct ExecBase **)4 = ExecBase;
684 ExecBase->ChkBase = ~(ULONG)ExecBase;
686 /* Set up system stack */
687 tss->ssp = (extmem) ? extmem : locmem; /* Either in FAST or in CHIP */
688 ExecBase->SysStkUpper = (APTR)tss->ssp;
689 ExecBase->SysStkLower = (APTR)tss->ssp - 0x10000; /* 64KB of system stack */
691 /* Store memory configuration */
692 ExecBase->MaxLocMem = (IPTR)locmem;
693 ExecBase->MaxExtMem = (APTR)extmem;
695 #warning "TODO: Write first step of alert.hook here!!!"
698 * Initialize exec lists. This is done through information table which consist
699 * of offset from begining of ExecBase and type of the list.
701 NEWLIST(&ExecBase->MemList);
702 ExecBase->MemList.lh_Type = NT_MEMORY;
703 NEWLIST(&ExecBase->ResourceList);
704 ExecBase->ResourceList.lh_Type = NT_RESOURCE;
705 NEWLIST(&ExecBase->DeviceList);
706 ExecBase->DeviceList.lh_Type = NT_DEVICE;
707 NEWLIST(&ExecBase->LibList);
708 ExecBase->LibList.lh_Type = NT_LIBRARY;
709 NEWLIST(&ExecBase->PortList);
710 ExecBase->PortList.lh_Type = NT_MSGPORT;
711 NEWLIST(&ExecBase->TaskReady);
712 ExecBase->TaskReady.lh_Type = NT_TASK;
713 NEWLIST(&ExecBase->TaskWait);
714 ExecBase->TaskWait.lh_Type = NT_TASK;
715 NEWLIST(&ExecBase->IntrList);
716 ExecBase->IntrList.lh_Type = NT_INTERRUPT;
717 NEWLIST(&ExecBase->SemaphoreList);
718 ExecBase->SemaphoreList.lh_Type = NT_SIGNALSEM;
719 NEWLIST(&ExecBase->ex_MemHandlers);
721 for (i=0; i<5; i++)
723 NEWLIST(&ExecBase->SoftInts[i].sh_List);
724 ExecBase->SoftInts[i].sh_List.lh_Type = NT_SOFTINT;
728 * Exec.library initializer. Prepares exec.library for future use. All
729 * lists have to be initialized, some values from ROM are copied.
732 ExecBase->TaskTrapCode = exec_DefaultTrap;
733 ExecBase->TaskExceptCode = exec_DefaultTrap;
734 ExecBase->TaskExitCode = exec_DefaultTaskExit;
735 ExecBase->TaskSigAlloc = 0x0000ffff;
736 ExecBase->TaskTrapAlloc = 0x8000;
738 /* Prepare values for execBase (like name, type, pri and other) */
740 ExecBase->LibNode.lib_Node.ln_Type = NT_LIBRARY;
741 ExecBase->LibNode.lib_Node.ln_Pri = 0;
742 ExecBase->LibNode.lib_Node.ln_Name = (char *)exec_name;
743 ExecBase->LibNode.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
744 ExecBase->LibNode.lib_PosSize = sizeof(struct ExecBase);
745 ExecBase->LibNode.lib_OpenCnt = 1;
746 ExecBase->LibNode.lib_IdString = (char *)exec_idstring;
747 ExecBase->LibNode.lib_Version = exec_Version;
748 ExecBase->LibNode.lib_Revision = exec_Revision;
750 ExecBase->Quantum = 4;
751 ExecBase->VBlankFrequency = 50;
752 ExecBase->PowerSupplyFrequency = 1;
754 rkprintf("OK\nBuilding JumpTable...");
756 /* Build the jumptable */
757 ExecBase->LibNode.lib_NegSize =
758 Exec_MakeFunctions(ExecBase, LIBFUNCTABLE, NULL, ExecBase);
760 rkprintf("OK\n");
762 /* Add FAST memory at 0x01000000 to free memory lists */
763 if (extmem)
765 ULONG base = ((ULONG)ExecBase + sizeof(struct ExecBase) + 15) & ~15;
767 AddMemList(extmem - (base + 0x10000),
768 MEMF_FAST | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL,
770 (APTR)base,
771 (STRPTR)exec_fastname);
773 AddMemList(locmem - 0x2000,
774 MEMF_CHIP | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL | MEMF_24BITDMA,
775 -10,
776 (APTR)0x2000,
777 (STRPTR)exec_chipname);
779 rkprintf("Chip Memory : %luMB\nFast Memory : %luMB\n",
780 locmem >> 20, (extmem - locmem) >> 20);
782 else
784 ULONG base = ((ULONG)ExecBase + sizeof(struct ExecBase) + 15) & ~15;
785 AddMemList(locmem - (base + 0x10000),
786 MEMF_CHIP | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL | MEMF_24BITDMA,
787 -10,
788 (APTR)base,
789 (STRPTR)exec_chipname);
791 rkprintf("Chip Memory : %luMB\n", locmem >> 20);
794 rkprintf("Memory added\n");
796 /* Protect kernel and RO data from beeing allocated by software */
797 AllocAbs((ULONG)&_end - 0x000a0000, (APTR)0x000a0000);
799 /* Protect bootup stack from being allocated */
800 AllocAbs(0x3000,0x90000);
802 rkprintf("Kernel protected\n");
804 rkprintf("Adding \"exec.library\"...");
806 /* Add exec.library to system library list */
807 SumLibrary((struct Library *)SysBase);
808 Enqueue(&SysBase->LibList,&SysBase->LibNode.lib_Node);
810 rkprintf("OK\n");
812 ExecBase->DebugAROSBase = PrepareAROSSupportBase();
814 #if SMP_SUPPORT
815 /* Early Boot CPU preperation.. */
816 prepare_primary_cpu( ExecBase );
817 #endif
819 rkprintf( "[CPU] Primary CPU Probed ..\n" );
821 for (i=0; i<16; i++)
823 if( (1<<i) & (INTF_PORTS|INTF_COPER|INTF_VERTB|INTF_EXTER|INTF_SETCLR))
825 struct Interrupt *is;
826 struct SoftIntList *sil;
827 is = AllocMem
829 sizeof(struct Interrupt) + sizeof(struct SoftIntList),
830 MEMF_CLEAR | MEMF_PUBLIC
832 if( is == NULL )
834 rkprintf("ERROR: Cannot install Interrupt Servers!\n");
836 sil = (struct SoftIntList *)((struct Interrupt *)is + 1);
838 is->is_Code = &IntServer;
839 is->is_Data = sil;
840 NEWLIST((struct List *)sil);
841 SetIntVector(i,is);
843 else
845 struct Interrupt *is;
846 switch (i)
848 case INTB_SOFTINT :
849 is = AllocMem
851 sizeof(struct Interrupt),
852 MEMF_CLEAR | MEMF_PUBLIC
854 if (is == NULL)
856 rkprintf("Error: Cannot install Interrupt Servers!\n");
857 // Alert(AT_DeadEnd | AN_IntrMem);
859 is->is_Node.ln_Type = NT_SOFTINT; //INTERRUPT;
860 is->is_Node.ln_Pri = 0;
861 is->is_Node.ln_Name = "SW Interrupt Dispatcher";
862 is->is_Data = NULL;
863 is->is_Code = (void *)SoftIntDispatch;
864 SetIntVector(i,is);
865 break;
870 #warning "TODO: Write CPU detailed detection scheme. Patch proper functions??"
872 Init_Traps();
873 irqSetup();
874 rkprintf("IRQ services initialized\n");
876 /* Create user interrupt used to enter supervisor mode */
877 set_gate(idt + 0x80, 14, 3, Exec_SystemCall);
879 /* Enable interrupts and set int disable level to -1 */
880 asm("sti");
881 ExecBase->TDNestCnt = -1;
882 ExecBase->IDNestCnt = -1;
884 /* Now it's time to calculate exec checksum. It will be used
885 * in future to distinguish whether we'd had proper execBase
886 * before restart */
888 UWORD sum=0, *ptr = &ExecBase->SoftVer;
889 int i=((int)&ExecBase->IntVects[0] - (int)&ExecBase->SoftVer) / 2,
892 /* Calculate sum for every static part from SoftVer to ChkSum */
893 for (j=0;j < i;j++)
895 sum+=*(ptr++);
898 ExecBase->ChkSum = ~sum;
901 rkprintf("Creating the very first task...");
903 /* Create boot task. Sigh, we actually create a Process sized Task,
904 since DOS needs to call things which think it has a Process and
905 we don't want to overwrite memory with something strange do we?
907 We do this until at least we can boot dos more cleanly.
910 struct Task *t;
911 struct MemList *ml;
913 ml = (struct MemList *)AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
914 t = (struct Task *) AllocMem(sizeof(struct Process), MEMF_PUBLIC|MEMF_CLEAR);
916 if( !ml || !t )
918 rkprintf("ERROR: Cannot create Boot Task!\n");
920 ml->ml_NumEntries = 1;
921 ml->ml_ME[0].me_Addr = t;
922 ml->ml_ME[0].me_Length = sizeof(struct Process);
924 NEWLIST(&t->tc_MemEntry);
925 NEWLIST(&((struct Process *)t)->pr_MsgPort.mp_MsgList);
927 /* It's the boot process that RunCommand()s the boot shell, so we
928 must have this list initialized */
929 NEWLIST((struct List *)&((struct Process *)t)->pr_LocalVars);
931 AddHead(&t->tc_MemEntry,&ml->ml_Node);
933 t->tc_Node.ln_Name = exec_name;
934 t->tc_Node.ln_Pri = 0;
935 t->tc_Node.ln_Type = NT_TASK;
936 t->tc_State = TS_RUN;
937 t->tc_SigAlloc = 0xFFFF;
938 t->tc_SPLower = 0; /* This is the system's stack */
939 t->tc_SPUpper = (APTR)~0UL;
940 t->tc_Flags |= TF_ETASK;
942 if (t->tc_Flags & TF_ETASK)
944 t->tc_UnionETask.tc_ETask = AllocTaskMem(t, sizeof(struct IntETask), MEMF_ANY|MEMF_CLEAR);
946 if (!t->tc_UnionETask.tc_ETask)
948 rkprintf("Not enough memory for first task\n");
951 GetIntETask(t)->iet_Context = AllocTaskMem(t
952 , SIZEOF_ALL_REGISTERS
953 , MEMF_PUBLIC|MEMF_CLEAR
956 if (!GetIntETask(t)->iet_Context)
958 rkprintf("Not enough memory for first task\n");
962 ExecBase->ThisTask = t;
965 rkprintf("Done\n");
968 Check whether the CPU supports SSE and FXSAVE.
970 Dirty check, without use of any defines and human readable constants. The
971 cpuid instruction with %eax=1 will return some essential cpu informations in %edx back,
972 including:
973 - bit 24: CPU does support FXSAVE and FXRSTOR for MMX/FPU/SSE context saving and restoring
974 - bit 25: CPU supports SSE
975 - bit 26: CPU supports SSE2
978 ULONG v1,v2,v3,v4;
979 cpuid(1, v1,v2,v3,v4);
981 rkprintf("cpuid 1 = %08x %08x %08x %08x\n", v1, v2, v3, v4);
983 if (v4 & (1 << 24))
985 rkprintf("The CPU supports FXSAVE and FXRSTOR. Good.\n");
986 rkprintf("CPU Supports ");
988 switch ((v4 >> 25) & 3)
990 case 3:
991 case 2:
992 rkprintf("SSE2 ");
993 case 1:
994 rkprintf("SSE\n");
995 /* Patch exec with SSE-aware CPU context functions */
996 SetFunction(&ExecBase->LibNode, -6*LIB_VECTSIZE, AROS_SLIB_ENTRY(PrepareContext_SSE, Exec));
997 SetFunction(&ExecBase->LibNode, -9*LIB_VECTSIZE, AROS_SLIB_ENTRY(Switch_SSE, Exec));
998 SetFunction(&ExecBase->LibNode, -10*LIB_VECTSIZE, AROS_SLIB_ENTRY(Dispatch_SSE, Exec));
999 /* tell the CPU that we will support SSE */
1000 wrcr(cr4, rdcr(cr4) | (3 << 9));
1001 /* Clear the EM and MP flags of CR0 */
1002 wrcr(cr0, rdcr(cr0) & ~6);
1003 rkprintf("SSE enabled.\n");
1004 break;
1006 default:
1008 Ha! Bloody PentiumII does supports MMX/FPU/SSE saving instructions,
1009 but it does not support SSE
1011 rkprintf("no SSE. Sorry :)\n");
1012 break;
1015 else
1017 #if ASSUME_FPU
1018 SetFunction(&ExecBase->LibNode, -6*LIB_VECTSIZE, AROS_SLIB_ENTRY(PrepareContext_FPU, Exec));
1019 SetFunction(&ExecBase->LibNode, -9*LIB_VECTSIZE, AROS_SLIB_ENTRY(Switch_FPU, Exec));
1020 SetFunction(&ExecBase->LibNode, -10*LIB_VECTSIZE, AROS_SLIB_ENTRY(Dispatch_FPU, Exec));
1022 rkprintf("FPU enabled.\n");
1023 #endif
1027 rkprintf("Jumping out from Supervisor mode...");
1029 #if 0
1031 asm("mov %0,%%ds\n\t" /* User DS */
1032 "mov %0,%%es\n\t" /* User ES */
1033 "movl %%esp,%%ebx\n\t" /* Hold the esp value before pushing! */
1034 "pushl %0\n\t" /* User SS */
1035 "pushl %%ebx\n\t" /* Stack frame */
1036 "pushl $0x3002\n\t" /* IOPL:3 */
1037 "pushl %1\n\t" /* User CS */
1038 "pushl $1f\n\t" /* Entry address */
1039 "iret\n" /* Go down to the user mode */
1040 "1:\tsti" /* Enable interrupts */
1042 : "eax"(USER_DS),"ecx"(USER_CS));
1043 #else
1044 # define _stringify(x) #x
1045 # define stringify(x) _stringify(x)
1047 asm("movl $" stringify(USER_DS) ",%%eax\n\t"
1048 "mov %%eax,%%ds\n\t" /* User DS */
1049 "mov %%eax,%%es\n\t" /* User ES */
1050 "movl %%esp,%%ebx\n\t" /* Hold the esp value before pushing! */
1051 "pushl %%eax\n\t" /* User SS */
1052 "pushl %%ebx\n\t" /* Stack frame */
1053 "pushl $0x3002\n\t" /* IOPL:3 */
1054 "pushl $" stringify(USER_CS) "\n\t" /* User CS */
1055 "pushl $1f\n\t" /* Entry address */
1056 "iret\n" /* Go down to the user mode */
1057 "1:\tsti":::"eax","ebx"); /* Enable interrupts */
1059 # undef stringify
1060 # undef _stringify
1061 #endif
1063 rkprintf("Done\n");
1065 ExecBase->TDNestCnt++;
1066 Permit();
1067 #if (AROS_SERIAL_DEBUG >0)
1068 SetFunction(&ExecBase->LibNode, -84*LIB_VECTSIZE, AROS_SLIB_ENTRY(SerialRawIOInit, Exec));
1069 SetFunction(&ExecBase->LibNode, -86*LIB_VECTSIZE, AROS_SLIB_ENTRY(SerialRawPutChar, Exec));
1070 RawIOInit();
1071 #endif
1074 /* Scan for valid RomTags */
1075 ExecBase->ResModules = exec_RomTagScanner();
1077 if (ExecBase->CoolCapture)
1079 void (*p)() = ExecBase->CoolCapture;
1080 (*p)();
1083 InitCode(RTF_SINGLETASK, 0);
1084 InitCode(RTF_COLDSTART, 0);
1087 * We suppose that at this point dos.library has already taken over.
1088 * The last thing to do is to call WarmCapture vector. After that this
1089 * task has completely nothing to do so it may execute Debug() in
1090 * forever loop
1093 if (ExecBase->WarmCapture)
1095 void (*p)() = ExecBase->WarmCapture;
1096 (*p)();
1099 do { Debug(0); } while(1);
1102 /* Small delay routine used by exec_cinit initializer */
1103 asm("\ndelay:\t.short 0x00eb\n\tret");
1105 /* Exec default trap routine */
1106 asm("\nexec_DefaultTrap:\n\t"
1107 "pushl 4\n\t"
1108 "pushl $0\n\t"
1109 "pushl $0\n\t"
1110 "jmp Exec_Alert");
1112 #warning "TODO: We should use info from BIOS here."
1113 int exec_RamCheck_dma(struct arosmb *arosmb)
1115 ULONG volatile *ptr,tmp;
1117 ptr = (ULONG *)(((int)&_end + 4095) &~4095);
1119 if(arosmb->flags & MB_FLAGS_MEM)
1121 /* If there is upper memory, assume that lower is 1MB. Dirty hack++ */
1122 if(arosmb->mem_upper)
1124 if ((arosmb->mem_upper<<10) & 0xff000000)
1126 /* More than 16MB in total, return 16 */
1127 return 16<<20;
1129 /* Lower 16MB is marked as DMA memory */
1130 tmp = (arosmb->mem_upper*1024) & 0x00ffffff;
1131 tmp += 1048576;
1132 return tmp;
1134 else
1136 /* No upper memory, return only lower mem.
1137 * Most likely fatal, can't see aros working with less than one MB of ram */
1138 return (arosmb->mem_lower*1024);
1141 /* No memory info from bios, do a scan */
1144 tmp = *ptr;
1145 *ptr = 0xdeadbeef;
1146 if (*ptr != 0xdeadbeef)
1147 break;
1148 *ptr = tmp;
1149 ptr += 4;
1150 } while ((int)ptr < 0x01000000);
1152 return (int)ptr;
1155 int exec_RamCheck_fast(struct arosmb *arosmb)
1157 ULONG volatile *ptr, tmp;
1159 ptr = (ULONG *)0x01000000;
1161 if(arosmb->flags & MB_FLAGS_MEM)
1163 /* If less than 15MB upper, no fastmem here */
1164 if (arosmb->mem_upper <= 15*1024)
1166 return 0;
1168 /* Found memory, so we need to do some quick math */
1169 tmp = (arosmb->mem_upper*1024)+1048576;
1170 return tmp;
1172 /* No memory info from bios, do a scan */
1175 tmp = *ptr;
1176 *ptr = 0xdeadbeef;
1177 if (*ptr != 0xdeadbeef)
1178 break;
1179 *ptr = tmp;
1180 ptr += 4;
1181 } while(1);
1183 return ((int)ptr > 0x01000000) ? (int)ptr : 0;
1186 void exec_DefaultTaskExit()
1188 struct ExecBase *SysBase = *(struct ExecBase **)4UL;
1189 RemTask(SysBase->ThisTask);
1193 * Check for valid ExecBase
1195 int exec_check_base()
1197 /* Get ExecBase from 0x00000004 */
1198 struct ExecBase *ExecBase=*(struct ExecBase **)4UL;
1200 /* Attempt first test. If ExecBase is not aligned to 4 byte boundary then
1201 * it is not proper ExecBase */
1202 if (!((ULONG)ExecBase & 0x3))
1205 * Assume for a while, that it is ExecBase indeed. Check complement of
1206 * this pointer, which is stored in ExecBase->ChkBase
1208 if (!~((LONG)ExecBase + ExecBase->ChkBase))
1211 * Still here? Nice, let's check one more thing. Static part of
1212 * ExecBase has its checksum calculated. Verify it please...
1214 UWORD sum=0, *ptr = &ExecBase->SoftVer;
1215 int i=((int)&ExecBase->IntVects[0] - (int)&ExecBase->SoftVer) / 2,
1218 /* Calculate sum for every static part from SoftVer to ChkSum */
1219 for (j=0;j < i;j++)
1221 sum+=*(ptr++);
1224 /* Do we have proper checksum? */
1225 if (!~sum)
1227 /* Well well, almost sure that we have ExecBase here. Hey, it's
1228 * time to execute ColdCapture code! */
1229 void (*p)() = ExecBase->ColdCapture;
1231 /* Only if there is ColdCapture code... */
1232 if (p)
1234 ExecBase->ColdCapture = NULL;
1235 (*p)();
1239 * Let's check ExecBase last time. Compare library version and
1240 * revision vs ones stored deep in the core. If they will differ
1241 * then ExecBase is damaged
1244 if ((ExecBase->LibNode.lib_Version == exec_Version) &&
1245 (ExecBase->LibNode.lib_Revision == exec_Revision))
1248 * Really last thing. Check MaxLocMem and MaxExtMem fields
1249 * in ExecBase. First cannot be grater than 16MB and smaller
1250 * than 2MB, second, if is not zero then has to be grater
1251 * than 16MB
1254 if ((ExecBase->MaxLocMem >= 0x00200000) &&
1255 (ExecBase->MaxLocMem <= 0x01000000))
1257 if (ExecBase->MaxExtMem && ((ULONG)ExecBase->MaxExtMem < 0x01000000))
1259 return 0;
1261 return 1;
1267 return 0;
1270 void _aros_not_implemented()
1275 * RomTag scanner.
1277 * This function scans kernel for existing Resident modules. If two modules
1278 * with the same name are found, the one with higher version or priority wins.
1280 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
1281 * checksummed. If checksum is proper and all memory pointed in KickMemPtr may
1282 * be allocated, then all modules from KickTagPtr are added to RT list
1284 * Afterwards the proper RomTagList is created (see InitCode() for details) and
1285 * memory after list and nodes is freed.
1288 struct rt_node
1290 struct Node node;
1291 struct Resident *module;
1294 ULONG **exec_RomTagScanner()
1296 struct ExecBase *SysBase = *(struct ExecBase **)4UL;
1298 struct List rtList; /* List of modules */
1299 UWORD *ptr = (UWORD*)0x00100000; /* Start looking here */
1301 struct Resident *res; /* module found */
1303 int i;
1304 ULONG **RomTag;
1306 /* Initialize list */
1307 NEWLIST(&rtList);
1309 kprintf("Resident modules (addr: pri version name):\n");
1311 /* Look in whole kernel for resident modules */
1314 /* Do we have RTC_MATCHWORD? */
1315 if (*ptr == RTC_MATCHWORD)
1317 /* Yes, assume we have Resident */
1318 res = (struct Resident *)ptr;
1320 /* Does rt_MatchTag point to Resident? */
1321 if (res == res->rt_MatchTag)
1323 /* Yes, it is Resident module */
1324 struct rt_node *node;
1326 /* Check if there is module with such name already */
1327 node = (struct rt_node*)FindName(&rtList, res->rt_Name);
1328 if (node)
1330 /* Yes, there was such module. It it had lower pri then replace it */
1331 if (node->node.ln_Pri <= res->rt_Pri)
1333 /* If they have the same Pri but new one has higher Version, replace */
1334 if ((node->node.ln_Pri == res->rt_Pri) &&
1335 (node->module->rt_Version < res->rt_Version))
1337 node->node.ln_Pri = res->rt_Pri;
1338 node->module = res;
1342 else
1344 /* New module. Allocate some memory for it */
1345 node = (struct rt_node *)
1346 AllocMem(sizeof(struct rt_node),MEMF_PUBLIC|MEMF_CLEAR);
1348 if (node)
1350 node->node.ln_Name = res->rt_Name;
1351 node->node.ln_Pri = res->rt_Pri;
1352 node->module = res;
1354 Enqueue(&rtList,(struct Node*)node);
1358 /* Get address of EndOfResident from RomTag but only when it's
1359 * higher then present one - this avoids strange locks when
1360 * not all modules have Resident structure in .text section */
1361 ptr = ((ULONG)res->rt_EndSkip > (ULONG)ptr) ? (UWORD *)res->rt_EndSkip : ptr + 2;
1362 if ((ULONG)ptr & 0x01)
1363 ptr = (UWORD *)((ULONG)ptr+1);
1364 continue;
1368 /* Get next address... */
1369 ptr++;
1370 } while (ptr < (UWORD*)&_end);
1373 * By now we have valid (and sorted) list of kernel resident modules.
1375 * Now, we will have to analyze used-defined RomTags (via KickTagPtr and
1376 * KickMemPtr)
1378 #warning "TODO: Implement external modules!"
1381 * Everything is done now. Allocate buffer for normal RomTag and convert
1382 * list to RomTag
1385 ListLength(&rtList,i); /* Get length of the list */
1387 RomTag = AllocMem((i+1)*4,MEMF_PUBLIC | MEMF_CLEAR);
1389 if (RomTag)
1391 int j;
1392 struct rt_node *n;
1394 for (j=0; j<i; j++)
1396 n = (struct rt_node *)RemHead(&rtList);
1397 kprintf("+ 0x%08.8lx: %4d %3d \"%s\"\n",
1398 n->module,
1399 n->node.ln_Pri,
1400 n->module->rt_Version,
1401 n->node.ln_Name);
1402 RomTag[j] = (ULONG*)n->module;
1404 FreeMem(n, sizeof(struct rt_node));
1406 RomTag[i] = 0;
1409 return RomTag;
1412 struct vbe_controller my_vbe_control;
1413 struct vbe_mode my_vbe_mode;
1415 unsigned char setupVesa(struct multiboot *mbinfo)
1417 char *str = mbinfo->cmdline;
1418 char *vesa = strstr(str, "vesa=");
1419 short r;
1420 unsigned char palwidth = 0;
1422 if (vesa)
1424 long x=0, y=0, d=0;
1425 long mode, setmode;
1426 unsigned long vesa_size = (unsigned long)&_binary_vesa_size;
1427 void *vesa_start = &_binary_vesa_start;
1428 vesa+=5;
1430 while (*vesa && *vesa != ',' && *vesa != 'x' && *vesa != ' ')
1432 x = x*10 + *vesa++ - '0';
1434 vesa++;
1435 while (*vesa && *vesa != ',' && *vesa != 'x' && *vesa != ' ')
1437 y = y*10 + *vesa++ - '0';
1439 vesa++;
1440 while (*vesa && *vesa != ',' && *vesa != 'x' && *vesa != ' ')
1442 d = d*10 + *vesa++ - '0';
1445 rkprintf("[VESA] module (@ %p) size=%d\n", &_binary_vesa_start, &_binary_vesa_size);
1446 memcpy((void *)0x1000, vesa_start, vesa_size);
1447 rkprintf("[VESA] Module installed\n");
1449 rkprintf("[VESA] BestModeMatch for %dx%dx%d = ",x,y,d);
1450 mode = findMode(x,y,d);
1452 getModeInfo(mode);
1454 rkprintf("%x\n",mode);
1455 if (modeinfo->mode_attributes & 0x80)
1456 setmode = mode | 0x4000;
1457 else
1458 setmode = mode;
1459 r = setVbeMode(setmode);
1460 if (r == 0x004f) {
1461 rkprintf("\x03");
1462 if (controllerinfo->capabilities & 0x01)
1463 paletteWidth(0x0800, &palwidth);
1464 else
1465 palwidth = 6;
1466 memcpy(&my_vbe_mode, modeinfo, sizeof(struct vbe_mode));
1467 memcpy(&my_vbe_control, controllerinfo, sizeof(struct vbe_controller));
1468 mbinfo->vbe_mode_info = (ULONG)&my_vbe_mode;
1469 mbinfo->vbe_control_info = (ULONG)&my_vbe_control;
1470 mbinfo->flags |= MB_FLAGS_GFX;
1471 mbinfo->vbe_mode = mode;
1472 } else
1473 rkprintf("[VESA] mode setting error: 0x%04X\n", r);
1475 return palwidth;
1478 AROS_LH1(struct ExecBase *, open,
1479 AROS_LHA(ULONG, version, D0),
1480 struct ExecBase *, SysBase, 1, Exec)
1482 AROS_LIBFUNC_INIT
1484 /* I have one more opener. */
1485 SysBase->LibNode.lib_OpenCnt++;
1486 return SysBase;
1487 AROS_LIBFUNC_EXIT
1490 AROS_LH0(BPTR, close,
1491 struct ExecBase *, SysBase, 2, Exec)
1493 AROS_LIBFUNC_INIT
1495 /* I have one fewer opener. */
1496 SysBase->LibNode.lib_OpenCnt--;
1497 return 0;
1498 AROS_LIBFUNC_EXIT
1501 AROS_LH0I(int, null,
1502 struct ExecBase *, SysBase, 4, Exec)
1504 AROS_LIBFUNC_INIT
1505 return 0;
1506 AROS_LIBFUNC_EXIT
1510 We temporarily redefine kprintf() so we use the real version in case
1511 we have one of these two fn's called before AROSSupportBase is ready.
1514 #undef kprintf
1515 #undef rkprintf
1516 #undef vkprintf
1518 #define kprintf(x...)
1519 #define rkprintf(x...)
1520 #define vkprintf(x...)
1522 struct Library * PrepareAROSSupportBase(void)
1524 struct AROSSupportBase *AROSSupportBase =
1525 AllocMem(sizeof(struct AROSSupportBase), MEMF_CLEAR);
1527 AROSSupportBase->kprintf = (void *)kprintf;
1528 AROSSupportBase->rkprintf = (void *)rkprintf;
1529 AROSSupportBase->vkprintf = (void *)vkprintf;
1531 NEWLIST(&AROSSupportBase->AllocMemList);
1533 #warning "FIXME Add code to read in the debug options"
1535 return (struct Library *)AROSSupportBase;
1538 /* IntServer:
1539 This interrupt handler will send an interrupt to a series of queued
1540 interrupt servers. Servers should return D0 != 0 (Z clear) if they
1541 believe the interrupt was for them, and no further interrupts will
1542 be called. This will only check the value in D0 for non-m68k systems,
1543 however it SHOULD check the Z-flag on 68k systems.
1545 Hmm, in that case I would have to separate it from this file in order
1546 to replace it...
1548 AROS_UFH5S(void, IntServer,
1549 AROS_UFHA(ULONG, intMask, D0),
1550 AROS_UFHA(struct Custom *, custom, A0),
1551 AROS_UFHA(struct List *, intList, A1),
1552 AROS_UFHA(APTR, intCode, A5),
1553 AROS_UFHA(struct ExecBase *, SysBase, A6))
1555 AROS_USERFUNC_INIT
1557 struct Interrupt * irq;
1559 ForeachNode(intList, irq)
1561 if( AROS_UFC4(int, irq->is_Code,
1562 AROS_UFCA(struct Custom *, custom, A0),
1563 AROS_UFCA(APTR, irq->is_Data, A1),
1564 AROS_UFCA(APTR, irq->is_Code, A5),
1565 AROS_UFCA(struct ExecBase *, SysBase, A6)
1567 break;
1570 AROS_USERFUNC_EXIT